***************************************************************** * * * BIOS and Loader BIOS for CP/M Plus (Beta V1.2) for DJ2D * * controller. * * Written November 1982 by Dave Hardy and Ken Jackson * * * ***************************************************************** TITLE 'BIOS and Loader BIOS For CP/M Plus' ***************************************************************** * * * To install this BIOS into CP/M Plus, perform the following * * steps: * * 1. Add your own console and printer I/O to this file * * at CONIN:, CONOUT:, CONST:, LIST:, and LISTST: * * 2. Add any initialization that you need at TINIT: * * 3. Set the LDRBIOS equate in this file to TRUE * * 4. RMAC SCB $PZ -S (assemble SCB.ASM, supplied) * * 5. RMAC BIOS3 $PZ -S (assemble LDRBIOS) * * 6. REN LDRBIOS.REL=BIOS3.REL * * 7. Set the LDRBIOS equate in this file FALSE * * 8. RMAC BIOS3 $PZ -S (assemble BIOS) * * 9. LINK BIOS3[B]=BIOS3,SCB * * 10. GENCPM * * (answer all questions with a carriage return, * * except answer "N" at "Bank switched memory?" * * question, and answer with your top page of * * memory when asked "Top page of memory?") * * 11. LINK CPMLDR[L100]=CPMLDR,LDRBIOS * * 12. CPMLDR (Load and run CP/M Plus) * * * ***************************************************************** FALSE EQU 0 ;Define TRUE and FALSE TRUE EQU NOT FALSE ***************************************************************** * * * The following revision number is in reference to the CP/M * * Plus BIOS. * * * ***************************************************************** REVNUM EQU 10 ;BIOS revision number CPMREV EQU 30 ;CP/M revision number ***************************************************************** * * * These are the routines called from the DJ2D's built-in EPROM. * * (model B only) * * * ***************************************************************** ORIGIN EQU 0F800H ;EPROM origin of your DJ2D board DJRAM EQU ORIGIN+400H ;DJ2D RAM address DJHOME EQU DJRAM+9H ;DJ2D track zero seek DJTRK EQU DJRAM+0CH ;DJ2D track seek routine DJSEC EQU DJRAM+0FH ;DJ2D set sector routine DJDMA EQU DJRAM+012H ;DJ2D set DMA address DJREAD EQU DJRAM+15H ;DJ2D read routine DJWRITE EQU DJRAM+18H ;DJ2D write routine DJSEL EQU DJRAM+1BH ;DJ2D select drive routine DJSTAT EQU DJRAM+27H ;DJ2D status routine DJSIDE EQU DJRAM+30H ;DJ2D set side routine ***************************************************************** * * * Miscellaneous internal BIOS equates. * * We've tried to maintain compatibility with the Morrow's DJ2D * * BIOS. * * * ***************************************************************** LDRBIOS EQU FALSE ;TRUE, if want to assemble as Loader BIOS UD2 EQU TRUE ;TRUE, if want to use User/Drive byte @ addr 4 CDISK EQU 4 ;Address of last logged disk BUFF EQU 80H ;Default buffer address TPA EQU 100H ;Transient memory ENTRY EQU 5 ;BDOS entry jump address RETRIES EQU 10 ;Max retries on disk i/o before error ACR EQU 0DH ;A carriage return ALF EQU 0AH ;A line feed MAXDISK EQU 4 ;Maximum # of disk drives CLEAR EQU 1AH ;Clear Screen code for LDRBIOS ***************************************************************** * * * PUBLIC and EXTERNAL declarations required for CP/M Plus. * * * ***************************************************************** CSEG PUBLIC ?BOOT,?WBOOT,?CONST,?CONIN,?CONO,?LIST,?AUXO,?AUXI PUBLIC ?HOME,?SLDSK,?STTRK,?STSEC,?STDMA,?READ,?WRITE PUBLIC ?LISTS,?SCTRN PUBLIC ?CONOS,?AUXIS,?AUXOS,?DVTAB,?DEVIN,?DRTBL,?MLTIO,?FLUSH PUBLIC ?MOV,?TIM,?BNKSL,?STBNK,?XMOV IF NOT LDRBIOS PUBLIC ?INIT,?LDCCP EXTRN @CIVEC,@COVEC,@AIVEC,@AOVEC,@LOVEC,@MXTPA ENDIF ***************************************************************** * * * THE BIOS JUMP TABLE * * * * The jump table below must remain in the same order, the * * routines may be changed, but the function executed must be * * the same. There are 33 jumps in the CP/M Plus BIOS vector. * * * ***************************************************************** ; ?BOOT: JMP CBOOT ; cold start entry point WBOOTE: ?WBOOT: JMP WBOOT ; warm start entry point ?CONST: JMP CONST ; console status A=ff=ready ?CONIN: JMP CONIN ; console input data in A COUT: ?CONO: JMP CONOUT ; console output data in C ?LIST: JMP LIST ; list device data in C ?AUXO: JMP AUXOUT ; punch device none ?AUXI: JMP AUXIN ; reader device none ?HOME JMP HOME ; seek home track ?SLDSK: JMP SETDRV ; select disk disk in C ?STTRK: JMP SETTRK ; seek track track in BC ?STSEC: JMP SETSEC ; set sector sector in BC ?STDMA: JMP SETDMA ; set dma dma in BC ?READ: JMP READ ; read sector ?WRITE: JMP WRITE ; write sector ?LISTS: JMP LISTST ; return list status A=FF=ready ?SCTRN: JMP SECTRAN ; sector translate sector in BC ?CONOS: JMP CONOST ; Return Output Status of Console ?AUXIS: JMP AUXIST ; Return Input Status of Aux. Port ?AUXOS: JMP AUXOST ; Return Output Status of Aux. Port ?DVTAB: JMP DEVTBL ; Return Address of Char. I/O Table ?DEVIN: JMP DEVINI ; Initialize Char. I/O Devices ?DRTBL: JMP DRVTBL ; Return Address of Disk Drive Table ?MLTIO: JMP MULTIO ; Set number of logically conseqcuitive ; sectors to be read or written ?FLUSH: JMP FLUSH ; Force Physical Buffer Flushing for ; user-supported deblocking ?MOV: JMP MOVE ; Memory Move for Large Memory Copy ?TIM: JMP ?TIME ; Get The Time ?BNKSL: JMP SELMEM ; Select Alternate Bank of Memory ?STBNK: JMP SETBNK ; Select Bank for DMA Operation ?XMOV: JMP XMOVE ; Set Bank When a Buffer is in a Bank ; other than 0 or 1 DJDRV JMP DJSEL ; Hook for SINGLE.COM program ; Reserved for System Implementor JMP RESERV1 ; Reserved for CP/M Plus JMP RESERV2 ; Reserved for CP/M Plus ; ; Device Table is not implemented, so return HL=0 DEVTBL: LXI H,0 RET ; ; Flush routine is not implemented, so return A=0 FLUSH: XRA A RET ; ; Drive Table is not used, so return HL=0FFFEH DRVTBL: LXI H,0FFFEH RET ; ; The following jumps from the BIOS jump vector are not implemented: CONOST: AUXIST: AUXOUT: AUXIN: AUXOST: DEVINI: MULTIO: XMOVE: SELMEM: SETBNK: RESERV1: RESERV2: ?TIME: RET ***************************************************************** * * * Cold-boot sign-on message * * * ***************************************************************** PROMPT: IF LDRBIOS DB ACR,ALF,ALF DB 'Loader for Morrow Designs DJ2D Controller.' DB ACR,ALF,0 ENDIF ; IF NOT LDRBIOS DB ACR,ALF,ALF DB 'CP/M Plus (V' ;CP/M version number DB CPMREV/10+'0' DB '.' DB (CPMREV MOD 10)+'0' DB '), BIOS rev ' DB REVNUM/10+'0','.' ;Cbios revision number DB REVNUM MOD 10+'0' DB ACR,ALF DB 'For Morrow Designs DJ2D Controller ' DB '@ 0' IF ORIGIN/4096 > 10 ;Controller origin (HEX) DB ORIGIN/4096+'A'-10 ELSE DB ORIGIN/4096+'0' ENDIF IF (ORIGIN/256 AND 0FH) > 10 DB (ORIGIN/256 AND 0FH)+'A'-10 ELSE DB (ORIGIN/256 AND 0FH)+'0' ENDIF DB '00H.' DB ACR,ALF,0 ENDIF ***************************************************************** * * * Utility subroutine to output the message pointed at by H&L, * * terminated with a null. Used only during cold boot. * * * ***************************************************************** MESSAGE MOV A,M ;Get a character of the message INX H ;Bump text pointer ANA A ;Test for end RZ ;Return if done PUSH H ;Save pointer to text MOV C,A ;Output character in C CALL COUT ;Output the character POP H ;Restore the pointer JMP MESSAGE ;Continue until null reached ***************************************************************** * * * System initialization Subroutine * * Put any initialization procedures required by your system * * here (e.g. setting up UARTS, etc.) * * * ***************************************************************** IF LDRBIOS ;Then perform any initializations TINIT: MVI C,CLEAR ; that your system requires CALL COUT ;Clear the console screen RET ENDIF ***************************************************************** * * * Cold boot routines * * * ***************************************************************** CBOOT: IF LDRBIOS ;Then Initialize terminal or whatever CALL TINIT ENDIF ; IF NOT LDRBIOS LXI SP,TPA ;Set up stack ENDIF ; LXI H,PROMPT ;Prep for sending signon message CALL MESSAGE ;Send the prompt XRA A ;Select disk A STA CPMDRV STA CDISK ; IF NOT LDRBIOS CALL ?INIT ;Initialize page zero and SCB JMP WBOOT ;Warm-boot ; ; System initialization subroutine ?INIT: MVI A,JMP ;Set up jumps at addresses 0 and 5 STA 0 STA 5 LXI H,WBOOTE SHLD 1 LHLD @MXTPA SHLD 6 LXI H,1 ;Initialize System Control Block SHLD @CIVEC SHLD @COVEC LXI H,2 SHLD @LOVEC LXI H,4 SHLD @AIVEC SHLD @AOVEC LXI H,LOG$MSG ;Print sign-on message on console CALL MESSAGE RET ***************************************************************** * * * Subroutine to load the CCP into memory at address 100H * * * ***************************************************************** ?LDCCP: XRA A STA CCP$FCB+15 ;Start with extent 0 LXI H,0 SHLD FCB$NR ;Record 0 LXI D,CCP$FCB CALL OPEN ;Open file CCP.COM INR A JZ NO$CCP ;Tell if no file found LXI D,0100H ;Else CALL SETBUF ;Set to load into TPA LXI D,128 CALL SETMULTI ;Allow up to 16k bytes LXI D,CCP$FCB CALL REBOOT ;Read file into memory RET ; ; Print error message if can't find CCP.COM on default drive NO$CCP: LXI H,CCP$MSG CALL MESSAGE ;REPORT THIS CALL ?CONIN ;GET A RESPONSE JMP ?LDCCP ;AND TRY AGAIN ; ; CP/M BDOS function interface used to load CCP.COM OPEN: MVI C,15 JMP BDOSGO ;OPEN FILE CONTROL SETMULTI: MVI C,44 JMP BDOSGO ;SET MULTI RECORD COUNT REBOOT: MVI C,20 JMP BDOSGO ;READ RECORDS SETBUF: MVI C,26 JMP BDOSGO ;SETDMA BDOSGO: LHLD @MXTPA PCHL ; ; Miscellaneous messages for console LOG$MSG: DB 13,10,13,10,'CP/M Version 3.0',00 CCP$MSG: DB 13,10,'BIOS Err on A: NO CCP.COM file',00 ; ; File Control Block used to load CCP.COM CCP$FCB: DB 1,'CCP ','COM',0,0,0,0 DS 16 FCB$NR: DB 0,0,0 ENDIF ;NOT LDRBIOS ***************************************************************** * * * Warm-boot subroutine * * * ***************************************************************** WBOOT: IF NOT LDRBIOS LXI SP,TPA ;Set up stack pointer ENDIF ; LXI D,BUFF ;Set up initial DMA address CALL SETDMA ; IF NOT LDRBIOS CALL ?LDCCP ;Load the CCP.COM file into the TPA ENDIF ; MVI A,JMP ;Set up jumps at addresses 0 and 5 STA 0 STA 5 LXI H,WBOOTE SHLD 1 ; IF NOT LDRBIOS LHLD @MXTPA SHLD 6 ; IF UD2 ; This conditional is used if you want the system to read the ; USER/DRIVE byte at address 4 during each warm-boot, to maintain ; compatibility with certain CP/M 2.2 programs that modify this byte ; to change default user area of drive. Making this conditional TRUE ; may cause some unusual side-effects when you warm-boot while logged ; into any drive other than 'A' drive. Note also that the location of ; the warm-boot user and drive bytes in the SCB is undocumented, so it ; may be changed from the address assumed here. This may also have been ; changed since the Beta 1.2 version that we evaluated, so use it with ; a great deal of caution. ; ; Copy USER/DRIVE byte from address 4 into the System Control Block LHLD 1 ;Get address page of BIOS DCR H ;Point to default drive byte in SCB MVI L,0AFH LDA 4 ;Get default drive from User/Drive byte ANI 0FH MOV M,A ;Store DRIVE in SCB INX H ;Point to default user byte in SCB LDA 4 ;Get default user from User/Drive byte RRC RRC RRC RRC ANI 0FH MOV M,A ;Store USER in SCB ; ENDIF ;UD2 ENDIF ;NOT LDRBIOS ; LDA CDISK ;Put current disk into A MOV C,A ; IF NOT LDRBIOS JMP 0100H ;Jump to CCP ENDIF ; IF LDRBIOS RET ;Return to loader ENDIF ***************************************************************** * * * General purpose memory move subroutine. * * Moves BC bytes from DE to HL * * * ***************************************************************** MOVE: LDAX D MOV M,A INX D INX H DCR C JNZ MOVE MOV A,B ORA C RZ DCR B JMP MOVE ***************************************************************** * * * Setsec subroutine saves the desired sector to seek to until * * an actual read or write is attempted. * * * ***************************************************************** SETSEC MOV A,C ;Save the sector number STA CPMSEC RET ***************************************************************** * * * Setdma subroutine saves the DMA address for the data transfer.* * * ***************************************************************** SETDMA MOV H,B ;Save DMA address that is in BC MOV L,C SHLD CPMDMA RET ***************************************************************** * * * Home subroutine does a seek to track zero. * * * ***************************************************************** HOME MVI C,0 ;Track to seek to ***************************************************************** * * * Settrk subroutine saves the TRK # to seek to. Nothing is done * * until an actual read or write. * * * ***************************************************************** SETTRK MOV A,C STA CPMTRK RET ***************************************************************** * * * Sectran subroutine translates a logical sector # into a * * physical sector #. Note that this routine is similar to the * * original one used in the DJ2D CP/M 2 BIOS, but has some * * significant differences. * * * ***************************************************************** SECTRAN INX B PUSH D ;Save table address PUSH B ;Save sector # CALL GETDPB ;Get DPB address into HL MOV A,M ;Get # of CP/M sectors/track ORA A ;Clear carry RAR ;Divide by two SUB C PUSH PSW ;Save adjusted sector JM SIDETWO SIDEA POP PSW ;Discard adjusted sector POP B ;Restore sector requested POP D ;Restor address of xlt table SIDEONE XCHG ;exchange DPB and table address DAD B ;bc = offset into table MOV L,M ;hl <- physical sector MVI H,0 RET SIDETWO LXI B,17 ;Offset to side bit DAD B MOV A,M ANI 8 ;Test for double sided JZ SIDEA ;Media is only single sided POP PSW ;Retrieve adjusted sector POP B CMA ;Make sector request positive INR A MOV C,A ;Make new sector the requested sector POP D CALL SIDEONE MVI A,80H ;Side two bit ORA L ; and sector MOV L,A RET ***************************************************************** * * * Setdrv subroutine selects the next drive to be used in * * read/write operations. If the drive has never been selected * * before, a parameter table is created which correctly * * describes the diskette currently in the drive. Diskettes can * * be of four different sector sizes: * * 1) 128 bytes single density. * * 2) 256 bytes double density. * * 3) 512 bytes double density. * * 4) 1024 bytes double density. * * Note the changes made for CP/M 3.0 * * * ***************************************************************** SETDRV MOV A,C ;Save the drive # STA CPMDRV CPI MAXDISK ;Check for a valid drive # JNC ZRET ;Illegal drive # MOV A,E ;Test if drive ever logged in before ANI 1 JNZ SETDRV1 ;Bit 0 of E = 0 means never selected before MVI A,1 ;Select sector 1 of track 1 STA TRUESEC STA CPMTRK CALL FILL ;Flush buffer and refill JC ZRET ;Test for error return CALL DJSTAT ;Get status on current drive ANI 2CH ;Look at side and denstiy bits MOV E,A ANI 20H MOV A,E JNZ SETDR1 ORI 10H SETDR1: RAR PUSH PSW ;Save DJSTAT single/double-sided info ANI 6 LXI H,XLTS ;Table of XLT addresses PUSH H MOV E,A MVI D,0 DAD D PUSH H ;Save pointer to proper XLT CALL GETDPB ;Get DPH pointer into DE XCHG ; POP D MVI B,2 ;Number of bytes to move CALL MOVLOP ;Move the address of XLT LXI D,10 ;Offset to DPB pointer DAD D ;Point HL to DPB address XCHG ;Point HL to DBP base, DE to &DPH.DPB POP H POP PSW ;Offset to correct DPB MOV C,A MVI B,0 DAD B ;Add to translate table to point to density ;(The DPB table is cleverly located right ; after the xlt table) XCHG ;Put DPB address in DPH MVI B,2 ;Move DPB address into DPH CALL MOVLOP SETDRV1 CALL GETDPB ;Get address of DPB in HL LXI B,17 ;Offset to sector size DAD B MOV A,M ;Get sector size ANI 7H STA SECSIZ MOV A,M RAR RAR RAR RAR ANI 0FH STA SECPSEC ;Single/double-sided flag XCHG ;HL to DPH RET ZRET LXI H,0 ;Seldrv error exit RET ***************************************************************** * * * Getdpb subroutine returns HL pointing to the DPB of the * * currently selected drive, DE pointing to DPH. * * * ***************************************************************** GETDPB: LDA CPMDRV ;Get drive # LXI H,DPZERO LXI D,19H GETDP1: ORA A JZ GETDP2 DAD D DCR A JMP GETDP1 ; GETDP2: PUSH H ;Save address of DPH LXI D,12 ;Offset to DPB DAD D MOV A,M ;Get low byte of DPB address INX H MOV H,M ;Get low byte of DPB MOV L,A POP D RET ***************************************************************** * * * xlts points to a table of addresses that point to each * * of the xlt tables for each sector size. * * * * The table following the xlt's is a table of the DPB's, used * * by the SETDRV subroutine to calculate density * * * ***************************************************************** XLTS DW XLT128 ;Xlt for 128 byte sectors DW XLT256 ;Xlt for 256 byte sectors DW XLT512 ;Xlt for 512 byte sectors DW XLT124 ;Xlt for 1024 byte sectors ; DW DPB128S ;DPB FOR 128 BYTE SECTORS SINGLE SIDE DW DPB256S ;DPB FOR 256 BYTE SECTORS SINGLE SIDE DW DPB512S ;DPB FOR 512 BYTE SECTORS SINGLE SIDE DW DP1024S ;DPB FOR 1024 BYTE SECTORS SINGLE SIDE DW DPB128D ;DPB FOR 128 BYTE SECTORS DOUBLE SIDE DW DPB256D ;DPB FOR 256 BYTE SECTORS DOUBLE SIDE DW DPB512D ;DPB FOR 512 BYTE SECTORS DOUBLE SIDE DW DP1024D ;DPB F0R 1024 BYTE SECTORS DOUBLE SIDE ***************************************************************** * * * Write subroutine moves data from memory into the buffer. If * * the desired CP/M sector is not contained in the disk buffer, * * the buffer is first flushed to the disk if it has ever been * * written into, then a read is performed into the buffer to get * * the desired sector. Once the correct sector is in memory, the * * buffer written indicator is set, so the buffer will be * * flushed, then the data is transferred into the buffer. * * * ***************************************************************** WRITE MOV A,C ;Save write command type STA WRITTYP MVI A,1 ;Set write command DB (MVI) OR (B*8) ;Fake "mvi b" instruction will ; cause the following "xra a" to ; be skipped over. ;This is the same (ugh) trick that ;Morrow's used, but it works... ***************************************************************** * * * Read subroutine to buffer data from the disk. If the sector * * requested from CP/M is in the buffer, then the data is simply * * transferred from the buffer to the desired dma address. If * * the buffer does not contain the desired sector, the buffer is * * flushed to the disk if it has ever been written into, then * * filled with the sector from the disk that contains the * * desired CP/M sector. * * * ***************************************************************** READ XRA A ;Set the command type to read STA RDWR ;Save command type ; ; Redwrt calculates the physical sector on the disk that ; contains the desired CP/M sector, then checks if it is the ; sector currently in the buffer. If no match is made, the ; buffer is flushed if necessary and the correct sector read ; from the disk. REDWRT MVI B,0 ;The 0 is modified to contain the log2 SECSIZ EQU $-1 ; of the physical sector size/128 ; on the currently selected disk. ;(Another Morrow trick) LDA CPMSEC ;Get the desired CP/M sector # PUSH PSW ;Temporary save ANI 80H ;Save only the side bit MOV C,A ;Remember the side POP PSW ;Get the sector back ANI 7FH ;Forget the side bit DCR A ;Temporary adjustment DIVLOOP DCR B ;Update repeat count JZ DIVDONE ORA A ;Clear the carry flag RAR ;Divide the CP/M sector # by the size ; of the physical sectors JMP DIVLOOP ; DIVDONE INR A ORA C ;Restore the side bit STA TRUESEC ;Save the physical sector number LXI H,CPMDRV ;Pointer to desired drive,track, and sector LXI D,BUFDRV ;Pointer to buffer drive,track, and sector MVI B,4 ;Count loop DTSLOP DCR B ;Test if done with compare JZ SECMOV ;Yes, match. Go move the data LDAX D ;Get a byte to compare CMP M ;Test for match INX H ;Bump pointers to next data item INX D JZ DTSLOP ;Match, continue testing ; ; If drive, track, and sector don't match, then flush the buffer if ; necessary and refill. CALL FILL ;Get correct physical sector into buffer RC ;Return error if no good ; ; SECMOV has been previously modified to cause either a transfer ; into or out of the buffer. (Yet another Morrow trick) SECMOV LDA CPMSEC ;Get the CP/M sector to transfer DCR A ;Adjust to proper sector in buffer ANI 0 ;Strip off high ordered bits SECPSEC EQU $-1 ;The 0 is modified to represent the # of ; CP/M sectors per physical sectors MOV L,A ;Put into HL MVI H,0 DAD H ;Form offset into buffer DAD H DAD H DAD H DAD H DAD H DAD H LXI D,BUFFER ;Beginning address of buffer DAD D ;Form beginning address of sector to transfer XCHG ;DE = address in buffer LXI H,0 ;Get DMA address, the 0 is modified to ; contain the DMA address CPMDMA EQU $-2 MVI A,0 ;The zero gets modified to contain ; a zero if a read, or a 1 if write RDWR EQU $-1 ANA A ;Test which kind of operation JNZ INTO ;Transfer data into the buffer CALL MOVER XRA A RET INTO XCHG ; CALL MOVER ;Move the data, HL = destination ; DE = source MVI A,1 STA BUFWRTN ;Set buffer written into flag MVI A,0 ;Check for directory write WRITTYP EQU $-1 DCR A MVI A,0 STA WRITTYP ;Set no directory write RNZ ;No error exit ***************************************************************** * * * FLUSHA subroutine writes the contents of the buffer out to * * the disk if it has ever been written into. * * * ***************************************************************** FLUSHA MVI A,0 ;The 0 is modified to reflect if ; the buffer has been written into BUFWRTN EQU $-1 ANA A ;Test if written into RZ ;Not written, all done LXI H,DJWRITE ;Write operation ; ; Prep prepares to read/write the disk. Retries are attempted. ; Upon entry, H&L must contain the read or write operation ; address. PREP XRA A ;Reset buffer written flag STA BUFWRTN SHLD RETRYOP ;Set up the read/write operation MVI B,RETRIES ;Maximum number of retries to attempt RETRYLP PUSH B ;Save the retry count LDA BUFDRV ;Get drive number involved in the operation MOV C,A CALL DJDRV ;Select the drive LDA BUFTRK ANA A ;Test for track zero MOV C,A PUSH B CZ DJHOME ;Home the drive if track 0 POP B ;Restore track # CALL DJTRK ;Seek to proper track LDA BUFSEC ;Get sector involved in operation PUSH PSW ;Save the sector # RLC ;Bit 0 of A equals side # ANI 1 ;Strip off unnecessary bits MOV C,A ;C <- side # CALL DJSIDE ;Select the side POP PSW ;A <- sector # ANI 7FH ;Strip off side bit MOV C,A ;C <- sector # CALL DJSEC ;Set the sector to transfer LXI B,BUFFER ;Set the DMA address CALL DJDMA CALL DJREAD ;The read operation is modified to write RETRYOP EQU $-2 POP B ;Restore the retry counter MVI A,0 ;No error exit status RNC ;Return no error DCR B ;Update the retry counter STC ;Assume retry count expired MVI A,0FFH ;Error return RZ JMP RETRYLP ;Try again ***************************************************************** * * * Fill subroutine fills the buffer with a new sector * * from the disk. * * * ***************************************************************** FILL CALL FLUSHA ;Flush buffer first RC ;Check for error LXI D,CPMDRV ;Update the drive, track, and sector LXI H,BUFDRV MVI B,3 ;Number of bytes to move CALL MOVLOP ;Copy the data LXI H,DJREAD JMP PREP ;Select drive, track, and sector. ; Then read the buffer ***************************************************************** * * * Mover subroutine moves 128 bytes of data. Source pointer * * in DE, Dest pointer in HL. * * * ***************************************************************** MOVER MVI B,128 ;Length of transfer MOVLOP LDAX D ;Get a bte of source MOV M,A ;Move it INX D ;Bump pointers INX H DCR B ;Update counter JNZ MOVLOP ;Continue moving until done RET ***************************************************************** * * * Terminal driver subroutines. Note that the console device * * is NOT the DJ2D memory-mapped serial I/O port. * * * ***************************************************************** ***************************************************************** * * * const: get the status for the console * * * ***************************************************************** CONST IN 80H ;Read console status port ANI 40H MVI A,0 RZ ;Return A=0, if no character waiting INR A RET ;Else return A=01H ***************************************************************** * * * conin: get a character from the console * * * ***************************************************************** CONIN: IN 80H ;Read console status port ANI 40H JZ CONIN ;Wait for a character IN 81H ;Read the console data port ANI 7FH ;Mask the MSB RET ;Return with the character in A ***************************************************************** * * * conout: send a character to the console * * * ***************************************************************** CONOUT IN 80H ;Read the console status port ANI 80H JZ CONOUT ;Wait until character can be sent MOV A,C OUT 81H ;Send character to console data port RET ;Return ***************************************************************** * * * listst: get the status for the list device. Note that the * * list device used is the memory-mapped DJ2D serial I/O port. * * * ***************************************************************** LISTST: LDA ORIGIN+3F9H ;Read printer status port (memory mapped) CMA ; (invert to positive logic) ANI 08H MVI A,00H RZ ;return A=0, if not ready MVI A,0FFH ;return A=0FFH, if ready RET ***************************************************************** * * * list: send a character to the list device * * * ***************************************************************** LIST: LDA ORIGIN+3F9H ;Read list device status (memory mapped) CMA ; (invert it to positive logic) ANI 08H ;Wait until ok to send JZ LIST MOV A,C ;Send the character CMA ; (invert it to positive logic) STA ORIGIN+3F8H ; to memory mapped I/O. RET ***************************************************************** * * * Xlt tables (sector skew tables) These tables * * define the sector translation that occurs when mapping CP/M * * sectors to physical sectors on the disk. There is one skew * * table for each of the possible sector sizes. * * * ***************************************************************** XLT128 DB 0 DB 1,7,13,19,25 DB 5,11,17,23 DB 3,9,15,21 DB 2,8,14,20,26 DB 6,12,18,24 DB 4,10,16,22 XLT256 DB 0 DB 1,2,19,20,37,38 DB 3,4,21,22,39,40 DB 5,6,23,24,41,42 DB 7,8,25,26,43,44 DB 9,10,27,28,45,46 DB 11,12,29,30,47,48 DB 13,14,31,32,49,50 DB 15,16,33,34,51,52 DB 17,18,35,36 xlt512 db 0 db 1,2,3,4,17,18,19,20 db 33,34,35,36,49,50,51,52 db 5,6,7,8,21,22,23,24 db 37,38,39,40,53,54,55,56 db 9,10,11,12,25,26,27,28 db 41,42,43,44,57,58,59,60 db 13,14,15,16,29,30,31,32 db 45,46,47,48 XLT124 DB 0 DB 1,2,3,4,5,6,7,8 DB 25,26,27,28,29,30,31,32 DB 49,50,51,52,53,54,55,56 DB 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 DB 57,58,59,60,61,62,63,64 DB 17,18,19,20,21,22,23,24 DB 41,42,43,44,45,46,47,48 ***************************************************************** * * * DISK PARAMETER BLOCKS. The following sizes and densities are * * specified to maintain compatibility with DJ2D CP/M 2.2: * * 128 bytes, SSSD * * 256 bytes, SSDD * * 512 bytes, SSDD * * 1024 bytes, SSDD * * 128 bytes, DSDD * * 256 bytes, DSDD * * 512 bytes, DSDD * * 1024 bytes, DSDD * * * ***************************************************************** ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and single sided. * * * ***************************************************************** DPB128S DW 26 ;SPT Number of CP/M sectors/track DB 3 ;BSH Block Shift Factor DB 7 ;BLM Block Mask DB 0 ;EXM Extent Mask DW 242 ;DSM Disk Space Maximum DW 63 ;DRM Directory Maximum DB 0C0H ;AL0 Initial Allocation Vectors DB 0 ;AL1 DW 16 ;CKS Directory Check Size DW 2 ;OFF Track Offset DB 00 ;PSH Physical Record Shift factor DB 00 ;PHM Physical Record Mask ;(Following byte is used only by the BIOS) DB 1H ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 256 byte sectors, * * double density, and single sided. * * * ***************************************************************** DPB256S DW 52 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 242 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 12H ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and single sided. * * * ***************************************************************** DPB512S DW 60 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 280 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 33H ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and single sided. * * * ***************************************************************** DP1024S DW 64 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 299 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 74H ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and double sided. * * * ***************************************************************** DPB128D DW 52 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 1 ;EXM DW 242 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 9H ***************************************************************** * * * The following DPB defines a diskette as 256 byte sectors, * * double density, and double sided. * * * ***************************************************************** DPB256D DW 104 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 486 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 1AH ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and double sided. * * * ***************************************************************** DPB512D DW 120 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 561 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 3BH ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and double sided. * * * ***************************************************************** DP1024D DW 128 ;CP/M sectors/track DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 599 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 00 ;PSH DB 00 ;PHM ; DB 7CH ***************************************************************** * * * DISK PARAMETER HEADERS (for four drives) * * * ***************************************************************** DPZERO DW 0 ;XLT Address of translation table (filled ; in by setdrv) DW 0,0,0,0 ;-0- BDOS Scratch Area DB 0 DB 0 ;MF Media Flag DW 0 ;DPB Address of DPB (filled in by setdrv) DW CSV0 ;CSV Directory check vector DW ALV0 ;ALV Allocation vector DW DIRBCB ;DIRBCB Directory Buffer Control Block DW 0FFFFH ;DTABCB Data Buffer Control Block DW 0FFFFH ;HASH Directory Hashing Table DB 0 ;HBANK Bank number of Hash Table ; DPONE DW 0 DW 0,0,0,0 DB 0 DB 0 DW 0 DW CSV1 DW ALV1 DW DIRBCB DW 0FFFFH DW 0FFFFH DB 0 ; DPTWO DW 0 DW 0,0,0,0 DB 0 DB 0 DW 0 DW CSV1 DW ALV1 DW DIRBCB DW 0FFFFH DW 0FFFFH DB 0 ; DPTHRE DW 0 DW 0,0,0,0 DB 0 DB 0 DW 0 DW CSV1 DW ALV1 DW DIRBCB DW 0FFFFH DW 0FFFFH DB 0 ***************************************************************** * * * Directory Buffer Control Block * * * ***************************************************************** DIRBCB: DB 0FFH ;DRV Drive number DB 00,00,00 ;REC# Record position in buffer DB 00 ;WFLG Buffer Written flag DB 00 ;00 BDOS scratch byte DW 0000 ;TRACK Buffer contents' phys track DW 0000 ;SECTOR Buffer contents' phys sector DW DIRBUF ;BUFFAD Buffer address ***************************************************************** * * * Miscellaneous ram locations used by the BIOS * * * ***************************************************************** CPMSEC DB 0 ;CP/M sector # CPMDRV DB 0 ;CP/M drive # CPMTRK DB 0 ;CP/M track # TRUESEC DB 0 ;Disk Jockey sector that contains CP/M sector BUFDRV DB 0 ;Drive that buffer belongs to BUFTRK DB 0 ;Track that buffer belongs to BUFSEC DB 0 ;Sector that buffer belongs to BUFFER DS 1024 ;Maximum size buffer for 1K sectors ***************************************************************** * * * Allocation Vectors (for four drives) * * Each vector requires 2 bits for each block on the drive * * * ***************************************************************** ALV0 DS 150 ;Allocation vector for drive A ALV1 DS 150 ;Allocation vector for drive B ALV2 DS 150 ;Allocation vector for drive C ALV3 DS 150 ;Allocation vector for drive D ***************************************************************** * * * Checksum Vectors (for four drives) * * Each vector requires 1 bit for every four directory entries * * * ***************************************************************** CSV0 DS 64 ;Directory check vector for drive A CSV1 DS 64 ;Directory check vector for drive B CSV2 DS 64 ;Directory check vector for drive C CSV3 DS 64 ;Directory check vector for drive D ***************************************************************** * * * Directory Buffer * * * ***************************************************************** DIRBUF DS 128 ; END