; BIOS.ASM   VERSION 1.31 REV 0     12/13/76
;
; BASIC I/O SYSTEM FOR IMSAI CP/M
;
;VERSION 0.0  GE  8/76
;         LATER VERSIONS BY JRB

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

;NUMBER OF DISK DRIVES IN SYSTEM
NDISKS  EQU     2

;MEMORY SIZE
MEMT    EQU     4000H           ;BEFORE RELOCATION WITH CPM PROGRAM

;WHERE TO ENTER CP/M SYSTEM AFTER WARM OR COLD BOOT:
CPMB    EQU     MEMT-1800H

BIOS    EQU     MEMT-3*256      ;LOCATION OF BASIC I/O SYSTEM
MESSAGE EQU     BIOS+33H        ;LOCATION OF SIGN-ON MSG TEXT
LOGDISK EQU     4               ;WHERE CPP PUTS LOGGED DISK #
BIOSTOR EQU     40H             ;WHERE BIOS STORAGE IS IN PAGE 0 RAM
FIFSTRING EQU   BIOSTOR         ;FLOPPY INTERFACE COMMAND STRING

;WARM BOOT ENTRY INTO BOOTSTRAP ROUTINE ON TRACK 0, SECTOR 1
WBOOTE  EQU     3
;
; I/O ASSGNMENT BYTE IN LOWER RAM
IOBYTE  EQU     3
;
; I/O PORT EQUATES
;
DISK    EQU     0FDH
SPTR    EQU     0               ;FIF STRING POINTER USED BY BIOS
TTY     EQU     02H
TTYS    EQU     03H
CRT     EQU     04H
CRTS    EQU     05H
;
;LINE PRINTER
PRINTER EQU     0F6H            ;OUTPUT PORT
PINIT   EQU     80H             ;INITIALIZE COMMAND
POFF    EQU     82H             ;TURN OFF MOTOR, FORM FEED
PRINTERS EQU    PRINTER         ;STATUS PORT IS SAME AS OUTPUT PORT
;PREADY EQU     XXX             ;MASK FOR PRINTER READY STATUS
;NO STATUS CHECK NEEDED AFTER SENDING COMMANDS OR SINGLE CHARS
;ANYTHING SEND TO PRINTER WITH B7=0 IS TAKEN AS ASCII CHAR TO PRINT

;
; EQUATES FOR ASCII CHARACTERS
;
CTRLC   EQU     3
TAB     EQU     9
LF      EQU     0AH
FF      EQU     0CH
CR      EQU     0DH
CTRLZ   EQU     1AH
UNDERLINE EQU   5FH
RUBOUT  EQU     7FH
;
        ORG     BIOS            ;ORIGIN EQUATED ABOVE
;
; ENTRY POINT TABLE
;
ENTAB:  JMP     CPMB            ;COLD START. BOOT HAS DONE ALL INIT, GO DIRECT TO CP/M
        JMP     WBOOT           ;COME HERE TO INITIATE REBOOT (VIA LOCATION 0)
        JMP     CONSTAT
        JMP     CONIN
        JMP     CONOUT
        JMP     LIST
        JMP     PUNCH
        JMP     READER
        JMP     HOME
        JMP     SELDSK
        JMP     SETTRK
        JMP     SETSEC
        JMP     SETDMA
        JMP     READ
        JMP     WRITE
        JMP     NXM             ;FOR RESTART 7: GIVE ERROR MESSAGE
        JMP     CPMB            ;WARM BOOT RETURNS HERE. GO DIRECT TO CP/M.
;
; SIGN-ON MESSAGE, TYPED BY BOOT ROUTINE
MESSAGE: DB     CR,LF,'IMSAI 16K CP/M VERS 1.31 ',0
        DB      '(C) 1976'
;
; ****************************************
;
;       DISK ROUTINES
;

;
; READ FROM SELECTED DRIVE/TRACK/SECTOR
;
READ:   LDA     CMD
        ANI     0FH             ;STRIP OLD CMD
        ORI     20H             ;CMD=READ
        JMP     W1              ;GO DO IT
;
; WRITE TO SELECTED DRIVE/TRACK/DISK
;
WRITE:  LDA     CMD
        ANI     0FH             ;STRIP OLD CMD
        ORI     10H             ;CMD=WRITE
W1:     STA     CMD
;
; EXECUTE COMMAND STRING
;
        PUSH    B               ;WARM BOOT REQUIRES BC PRESERVED
        MVI     C,15            ;RETRY COUNT: KEEP AT IT!
EX0:    LXI     H,STAT          ;POINT AT STATUS
        XRA     A
	MOV     M,A             ;ZERO STAT BYTE
        OUT     DISK            ;EXEC CMD STRING
EX1:    ADD     M               ;GET STATUS
        JZ      EX1             ;LOOP UNTIL STAT<>0
        CPI     1               ;TEST FOR EXACT GOOD RETURN
        JZ      EX2             ;GO EXIT IF GOOD
;DISC ERROR. CONTROLLER HAS ALREADY RETRIED CRC ERRORS 10 TIMES.
        CPI     0A1H            ;TEST FOR NOT READY
        JZ      EX0             ;WAIT FOREVER FOR DOOR TO BE CLOSED
;OTHER ERRORS, DISPLAY CODE IN LIGHTS
        CMA                     ;CAUSE LIGHTS DISPLAY COMPLEMENT
        OUT     0FFH            ;TO LIGHTS
;HOME THE DRIVE - IT SEEMS TO HELP
        MVI     A,2FH           ;HOMES ALL DRIVES
        OUT     DISK
        DCR     C
        JNZ     EX0
EX2:
        ANI     0F0H            ;ISOLATE ERROR CLASS
        RAR                     ;PUT IN LOWER HALF BYTE
        RAR
        RAR
        RAR
        POP     B
        RET
;
;  ALL DRIVES TO TRACK 0
;AND SET TRACK 0 FOR NEXT OP
;
;CLOBBERS C
HOME:   MVI     A,02FH
        OUT     DISK
        MVI     C,0
        ;JMP    SETTRK
;
; SET TRACK. GET IN REG C.
;
SETTRK: MOV     A,C
        STA     TRK+1
        RET
;
; SET SECTOR. GET IN REG C.
;
SETSEC: MOV     A,C
        STA     SECT
        RET
;
; SET DMA BUFFER ADDRESS.
;   GET IN REG BC.
;
SETDMA: MOV     A,C
        STA     BUFADR
        MOV     A,B
        STA     BUFADR+1
        RET
;
; SELECT DISK DRIVE. GET IN REG C.
;   C=0 FOR DRIVE 0, C=1 FOR DRIVE 1
;
;CLOBBERS BC.
SELDSK: MOV     A,C
        CPI     NDISKS
        ;RP                     ;TOO BIG. DO SOMETHING REASONABLE
        MVI     A,80H           ;TRANSLATE TO IMSAI BIT
SD1:    RLC
        DCR     C
        JP      SD1
        STA     CMD
        RET
;
; ****************************************
;
;       LOGICAL DEVICE ROUTINES
;
;THESE ROUTINES USE VARIOUS PHYSICAL DEVICES
;  DEPENDING ON CONTENTS OF IOBYTE
;

;
; CONSOLE STATUS
;
CONSTAT: CALL   CONS            ;GETS STATUS OF SPECIFIC DEVICE
        ORA     A
        RZ                      ;IF NOT READY RETURN 0 IN A
        MVI     A,0FFH          ;ELSE RETURN FF
        RET
;
CONS:   LDA     IOBYTE          ;USE BITS 1-0 TO DETERMINE CONSOLE DEVICE
        CALL    RLCDISPATCH
        DW      TTYSTAT
        DW      CRTSTAT
        DW      READERSTAT      ;2: BATCH MODE, USE READER DEVICE
        DW      NULLSTAT        ;3: UNASSGNED CHANNEL
;
;READER STATUS FOR BATCH MODE: NEVER A CHARACTER READY.
;THIS IS CAUSE PRESENCE OF A CHARACTER FREQUENTLY MEANS
;"ABORT WHAT YOU'RE DOING".
READERSTAT: XRA A
        RET
;
; CONSOLE IN
;
CONIN:  LDA     IOBYTE
        CALL    RLCDISPATCH
        DW      TTYIN           ;0: TTY
        DW      LSCRTIN         ;1: CRT
                                ;CHANGE ABOVE TO 'CRTIN' TO GET RID OF SPECIAL FEATURE
        DW      READER          ;2: BTACH MODE: READER INPUT
        DW      NULLI           ;3: UNASSIGNED CHANNEL
;
; CONSOLE OUT
;
;MUST PRESERVE HL FOR NXM AND BOOTSTRAP
CONOUT: LDA     IOBYTE
        CALL    RLCDISPATCH     ;GO TO ONE OF FOLLOWING ADDRESSES
        DW      TTYOUT          ;BITS=0: USE TTY AS CONSOLE
        DW      CRTOUT          ;1: CRT
        DW      LIST            ;2: BATCH MODE: OUTPUT TO LIST DEVICE
        DW      NULLO           ;3: UNASSIGNED
;
; LIST OUT
;
LIST:   LDA     IOBYTE
        RLC                     ;BITS 7-6 TO 2-1
        RLC
        CALL    RLCDISPATCH
        DW      TTYOUT          ;0: TTY
        DW      CRTOUT          ;1: CRT
        DW      LPTOUT          ;2: LINE PRINTER
        DW      NULLO           ;3: UNASSIGNED
;
; PUNCH OUT
;
PUNCH:  LDA     IOBYTE          ;BITS 4-5 TO 1-2
        RRC
        RRC
        RRC
        CALL    DISPATCH
        DW      TTYOUT          ;0: TTY
        DW      PUNO            ;1: HIGH SPEED PUNCH
        DW      NULLO           ;2: UNASSIGNED
        DW      NULLO           ;3: UNSASSIGNED
;
; READER IN
;
READER: LDA     IOBYTE          ;BITS 3-2 TO 2-1
        RRC
        CALL    DISPATCH
        DW      TTYIN           ;0: TTY
        DW      RDRIN           ;1: HIGH SPEED
        DW      NULLI           ;2: UNASSIGNED
        DW      NULLI           ;3: UNASSIGNED
;
;SUBROUTINE TO DISPATCH TO ONE OF 4 FOLLOWING ADDRESSES
;DEPENDING ON IOBYTE BITS CALLER HAS POSITIONED IN
;BITS 2 AND 1 OF A
;RETURN TO SUBROUTINE CALL PRIOR TO CALL TO DISPATCH.
RLCDISPATCH: RLC
DISPATCH: ANI   06H             ;MASK BITS
        XTHL                    ;SAVE CALLER'S H, GET TABLE ADDRESS
        PUSH    D               ;**
        MOV     E,A
        MVI     D,0             ;SET UP FOR DAD
        DAD     D               ;INDEX INTO TABLE
        MOV     A,M
        INX     H
        MOV     H,M             ;TABLE WORD TO HL
        MOV     L,A             ;..
        POP     D               ;**
        XTHL                    ;PUT ADDRESS OF ROUTINE, GET CALLER'S H
        RET                     ;GO TO ROUTINE !
;
; ****************************************
;
;       PHYSICAL DEVICE ROUTINES
;
;  ADDRESSED BY LOGICAL DEVICE ROUTINES ABOVE,
;ALSO TTY AND CRT MAY HAVE EXTERNAL ENTRY POINTS

;
; TELETYPE INPUT
;
TTYIN:  CALL    TTYSTAT
        JZ      TTYIN           ;WAIT FOR A CHAR TO BE AVAILABLE
        IN      TTY             ;INPUT IT
        ANI     7FH             ;REMOVE PARITY
        RET
;
TTYSTAT:                        ;USED HERE AND IN CONSTAT ABOVE
        IN      TTYS            ;GET STATUS
        ANI     02H             ;MASK BITS
        RET                     ;A IS NON-0 IF CHAR AVAILABLE
;
; TELETYPE OUTPUT
;
;CLOBBERS DE. BOOT DEPENDS ON PRESERVING HL
;MUST PRESERV HL FOR NXM, BOOTSTRAP
TTYOUT: IN      TTYS            ;STATUS
        RRC                     ;TEST BIT 0
        JNC     TTYOUT          ;WAIT TILL READY TO ACCEPT CHARACTER
        MOV     A,C
        OUT     TTY             ;OUTPUT THE CHARACTER
        CPI     CR
        RNZ                     ;DONE EXCEPT CR
;DELAY 100 MSEC FOR CR, FOR SLOW-RETURNING TERMINALS
        LXI     D,10500D
TTYWT1: DCX     D
        ORA     D               ;DEPENDS ON AT=0 AT ENTRY ROUTINE
        JP      TTYWT1          ;LOOP TAKES 9.5 USEC PER COUNT
        RET
;
; CRT INPUT
;
CRTIN:  CALL    CRTSTAT
        JZ      CRTIN
        IN      CRT
        ANI     7FH
        RET
;
CRTSTAT: IN     CRTS
        ANI     02H
        RET
;
;MORE CONVENIENT CRT INPUT LEAR-SIEGLER ADM-3
LSCRTIN:
        CALL    CRTIN           ;GET CHAR FROM REGULAR ROUTINE
;IGNORE BREAK KEY - ITS EASY TO FUMBLE AND HIT IT
        JZ      LSCRTIN
;CONVERT UNDERLINE (ARROW ON OLDER KEYBOARDS) TO RUBOUT
;SO IT ISN'T NECESSARY TO USE SHIFT KEY TO CORRECT ERRORS
;NOT DESIRABLE IF YOUR KEYBOARD HAS BACK ARROW.
        CPI     UNDERLINE
        RNZ
        MVI     A,RUBOUT
        RET
;
; NOTE: TYPEING ^Z TO THE EDITOR ERASES THE SCREEN ON YOUR ADM-3,
; OPEN IT UP AND SET THE 'CLEAR SCREEN' SWITCH TO 'DISABLE'.

;
; CRT OUTPUT
;
;MUST PRESERVE HL FOR BOOT, NXM
;CLOBBERS DE
CRTOUT: IN      CRTS
        RRC
        JNC     CRTOUT
        MOV     A,C
        OUT     CRT
        CPI     CR
        RNZ
;HOOK FOR USER TO PATCH IN CR WAIT IF DESIRED ON THIS CHANNEL
        LXI     D,1             ;PUT COUNT HERE A LA TTYOUT ABOVE
        JMP     TTYWT1
;
; LINE PRINTER OUT
;
LPTOUT:
; INSERT A STATUS CHECK HEERE TO BE SAVE ?
        MOV     A,C             ;THE CHARACTER
        OUT     PRINTER
        RET
;
; NULL DEVICE, FOR UNDEFINED DEVICES.
;
;FOR UNSASSIGNED AND UNIMPLEMENTED INPUT DEVICES,
;HERE IS AN INFINITE SOURCE OF EOF'S:
NULLI:  MVI     A,CTRLZ
        RET
NULLSTAT EQU    NULLI           ;CHARACTER ALWAYS READY

;DON'T USE CRT FOR UNASS INPUT DEVICES CAUSE IF THERE
; IS NO CRT ON SYSTEM BUT INTERFACE BOARD IS PRESENT,
; SYSTEM WILL HANG.
;
;FOR UNASS AND UNIMP OUTPUT DEVICES, USE CRT.
; IF NO CRT IS PRESENT, THIS IS AN INFINITE DATA SINK.
NULLO   EQU     CRTOUT
;
; HERE IS WHERE TO PUT HIGH SPEED READER DRIVER
;
RDRIN   EQU     NULLI           ;MEANWHILE, USE NULL DEVICE
RDRSTAT EQU     NULLSTAT
;
; HERE IS WHERE TO PUT HIGH SPEED PUNCH DRIVER
PUNO    EQU     NULLO           ;MEANWHILE, USE NULL DEVICE
;
; ****************************************
;
;       STARTUP & RESTART STUFF
;

; RESTART 7 ROUTINE. PRESUMABLY MEANS JMP TO NON-EXISTENT MEMORY
;       TYPES "CRASH" AND TOP OF STACK (PRESUMED TO BE PC)
;       AND BYTE TOP OF STACK POINTS TO
;
NXM:    POP     B               ;GET PC OF CRASH (OR MAYBE GARBAGE)
        LXI     SP,100H         ;SET UP STACK BELOW 100H
        PUSH    B               ;SAVE THAT PC
;TYPE "CRASH"
        LXI     H,NXMMSG
        CALL    CONOMSG
;TYPE WHAT IS PROBABLY THE PC OF THE PROBLEM
        POP     H               ;GET WHAT WAS ON STACK AT ENTRY TO NXM
        MOV     A,H             ;HI ORDER BYTE
        CALL    HOUT            ;HEX OUTPUT A
        MOV     A,L             ;LO ORDER BYTE
        CALL    HOUT
;TYPE BYTE TOP OF STACK-1 POINTS TO: THIS MIGHT BE THE INSTRUCTION
; THAT CAUSED CRASH (RST-7, ETC)
        MVI     C,' '
        CALL    CONOUT          ;TYPE A SPACE
        DCX     H               ;POINT ONE LESS
        MOV     A,M             ;GET BYTE
        CALL    HOUT            ;OUTPUT UT
;REBOOT THE SYSTEM, SAME AS WARM START
        ;JMP    WBOOT
;
; ROUNTINE TO INITIALIZE WARM RESTART
;
;SET UP TO
;READ UNIT A, TRACK 0, SECTOR 1 TO LOCATION 0
WBOOT:  MVI     A,1
        STA     CMD             ;UNIT 0
        STA     SECT            ;SECTOR 1
        LXI     H,0
        SHLD    TRK             ;TRACK 0
        SHLD    BUFADR          ;RAM LOCATION 0
;
;PRESERVE IOBYTE IN B, SELETED DISK IN C
;(BOOT DOES NOT ALTER THESE REGISTERS)
        LDA     LOGDISK         ;CCP SETS THIS.
        MOV     C,A
        LDA     IOBYTE
        MOV     B,A
;
;NOW DO READ - CLOBBERS IOBYTE, DISKN
        CALL    READ            ;PRESERVE BC
;
;GO TO EOUTINE READ FROM SECTOR 1
        JMP     WBOOTE
;
;ROUTINE READ FROM SECTOR 1 RETURNS TO WBOOTR ENTRY TO THIS PACKAGE.
;ENTRY CURRENTLY JMPS DIRECTLY TO CONSOLE COMMAND PROCESSOR.
;
;OUT OF LINE STUFF FOR NXM
;
;TYPE MESSAGE HL POINTS TO ON CONSOLE. TERMINATED BY 0 BYTE
CONOMSG:
        MOV     A,M             ;GET A CHAR OF MESSAGE
        ORA     A               ;SET FLAGS
        RZ                      ;DONE IF 0 BYTE
        MOV     C,A             ;TO C-REG FOR CONOUT
        CALL    CONOUT          ;OUTPUT IT ON CONSOLE
        INX     H               ;POINT NEXT CHARACTER
        JMP     CONOMSG         ;KEEP OUTPUTTING TO END

NXMMSG: DB      'CRASH ',0      ;TEXT USED BY "NXM" ROUTINE
;
;HEX OUTPUT (A) TO CONSOLE
HOUT:   PUSH    PSW
        RRC
        RRC
        RRC
        RRC
        CALL    HOUTNIBL
        POP     PSW
HOUTNIBL:
        ANI     0FH             ;MASK 4 BITS
        CPI     10              ;IS IT A OR BIGGER
        JM      HNBL1           ;IF NO
        ADI     'A'-'0'-10      ;YES, ADD DIFFERENCE BETWEEN ASCII A AND 9+1
HNBL1:  ADI     '0'             ;CONVERT IT TO ASCII CHARACTER
        MOV     C,A             ;TO C REGISTER FOR CONOUT
        JMP     CONOUT          ;PRINT IT AND RETURN
;
ENDBIOS:
;
; I/O VARIABLES
;
;IN PAGE 0 RAM

        ORG     BIOSTOR
;
; DISC INTERFACE COMMAND STRING
FIFSTRING:
CMD:    DS      1
STAT:   DS      1
TRK:    DS      2
SECT:   DS      1
BUFADR: DS      2

;
; OLD ENTRY POINT FOR SYS
;       OFFICIAL ENTRY IS NOW VIA 5, BUT SOME PROGRAMS MAY STILL USE THIS
;
        ORG     MEMT-3
        JMP     NXM             ;GO TO NXM ROUTINE WHICH WILL PRINT LOC OF "CALL 3FFD"
;
        ORG     ENDBIOS         ;MAKES ASSEMBLER TYPE OUT END OF VARIABLE CODE

        END
