Subttl -Firmware BIOS Support Routines (Rev_20 11_Jan_84) ; ; Copyright 1983, 1984 ; Morrow Designs, inc. ; San Leandro, Ca. ; Howard Fulmer, John Zalabak .z80 ; switch set to assemble z80 nemonics include HD20DEF.MAC ; Include Global Equates aseg org o_bios ;See the hd*def.mac module for definition ; Index: ROM BIOS Routines ;------------------------- ; ; home Home the Disk Heads ; gdsk set hl pair as a pointer to mtab ; rdlsec read a logical sector ; wrlsec write a logical sector ; rwoper common routine section for read/write logical sectors ; rdhst read a sector (host level translation) ; wrthst write a sector (host level translation) ; fmthst format a track (host level translation) ; iohost Hst* to Phy* Translations for read/write/format page 64 ;---------------------------------------------------------------------- ; Linkage Definitions ;-------------------- ; public home ;Home the Disk Heads public gdsk ;Return a pointer to the current MTAB public rdlsec ;read a logical sector public wrlsec ;write a logical sector public rdhst ;read a physical sector handeling public wrthst ;write a physical sector handeling public fmthst ;Format a track ; In the Disk Module external discio ;Read/Write a sector w/error handeling external rdio ;read a physical sector external wrio ;write a physical sector external fmtio ;format a physical track ;---------------------------------------------------------------------- ; Local Equates ;-------------- ; ; NONE page ;---------------------------------------------------------------------- ; Macro Definitions ;------------------ ; ; ; Move a byte from IY+SOURCE to IY+DEST ;-------------------------------------- ; IYtoIY1 macro SOURCE, DEST ld a,(iy+SOURCE) ld (iy+DEST),a endm ; Move a word from IY+SOURCE to IY+DEST ;-------------------------------------- ; IYtoIY2 macro SOURCE, DEST ld a,(iy+SOURCE) ld (iy+DEST),a ld a,(iy+SOURCE+1) ld (iy+DEST+1),a endm ; Increment a byte whose locations is given relative to the IY register ;---------------------------------------------------------------------- ; incIY1 macro SOURCE inc (iy+SOURCE) endm ; Increment a word whose locations is given relative to the IY register ;---------------------------------------------------------------------- ; incIY2 macro SOURCE local SKIP inc (iy+SOURCE) jr nz,SKIP inc (iy+SOURCE+1) SKIP: endm page ; If byte-arg1 (IY) not equal to byte-arg2 (IY) then goto VECTOR ;--------------------------------------------------------------- ; IYneIY1 macro ARG1, ARG2, VECTOR ld a,(iy+ARG1) cp (iy+ARG2) jp nz,VECTOR endm ; If word-arg1 (IY) not equal to word-arg2 (IY) then goto VECTOR ;--------------------------------------------------------------- ; IYneIY2 macro ARG1, ARG2, VECTOR ld a,(iy+ARG1+1) cp (iy+ARG2+1) jp nz,VECTOR ld a,(iy+ARG1) cp (iy+ARG2) jp nz,VECTOR endm ; If word-arg1 (IY) less-than-or-equal-to word-arg2 (IY) then goto VECTOR ;------------------------------------------------------------------------ ; IYltIY2 macro ARG1, ARG2, VECTOR ld l,(iy+ARG1) ld h,(iy+ARG1+1) ld e,(iy+ARG2) ld d,(iy+ARG2+1) scf ccf sbc hl,de jr nc,VECTOR endm page ;====================================================================== ; HOME - home the disk head ;========================== ; home: bit @HSTWRT,(iy+DFlag) ;clear host active flag jr nz,hmsk ;unless write is pending. res @HSTACT,(iy+DFlag) hmsk: ld (iy+sektrk),0 ;set track to 0 ret ;====================================================================== ; GDSK - set hl pair as a pointer to mtab ;======================================== ; gdsk: push iy pop hl ;HL:= Start of the IY area ld de,MToff ;DE:= Offset to the start of MTABs add hl,de ;HL:= Base of MTAB tables rlca rlca rlca rlca ;A:= Drive Number * 16 ld e,a ld d,0 add hl,de ;HL:= Start of this drive's MTAB ret page ;====================================================================== ; RDLSEC - read a logical sector (13_Oct_83) ;=========================================== ; rdlsec: ld (iy+unacnt),0 ;clear unacnt set @READOP,(iy+DFlag) ;set for read op set @RSFLAG,(iy+DFlag) ;force read ld (iy+wrtype),wrual ;treat as unalloc jp rwoper ;====================================================================== ; WRLSEC - write a logical sector (13_OCT_83) ;============================================ ; 1) The write type (in the C register on entry) is saved and the ; read operation flag is set ; 2) If this is an UNallocated write then the unallocated count, disk ; track and sector are initialized ; 3) If there is space remaining in the current block AND it matches the ; the SEK* block then the unallocated sector (unacnt) is incremented ; (If the unallocated sector is equal to the maximum number of sectors ; per track then it is reset to 1 and the unallocated track number is ; incremented) ; 4) If there isn't space or the current unallocated block doesn't match ; the desired block then the current unallocated count (unacnt) is ; reset to zero and the read sector flag is set. ; wrlsec: res @READOP,(iy+DFlag) ;operation:= write ld a,(iy+wrtype) ;If (this is an unallocated write) cp wrual jr nz,chkuna IYtoIY1 unamax, unacnt ; Unallocated_Count:= Max-count IYtoIY1 sekdsk, unadsk ; Unallocated_Disk:= Seek_Disk IYtoIY2 sektrk, unatrk ; Unallocated_Track:= Seek_Track IYtoIY2 seksec, unasec ; Unallocated_Sector:= Seek_Sector chkuna: ld a,(iy+unacnt) ;If (there are Unallocated blocks left) or a jr z,alloc ; (goto alloc if not) dec (iy+unacnt) ; Dec Current_Unallocated_Count IYneIY1 sekdsk, unadsk, alloc ; if (unalloc-disk eq Sek-Disk) & IYneIY2 sektrk, unatrk, alloc ; (unalloc-trk eq Sek-Trk) & IYneIY2 seksec, unasec, alloc ; (unalloc-sect eq Sek-Sect) incIY2 unasec ; inc unalloc sector count IYltIY2 sectrk, unasec, noovf ; If (Sectors/Track lt Current Sector) incIY2 unatrk ; inc unalloc-track ld (iy+unasec),1 ; unalloc-sector = 1 ld (iy+unasec+1),0 noovf: res @RSFLAG,(iy+DFlag) ; (else - no read needed) jr rwoper alloc: ld (iy+unacnt),0 ;Else clear unalloc count set @RSFLAG,(iy+DFlag) ; read needed page ;---------------------------------------------------------------------- ; RWOPER - Common section for read/write logical sectors (27_Dec_83) ;------------------------------------------------------------------- ; This routine does the following: ; 1) Calculates the physical sector (hstsec) within which the ; logical sector (seksec) resides ; 2) Generates an offset (trusec) that is used to calculate the ; logical sector's starting location within the physical ; sector's buffer ; 3) Checks if the host buffer already contains a sector ; -If the buffer is empty then it is filled. ; -If the buffer is active then: ; -If this isn't the right sector then the buffer ; is flushed and then filled with the right sector ; 4) Then a pointer is generated using trusec (remember trusec?) ; to the starting address of the logical sector. ; 5) The HL, DE and C are setup for the data move (done using an ; LDIR command in the calling program) ; HL:= Starting Address of Logical Sector in the host buffer ; DE:= The current DMA_Address ; C:= Bank select mask (for setting destination bank) ; 6) If this was a write operation then the the HL (Source) and ; DE (Destination) are register pairs are swapped. ; ; Calculate the physical sector within which the logical sector resides rwoper: res @InMap,(iy+OpFlag) ld a,(iy+sekdsk) call gdsk ;HL:= Pointer->Base of MTAB inc hl ld a,(hl) ;A:= Disk Definition 1 and $SIZMSK ;A:= Sector size code (0=128...3=1024) ld e,(iy+seksec) ld d,(iy+seksec+1) ;DE:= BDOS sector Number dec de ;(sector number to zero base offset) ld c,e ;C:= zero based sector number ld b,00000000b ;128 byte mask (1 sector max) cp 0 ;see if 128 jr z,s128 ;jmp if 128 ld b,00000001b ;256 byte mask (2 sectors max) cp 1 ;see if 256 jr z,s256 ;jmp if 256 ld b,00000011b ;512 byte mask (4 sectors max) cp 2 ;see if 512 jr z,s512 ;jmp if 512 ld b,00000111b ;1024 byte mask (8 sectors max) s1024: srl d ;calc physical sector rr e ;(divide by 8 logical sectors) s512: srl d rr e ;(divide by 4 logical sectors) s256: srl d rr e ;(divide by 2 logical sectors) s128: dec hl ;HL:= dskdef0 inc e ;(restore 1 based sector number) ld (iy+sekhst),e ;save the one based sector number page ; Generate offset to start of logical sector within the physical sector ld a,b ;A:= Logical Sector Mask and c ;A:= Logical sector MOD physical sector ld (iy+trsec),a ; Decide if the buffer has to be flushed bit @HSTACT,(iy+DFlag) ;If (host buffer has a sector in it) set @HSTACT,(iy+DFlag) ; (set host active flag NOW) jr z,filhst ; (NOT active -> goto fill host buffer) IYneIY1 sekdsk, hstdsk, nomtch ; If (Sek-Disk eq Host-Disk) & IYneIY2 sektrk, hsttrk, nomtch ; (Sek-Track eq Host-Track) & IYneIY2 sekhst, hstsec, nomtch ; (Sek-Sect eq Host-Sect) jr z,match ; GOTO Match ; Flush the buffer (if necessary) nomtch: xor a ; A:= no error status set @BufOK,(iy+OpFlag) ; Set the Buffer OK Flag bit @HSTWRT,(iy+DFlag) ; If (Host buffer currently active) call nz,WrtHst ; flush the buffer or a ; if (status eq error) ret nz ; return ; Update the Host's Disk, Track and sector filhst: IYtoIY1 sekdsk, hstdsk ;Host_Disk:= Seek_Disk IYtoIY2 sektrk, hsttrk ;Host_Track:= Seek_Track IYtoIY2 sekhst, hstsec ;Host_Sector:= Seek_Sector ; Fill the buffer (if necessary) xor a ;A:= no error status res @BufOK,(iy+OpFlag) ;Clear the Buffer OK Flag bit @RSFLAG,(iy+DFlag) ;If (read sector flag eq true) call nz,RdHst ; read or a ; if (status eq error) ret nz ; return res @HSTWRT,(iy+DFlag) ;no pending write match: ld l,(iy+trsec) ;get masked sector ld h,0 add hl,hl ;calc 2**hl add hl,hl add hl,hl add hl,hl add hl,hl add hl,hl add hl,hl ld e,(iy+hstbuf) ;(DE:= Host_Buffer_Base_Address) ld d,(iy+hstbuf+1) add hl,de ;HL:= Starting Address of Logical Sector ld e,(iy+dmaadr) ;DE:= DMA_Address ld d,(iy+dmaadr+1) ld a,0 ;A:= No Error Status ld c,00000000b or (000000);C:= Bank select mask (bank 1 source) bit @READOP,(iy+DFlag) ;If (this was a read operation) ret nz ; return set @HSTWRT,(iy+DFlag) ;Else set the host buffer written flag ld c,00000000b or ($BANK2); C:= Bank select mask (bank 2 source) ex de,hl ; swap direction (for ldir) ret ; Return page ;====================================================================== ; RDHST - Read a Physical Sector (11_Jan_84) ;=========================================== ; rdhst: res @nover,(iy+OpFlag) ;Clear the no verify after seek flag ld hl,rdio ;get read address ld (iy+ioadd),l ;put address in ramdatx ld (iy+ioadd+1),h call iohst ret ;====================================================================== ; WRTHST - Write a Physical Sector (11_Jan_84) ;============================================= ; wrthst: res @nover,(iy+OpFlag) ;Clear the no verify after seek flag ld hl,wrio ;get write address ld (iy+ioadd),l ;put address in ramdatx ld (iy+ioadd+1),h call iohst ret ;====================================================================== ; FMTHST - Format a Physical Track (27_Dec_83) ;============================================= ; fmthst: set @nover,(iy+OpFlag) ;Set the no verify after seek flag ld hl,fmtio ld (iy+ioadd),l ld (iy+ioadd+1),h ;Set the io address call iohst ret page ;---------------------------------------------------------------------- ; IOHST - Hst* to Phy* Translations for read/write/format (12_Nov_83) ;-------------------------------------------------------------------- ; 1) This routine does all host to physical translations ; iohst: ld a,(iy+hstdsk) call gdsk ;HL:= pointer to Disk Definition 0 ld a,(hl) push af ;(Stack:= Dskdef0) and $PHYADR ;(remove all but physical drive addr) ld (iy+phydrv),a ;save the PHYSICAL DRIVE number ld a,(iy+hstsec) bit @SECZRO,(hl) ;If (sector numbering starts with zero) jr z,iohsk1 dec a ; Crnt_Sector:= Crnt_Sector - 1 iohsk1: ld (iy+physec),a ;Save the PHYSICAL SECTOR number ld e,(iy+hsttrk) ld d,(iy+hsttrk+1) ;DE:= BDOS track number pop af and $HDMSK ;(Remove all bits except the Head Mask) srl a srl a ;(Move head mask to l.s.bit's) push af ;(Stack:= head mask in the lsb's) and e ;Remove head number from track number ld (iy+phyhd),a ;Save the PHYSICAL HEAD number pop af ;(Restore the head mask) iohlp1: srl a ;While (still in the 'head field') jr nc,iohsk2 srl d rr e ; shift track over jr iohlp1 iohsk2: ld (iy+phytrk),e ld (iy+phytrk+1),d ;save the PHYSICAL TRACK number call discio ;Execute the disk i/o routine or a ;(set the zero flag) ret if ($ lt o_dsk1 - 1) ;If (we haven't overwritten hd*dsk1) e_bios: ds (o_dsk1 - $) - 1, 0 ; Zero Fill to the disk module else ;Else if2 ; print an error message on pass2 .printx "The bios module has overflowed into dsk1 module" endif endif end