Subttl -Firmware BIOS Support Routines (Rev_22 17_May_84) ; ; Copyright 1983, 1984 ; Morrow Designs, inc. ; San Leandro, Ca. ; Howard Fullmer, John Zalabak .z80 ; switch set to assemble z80 nemonics Include HD22DEF.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 (17_May_84) ;============================================ ; 1) This routine sets the ReadOp flag indicating that a write operation ; is to be preformed and sets the RsFlag for pre-reads. ; wrlsec: res @ReadOp,(iy+DFlag) ;operation:= write set @RsFlag,(iy+DFlag) ;read needed page ;---------------------------------------------------------------------- ; RWOPER - Common section for read/write logical sectors (17_May_84) ;------------------------------------------------------------------- ; 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: 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) ; BufOK:= True (buffer is valid) 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) jr z,NoRead res @InMap,(iy+OpFlag) ; InMap:= Cleared (not in BadMap) call RdHst ; Read a Sector or a ; if (status eq error) ret nz ; return NoRead: 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 (20_Mar_84) ;-------------------------------------------------------------------- ; 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) 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 a,(hl) and $HDMSK ;(Remove all bits except the Head Mask) srl a srl a ;(Move head mask to l.s.bit's) inc a ;Convert Head MASK to NUMBER of Heads ld c,a ;C:= Number of Heads ld l,(iy+hsttrk) ld h,(iy+hsttrk+1) ;HL:= BDOS track number call divide ld (iy+phyhd),a ;Save the PHYSICAL HEAD number ld (iy+phytrk),l ld (iy+phytrk+1),h ;Save the PHYSICAL TRACK number call discio ;Execute the disk i/o routine or a ;(set the zero flag) ret page ;---------------------------------------------------------------------- ; Divide (20_Mar_84) ;------------------- ; 1) Register Usage ; A -> On Exit = Remainder ; B -> Loop Counter ; C -> Divisor ; HL -> On Entry = Dividend; On Exit = Result ; Divide: ld a,h ;If (Dividend eq 0) or l ret z ; Return ld b,17 ;B:= Loop Counter DivLp0: dec b ;Repeat Decrement the Loop counter add hl,hl ; Shift dividend jp nc,DivLp0 ;Until (Dividend's msb is in carry) ld a,0 ;A:= 0 DivLp1: rla ;Repeat Rotate next bit into accm sub c ; Accm:= Accm - Number of heads ccf ; (complement the carry) jr c,DivSk1 ; If (there was an underflow) adc a,c ; Restore the Accm or a ; (Clear the Carry) DivSk1: adc hl,hl ; Move partial result djnz divLp1 ;Until (Loop Counter eq Zero) ret ;Return If ($ lt O_Dsk1 - 1) ;If (we haven't overwritten hd*dsk1) E_Bios: ds (O_Dsk1 - $) - 1, 0FFh ; 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