.Z80 ; ; *********************************************** ; SUBROUTINES TO SUPPORT ALL THE MODULES IN CBIOS ; *********************************************** ; ; ; This routine transfers control to the ; I/O driver indicated by the appropriate ; bits in IOBYTE at address (0003H) ; and save I/O port address pointer in ; register IX. Do LD C,(IX) to get a data ; port, LD C,(IX+1) to get a status port, ; and LD C,(IX+2) to get a number of mask ; bits from the I/O driver. ; ; ENTRY (SP) --> (DEVICE TYPE) ; (DEVICE 1 INDEX) ; (DEVICE 2 INDEX) ; (DEVICE 3 INDEX) ; (DEVICE 4 INDEX) ; IODISP: POP HL PUSH BC LD A,(HL) ; GET DEVICE TYPE LD D,A ; SAVE IT FOR LATER LD E,A OR A LD A,(IOBYTE) ; GET CURRENT IOBYTE JR Z,IODI20 ; IF NO SHIFTING NEEDED ; IODI10: RRCA ; ROTATE BYTE UNTIL DEVICE BITS DEC D ; ARE LINED UP WITH BIT #0 JR NZ,IODI10 ; IODI20: AND 03H ; MASK OFF DON'T CARE BITS LD C,A RLCA ADD A,C ;IOBYTE * 3 ; PUSH AF LD A,E ADD A,A LD B,A ADD A,A ADD A,B LD E,A ;E = DEVICE TYPE*6 POP AF ; LD IX,IOPTAB ;IO PORT ADDRESS TABLE ADD IX,DE ;OFFSET TO APPROPRIATE DEVICE TYPE LD E,A ADD IX,DE ;OFFSET ACCORDING TO IOBYTE INC HL ;ADDRESS OF DEVICE 1 DRIVER LD E,C ADD HL,DE LD E,(HL) ; GET DISPATCH ADDRESS INTO DE LD HL,DRIVER ADD HL,DE POP BC ; RESTORE BC LD E,(HL) INC HL LD D,(HL) EX DE,HL JP (HL) ; AND GO TO I/O ROUTINE ; ; KEYBOARD INTERRUPT SERVICE ROUTINE ; INTKEY: DI ; DISABLE SYSTEM INTERRUPT LD (KEYSTK),SP LD SP,KB_LOCSTK ; SET LOCAL STACK POINTER ; ; SAVE AF, BC REGISTERS IN LOCAL STACK PUSH BC PUSH AF ; IN A,(KBDDP) ; GET A BYTE OF CHAR LD B,A ; STORE IT FOR LATER BIT 7,A ; IS KEY RELEASED? JR Z,CHK80 ; YES, NO BELL SOUND NEEDED CPL ; COMPLEMENT KEY DATA CP 29 ; IS KEY CONTROL KEY JR Z,CHK80 ; IF SO, NO BELL SOUND NEEDED CP 42 ; IS KEY LEFT OR RIGHT SHIFT JR Z,CHK80 ; IF SO, NO BELL SOUND NEEDED CP 54 JR Z,CHK80 ; IS KEY ALT? CP 56 ; IF SO, NO BELL SOUND NEEDED JR Z,CHK80 LD A,(KEYCLK) ; IS KEYCLICK ON? OR A JR NZ,CHK80 ; NO,SKIP BELL SOUND ROUTINE LD A,0F0H ; SET FREQUENCY TO 0F0H BELAGAN: OUT (PRNTDP),A ; NOW, RING THE BELL ; ; CHECK KEYBOARD INPUT DATA IS LESS THEN 80H. ****8/9/83*** ; IF SO, DISREGARD KEY BOARD DISABLE. ; IF NOT, CHECK KEY BOARD DISABLE. ; CHK80: LD A,B IF TS803 OR TS803H OR TS800 CP 80H JR C,KB_ENABLE ELSE CP 1 ; IS KEY ESC? JR Z,CHK_KYB ; YES, CHECK KYB DISABLE CP 59 ; IS KEY BELOW MATRIX 59? JR C,KB_ENABLE ; YES, KYB DISABLE IS UNAFFECTED. ENDIF ;******** ****6/7/83*** ; CHECK KEYBOARD INPUT DISABLE FLAG ; BECAUSE ALPHA DRIVER ACTIVE. ;******** CHK_KYB: LD A,(KB_DISABLE) OR A JR NZ,EXITKX ; IF KBD DISABLE THEN IGNORE INPUT KEYS. ; ****6/7/83*** ; SAVE ALL REGISTERS IN LOCAL STACK KB_ENABLE: PUSH IX PUSH IY PUSH HL PUSH DE ; ; NOTE: TO IMPROVE KEYBOARD TYPE AHEAD "KEYBOARD FILTER" ; MUST RESIDE IN COMMON MEMORY INSTEAD OF PAGE #0 ; ; CALL KEYBOARD FILTER RESIDED IN PAGE 0 ; ENTRY: A = CURRENT KEY ; D = CONSOLE BUFFER SIZE ; HL = POINTER TO THE BEGINNING OF CONSOLE BUFFER ; LD A,B ; SET A = KEY LD HL,CONBUF ; SET HL = CONSOLE BUFFER POINTER LD D,BUFSIZ ; SET D = CONSOLE BUFFER SIZE LD B,0 LD C,BANKSW OUT (C),B ; SWITCH MEMORY BANK TO 0 CALL KBDFTR ; CALL KEYBOARD FILTER LD A,(C_BANK) OUT (BANKSW),A ; SWITCH BACK TO MEMORY BANK 1 POP DE ; RESTORE ALL REGISTERS POP HL POP IY POP IX EXITKX: ; XOR A ; SET FLAG THAT NEXT BYTE IS 1ST BYTE ; ;EXITKY: LD (BYTFLG),A ; SET BYTE-ORDER FLAG ; POP AF ; RESTORE AF, BC REGISTERS FROM LOCAL STACK POP BC ; LD SP,(KEYSTK) ; RESTORE STACK POINTER ; EI ; ENABLE SYSTEM INTERRUPT RETI ; ;KEYSTK: DEFS 2 ; USER STACK POINTER ; DEFS 32 ; 16 LEVELS OF STACK AREA ;KB_LOCSTK EQU $ ; KEYBOARD STACK START ADDRESS ; ; TIMER INTERRUPT SERVICE ROUTINE ; Keeps time and date. ; Provides capability to set and read time and date. ; Shuts off floppy disk motor after 5 sec of no access. ; TCOUNT: DI LD (TUSTACK),SP ; SAVE USER STACK LD SP,LSTACK ; SET STACK POINTER TO LOCAL PUSH AF PUSH HL ; LD HL,(MSECNT) INC HL LD (MSECNT),HL ; INCREMENT 16-BIT MS COUNTER ; LD HL,CLOCK CALL TCOUN4 ; COUNT 1/100 SEC. JP NZ,TEXIT ; SKIP IF NOT OVERFLOW 99 (BCD) ; IF XONDRV LD A,(XOFFTM) ; GET XOFF TIMER COUNTER OR A JR Z,TCOUN0 ; CHANGE TO XON-MODE INC A ; INCREMENT COUNTER LD (XOFFTM),A ; IF TIMER EXPIRED JR NZ,TCOUN0 ; THEN LD A,0FFH ; CHANEGE TO XON-MODE LD (XONOFF),A ENDIF ; TCOUN0: CALL FLOPOFF ; TURN OFF FLOPPY DISK? ; ; ELSE RESET PRECOUNTER AND ADD 1 TO SEC. ; CALL TCOUN1 CP 060H ; CHECK FOR SEC. OVERFLOW JP NZ,TEXIT ; SKIP IF NOT ; CALL TCOUN1 ; ADD 1 TO MINUTE COUNT CP 060H JR NZ,TEXIT ; SKIP IF NOT OVERFLOW ; ; ELSE RESET MINUTE COUNT AND ADD 1 TO HOUR ; CALL TCOUN1 CP 024H ; CHECK OVERFLOW JR NZ,TEXIT ; CALL TCOUN1 ; RESET HOUR TO 0 AND ADD 1 TO DATE COUNT CP 029H ; CHECK DATE = 29 JR C,TEXIT ; SKIP IF DATE < 29 ; CALL NC,CHKM28 ; IF DATE >= 29 THEN CHECK MONTH = FEB JR Z,TCOUN3 ; SKIP IF FEB 29TH ; LD A,(HL) ; CHECK DATE = 31 CP 031H CALL NC,CHKM30 ; IF DATE >= 30 THEN CHECK MONTH=4,6,9,11? JR Z,TCOUN3 ; SKIP IF MONTH = 4,6,9,11 ; LD A,(HL) CP 032H ; CHECK DATE = 32 JR C,TEXIT ; ; ADJUST MONTH AND RESET SET DATE = 1 ; TCOUN3: LD (HL),1 ; RESET DATE = 1 CALL TCOUN2 ; MONTH = MONTH + 1 CP 013H JR C,TEXIT ; SKIP IF MONTH < 13 LD (HL),1 ; RESET MONTH = 1 CALL TCOUN2 ; AND ADD 1 TO YEAR JR NZ,TEXIT ; SKIP IF LSB OF YEAR > 0 CALL TCOUN2 ; ELSE ADD 1 TO MSB OF YEAR COUNT TEXIT: POP HL POP AF LD SP,(TUSTACK) ; RESTORE USER STACK EI RETI ; TCOUN1: LD (HL),0 ; RESET BCD TO 0 ; TCOUN2: INC HL ; TCOUN4: LD A,(HL) ; ADD 1 TO NEXT COUNT ADD A,1 DAA LD (HL),A RET ; ; CHECK MONTH = 2 ; RETURN Z = 1 IF YES, ELSE Z = 0 ; CHKM28: INC HL LD A,(HL) DEC HL CP 2 RET ; ; CHECK MONTH = 4,6,9 OR 11 ; RETURN Z = 1, ELSE Z = 0 ; CHKM30: INC HL LD A,(HL) DEC HL CP 4 RET Z CP 6 RET Z CP 9 RET Z CP 011H RET ; ; DATE AND TIME INTERFACE ROUTINE ; ENTRY: READ CURRENT DATE AND TIME ; C-REG = 0 AND DE = DATE AND TIME BUFFER POINTER ; SET CURRENT DATE AND TIME ; C-REG = 1 AND DE = BUFFER POINTER ; RETURN: CURRENT DATE AND TIME IN USER BUFFER ; FORMAT: MM?DD?YYYY?HH?MM?SS?NN ; TOD: DEC C JR Z,SETOD ; SET CURRENT DATE AND TIME ; RDTOD: LD HL,MONTH CALL BCDASC ; CONVERT BCD TO ASCII AND SAVE INTO (DE) INC DE DEC HL ; ADDRESS DATE CALL BCDASC INC DE INC HL ; ADDRESS YEAR INC HL INC HL CALL BCDASC ; SAVE MSB OF YEAR DEC HL ; ADDRESS LSB OF YEAR CALL BCDASC ; SAVE LSB OF YEAR ; INC DE ; SKIP FILLER LD HL,HOUR CALL BCDASC ; SAVE HOUR INC DE DEC HL CALL BCDASC ; SAVE MINUTE INC DE DEC HL CALL BCDASC ; SAVE SECOND INC DE DEC HL CALL BCDASC ; SAVE 1/100 SEC LD A,(TINITF) ; SET A = INITIALIZE FLAG RET ; ; SET CURRENT DATE AND TIME ; SETOD: LD HL,MONTH CALL ASCBCD LD (HL),A ; SET MONTH INC DE DEC HL CALL ASCBCD LD (HL),A ; SET DATE INC DE LD HL,YEAR+1 CALL ASCBCD LD (HL),A ; SET YEAR MSB DEC HL CALL ASCBCD ; SET YEAR LSB LD (HL),A ; INC DE LD HL,HOUR CALL ASCBCD LD (HL),A ; SET HOUR DEC HL INC DE CALL ASCBCD LD (HL),A ; SET MINUTE DEC HL INC DE CALL ASCBCD LD (HL),A ; SET SECOND DEC HL XOR A LD (HL),A ; RESET 1/100 SEC COUNT TO 0 LD (TINITF),A ; SET DATE AND TIME INITIALIZE FLAG RET ; ; CONVERT 1 BYTE BCD TO 2 BYTE ASCII ; AND SAVE IT INTO (DE) ; BCDASC: LD A,(HL) RRA RRA RRA RRA CALL BCDAS1 LD A,(HL) BCDAS1: AND 0FH OR '0' LD (DE),A INC DE RET ; ; CONVERT 2 BYTE ASII DIGIT TO 1 BYTE BCD ; ASCBCD: LD A,(DE) RLA RLA RLA RLA AND 0F0H LD C,A ; SAVE MSN TO C-REG INC DE LD A,(DE) AND 0FH ; GET LSN OR C ; PACK IT INC DE RET ; ; TURN FLOPPY DRIVES MOTOR OFF? ; FLOPOFF: LD A,(FDTIME) ; MOTOR OFF DISABLE OR A RET Z DEC A ; TIME = TIME - 1 LD (FDTIME),A RET NZ ; EXIT IF NOT TIMEOUT LD A,11110110B ; SET MOTOR OFF OUT (DSELOP),A ; ELSE RESET DRIVE SELECT AND TURN MOTOR OFF XOR A LD (FDMOT),A ; SET MOTOR OFF INDICATION RET ; ; THIS ROUTINE SET UP TO CALL ROUTINES RESIDES IN EPROM ; EXCEPTS: IX: ADDRESS OF JUMP ROUNTINE RESIDES ; ROMSW: DI LD (USER_STACK),SP ; SAVE STACK POINTER IN IY REG LD SP,LOCSTK ; SWITCH TO LOCAL STACK PUSH AF ; XOR A OUT (BANKSW),A ; SWITCH BANK TO ZERO LD (C_BANK),A POP AF LD IY,RETADR ; GET RETURN ADDRESS PUSH IY PUSH BC ; SAVE JUMP TABLE ADDRESS EI ; ***** ENABLE INTERRUPT ***** RET ; GO TO JUMP TABLE ADDRESS RETADR: DI PUSH AF LD A,1 OUT (BANKSW),A ; RESTORE BANK TO 1 LD (C_BANK),A ; AND RESTORE STACK. POP AF LD SP,(USER_STACK) EI RET ; ; RETURN DE=ADDRESS OF INTERRUPT VECTOR TABLE ; FOR USER PROGRAM WANT TO USE 16-BIT COUNTER ; THAT INCREMENT AT EVERY 10 MS THEN ; DE-2=LSB COUNT, DE-1=MSB COUNT ; INTADD: LD DE,INTVEC ; SET DE=INTERRUPT TABLE ADDRESS RET ; ; FILL LOGICAL DRIVE, SECTOR, TRACK NUMBER ; IN ERROR TABLE AND REPORT TO OPERATOR ; ERRHST: LD A,(HSTDSK) ; CURRENT HOST DISK ADD A,41H ; MAKE IT ASCII CHARACTER LD HL,VDRV ; GET DRIVE TABLE ADDRESS LD (HL),A ; STORE IT IN TABLE LD DE,(HSTTRK) ; GET TRACK NUMBER LD HL,VTRK ; GET TRACK TABLE ADDRESS CALL CVD3 ; CONVERT IT AS DECIMAL LD A,(HSTSEC) ; CURRENT SECTOR LD E,A LD D,0 ; DE = SECTOR NUMBER LD HL,VSEC ; GET SECTOR TABLE ADDRESS CALL CVD2 LD HL,VTAB ; VARIABLE TABLE RECORDED CALL PRNT RET ; ; DECIMAL CONVERSION SUBROUTINE ; CVD3: LD BC,CVD3ROM JR ROMSW CVD2: LD BC,CVD2ROM JR ROMSW ; ; PRINT ROUTINE ; PRNT: LD A,(HL) ; PRINT CHAR INC HL ; FOR NEXT CHAR OR A RET Z ; RIF DONE LD C,A PUSH HL CALL CONOUT ; PRINT A CHAR POP HL JR PRNT ; DO NEXT CHAR ; ; THIS ROUTINE CONVERTS HEX CODE INTO ASCII AND FILL OUT THE TABLE ; FTAB: LD BC,FTABROM JP ROMSW ; IF USRCPM CVHEX: RRCA RRCA RRCA RRCA ; ; HEX INTO ASCII ROUTINE ; GHEX: AND 0FH ; STRIP HIGH 4 BITS CP 10 ; NUMERIC? JR C,G10 ; YES, SKIP FOR NUMERIC ADD A,7 ; ADD 40 G10: ADD A,'0' ; ADD 30 RET ENDIF ; ; ENTRY FOR APPLICATION PROGRAM TO GRAPHIC DRIVER ; CALL GRAPHIC DRIVER RESIDED ; IN MEMORY BANK 0 USING RST 5. ; GRPDRV: DI ; DISABLE SYSTEM INTERRUPT LD IX,0 ADD IX,SP ; SAVE CURRENT STACK POINTER LD SP,LOCSTK ; SET LOCAL STACK POINTER LD A,0 OUT (BANKSW),A ; SWITCH TO MEM BANK 0 PUSH IX CALL GROUT ; CALL GRAPHIC DRIVER POP IX LD A,1 OUT (BANKSW),A ; SWITCH BACK TO MEM BANK 1 LD SP,IX ; RESTORE STACK POINTER EI ; ENABLE SYSTEM INTERRUPT RET ; ; ; ROUTINE TO STORE CHARACTER ON KEY BOARD BUFFER ; STORKB: LD HL,CONBUF+1 LD A,(HL) INC A CP BUFSIZ JR NZ,SKIPP XOR A SKIPP: DEC HL CP (HL) RET Z INC HL LD E,(HL) LD (HL),A LD D,0 INC HL ADD HL,DE LD (HL),B RET ; ; IF USRCPM ; ; ipc transfer logic ; hl has address of data ; b has length of transfer ; pnxo: push hl push bc ; ld hl,txtab ;get sdlc txmt table call prtini ;initialize sdlc txmt for sio xor a out (sioatc),a ;sio auto-wait on ; pop bc pop hl ld c,b ;modify hl to end of buffer ld b,0 add hl,bc dec hl ld (dmaddr),hl ld a,c ld (dmalng),a ld a,retries ;store number of retries at retrycnt ld (retrycnt),a ld a,5 ;assert rts out (status),a ld a,xmtlng or 2 out (status),a ctslp: ld a,10h out (status),a in a,(status) and 20h jr z,ctslp ;WAIT IF MMMOST BUSY ; ld a,10h ;check cts again out (status),a in a,(status) and 20h jr z,ctslp ;id false then wait ; tryagain: di ;disable system interrupt ld a,5 ;clear rts out (status),a ld a,xmtlng out (status),a ld b,62 ;200 us delay trylup: djnz trylup ld a,1 ;enable sio wait/ready line out (status),a ld a,xmtrdy out (status),a ; ld a,80h ;reset crc checker out (status),a ld hl,(dmaddr) ;set up for initial outd ld c,data ld a,(dmalng) ld b,a outd ld a,0c0h ;set up to clear underun latch out (status),a otdr jp morelp CTSLP4: ld a,(retrycnt) dec a jp z,erroret ld (retrycnt),a ; ld a,5 out (status),a ld a,xmtlng or 2 out (status),a ld b,33 ;set synch. window (.5 ms) ctslp5: dec b jp z,tryagain ;skip if time out ld a,10h out (status),a in a,(status) ;make sure receiver still in retry loop and 20h jp nz,ctslp5 ld a,10h out (status),a in a,(status) and 20h jr nz,ctslp5 jp erroret ;else exit txmt with error ; ; WAIT UNTIL TXMIT END OF BLOCK ; morelp: in a,(status) ;--2.75 and 40h ;--1.75 jr z,morelp ;WAIT IF NOT EOB --1.75 ; ; WAIT FOR RCV. "ACK" BY DROPPING CTS SIGNAL ; WITHIN 4MS AFTER TXMIT EOB ; ld b,0 CTSLP3: dec b jr z,CTSLP4 ;if timeout then do error retry ld a,10h ;check cts out (status),a in a,(status) and 20h ;cts = true? jr nz,ctslp3 ;if cts = true then loop more ; LD A,10H OUT (STATUS),A IN a,(STATUS) ;double checl CTS = FALSE? AND 20H JR NZ,CTSLP3 ;WAIT MORE IF CTS = TRUE ; ERROR0: LD B,0 ;if here then okay ERROR1: LD A,1 OUT (STATUS),A ;RESET SIO WAIT/READY LINE LD A,40H OUT (STATUS),A LD A,35H ;RESET ERROR FLAGS,SELECT REG #5 OUT (STATUS),A LD A,XMTLNG ;SHUT OFF DTR AND RTS OUT (STATUS),A LD A,B ei ;enable system interrupt ret ; erroret: LD B,4 ;RETURN WITH ERROR CODE IN A-REG JR ERROR1 ; ; sdlc receiver routine ; accept: hl = buffer pointer ; b = size ; return: a = 0 if no error ; a = 4 if receive error ; pnxi: LD C,B LD B,0 LD A,C LD (DMARXL),A ;SET RCV. INTO DMA TABLE ADD HL,BC ;FIND END OF BUFFER ADDRESS DEC HL LD (DMARXA),HL ;SAVE BUFFER ADDRESS TO DMA TABLE ; ld a,retries-1 ;initialize retry count ld (irtrycnt),a ictslp: ld a,10h ;WAIT FOR CTS (HOST POLLING) out (status),a in a,(status) and 20h jr z,ictslp LD A,10H OUT (STATUS),A IN A,(STATUS) AND 20H ;CTS = TRUE JR Z,ICTSLP ;WAIT IF NOT ; ; initialize sio for receive: current hl = rxtab pointer ; again: di ;disable system interrupt ld hl,rxtab call prtini ld hl,(dmarxa) ld c,data LD A,(DMARXL) LD E,A ; loopcb: in a,(status) and 01 jr z,pnxiw0 in a,(data) jp loopcb ; pnxiw0: ld b,100 ;set b = time out(1ms) PNXIW: DJNZ PNXIW1 JP PNXIW2 PNXIW1: IN A,(STATUS) RRCA JR NC,PNXIW ;WAIT IF RCV. NOT READY ; LD B,E ; INDR LD B,12 ;DELAY FOR 40US FOR SIO TO RCV. CRCC AND FLAG PNXIW4: DJNZ PNXIW4 IN A,(DATA) ;READ IN FIRST CRCC BYTE NOP IN A,(DATA) ;READ IN SECOND CRCC BYTE NOP ; IN A,(STATUS) ;CHECK SIO RCV. STATUS AND 080H ;RCV. ABORT? JR NZ,PNXIW2 ;YES, THEN BAD XFER TRY AGAIN ; LD A,1 ;CHECK CRC, OVERUN ERROR OUT (STATUS),A IN A,(STATUS) BIT 7,A JR Z,PNXIW2 AND 60H JP Z,ERROR0 ;NO ERROR THEN EXIT WITH B = 0 ; PNXIW2: LD B,200 ;B = (3MS) TIMEOUT FOR SYNCH. RETRY PNXIW6: DEC B JP Z,PNXIW8 LD A,10H OUT (STATUS),A IN A,(STATUS) AND 20H ;WAIT FOR CTS ACTIVE JP Z,PNXIW6 LD A,10H OUT (STATUS),A IN A,(STATUS) ;CHECK CTS ACTIVE AGAIN AND 20H JR Z,PNXIW6 ;WAIT IF NOT ACTIVE ; ; CHECK RETRY MORE ? ; PNXIW8: ld a,(irtrycnt) ;decrement retry count dec a JP Z,ERRORET ;SKIP IF NO MORE RETRY ld (irtrycnt),a jp again ; ; sdlc transmitter initialization for sio ; txtab: defb status defb txtabs txtab1: db chnrst db 4,sdlcmd db 6,global db 7,flag db 3,rcvlng db 5,xmtlng db 1,xmtrdy txtabs equ $-txtab1 ; ; sdlc receiver initialization for sio ; rxtab: defb status defb rxtabs rxtab1: defb 7 defb 7eh ;sdlc flag defb 11h ;RESET EXT/STATUS INTERRUPT defb 0a0h ;ENABLE WAIT/RECEIVE defb 75h ;CRC, ERROR RESET, ADDRESS REG #5 defb xmtlng or 2 ;SET RTS, TX8B, TX ENABLE, TX CRCC ENABLE defb 3 ;POINTER #3 defb 0d9h ;RX8B, ENTER HUNT, CRCC ENABLE, RX ENABLE rxtabs equ $-rxtab1 ; RETRYCNT: defs 1 ;RETRY COUNT IRTRYCNT: defs 1 DMALNG: defs 1 ;FILLED IN TRANSFER LENGTH DMARXL: defs 1 ;RECEIVE BLOCK LENGTH(LSB) DMARXA: defs 2 ;END ADDRESS OF RECEIVE BLOCK DMADDR: defs 2 ;DMA BUFFER ADDRESS ;* ;* M M M O S T 2 . 0 ;* ; SET UP BDOS INTERCEPT ADDRESS IN BDOS AND CLEAR OPEN FILE TABLE ; .8080 BDOSSET:LXI H,BIOSDOS ;PUT IN BDOS INTERCEPT ADDRESS SHLD BDOS+1 ;INTO INITIAL BDOS JUMP LXI H,BDOSTRT ;PUT REAL BDOS JUMP ADDRESS IN REALDOS SHLD REALDOS MVI A,TABLEN ;RESET DRIVE BYTE TO 80H (EMPTY) LXI H,FILETAB ;START OF FILE TABLE LXI D,14 ;LENGTH OF TABLE ENTRIES ZEROLP: MVI M,80H DAD D DCR A JNZ ZEROLP MVI M,0FFH ;END OF TABLE FLAG RET ; ; *END MMMOST 2.0 ; ; WARM BOOT REQUEST BLOCK ; WRQBLK: DB SOR WRQCOD: DB IPL DB USRPROM DB 0 DB 2BH ;REQUEST XFER LENGTH.-2 CP/M SECTORS WRECNO: DS 1 DS 4 WCKSM: DS 1 ; ; PRNTERR ROUTINE WILL PRINT ALL ERROR MESSAGES FROM MMMOST 2.0 ; IT EXPECTS REGISTER B TO HAVE A ERROR PRINTING CODE AND C TO =0 ; FOR BDOS ERR, 1 FOR BIOS READ ERR, 2 FOR BIOS WRITE ERR AND 3 FOR ; BIOS SELECT ERROR ; THE ROUTINE WILL PRINT MAX OF THREE LINES OF CODE BASED ON BITS OF ; REG. B AS DESCRIBED IN CODE ; PRNTERR:MOV A,B ;RETURN IF B=0 (PRINT NOTHING) ORA A RZ PUSH B ;SAVE ERROR CODES ON STACK CALL PCRLF ;PRINT A CARRIAGE RETURN, LINE FEED POP B PUSH B MOV A,B ANI 70H ;BITS D6-D4 => BDOS ERROR PRINTING JZ NOP1 ;IF 0 NO PSEUDO BDOS ERROR MESSAGES LXI H,M11 ;IF <>0 THEN PRINT "BDOS ERROR ON " CALL PRNT CALL PRTDK ;PRINT "(DRIVE)" LXI H,M11TAB ;GET ADDRESS OF SECOND MESSAGE TABLE POP B PUSH B MOV A,B ;PUT OFFSET INTO A ANI 30H ;MASK OFF IRRELEVANT BITS RRC ;ROTATE INTO LOW ORDER RRC RRC RRC CALL PIMSG1 ;CALL ROUTINE TO PRINT ON INDEX ;PRINT "BAD SECTOR","R/O",ETC. CALL PCRLF ;PRINT CR,LF NOP1: POP B ;CHECK IF PRINT SECOND ERROR LINE PUSH B MOV A,B ORA A JP NOP2 ;IF MSB=0 THEN DON'T PRINT MOV A,C ORA A ;CHECK IF BIOS OR BDOS JZ PBDOSE ;IF ZERO THEN BDOS ERROR LXI H,M21A ;PRINT "BIOS " CALL PRNT POP B PUSH B ;PRINT "READ","WRITE" OR "SELECT" LXI H,M22ATAB MOV A,C CALL PIMSG ;USING INDEXED PRINT ROUTINE LXI H,M23A ;PRINT "ERROR ON DRV=" CALL PRNT CALL PRTDK ;PRINT "(DISK)" LXI H,M24A ;PRINT "; TRK=" CALL PRNT LDA TRK16+1 ;PRINT MSB OF TRACK NO. CALL PBYTE LDA TRK16 ;PRINT LSB OF TRACK NO. CALL PBYTE LXI H,M25A ;PRINT "; SCTR=" CALL PRNT LDA SECT+1 ;PRINT MSB OF SECTOR CALL PBYTE LDA SECT ;PRINT LSB OF SECTOR CALL PBYTE POP B ;CHECK IF WRITE ERROR PUSH B MOV A,C CPI 2 JNZ NOPWRT LXI H,M26A ;IF SO PRINT "; WRT TYPE=" CALL PRNT LDA WRTYPE ;PRINT WRITE TYPE CALL PBYTE NOPWRT: LXI H,M27AB ;PRINT "; RTN CODE=" CALL PRNT LDA STABUF JMP ENDP2 ;PRINT RETURN CODE THEN CR,LF PBDOSE: LXI H,M21B ;PRINT "BDOS ERROR ON FUNC=" CALL PRNT LDA BDOSFUN ;PRINT CURRENT BDOS FUNCTION CALL PBYTE LXI H,M22B ;PRINT "; DRV=" CALL PRNT LDA LOGDRV CALL PRTDK2 ;PRINT DISK OF ERROR LXI H,M23B ;PRINT "; FILE=" CALL PRNT LHLD FCBA ;PRINT FILE NAME FROM FCB INX H MVI B,11 PFCBLP: MOV C,M PUSH B PUSH H CALL CONOUT POP H POP B INX H DCR B JNZ PFCBLP LXI H,M27AB ;PRINT "; RTN CODE=" CALL PRNT LDA RTNCODE ENDP2: CALL PBYTE ;PRINT RETURN CODE CALL PCRLF NOP2: POP B ;CHECK IF MMMOST ERROR CODE MOV A,B ANI 0FH ;LOW ORDER 4 BITS = MMMOST ERROR JZ PEXIT LXI H,M3TAB ;USE INDEX PRINT ROUTINE TO PRINT CALL PIMSG PEXIT: CALL PCRLF RET ; ; PCRLF ROUTINE SIMPLE OUTPUTS A CARRIAGE RETURN, LINE FEED ; PCRLF: MVI C,0DH ;OUTPUT CR CALL CONOUT MVI C,0AH ;OUTPUT LF JMP CONOUT ; ; PRTDRV ROUTINE WILL PRINT OUT LETTER OF CURRENTLY SELECTED DRIVE ; PRTDK: LDA SELDRV ;GET DISK NUMBER PRTDK2: ADI 'A' ;CONVERT TO LETTER MOV C,A JMP CONOUT ;PRINT IT ; ; PIMSG ROUTINE USES THE ACCUMLATOR AS INDEX INTO A TABLE WHOSE ; BASE IS GIVEN IN HL, THE ADDRESS STORED IN THE TABLE LOCATION ; THEN POINTS TO A MESSAGE TO BE PRINTED BY PRNT ; PIMSG: SUI 1 ;OFFSET RELATIVE ZERO PIMSG1: ADD A ;TURN INDEX INTO OFFSET ADD L ;ADD TO HL MOV L,A MVI A,0 ADC H MOV H,A MOV E,M ;GET ADDRESS STORED IN TABLE INX H MOV D,M XCHG ;HL NOW POINTS TO MESSAGE TO PRINT JMP PRNT ; ; PBYTE ROUTINE SIMPLY PRINTS THE HEX VALUE ; WHICH IS IN THE ACCUMULATOR ; .Z80 PBYTE: PUSH AF CALL CVHEX ;CONVERT HEX FOR MSD LD C,A CALL CONOUT ;PRINT MSD POP AF CALL GHEX ;CONVERT HEX FOR LSD LD C,A JP CONOUT ;PRINT LSD .8080 ;* ;* END MMMOST 2.0 ;* ; SETUP ERROR RETRY COUNT FOR READ/WRITE ROUTINES ; SETERRC: MVI A,RWRETRIES STA ECOUNT RET ; ; DECREMENT ERROR RETRY COUNT ; RETURN Z-FLAG = TRUE IF COUNT = 0 ; Z-FLAG = FALSE IF COUNT > 0 ; DECERRC: LDA ECOUNT DCR A STA ECOUNT RET ; ; BREAKPOINT A PRINT FILE ; BRKPT: CALL FORCL ;PUT FIRST BREAKPOINT PRINT MMMOST2.0 ; REQBRK: MVI A,BRKCD ;NOW REQUEST BREAKPOINT STA IRQCOD ; LDA IOBYTE RLC ;ROTATE LOGICAL LIST RLC ;DEVICE BITS TO BITS #0-#1 STA WRTYPE ;PASS THE CURRENT I/O BYTE ; LXI H,IRQBLK MVI B,10 CALL PNXO ;BREAK POINT DONE RET ;FROM BREAKPOINT ; ;* ;* M M M O S T 2 . 0 ;* ; ; THIS CODE WILL INTERCEPT SOME BDOS CALLS MADE ON DRIVES CLASSIFIED IN ; DRVTAB AT THE END ON BIOS. IF THE CALL IS NOT ONE OF THOSE INDICATED ; OR IS TO A DRIVE NOT INDICATED CONTROL IS PASSED TO THE LOCAL BDOS. ; OTHERWISE, CONTROL IS PASSED TO THE SERVICE PROCESSOR BDOS THROUGH ; MMMOST ; BIOSDOS: PUSH H .Z80 LD (USTACK),SP ;SAVE USER'S STACK POINTER .8080 LXI SP,TOS PUSH D PUSH B PUSH PSW MOV A,C ;CHECK CALL STA CURBFNC ;STORE OFF CURRENT FUNCTION # CPI 41 ;CHECK IF IN TABLE JC OKFUNC ENTRDOS:POP PSW ;IF FUNC. OVER TABLE THEN CALL LOCAL BDOS POP B POP D LHLD USTACK SPHL LHLD REALDOS ;GET JUMP ADDRESS XTHL RET OKFUNC: STA BDOSFUN LXI H,BDOSTAB ;CHECK IF THIS IF FUCTION IS INTERCEPTED ADD L MOV L,A MVI A,0 ADC H MOV H,A MOV A,M ;LOAD ACTIVITY TABLE BYTE, BIT 0=1 => INTERCEPT STA CURFNCA ANI 1 JZ ENTRDOS ;IF NOT 1 THEN JUMP TO LOCAL BDOS XCHG ;HL=FCB ADDRESS FROM CALLING ROUTINE SHLD FCBA MOV A,M ;READ IN DRIVE CODE FROM FCB ORA A ;CHECK IF DEFAULT JNZ HAVDSK ;IF NOT DEFAULT THEN A = DRIVE + 1 LDA SELDRV ;IF DEFAULT THEN READ CURRENT DISK ANI 0FH ;AND OUT USERCODE JMP OVERDSK HAVDSK: SUI 1 OVERDSK:STA CURBDSK SUI 8 ;SEE IF DRIVE BIT IN HIGH OF LOW BYTE OF DRVTAB JC LOWBYTE MOV C,A LDA DRVTAB JMP DRVSTAT LOWBYTE:ADI 8 ;RECTIFY DRIVE NUMBER MOV C,A LDA DRVTAB+1 DRVSTAT:INR C ;ROTATE DRIVE BIT INTO CARRY ROTLP: RAL DCR C JNZ ROTLP JNC ENTRDOS ;IF BIT NOT 1 THEN GO TO LOCAL BDOS ; ; section added july 1982 ; make sure search get initially intercepted ; so the high water mark can be syncronized ; lda bdosfun cpi 17 ;search for first jnz nsear lda curbdsk sta hidrv ;place drive in request block lxi h,hireq mvi b,10 call pnxo jnz entrdos lxi h,retbuf mvi b,4 call pnxi jnz entrdos lda curbdsk mov l,a mvi h,0 lxi d,dpbase+2 dad h dad h dad h dad h dad d xchg ; now de points to high water mark in drive's dph lhld retbuf mov a,l ora h jz entrdos xchg mov m,e inx h mov m,d jmp entrdos ;now go to the local bdos ; hireq: db 01,'C' hidrv: ds 1 hicod: db 'H' ; nsear: ; ; CNGSEQ#2 FOLLOWS MMMOST2.0 ; LXI H,SAVUSR ; MMMOST2.0 PUSH H ; MMMOST2.0 LXI H,BDOSTRT ; MMMOST2.0 MVI C,20H ; MMMOST2.0 MVI E,0FFH ; MMMOST2.0 PCHL ;CALL BDOS FOR USERCODE MMMOST2.0 SAVUSR: ;END CNGSEQ#2 MMMOST2.0 STA USERCOD ; LDA CDISK ; MOV C,A LDA SELDRV ;GET LOGGED IN DRIVE ANI 0FH ;GET RID OF USER CODE STA LOGDRV ;PUT INTO REQUEST BLOCK LXI H,0FFFFH ;FILINDX = FFFFH IF FILE NOT IN TABLE SHLD FILINDX INX H SHLD FILEN1 ;DEFAULT IF NOT FOUND LXI H,FILETAB ;CHECK IF FILE IN TABLE => FILE OPEN LXI D,14 ;TABLE ENTRY LENGTH LDA CURBDSK MOV B,A NXTNTRY:MOV A,M ;FIRST CHECK DRIVE MATCH CPI 0FFH ;CHECK IF END OF TABLE FLAG JZ OKOPEN CMP B JZ MTCHMOR ;IF DRIVE MATCH GO ON TO CHECK NAME GETNEXT:DAD D ;IF NOT INCREMENT TO NEXT TABLE ENTRY JMP NXTNTRY MTCHMOR:PUSH H ;SAVE OF SEARCH PARAMETERS PUSH D PUSH B INX H ;HL=FILE NAME PART OF ENTRY XCHG LHLD FCBA INX H ;HL=FCB NAME, DE=TABLE NAME MVI B,11 ;B=LENGTH OF NAME MTCHLP: LDAX D CMP M JNZ NOMTCH INX H INX D DCR B JNZ MTCHLP LDAX D ;IF HERE THEN MATCH SO MOVE FILE NO. STA FILEN1 ;INTO REQUEST BLOCK INX D LDAX D STA FILEN1+1 XCHG LXI D,-13 ;STORE OFF CURRENT FILE ENTRY ADDRESS DAD D SHLD FILINDX POP B ;RESTORE STACK POP D POP H JMP OKOPEN ; NOMTCH: POP B POP D POP H JMP GETNEXT ; BADRET: MVI A,0FFH ;IF HERE FILE STATUS ~= FUNC. ACTIVITY STA RTNCODE RETROT: POP PSW POP B ;RETURN TO CALLING ROUTINE POP D LHLD USTACK ;RELOAD USER'S STACK POINTER SPHL POP H LDA RTNCODE RET ; ; IF HERE THEN PROPER ENTRY INTO MMMOST BDOS CALL => MAKE CALL ; OKOPEN: LXI H,BDRQBLK ;REQUEST BLOCK HAS BEEN FILLED IN MVI B,10 ;THEREFORE, SEND IT CALL PNXO ORA A ;A=0 => GOOD TRANSFER JNZ XOTERRT ;PRINT ERROR AND RETURN ERROR ; OKXFR1: LHLD FCBA ;SEND FCB TO SERVICE MVI B,36 CALL PNXO ORA A JNZ XOTERRT ;PRINT ERROR AND RETURN ; OKXFR2: LDA CURFNCA ;IF WRITE THEN SEND 128 BYTE DATA ANI 04H JZ NONWRT LHLD DMAADR MVI B,128 CALL PNXO ;SEND DATA ORA A JNZ XOTERRT ;PRINT ERROR AND RETURN ERROR ; NONWRT: MVI B,4 ;READ IN RETURN CODE LXI H,RETBUF CALL PNXI CPI TIMERR ; MMMOST2.04 JZ NONWRT ; MMMOST2.04 ORA A JNZ XINERRT ; MMMOST2.04 ; OKXFR4: LHLD FCBA ;READ IN NEW FCB MVI B,36 CALL PNXI ORA A JNZ XINERRT ; OKXFR5: LDA PRNTRTN ORA A JZ NOMESSGE MOV B,A ;B HAS PRINT ERROR CODE MVI C,0 ;C HAS 0 TO INDICATE BDOS ERR. CALL PRNTERR LDA PRNTRTN ;IF ERROR PRINT BYTE = X010XXXX ANI 20H ;THEN JUMP TO WARM BOOT CPI 20H ;BECAUSE R/O ERROR JZ WBOOT ;AS PER CP/M 2.2 STANDARD JMP RETROT ; NOMESSGE: LDA CURFNCA ;ERROR IF FF OR ~00 ANI 40H ;DO6=1 IF ERR ON ~00 =0 IF ON FF LDA RTNCODE JZ ERRFF ORA A JNZ RETROT JMP NOERR ERRFF: CMA ORA A ;SET FLAGS, ZERO SET IF A WAS FFH JZ RETROT NOERR: LDA CURFNCA ;CHECK IF NEED TO READ SECTOR ANI 8 JZ NONREAD LHLD DMAADR ;IF READ THEN READ 128 BYTES INTO DMAADR MVI B,128 CALL PNXI ORA A JNZ XINERRT ;PRINT ERROR AND RETURN ERROR ; NONREAD:LDA CURFNCA ;CHECK IF OPEN OR MAKE ANI 10H JZ NONOPEN LHLD FILINDX ;IF FILINDX ~=FFFF THEN REOPEN MOV A,H ANA L CPI 0FFH ;A=FF IF FILINDX = FFFF JZ FILLIN LXI D,12 ;IF HERE THEN REOPEN => DAD D LDA FILENO ;FILL IN POSSIBLY NEW FILE NUMBER MOV M,A LDA FILENO+1 INX H MOV M,A JMP RETROT ;IF OPEN AND FILLED IN THEN DONE ; FILLIN: LXI H,FILETAB ;IF OPEN OR MAKE GET OPEN SPACE LXI D,14 LOOPLP: MOV A,M CPI 80H ;80H = EMPTY RECORD JZ HOLE CPI 0FFH JZ RETROT ;TOO BAD TABLE FULL ; ;BUT IT'S OK KEEPLK: DAD D JMP LOOPLP ; HOLE: LDA CURBDSK MOV M,A INX H XCHG ;MOVE OVER DRIVE, FILE NAME, FILE NUM. LHLD FCBA INX H MVI B,11 FILLLP: MOV A,M STAX D INX H INX D DCR B JNZ FILLLP LDA FILENO STAX D INX D LDA FILENO+1 STAX D JMP RETROT ;FINISHED IF OPEN => RETURN ; NONOPEN: LDA CURFNCA ANI 20H JZ RETROT ;IF NOT CLOSE THEN DONE => RETURN LHLD FILINDX ;IF CLOSE THEN PUT DRIVE TO 80H MVI M,80H JMP RETROT ; XOTERRT: MVI B,06H ;PRINT XFER OUT ERR CODE OTHERP: CALL PRNTERR JMP BADRET ;RETURN WITH FF IN A ; XINERRT: MVI B,07H ;PRINT XFER IN ERR CODE JMP OTHERP ENDIF ;END OF USERCPM ; ; END OF TPCISUBS.MAC