;****************************************************************************** ;****************************************************************************** ; BIOS21I VERSION 820505/1200|RACIII/JCM ;------------------------------------------------------------------------------ ; SUPPORTING ; DRIVE NAME DENSITY CONTROLLER BASE ADDRESS ; ---------- ------- ---------- ------------ ; A:, B: DOUBLE 202 78H ; C:, D: SINGLE 201 88H ; E: SINGLE IOC C0H ;------------------------------------------------------------------------------ ; COPYRIGHT (C) 1978, 1979 | COPYRIGHT (C) 1982 ; DIGITAL RESEARCH | INTEL CORP. ; BOX 579, PACIFIC GROVE | 3065 BOWERS AVENUE ; CALIFORNIA, 93950 | SANTA CLARA, CALIFORNIA 95051 ;****************************************************************************** ;****************************************************************************** ;******************** EQUATES ************************************************* MACLIB DISKDEF VERS EQU 22 ; CP/M VERSION 2.2 FALSE EQU 0 TRUE EQU NOT FALSE RELOC EQU FALSE IF NOT RELOC MSIZE EQU 62 ; MEMORY SIZE IN KILOBYTES RAM$TOP EQU MSIZE*1024 ; TOP ADDRESS+1 BIOS EQU RAM$TOP-800H ; BASIC INPUT/OUTPUT SYSTEM BDOS EQU BIOS-0E00H ; BASE OF THE BDOS CCP EQU BDOS-0800H ; THE CONSOLE COMMAND PROCESSOR ORG BIOS ENDIF IF RELOC ORG 0 ; OR 0100H FOR REL-1 CCP EQU $ BDOS EQU CCP+0800H BIOS EQU BDOS+0E00H MSIZE EQU 0 ; DUMMY FOR SIGN-ON MESSAGE ORG 0800H+0E00H ; PLUS ANOTHER 0100H FOR REL-1 ENDIF CPML EQU BIOS-CCP NSECTS EQU CPML/128 ; NUMBER OF SECTORS TO LOAD CDISK EQU 0004H ; ADDRESS OF LAST LOGGED DISK ON WARM START BUFF EQU 0080H ; DEFAULT BUFFER ADDRESS IOBYTE EQU 0003H ; ADDRESS OF IO BYTE FOR MONITOR IOBYTI EQU 0081H ; Initial value for IOBYTE INT$CONT$1 EQU 0FDH ; INTERRUPT PRIORITY RESTORE PORT INT$CONT$0 EQU 0FCH ; INTERRUPT MASK PORT MON$INT EQU 0F3H ; INTERRUPT CONTROL PORT INT$MASK EQU 0111$1110B ; ENABLE RST 0(WBOOT), RST 7 (MONITOR) ; MDS MONITOR EQUATES MON80 EQU 0F800H RMON80 EQU 0FF0FH ; RESTART MON80 (BOOT ERROR) CI EQU 0F803H CO EQU 0F809H CSTS EQU 0F812H RI EQU 0F806H PO EQU 0F80CH LO EQU 0F80FH CR EQU 0DH ; CARRIAGE RETURN LF EQU 0AH ; LINE FEED ;*************** DISK EQUATES ************************************************* RETRY EQU 10 ; MAX RETRIES ON DISK I/O BEFORE ERROR NUM$DISKS EQU 5 ; NUMBER OF DRIVES AVAILABLE ;*************** 202 CONTROLLER EQUATES *************************************** BASE2 EQU 78H ; BASE OF DISK COMMAND IO PORTS DSTAT2 EQU BASE2 ; DISK STATUS (INPUT) RTYPE2 EQU BASE2+1 ; RESULT TYPE (INPUT) RBYTE2 EQU BASE2+3 ; RESULT BYTE (INPUT) ILOW2 EQU BASE2+1 ; IOPB LOW ADDRESS (OUTPUT) IHIGH2 EQU BASE2+2 ; IOPB HIGH ADDRESS (OUTPUT) READF EQU 4H ; READ FUNCTION WRITF EQU 6H ; WRITE FUNCTION RECAL EQU 3H ; RECALIBRATE DRIVE IORDY EQU 4H ; I/O FINISHED MASK ;*************** 201 CONTROLLER EQUATES *************************************** BASE EQU 88H ; BASE OF DISK COMMAND IO PORTS DSTAT EQU BASE ; DISK STATUS (INPUT) RTYPE EQU BASE+1 ; RESULT TYPE (INPUT) RBYTE EQU BASE+3 ; RESULT BYTE (INPUT) ILOW EQU BASE+1 ; IOPB LOW ADDRESS (OUTPUT) IHIGH EQU BASE+2 ; IOPB HIGH ADDRESS (OUTPUT) READF EQU 4H ; READ FUNCTION WRITF EQU 6H ; WRITE FUNCTION RECAL EQU 3H ; RECALIBRATE DRIVE IORDY EQU 4H ; I/O FINISHED MASK ;*************** IOC CONTROLLER EQUATES *************************************** ;*** IOC COMMANDS *** RDSTAT EQU 00011B ; READ DEVICE STATUS WPBC EQU 10101B ; WRITE FIRST BYTE OF PBC WPBCC EQU 10110B ; WRITE NEXT BYTE OF PBC (5 BYTES TOTAL) WDBC EQU 10111B ; WRITE DISKETTE DATA BYTES RDBC EQU 11001B ; READ DISKETE DATA BYTES RRSTS EQU 11011B ; READ DISKETTE RESULT BYTE RDSTS EQU 11100B ; READ DISKETTE STATUS BYTE ;**** I/O PORTS **** IOCDATA EQU 0C0H ; DATA PORT IOCCNTR EQU 0C1H ; CONTROL PORT ;**** DISK RESULT BYTE **** SEEKERR EQU 0000100B ; SEEK ERROR ;**** DBB STATUS BYTE **** OBF EQU 1B ; OUTPUT BUFFER FULL IBF EQU 10B ; INPUT BUFFER FULL F0 EQU 100B ; COMMAND STATUS FLAG (ON=ACCEPTED OFF=COMPLETED) CD EQU 1000B ; COMMAND/DATA FLAG (ON=STATUS OFF=DATA) ;**** DISKETTE STATUS BYTE FLAGS **** READY EQU 1B ; ON=DEVICE IS READY OPCOMP EQU 100B ; OPERATION COMPLETED PRESENT EQU 1000B ; DEVICE IS PHISICALLY PRESENT ILLDATA EQU 100000B ; ILLEGAL DATA SENT ILLSTAT EQU 1000000B ; ILLEGAL INTERUPT REQUEST ;**** DEVICE STATUS BYTE **** DSKERR EQU 10000000B ; DISK ERROR FLAG ;**** UNIQUE DISKETTE OPERATION CODES **** RECALB EQU 011B ; RECALIBRATE DISK ;****************************************************************************** ; JUMP VECTOR FOR INDIVIUAL ROUTINES ;****************************************************************************** JMP BOOT WBOOTE: JMP WBOOT 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 LIST$ST ; LIST STATUS POLL JMP SECT$TRAN ; SECTOR TRANSLATION ;****************************************************************************** ; CODE SECTION ;****************************************************************************** BOOT: LXI SP,BUFF+80H ; TEMPORARY STACK POINTER ; SET UP INTERRUPTS FOR 0 AND 7 ENABLED DI MVI A,12H ; GIVE NON-EXISTANT I8259 INTERRUPT CONTROLLER OUT INT$CONT$1 ; IT'S INTIALIZATION SEQUENCE XRA A OUT INT$CONT$0 ; THIS ACTUALLY ALLOWS PENDING INTERRUPTS ; ON TO HAPPEN, BUT INTEL SEZ ; DO IT TO IT FOR THE I8259 COMPATIBILITY MVI A,INT$MASK ; RST0 AND RST7 BITS ON OUT INT$CONT$0 XRA A OUT MON$INT ; MASK ALL MONITOR BOARD INTERRUPTS ; PLUG ALL UNUSED INTERRUPT VECTORS WITH RST 7 ; SO UNEXPECTED INTERRUPTS WILL BREAKPOINT TO MDSMON LXI H,00008H ; POINT TO RESTART 1 LOCATION MOV D,H ; KEEP VALUE 8 FOR INCREMENT MOV E,L ; MVI C,6 ; WE WANT TO INIT. SIX RESTARTS FILL$LOOP: MVI M,0FFH ; PLUG IN A RESTART 7 INSTR. DAD D ; POINT TO NEXT RESTART LOCATION DCR C ; DROP COUNT JNZ FILL$LOOP ; AND ITERATE LDA 5 ; GET MDSMON'S LOCATION 5 TO SAVE STA HOLD$5 ; FOR COMPATIBILITY WITH MDS230 XRA A ; CLEAR ACCUMULATOR STA CDISK ; SET INITIALLY TO DISK A/USER 0 LXI H,SIGN$ON ; CALL PRMSG ; JMP GOCPM ; GO TO CP/M WBOOT: LXI SP,0100H ; TEMP STACK POINTER WBOOT0: LXI B,CCP ; SET DMA ADDRESS TO START OF DISK SYSTEM CALL SETDMA MVI C,0 ; BOOT FROM DRIVE 0 CALL SELDSK CALL HOME MVI C,2 ; START READING SECTOR 2 CALL SETSEC ; READ MULTIPLE SECTORS, COUNT NSECTS TO ZERO ;* IF NSECTS EVER GETS LARGER THAN 51 THAN THIS BOOT NEEDS TO ;* BE MODIFIED. MVI A,NSECTS STA ION ; SAVE IN IOPB CALL READ ; DO READ JNZ WBOOT ; REPEAT IF ERROR MVI A,1 ; SET NUMBER OF SECTORS TO 1 STA ION ; FOR REST OF WORLD ; GOCPM: ;(ENTER HERE FROM COLD START BOOT) ; SET UP PAGE ZERO JUMPS TO WARM BOOT, BDOS, AND MDSMON BREAKPOINT MVI A,JMP STA 0 LXI H,WBOOTE SHLD 1 ; JMP WBOOT AT LOCATION 00 STA 5 LXI H,BDOS+6 SHLD 6 ; JMP BDOS AT LOCATION 5 STA 7*8 ; JMP TO MON80 (MAY HAVE BEEN CHANGED BY DDT) LXI H,RMON80 SHLD 7*8+1 ; Set I/O byte MVI A,IOBYTI ; Initial value for IOBYTE STA IOBYTE ; *** LDA CDISK ; LAST LOGGED DISK NUMBER MOV C,A ; SEND TO CCP TO LOG IT IN EI JMP CCP CONIN: CALL CI1 ANI 7FH RET CI1: CALL MON DB 0FFH AND CI CONOUT: CALL MON DB 0FFH AND CO CONSTAT: CALL MON DB 0FFH AND CSTS LIST: CALL MON DB 0FFH AND LO READER: CALL MON DB 0FFH AND RI PUNCH: CALL MON DB 0FFH AND PO MON: ; PATCH FOR LOC. 5 LXI H,00005H ; RESTORE MDS LOC. 5 LDA HOLD$5 ; MOV M,A ; XTHL ; FETCH & BUILD MON CALL ADDRESS MOV L,M ; MVI H,0F8H ; CALL CALLER ; VECTOR TO APPROPRITIATE MDSMON ENTRY POP H ; RESTORE CP/M'S BDOS VECTOR OPCODE MVI M,0C3H ; RET ; CALLER: PCHL LIST$ST:XRA A ; NOT IMPLEMENTED RET ; SELDSK: ;SELECT DISK GIVEN BY REGISTER C LXI H,0000 ; FIRST, INSURE GOOD SELECT MOV A,C ; CPI NUM$DISKS ; RNC ; LXI H,SEL$TABLE ; MVI B,0 ; DAD B ; MOV A,M ; STA IOF ; STA IOFSV ; SAVE DRIVE ADDRESS MOV H,B ; GET DRIVE CODE TO [HL] MOV L,C ; DAD H ; MULTIPLY BY 16 DAD H ; DAD H ; DAD H ; LXI D,DPBASE ; AND MAKE ADDRESS OF DRIVE TABLE DAD D ; RET HOME: ;MOVE TO HOME POSITION MVI C,0 SETTRK: ;SET TRACK ADDRESS GIVEN BY C LXI H,IOT MOV M,C RET ; SETSEC: ; SET SECTOR NUMBER GIVEN BY C MOV A,C ; SECTOR NUMBER TO ACCUM STA IOS ; STORE SECTOR NUMBER TO IOPB RET ; SETDMA: ; SET DMA ADDRESS GIVEN BY REGS B,C MOV L,C MOV H,B SHLD IOD RET SECT$TRAN: ; TRANSLATE THE SECTOR # IN IF NEEDED MOV H,B ; IN CASE OF NO TRANSLATION MOV L,C ; INX H ; MOV A,D ; (TRANTAB) = 0 , AND RETURN ORA E ; RZ ; XCHG ; ELSE, OFFSET TABLE LOGICAL SECTOR DAD B ; MOV L,M ; THEN FETCH THE PHYSICAL SECTOR MVI H,0 ; RET ;****************************************************************************** ; DISK DRIVERS ;****************************************************************************** READ: LDA IOFSV ; CHOOSE WHICH DRIVER CODE TO USE MOV C,A ; HOLD SELECT CODE ANI 040H ; TEST IF IOC SELECTED JNZ READI ; YES - USE IOC DRIVER MOV A,C ; RESTORE [A] ANI 020H ; TEST IF 201 SELECTED JNZ READ1 ; YES - USE 201 DRIVER JMP READ2 ; IF NONE OF THE ABOVE - USE 202 DRIVER WRITE: LDA IOFSV ; CHOOSE WHICH DRIVER CODE TO USE MOV C,A ; HOLD SELECT CODE ANI 040H ; TEST IF IOC SELECTED JNZ WRITEI ; YES - USE IOC DRIVER MOV A,C ; RESTORE [A] ANI 020H ; TEST IF 201 SELECTED JNZ WRITE1 ; YES - USE 201 DRIVER JMP WRITE2 ; IF NONE OF THE ABOVE - USE 202 DRIVER ;*************** 202 CONTROLLER DRIVER CODE *********************************** READ2: ; READ NEXT DISK RECORD ( DISK/TRK/SEC/DMA SET) MVI C,READF ; SET TO READ FUNCTION JMP SETFUNC2 WRITE2: ; DISK WRITE FUNCTION MVI C,WRITF SETFUNC2: ; SET FUNCTION FOR NEXT I/O (COMMAND IN REG-C) MVI A,80H ; INITIALIZE IOPB FOR DUAL DENSITY 202 STA IOPB ; * LXI H,IOF ; IO FUNCTION ADDRESS MOV A,M ; GET IT TO ACCUMULATOR FOR MASKING ANI 1111$1000B ; REMOVE PREVIOUS COMMAND ORA C ; SET TO NEW COMMAND MOV M,A ; REPLACED IN IOPB WAITIO2: MVI C,RETRY ; MAX RETRIES BEFORE PERM ERROR REWAIT2: ; START THE I/O FUNCTION AND WAIT FOR COMPLETION CALL INTYPE2 ; IN RTYPE CALL INBYTE2 ; CLEARS THE CONTROLLER MVI A,IOPB AND 0FFH ; LOW ADDRESS FOR IOPB MVI B,IOPB SHR 8 ; HIGH ADDRESS FOR IOPB OUT ILOW2 ; LOW ADDRESS TO CONTROLLER MOV A,B OUT IHIGH2 ; HIGH ADDRESS WAIT02: CALL INSTAT2 ; WAIT FOR COMPLETION ANI IORDY ; READY? JZ WAIT02 ; CHECK IO COMPLETION OK CALL INTYPE2 ; MUST BE IO COMPLETE (00) UNLINKED ; 00 UNLINKED I/O COMPLETE, 01 LINKED I/O COMPLETE (NOT USED) ; 10 DISK STATUS CHANGED 11 (NOT USED) CPI 10B ; READY STATUS CHANGE? JZ WREADY2 ; MUST BE 00 IN THE ACCUMULATOR ORA A JNZ WERROR2 ; SOME OTHER CONDITION, RETRY ; CHECK I/O ERROR BITS CALL INBYTE2 RAL JC WREADY2 ; UNIT NOT READY RAR ANI 11111110B ; ANY OTHER ERRORS? (DELETED DATA OK) JNZ WERROR2 ; READ OR WRITE IS OK, ACCUMULATOR CONTAINS ZERO RET WREADY2: ; NOT READY, TREAT AS ERROR FOR NOW CALL INBYTE2 ; CLEAR RESULT BYTE JMP TRYCOUNT2 WERROR2: ; RETURN MALFUNCTION (CRC, TRACK, SEEK, ETC.) ; THE MDS CONTROLLER HAS RETURNED A BIT IN EACH POSITION ; OF THE ACCUMULATOR, CORRESPONDING TO THE CONDITIONS: ; 0 - DELETED DATA (ACCEPTED AS OK ABOVE) ; 1 - CRC ERROR ; 2 - SEEK ERROR ; 3 - ADDRESS ERROR (HARDWARE MALFUNCTION) ; 4 - DATA OVER/UNDER FLOW (HARDWARE MALFUNCTION) ; 5 - WRITE PROTECT (TREATED AS NOT READY) ; 6 - WRITE ERROR (HARDWARE MALFUNCTION) ; 7 - NOT READY ; (ACCUMULATOR BITS ARE NUMBERED 7 6 5 4 3 2 1 0) TRYCOUNT2: ; REGISTER C CONTAINS RETRY COUNT, DECREMENT 'TIL ZERO DCR C JNZ REWAIT2 ; FOR ANOTHER TRY ; CANNOT RECOVER FROM ERROR MVI A,1 ; ERROR CODE RET ; INTYPE, INBYTE, INSTAT READ DRIVE BANK 00 OR 10 INTYPE2: IN RTYPE2 RET INBYTE2: IN RBYTE2 RET INSTAT2: IN DSTAT2 RET ;*************** END 202 CODE *** ;*************** 201 CONTROLLER DRIVER **************************************** READ1: ; READ NEXT DISK RECORD ( DISK/TRK/SEC/DMA SET) MVI C,READF ; SET TO READ FUNCTION JMP SETFUNC ; WRITE1: ; DISK WRITE FUNCTION MVI C,WRITF ; SETFUNC: ; SET FUNCTION FOR NEXT I/O (COMMAND IN REG-C) mvi a,80h sta iopb ; restore IOPB channel command 820504 LXI H,IOF ; IO FUNCTION ADDRESS MOV A,M ; GET IT TO ACCUMULATOR FOR MASKING ANI 1111$1000B ;REMOVE PREVIOUS COMMAND ORA C ; SET TO NEW COMMAND MOV M,A ; REPLACED IN IOPB ; SINGLE DENSITY DRIVE 1 REQUIRES BIT 5 ON IN SECTOR # ; MASK THE BIT FROM THE CURRENT I/O FUNCTION ANI 0010$0000B ;MASK THE DISK SELECT BIT LXI H,IOS ;ADDRESS THE SECTOR SELECT BYTE ORA M ;SELECT PROPER DISK BANK MOV M,A ;SET DISK SELECT BIT ON/OFF ; WAITIO: MVI C,RETRY ; MAX RETRIES BEFORE PERM ERROR REWAIT: ; START THE I/O FUNCTION AND WAIT FOR COMPLETION CALL INTYPE ; IN RTYPE CALL INBYTE ; CLEARS THE CONTROLLER MVI A,IOPB AND 0FFH ; LOW ADDRESS FOR IOPB MVI B,IOPB SHR 8 ; HIGH ADDRESS FOR IOPB OUT ILOW ; LOW ADDRESS TO CONTROLLER MOV A,B OUT IHIGH ; HIGH ADDRESS JMP WAIT0 ; TO WAIT FOR COMPLETE WAIT0: CALL INSTAT ; WAIT FOR COMPLETION ANI IORDY ; READY? JZ WAIT0 ; CHECK IO COMPLETION OK CALL INTYPE ; MUST BE IO COMPLETE (00) UNLINKED ; 00 UNLINKED I/O COMPLETE, 01 LINKED I/O COMPLETE (NOT USED) ; 10 DISK STATUS CHANGED 11 (NOT USED) CPI 10B ; READY STATUS CHANGE? JZ WREADY ; MUST BE 00 IN THE ACCUMULATOR ORA A JNZ WERROR ; SOME OTHER CONDITION, RETRY ; CHECK I/O ERROR BITS CALL INBYTE RAL JC WREADY ; UNIT NOT READY RAR ANI 11111110B ; ANY OTHER ERRORS? (DELETED DATA OK) JNZ WERROR ; READ OR WRITE IS OK, ACCUMULATOR CONTAINS ZERO RET WREADY: ; NOT READY, TREAT AS ERROR FOR NOW CALL INBYTE ; CLEAR RESULT BYTE JMP TRYCOUNT WERROR: ; RETURN MALFUNCTION (CRC, TRACK, SEEK, ETC.) ; THE MDS CONTROLLER HAS RETURNED A BIT IN EACH POSITION ; OF THE ACCUMULATOR, CORRESPONDING TO THE CONDITIONS: ; 0 - DELETED DATA (ACCEPTED AS OK ABOVE) ; 1 - CRC ERROR ; 2 - SEEK ERROR ; 3 - ADDRESS ERROR (HARDWARE MALFUNCTION) ; 4 - DATA OVER/UNDER FLOW (HARDWARE MALFUNCTION) ; 5 - WRITE PROTECT (TREATED AS NOT READY) ; 6 - WRITE ERROR (HARDWARE MALFUNCTION) ; 7 - NOT READY ; (ACCUMULATOR BITS ARE NUMBERED 7 6 5 4 3 2 1 0) TRYCOUNT: ; REGISTER C CONTAINS RETRY COUNT, DECREMENT 'TIL ZERO DCR C JNZ REWAIT ; FOR ANOTHER TRY ; CANNOT RECOVER FROM ERROR MVI A,1 ; ERROR CODE RET INTYPE: IN RTYPE RET INBYTE: IN RBYTE RET INSTAT: IN DSTAT RET ;*************** END 201 CODE *** ;*************** IOC CONTROLLER DRIVER CODE *********************************** READI: ; READ NEXT DISK RECORD ( DISK/TRK/SEC/DMA SET) MVI C,READF ; SET TO READ FUNCTION JMP SETFUNCI ; WRITEI: ; DISK WRITE FUNCTION MVI C,WRITF ; SETFUNCI: ; SET FUNCTION FOR NEXT I/O (COMMAND IN REG-C) MVI A,80H ; INITIALIZE IOPB FOR DUAL DENSITY 202 STA IOPB ; * LXI H,IOF ; IO FUNCTION ADDRESS MOV A,M ; GET IT TO ACCUMULATOR FOR MASKING ANI 1111$1000B ; REMOVE PREVIOUS COMMAND ORA C ; SET TO NEW COMMAND MOV M,A ; REPLACED IN IOPB LDA IOFSV ; RESTORE DRIVE ADDRESS ANI 0100$0000B ; IOC ? JZ WAITIO ; NO - CONTINUE WITH DUAL ;* VERIFY DISK IS READY * CALL DISABLE ; DISABLE INTERRUPTS SDSKSTAT: MVI C,RETRY ; SET RETRY COUNT SDSK1: CALL DSKSTAT ; GET THE STATUS BYTE PUSH PSW ; SAVE STATUS BYTE ANI READY ; DISK READY ? JNZ SDSKSOK ; YES ... NO ERROR ; NO ... TEST FOR MAX RETRIES DCR C ; = MAX RETRIES? JZ SDERROR ; YES ... REPORT ERROR POP PSW JMP SDSK1 ; RETRY! SDSKSOK: POP PSW ; RESTORE STATUS BYTE ANI OPCOMP ; ANY PENDING OPERATIONS ? JZ BLDIOPB ; NO - GO BUILD THE CONTROL BLOCK ;* CLEAR ANY ACTIVITY ON THE DISK DRIVE * CALL DSKRSLT ; GET THE RESULT BYTE JMP SDSKSTAT ; GO MAKE SURE IT IS CLEARED ;**** MODIFY CONTROL BLOCK TO IOC FORMAT *** ;* BYTE TWO - MODIFY OP CODE * BLDIOPB: ;* BYTE 1 MVI A,0H ; SET FIRST BYTE TO 0 STA IOPB ; LDA IOF ; PUT 202 OP CODE IN ACCUMULATOR ANI 0000$0111B ; ISOLATE OP CODE STA IOF ; PUT BACK IN IOPB MVI C,RETRY ; INITIALIZE RETRY COUNTER ;* DETERMINE IF READ OR WRITE * CPI READF ; READ ? JZ SDREAD ; YES - BRANCH ;*** BEGIN IOC WRITE ROUTINE *** SDWRITE: CALL DBBWAIT ; WAIT FOR IOC TO BE READY MVI A,WDBC ; LOAD WRITE COMMAND OUT IOCCNTR ; ISSUE COMMAND TO IOC CALL DBBWAIT ; WAIT FOR IOC TO HANDLE COMMAND LDA ION ; # OF SECTORS OUT IOCDATA ; SEND TO IOC CALL DBBWAIT ; WAIT FOR IOC TO HANDLE ;* PASS DATA TO IOC RAM * LHLD IOD ; LOAD ADDRESS OF DATA LDA ION ; LOAD NUMBER OF SECTORS SDWLP1: PUSH PSW ; SAVE SECTOR COUNT MVI D,128 ; INITIALIZE BYTE COUNT FOR SECTOR SDWLP2: MOV A,M ; PUT DATA IN ACCUMULATOR OUT IOCDATA ; PASS TO IOC RAM CALL OUTWAIT ; WAIT FOR IOC TO HANDLE INX H ; BUMP CHARACTER POINTER DCR D ; DECREMENT CHARACTER COUNTER JNZ SDWLP2 ; LOOP TILL SECTOR DONE POP PSW ; LOAD SECTOR COUNT DCR A ; DECREMENT JNZ SDWLP1 ; LOOP TILL END OF SECTORS CALL OUTIOPB ; PASS IOPB TO IOC CALL ENABLE ; ENABLE INTERRUPTS CALL CKRESULT ; CHECK RESULTS OF WRITE ORA A ; SET FLAGS RZ ; RETURN OF OK DCR C ; OVER RETRY LIMIT ? JNZ SDWRITE ; NO - TRY AGAIN MVI A,1 ; ELSE SET BAD RETURN CODE RET ; AND RETURN ;* IOC READ ROUTINE * SDREAD: CALL DBBWAIT ; WAIT FOR DBB TO BE READY CALL OUTIOPB ; SEND IOPB TO IOC CALL CKRESULT ; CHECK RESULT OF READ ORA A ; SET FLAGS JZ SDRDATA ; GET DATA IF OK DCR C ; BEYOND RETRY LIMIT ? JNZ SDREAD ; NO - TRY AGAIN CALL ENABLE ; ENABLE THE INTERRUPTS MVI A,1 ; ELSE SET BAD RETURN CODE RET ; AND RETURN ;* GET THE DATA * SDRDATA: CALL DBBWAIT ; WAIT FOR IOC TO BE READY MVI A,RDBC ; SET COMMAND TO GET THE DATA OUT IOCCNTR ; SEND TO IOC LHLD IOD ; LOAD DMA ADDRESS LDA ION ; LOAD NUMBER OF SECTORS SDRLP1: PUSH PSW ; SAVE SECTOR COUNT MVI D,128 ; SET BYTES/SECTOR COUNT SDRLP2: CALL INWAIT ; WAIT FOR A BYTE TO BE READY IN IOCDATA ; GET THE BYTE MOV M,A ; MOVE TO BUFFER INX H ; INCREMENT POINTER DCR D ; DECREMENT CHARACTER COUNTER JNZ SDRLP2 ; LOOP THROUGH SECTOR POP PSW ; LOAD SECTOR COUNTER DCR A ; DECREMENT JNZ SDRLP1 ; LOOP THROUGH THE SECTORS CALL ENABLE ; ENABLE INTERRUPTS AT END OF DATA MVI A,0 ; SET GOOD RETURN CODE RET ; RETURN ;* IOC SUBROUTINES * ;* PASS THE IOPB * OUTIOPB: LXI H,IOPB ; POINT AT IOPB MVI D,5 ; LOAD BYTE COUNTER MVI A,WPBC ; LOAD COMMAND FOR IOC JMP SDWPB ; GO ISSUE THE COMMAND SDWPBL1: MVI A,WPBCC ; LOAD COMMAND FOR IOC SDWPB: OUT IOCCNTR ; OUTPUT COMMAND TO IOC CALL DBBWAIT ; WAIT FOR IOC TO HANDLE MOV A,M ; PUT DATA IN ACCUMULATOR OUT IOCDATA ; PASS TO IOC CALL OUTWAIT ; WAIT FOR IOC TO HANDLE INX H ; INCREMENT CHARACTER POINTER DCR D ; DECREMENT CHARACTER COUNTER JNZ SDWPBL1 ; LOOP THROUGH IOPB RET ; RETURN ;* CHECK RESULTS OF I/O * CKRESULT: CALL DSKWAIT ; WAIT FOR WRITE TO COMPLETE CALL DSKRSLT ; GET THE RESULT BYTE MOV D,A ; SAVE ANI 1111$1110B ; DELETED DATA ? RZ ; YES - RETURN (OK FOR NOW) MOV A,D ; RESTORE BYTE ANI SEEKERR ; SEEK ERROR ? CNZ RECALIB ; YES - TRY TO RECOVER MVI A,1 ; SET BAD RETURN CODE RET ; RETURN ;* GET DISK STATUS BYTE * DSKSTAT: CALL DBBWAIT ; WAIT FOR IOC TO BE FREE MVI A,RDSTS ; SET COMMAND FOR OUTPUT OUT IOCCNTR ; ISSUE COMMAND CALL INWAIT ; WAIT FOR DATA TO BE READY IN IOCDATA ; GET THE RESULT BYTE RET ; RETURN ;* GET DISK RESULT BYTE * DSKRSLT: CALL DBBWAIT ; WAIT FOR IOC TO BE FREE MVI A,RRSTS ; SET UP COMMAND FOR OUTPUT OUT IOCCNTR ; ISSUE COMMAND CALL INWAIT ; WAIT FOR COMMAND TO COMPLETE IN IOCDATA ; READ RESULT BYTE RET ; RETURN ;* DISABLE INTERRUPTS * DISABLE: MVI A,0DH ; SET DISABLE COMMAND OUT 0FFH ; WRITE TO CONTROL PORT RET ; RETURN ;* ENABLE INTERRUPTS * ENABLE: MVI A,05H ; SET ENABLE COMMAND OUT 0FFH ; WRITE TO CONTROL PORT RET ; RETURN ;* WAIT FOR IOC TO BE FREE * DBBWAIT: IN IOCCNTR ; READ DBB STATUS BYTE ANI F0 OR OBF OR IBF ; ANYTHING PENDING JNZ DBBWAIT ; YES - SPIN RET ; ELSE RETURN ;* WAIT FOR INPUT TO BE READY * INWAIT: IN IOCCNTR ; GET THE IOC STATUS BYTE ANI OBF OR F0 OR IBF ; OUTPUT BUFFER FULL ? CPI OBF ; VALID BUFFER ? JNZ INWAIT ; NO - SPIN RET ; RETURN ;* DISK NOT READY * SDERROR: POP PSW ; CLEAN UP STACK CALL ENABLE ; ENABLE INTERRUPTS MVI A,1 ; SET RETURN CODE RET ; RETURN ;* RECALIBRATE DISK DRIVE * RECALIB: LDA IOF ; LOAD CURRENT OP CODE PUSH PSW ; SAVE MVI A,RECALB ; SET RECALIBRATE OP CODE STA IOF ; STORE IN IOPB CALL OUTIOPB ; SEND IOBP TO IOC POP PSW ; RELOAD OP CODE STA IOF ; PUT BACK IN IOPB RET ; RETURN ;* WAIT FOR IOC TO TAKE DATA ON WRITE * OUTWAIT: IN IOCCNTR ; READ STATUS PORT ANI IBF OR F0 ; DATA TAKEN ? JNZ OUTWAIT ; NO - SPIN RET ; RETURN WHEN TAKEN ;* GET DEVICE STATUS * DEVSTAT: CALL DBBWAIT ; WAIT FOR IOC TO BE READY MVI A,DSTAT ; SET OP CODE FOR GET STATUS BYTE OUT IOCCNTR ; SEND TO IOC CALL INWAIT ; WAIT FOR IT TO BE READY IN IOCDATA ; GET IT RET ; RETURN ;* WAIT FOR DISK TO BE READY * DSKWAIT: CALL DSKSTAT ; GET DISK STATUS ANI OPCOMP ; OPERATION COMPLETED ? JZ DSKWAIT ; NO - SPIN RET ; ELSE RETURN ;*************** END IOC CODE *** ;****************************************************************************** ; UTILITY SUBROUTINES PRMSG: ; PRINT MESSAGE AT H,L TO 0 MOV A,M ; ORA A ; END OF STRING? RZ ; YES PUSH H ; NO - PRINT THIS CHARACTER MOV C,A ; CALL CONOUT ; POP H ; INX H ; JMP PRMSG ; ;****************************************************************************** ; DATA AREA ;****************************************************************************** SIGNON: ;SIGNON MESSAGE: XXK CP/M VERS X.Y DB CR,LF DB MSIZE/10+'0',MSIZE MOD 10 + '0' DB 'K CP/M VERS ' DB VERS/10+'0','.',VERS MOD 10+'0',CR,LF DB 0 ; END OF SIGNON MESSAGE IOPB: ; IO PARAMETER BLOCK DB 80H ; NORMAL I/O OPERATION IOF: DB READF ; IO FUNCTION, INITIAL READ ION: DB 1 ; NUMBER OF SECTORS TO READ IOT: DB 2 ; TRACK NUMBER IOS: DB 1 ; SECTOR NUMBER IOD: DW BUFF ; IO ADDRESS SEL$TABLE: ;* DRIVE SELECT BITS * DB 00H,10H,20H,30H,40H DISKS NUM$DISKS ; GENERATE DRIVE TABLES DISKDEF 0,1,52,,2048,243,128,128,2 DISKDEF 1,0 DISKDEF 2,1,26,6,1024,243,64,64,2 DISKDEF 3,2 DISKDEF 4,2 ENDEF IOFSV DS 1 ; SAVE AREA FOR DRIVE ADDRESS HOLD$5 DS 1 IF RELOC DB 0 ; FORCE OUT LAST ADDRESS FOR RELOCATION ENDIF END