PAGE 60 TITLE CP/M and MP/M Loader BIOS ; ; LDRFBIOS.MAC ; Front-end Loader BIOS for CP/M-MP/M loaders ; Source created from MSCBIOS ; ; Created 80Dec03 by: John E. Lauber ; Copyright 1980, Measurement Systems and Controls, Inc. ; Edit history, ; 80Nov01 - Source created from front end BIOS. ; 81Jan24 - Converted to 16-bit sector operations. ; 81Jul16 - Added NEW low-level driver link. ; This source is written for MACRO-80 (Microsoft's Z-80 macro assembler) .Z80 ; for ZILOG ; Loader equates LDRE EQU 100H ; MP/M or CP/M loader entry point STACK EQU 80H ; stack area @UDSK EQU 4 ; default drive number location ; These entry points are used for console I/O EXTRN CONOT ; console output EXTRN INITIO ; I/O device initialization ; These entry points are used for physical device I/O ; NOTE - See the implementation guide for definitions. EXTRN SECBUF ; Base of Sector buffer EXTRN DPH.A ; only valid header address ; Globals for device drivers. GLOBAL DVRTBL ; base of drive descriptor block GLOBAL DIRBUF ; base of directory buffer GLOBAL OPFLGS ; driver option flags GLOBAL PNTMSG ; dummy print message routine ; I/O Jump Vector. JP LDRE ; from cold start loader JP LDRE ; from page 0 Warm Boot entry point JP DUMMY ; check console status JP DUMMY ; get console character JP CONOT ; put console character JP DUMMY ; put list device character JP DUMMY ; put punch device character JP DUMMY ; get reader character JP HOME ; Home the head to track zero JP SELDSK ; select disk JP SETTRK ; seek track JP SETSEC ; set sector JP SETDMA ; set DMA address JP READ ; read selected sector JP WRITE ; write selected sector JP DUMMY ; check list device status JP SECTRN ; translate logical to physical sector DUMMY: XOR A PNTMSG: RET ; dummy entry point ; Select Disk routine. ; Note - only one disk supported SELDSK: PUSH BC ; save disk number in reg C CALL INITIO ; initialize I/O driver CALL INIDVR ; initialize disk driver LD A,(@UDSK) ; get default drive number LD (DVRTBL+DSK),A ; set returned drive # in table LD (USRDSK),A ; and current drive storage POP BC ; restore disk number ; LD A,C ; get disk # in ACC OR A ; set flags LD HL,0 RET NZ ; if not disk 0 ; LD HL,DPH.A ; load header address LD A,L OR H RET Z ; if device not present ; CALL DFMT ; look up device format LD A,L OR H RET Z ; if device format unknown ; EX DE,HL LD A,(DE) ; get FMT byte LD (FMTFL),A ; set as current format type ; LD HL,DPH.A ; load header address INC DE ; point to translate table address LD A,(DE) LD (HL),A INC HL INC DE LD A,(DE) LD (HL),A ; patch translate table into header INC DE ; point to DPB LD (USRDPB),DE ; store it away LD BC,9 ADD HL,BC ; point to DPB in DPH LD (HL),E INC HL LD (HL),D ; store in DPH ; LD HL,DPH.A ; load header addr RET ; done, back to loader ; Home routine. ; Position R/W head on track zero ; HOME: LD BC,0 ; prep for SETTRK ; ; Set Track routine. ; New track number in reg C ; SETTRK: LD (USRTRK),BC ; update storage RET ; done ; Set Sector routine. ; New sector number in reg C ; SETSEC: LD (LACSEC),BC ; set varible RET ; done ; Sector Translation routine. ; Logical CP/M sector in BC, DE->translate table ; If (SPT) greater than 256, then 16-bit translate table is referenced ; If (SPT) less than 256, 8-bit translate table is referenced ; with register H set to 0. ; if DE=0 then no translation will take place (sector adjusted by 1). ; Return with physical sector in reg HL. ; SECTRN: LD (USRSEC),BC ; set unlace user sector LD H,B LD L,C ; move sector to HL LD A,E OR D ; check DE for zero JR Z,NOTRN ; yes, no translation PUSH HL ; save sector LD HL,(USRDPB) INC HL ; point to SPT high order byte LD A,(HL) ; get the byte POP HL ; restore sector OR A JR NZ,SECT16 ; branch if 16-bit sector field ADD HL,DE ; point to entry LD L,(HL) ; get 8-bit sector LD H,0 ; mask to 8-bit sector RET ; done SECT16: ADD HL,HL ; sector number times 2 ADD HL,DE ; point to 16-bit entry LD A,(HL) ; get low order byte INC HL LD H,(HL) ; get high order byte LD L,A ; join with low order RET ; done NOTRN: INC HL ; adjust 0-x to 1-x+1 RET ; done ; Set DMA address routine. ; New DMA address in regs BC ; SETDMA: LD (DMAADD),BC ; set it LD A,(OPFLGS) ; get driver option flags RET ; done ; Loader Write entry. ; Note - Not supported ; WRITE: LD A,1 RET ; return with error code ; CP/M read record entry. ; READ: ; ; This point begins the proccedure for blocking the logical ; CP/M sector up to the physical sector. ; LD HL,(LACSEC) ; get lace sector DEC HL ; adjust relative 0 LD A,(FMTFL) ; get format flags PUSH AF AND 7FH ; pre-select side 0 LD B,A ; store it in B POP AF BIT SD2,A ; test for double-sided device JR Z,BLKSEC ; skip side select if single-sided ; ; Select side 0 or side 1 of device by subtracting 1/2 the ; SPT value to select side and new sector on side 1. ; PUSH HL ; save logical sector LD HL,(USRDPB) ; get user DPB INC HL LD D,(HL) SRL D DEC HL LD E,(HL) RR E ; 1/2 SPT in DE POP HL ; restore logical sector PUSH HL OR A SBC HL,DE ; sector - 1/2 SPT POP HL JR C,BLKSEC ; CY set if side 0 SBC HL,DE SET SD2,B ; ; Now block up to the physical sector and create ; a sector mask byte for future use. ; BLKSEC: LD A,B ; get FMT value LD (USRFMT),A ; set in block AND 3 ; mask sector size LD B,A ; and place in B XOR A BLKS1: DEC B ; decrement sector size JP M,BLKS2 ; if done SRL H RR L ; divide sector by 2 SCF RLA ; extend sector mask JR BLKS1 ; and loop BLKS2: LD (RECMSK),A ; store record mask INC HL ; adjust relative 1 LD (USRSEC),HL ; store physical sector ; ; Compare the selected physical sector with the ; current physical sector and skip reading if buffer current. ; LD HL,DVRTBL ; point to disk I/O table LD DE,USRTBL ; point to user select table LD B,6 CHKSEC: LD A,(DE) CP (HL) JR NZ,NEWSEC ; if bad match, select new sector INC HL INC DE ; bump pointers DJNZ CHKSEC JR SAMSEC ; must be same sector NEWSEC: ; ; Copy the new sector into physical I/O table. ; LD HL,USRTBL LD DE,DVRTBL LD BC,6 LDIR ; update current disk table XOR A LD (RESULT),A CALL DREAD ; call physical driver I/O LD A,(RESULT) OR A LD A,1 RET NZ ; if errors SAMSEC: LD A,(LACSEC) ; get selected sector DEC A ; adjust for logical record (0-x) LD HL,RECMSK AND (HL) ; de-block sector RRA LD D,A LD A,0 RRA LD E,A ; relative offset in buffer LD HL,SECBUF ADD HL,DE ; HL=absolute address LD DE,(DMAADD) ; get CP/M DMA address LD BC,128 LDIR ; move the record XOR A ; zero ACC RET ; done ; Find and execute DFMT routine of current DVRTBL drive number. ; DFMT: LD BC,18 ; offset for DFMT routine address JR EXCDVR ; execute routine ; Find and execute DREAD routine of current DVRTBL drive number. ; DREAD: LD BC,20 ; offset for DREAD routine addr JR EXCDVR ; execute routine ; Find and execute DWRITE routine of current DVRTBL drive number. ; DWRITE: LD BC,22 ; offset for DWRITE routine addr ; ; Common code for executing low-level driver routine. ; EXCDVR: LD HL,DPH.A ; load header address ; ADD HL,BC ; point to routine addr LD A,(HL) INC HL LD H,(HL) LD L,A ; load address JP (HL) ; and execute ; Initialize low-level driver ; INIDVR: LD HL,DPH.A ; load header addr LD DE,16 ; offset for init routine ADD HL,DE LD A,(HL) INC HL LD H,(HL) LD L,A OR H ; test for routine presence RET Z ; skip if not there JP (HL) ; or execute it ; Variable and data area. ; user selected table USRTBL EQU $ ; user select table USRDSK: DB 0 ; user selected disk USRTRK: DW 0 ; track USRSEC: DW 0 ; sector USRFMT: DB 0 ; format DMAADD: DW 0 ; CP/M DMA address USRDPB: DW 0 ; current DPB LACSEC: DW 0 ; CP/M laced sector RECMSK: DB 0 ; record mask FMTFL: DB 0 ; device format flag SD2 EQU 7 ; two sided OPFLGS: DB 0 ; driver option flags ; Physical driver table DVRTBL EQU $ ; primitive disk I/O driver table DB 0 ; current disk DW 0 ; track DW 0 ; sector DB 0 ; format specifier DW SECBUF ; DMA address DW DPH.A ; DPH address DB 0 ; I/O operation results ; driver table layout DSK EQU 0 TRK EQU 1 SEC EQU 3 FMT EQU 5 DMA EQU 6 DPH EQU 8 RESULT EQU 10 ; Directory buffer DIRBUF: DS 128 ; end of variables END