; BOOT.ASM  VER 1.31 REV 0   JRB  12/13/76
;
; IMSAI CP/M BOOTSTRAP ROUTINE
;
;THIS PROGRAM RESIDES ON TRACK 0, SECTOR 1 AND 2 OF
;ALL CP/M SYSTEM DISKS AND IS READ INTO RAM AT
;LOCATION 0 AND EXECUTED FOR BOTH COLD AND WARM
;START BOOTSTRAPS.


; COPYRIGHT (C) 1976,
;       IMSAI MANUFACTURING CORP.
;       14860 WICKS BLVD, SAN LEANDRO, CA 94577, USA

;
; SYSTEM RAM EQUATES
;
BBASE   EQU     0               ;WHERE THIS PROGRAM RUNS
BBASE2  EQU     80H             ;WHERE SECTOR 2 OF THIS PROGRAM RUNS
MEMT    EQU     4000H           ;TOP OF MEMORY, BEFORE RELOCATION BY CPM PROGRAM
SYSBOTTOM EQU   MEMT-1800H      ;FIRST LOCATION OCCUPIED BY SYSTEM
ENTRYPOINT EQU  MEMT-4*1024+256+6 ;WHERE SYSTEM CALLS ENTER SYSTEM
BIOS    EQU     MEMT-300H       ;WHERE BASIC I/O SYSTEM ENTRIES ARE
BOOTR   EQU     BIOS            ;WHERE COLD BOOT EXITS TO
WBOOT   EQU     BIOS+3          ;WHERE TO GO TO INITIATE WARM BOOT
                                ;(IE TO GET THIS PROGRAM READ IN AND ENTERED)
CONOUT  EQU     BIOS+0CH        ;ROUTINE TO OUTPUT CHARACTER TO CONSOLE
NXM     EQU     BIOS+02DH       ;WHERE RESTART 7 SHOULD GO
WBOOTR  EQU     BIOS+030H       ;WHERE WARM BOOT RETURNS TO
FIFSTRING EQU   40H             ;WHERE TO PRESET FIF STRING PTR 0 TO FOR BIOS
MESSAGE EQU     BIOS+33H        ;LOCATION OF SIGN-ON MSG TEXT IN BIOS
                                ;N. B. ABOVE MUST MATCH VALUES USED IN BIOS!
ENTRYJMP EQU    5               ;WHERE TO PUT JMP ENTRYPOINT
WBOOTJMP EQU    0               ;WHERE TO PUT JMP REBOOT
IOBYTE  EQU     3               ;LOCATION OF IO STATUS BYTE

;
; SYSTEM DISK LAYOUT EQUATES
;
FTRK    EQU     0               ;FIRST TRACK TO READ
LTRK    EQU     1               ;LAST TRACK TO READ
NSECTB4SYSTEM EQU 1             ;NUMBER OF SECTORS TO SKIP BEFORE READING SYSTEM:
                                ;THE ONE SECTOR CONTAINING THIS PROGRAM
                                ;SECOND SECTOR OF THIS PROGRAM IS TREATED
                                ;AS PART OF SYSTEM EXCEPT IT IS REDIRECTED TO 80H
;AFTER SECTOR 2 SECTORS ON DISK ARE READ INTO MEMORY IN ORDER,
;STOPPING AT MEMT.

;
; I/O DEVICE CONFIGURATION EQUATES
;
DISK    EQU     0FDH            ;FLOPPY DISK PORT
;
PIC8    EQU     0F7H            ;PRI INT CNTRL BOARD. INITIALIZED, NOT USED.
;
SIOBD   EQU     0               ;BASE PORT # OF SIO BOARD
SIOS1   EQU     SIOBD+3         ;STATUS PORT OF IMSAI SERIAL I/O BOARD TO INITIALIZE
SIOS2   EQU     SIOBD+5         ;STATUS PORT OF THE OTHER...
SIOC    EQU     SIOBD+8         ;CONTROL PORT FOR SIO BOARD (BOTH CHANNELS)
;
PRINTER EQU     0F6H            ;IMSAI PTR-300 LINE PRINTER PORT
PINIT   EQU     80H             ;COMMAND TO INIT LINE PRINTER
POFF    EQU     82H             ;COMMAND TO TURN MOTOR OFF AND FORM FEED

;
; MISCELLANEOUS
;
SPTR    EQU     0               ;FIF STRING POINTER USED BY BIOS AND BOOT
FF      EQU     0CH             ;ASCII FORM FEED CHARACTER

;
;     THE BOOTSTRAP PORTION OF THIS PROGRAM READS
;EVERY NTH SECTOR ON ONE DISK REVOLUTION FOR SPEED,
;INTO APPROPRIATE MEMORY LOCATIONS. DISC CONTAINS
;DIRECT MEMORY IMAGE.
;       TO MAKE ITS ADDRESS INCREMENTING SCHEME WORK,
;THE PROGRAM MUST LOOP OVER AN INTEGRAL NUMBER OF TRACKS.
;       HOWEVER, THE PROGRAM DOES NO IO FOR SECTORS
;AT BEGINNING OF FIRST TRACK OR END OF LAST TRACK WHICH
;DO NOT CONTAIN INFORMATION TO BE READ.
;
;FLASH!; ANOTHER KLUDGE!; THE SYSTEM INITIALIZER TURNS OUT TO BE
;TOO BIG FOR ONE SECTOR AND THE DISK READER IS A VERY TIGHT FIT.
;THE MINIMUM MEMORY MODIFICATION TO READ TRACK 0, SECTOR 2 INTO
;LOCATION 80H AS THE REST OF THE INITIALIZER TURNS OUT TO BE
;TO ALTER THE RAM ADDRESS FOR THE LOWEST
;SECTOR READ. HENCE THE FOLLOWING 2 EQUATES ARE AS THOUGH
;THE SYSTEM STARTS 128 BYTES LOWER IN RAM THAN IT DOES.
;
FSTDMA  EQU     SYSBOTTOM-NSECTB4SYSTEM*128-128
                                ;WHERE 1ST SECTOR WOULD BE READ
                                ;IF IT WERE TO BE READ
FSTRDMA EQU     SYSBOTTOM-128   ;FIRST LOCATION TO REALLY READ INTO
                                ;EXCEPT SEE FLASH NOTE ABOVE
LSTDMA  EQU     MEMT            ;FIRST LOCATION BEYOND END OF PROGRAM
;
;PARAMETERS FOR SKEWING SCHEME
SKEW    EQU     5               ;READ EVERY 5TH SECTOR. CHANGE WITH
                                ;CARE!; 7 ALSO WORKS.
ETSCT   EQU     27              ;ENDTEST SECTOR NUMBER. 27 WORKS
                                ;FOR 5 AND 7, BUT OTHER SKEWS MAY
                                ;CHANGE THIS!
;
NSCTPT  EQU     26              ;NUMBER OF SECTORS PER TRACK
                                ;N.B. IF THIS CHANGES, REVIEW SKEW AND ETSCT!
FSCT    EQU     1               ;NUMBER OF FIRST SECTOR
SCTSIZ  EQU     128             ;SIZE OF SECTORS

STACK   EQU     100H            ;WHERE TO PUT STACK
;
;
        ORG     BBASE

        ;*************************************************
        ;* WARNING TO ANYONE ALTERING FOLLOWING CODE:    *
        ;* THERE IS SOMETHING ORG'D AT 40H A FEW LINES   *
        ;* DOWN. IF YOU INSERT INSTRUCTIONS BEFORE       *
        ;* IT, YOU MUST MOVE SOME INSTRUCTIONS           *
        ;* FROM ABOVE TO BELOW IT                        *
        ;*************************************************
;
; ENTRY VECTOR
;
        MVI     D,0FFH          ;COLD START, ENTERED BY HARDWARE BOOT
        DB      21H             ;LXI H, OP CODE: SKIP OVER MVI D,0
        ORG     BBASE+3
WBOOTE: MVI     D,0             ;WARM START. BIOS JMPS HERE AFTER READING SECTOR
                                ;1, TRACK 0. B AND C CONTAIN VALUES TO
                                ;PRESERVE!!
                ;FLAG IN D IS PRESERVED THRU DISK READ:
                ;NON-0 FOR COLD START, 0 FOR WARM START.


; ***********************************************************
;
;      ROUTINE TO READ SYSTEM OFF DISK
;
;
; REGISTER USE
;       A      SCRATCH
;       BC     WARM START PARAMETERS TO SAVE
;       D      WARM/COLD FLAG
;       E      SECTOR NUMBER
;       HL     RAM ADDRESS/SCRATCH
;       SP     SCRATCH/RAM ADDRESS
;   STACK IS NOT AVAILABLE UNTIL READ IS COMPLETE:
;   A SECTOR IS READ IN OVER IT.
;       N. B. DO NOT CLOBBER B, C, OR D !

;
; INITIALIZE TO READ OFF DISK
;
        MVI     A,10H+SPTR      ;"SET STRING PTR"
        OUT     DISK
        MVI     A,FIFSTRING AND 0FFH
        OUT     DISK            ;SET LO STRING ADDRESS
        XRA     A               ;MVI A,FIFSTRING SHR 8 AND 0FFH
        OUT     DISK            ;SET HI STRING ADDRESS
;
; INIT RAM ADDRESS IN HL
;
        LXI     H,FSTDMA
;
; TOP OF READ TRACKS LOOP
;
R0:     MVI     A,(FSCT-SKEW) AND 0FFH ;FIRST SECTOR
;
; TOP OF READ SECTOR LOOP
;
R1:     ADI     SKEW            ;COMPUTE NEXT SECTOR
        MOV     E,A             ;SAVE SECTOR NUMBER FOR PROGRAM
        STA     BSECT           ;STORE SECTOR FOR FLOPPY INTERFACE
        SHLD    BBUFAD          ;SET MEMORY ADDRESS FOR DISC
; DON'T READ IF OUT OF ADDR RANGE, BUT CONTINUE LOOPING
        SPHL                    ;RAM ADDRESS TO SP UNTIL INCREMENTED BELOW
        LXI     H,FSTRDMA       ;THIS MUST BE POSITIVE FOR RELOCATION
        ; NEGATE HL
            XRA A
            SUB L
            MOV L,A
            MVI A,0
            SBB H
            MOV H,A
        DAD     SP
        JNC     OK ;ADDR TOO LOW:PROVISION FOR THIS PROGRAM TO BE ON 1ST SCTR
        ;FLASH KLUDGE!; IF ADDRESS IS EXACTLY LOWEST, READ
        ;TO 80H INSTEAD. THIS GETS 2ND HALF OF THIS PROGRAM.
        MOV      A,L
        ORA      H
        JNZ      R1A
        LXI      H,BBASE2
        SHLD     BBUFAD
R1A:
        LXI      H,LSTDMA
        ;AGAIN, NEGATE HL
           XRA A
           SUB L
           JMP BOOT1

;
; PRE-INITIALIZED FIF COMMAND STRING
;
; STUCK IN THIS REDICULOUS PLACE CAUSE IT'S WHERE BIOS
; USES IT, AND IT SAVES THE FEW BYTES OF CODE IT TAKES
; TO SET STRING POINTER AGAIN IN BOOT.
;
        ORG     FIFSTRING
BCMD:   DB      21H             ;READ SECTOR, UNIT 0 COMMAND
BSTAT:  DB      0               ;STATUS BYTE
BTRK:   DB      0,FTRK          ;TRACK
BSECT:  DB      1               ;SECTOR
BBUFAD: DW      FSTDMA          ;BUFFER ADDRESS

BOOT1:                          ;NOW, BACK TO WHAT WE WERE DOING
           MOV L,A              ;FINISH NEGATING HL
           MVI A,0
           SBB H
           MOV H,A
        DAD     SP
        JC      OK              ;JMP IF ADDRESS TOO HI:
                                ;THIS IS TO ALLOW FOR SYSTEM LENGTH
                                ;BEEING OTHER THAN WHOLE # OF TRACK LENGTHS
;READ THIS SECTOR
R2:     XRA     A               ;HERE TO RETRY AFTER ERROR
        LXI     H,BSTAT         ;POINT STATUS BYTE
        MOV     M,A             ;ZERO STATUS BYTE
        ;N. B. A=0 IS ALSO COMMAND FOR DISK
        OUT     DISK            ;DO IT !
WAIT:   ADD     M               ;TOP OF WAIT LOOP
        JZ      WAIT            ;WAIT FOR FIF TO STORE NON-0 STATUS
        CPI     1               ;TEST FOR EXACT GOOD RETURN
        JZ      OK              ;GO INCREMENT TO NEXT SECTOR
;
;DISPLAY ERROR CODE IN LIGHTS
        CMA                     ;LIGHTS DISPLAY COMPLEMENT
        OUT     0FFH
        MVI     A,21H           ;RESTORE THE DRIVE - IT HELPS
        OUT     DISK
        JMP     R2              ;TRY AGAIN, AND AGAIN
OK:
;
; INCREMENT ADDRESSES WITH SKEW
;
;NEXT SECTOR: MOVE UP "SKEW" SECTORS, AND ADJUST
;MEMORY ADDRESS CORRESPONDINGLY
        MOV     A,E             ;SECTOR NUMBER TO A
                                ;("SKEW" IS ADDED TO THIS AT TOP OF LOOP)
        LXI     H,SKEW*SCTSIZ   ;MEM ADDR INCREMENT
;END OF PASS THRU THIS TRACK TEST
        CPI     NSCTPT+FSCT-SKEW
        JM      DADSP           ;GO UPDATE HL THEN READ. SECTOR IS IN A
;END OF TRACK TEST
        ;CPI    ETSCT-SKEW      ;TEST ON MAGIC NUMBER
                 ;N.B. MAGIC NUMBER IS SAME AS NUMBER JUST TESTED ON !
        JZ      NXTTRK          ;IF DONE THIS TRACK, GO INCREMENT TRACK
;RECYCLE THRU THIS TRACK, GETTING A DIFFERENT GROUP
;OF SPACED SECTORS
        SBI     NSCTPT          ;INCREMENT SECTOR #
        LXI     H,(SKEW-NSCTPT)*SCTSIZ ;MEMORY ADDRESS DECREMENT
DADSP:  DAD     SP              ;COMPUTE NEXT MEM ADDR, LEAVE IN HL
        JMP     R1              ;NOW GO READ. SECTOR IS IN A
        ;CODE ABOVE HERE MUST FIT BELOW 80H.
        ;BYTES 80H-EFH ARE READ IT BY THE TIME FIRST
        ;TRACK READ IS COMPLETE.
;NEXT TRACK
NXTTRK: DAD     SP              ;INCREMENT MEM ADDR
        LDA     BTRK+1          ;TRACK
        INR     A
        STA     BTRK+1
        CPI     LTRK+1          ;HAVE WE DONE LAST TRACK?
        JM      R0              ;NO, GO READ TRACK
;
; DONE READING FROM DISC !
;
;AT THIS POINT STACK CAN BE USED
        LXI     SP,STACK
;
; INITIALIZE BOTH CHANNELS OF IMSAI SERIAL INTERFACE BOARD
;
;IF SIO JUST BEEN RESET, IT EXPECTS A "MODE" THEN A "COMMAND".
;BUT IF IT HASN'T BEEN RESET (WARM START), IT IS NOT EXPECTING A "MODE".
;SO WE SEND IT A DUMMY THAT LEAVES IT EXPECTING A COMMAND REGARDLESS,
;THEN A RESET COMMAND (40H), THEN DESIRED MODE AND COMMAND.
        LXI     H,SIOSTRING
        MOV     A,M
SIOLUP: OUT     SIOS1
        OUT     SIOS2
        INX     H
        MOV     A,M
        ORA     A
        JNZ     SIOLUP
        XRA     A               ;TURN OFF INTERRUPTS AND
        OUT     SIOC            ;...CARRIER DETECT, BOTH CHANNELS
;
; INITIALIZE LINE PRINTER
;
        MVI     A,PINIT         ;PRINTER INITIALIZE COMMAND
        OUT     PRINTER
;
; PUT THE VARIOUS JUMPS IN LOWER RAM
;
        MVI     A,0C3H          ;"JMP" OP CODE
  ;"JMP REBOOT" AT 0
        LXI     H,WBOOT
        STA     WBOOTJMP
        SHLD    WBOOTJMP+1
  ;"JMP ENTRYPOINT" AT 5 FOR SYSTEM CALLS
        LXI     H,ENTRYPOINT
        STA     ENTRYJMP
        SHLD    ENTRYJMP+1
  ;"JMP NXM" FOR RESTART 7 (DDT WILL CHANGE IF USED). THIS IS ACCESSED AFTER
  ;  A JMP INTO NON-EXISTENT MEMORY, ALSO BY WRITE PROTECT VIOLATION ON RAM-4A
  ;  IF WIRED DIRECT TO "INT" LINE BY USER. AN IMSAI EXTENSION OF BIOS FUNCTIONS
        LXI     H,NXM
        STA     038H
        SHLD    038H+1
;
; INITIALIZE IOBYTE FROM SWITCHES
;
        IN      0FFH
        STA     IOBYTE
;
        MOV     A,D
        ORA     A
        JZ      WBOOT9          ;IF WARM RESTART
;
; COLD START ONLY:
;
;    SIGN-ON MESSAGE
        LXI     H,MESSAGE       ;MESSAGE TEXT IS IN BIOS
MSLOOP: MOV     C,M
        CALL    CONOUT          ;USE CHAR TYPING ROUTINE IN BIOS
        INX     H
        MOV     A,M
        ORA     A
        JNZ     MSLOOP
;
;    INITIALIZE IMSAI PRIORITY INTERRUP CONTROL BOARD
;       THIS CODE SETS IT AS THO A LEVEL 6 INT IS RUNNING,
;       TO DISABLE CHANNELS AND MINIMIZE CHANCE OF PROBLEM FROM
;       SPURIOUS INTERRUPT.
;       BUT CHANNEL 7 IS LEFT ACTIVE FOR USER TO USE FOR MEMORY
;       PROTECT VIOLATION, SINCE IMSAI CP/M DOES INTERCEPT RST-7'S
;    USERS USING OTHER INTERRUPTS MAY CHANGE THIS.
        MVI     A,00001001B
        OUT     PIC8
;
;     EXIT TO BIOS WITH DISK SELECTED IN C
        MVI     C,0             ;SAY SELECT DISK A
        JMP     BOOTR           ;EXIT TO BIOS
;
; WARM RESTART ONLY:
;       RESTORE I/O BYTE SAVED IN B REGISTER
;       SAVED LOGGED DISK NUMBER IN C IS USED BY CCP
;
WBOOT9: MOV     A,B
        STA     IOBYTE
        JMP     WBOOTR          ;GO TO BIOS WITH DISK # IN C

; BYTES TO SEND TO SIO STATUS PORTS
SIOSTRING: DB   0AEH,40H,0AEH,37H,0
        DB      '(C) 1976'

; NOTE THAT STACK WRITES OVER END OF THIS SECTOR

        END

