.z80 include SUPERBIOS.LIB rtrys equ 010d ;---------------------------------- ; HDC-1001 REGISTER PORT ADDRESSES ; --------------------------------- hbase equ 0e0h ; base port address of hdc-1001 hdata equ hbase+0 ; data register herror equ hbase+1 ; error register hwrtpre equ hbase+1 ; write pre-compensation register hseccnt equ hbase+2 ; sector count register hsec equ hbase+3 ; sector number register hcyllow equ hbase+4 ; cylinder low register hcylhi equ hbase+5 ; cylinder high register hsdh equ hbase+6 ; size - drive - head register hstatus equ hbase+7 ; status register port hcmd equ hbase+7 ; command register port ;------------------- ; HDC-1001 COMMANDS ;------------------- cmdrst equ 010h ; restore command cmdrd equ 020h ; read sector command ;----------------------------- ; STATUS REGISTER BIT TESTERS ;----------------------------- bsybit equ 080h ; busy bit rdybit equ 040h ; data request bit errbit equ 001h ; error bit ;------------------ ; BIOS JUMP VECTOR ;------------------ start: jp boot jp wboot jp const jp conin jp conout jp list jp punch jp reader jp hhome jp hseldsk jp hsettrk jp hsetsec jp setdma jp hread jp hwrite jp listst jp sectran ;----------- ; COLD BOOT ;----------- boot: ret ;----------- ; WARM BOOT ;----------- wboot: ret ;------------- ; LIST OUTPUT ;------------- list: ret ;-------------- ; PUNCH OUTPUT ;-------------- punch: ret ;--------------- ; READER OUTPUT ;--------------- reader: ret ;------------- ; LIST STATUS ;------------- listst: ret ;---------------- ; CONSOLE STATUS ;---------------- const: ;poll serial in-return A=0ff if char ready, else 0 add A,A inc A ;A=command port ld C,A in A,(C) and 1 ret z ;no character waiting ld A,0ffh ret ;--------------- ; CONSOLE INPUT ;--------------- conin: ld B,A call const ld A,B jr z,conin ;loop until character received add A,A ld C,A in A,(C) and 7fh ;mask high order bit ret ;---------------- ; CONSOLE OUTPUT ;---------------- conout:: ld B,C ;character to output add A,A inc A ld C,A serst:: in A,(C) and 4 jr z,serst dec C out (C),B ret ; miscellaneous character i/o routines pmsg:: ;equivalent to BDOS function 9 (print) ld A,(DE) cp '$' ret z ld C,A inc DE push DE xor A call conout pop DE jr pmsg phex:: ;print A in hex push AF rra rra rra rra call hex1 pop AF hex1:: and 0fh add A,90h daa adc A,40h daa ld C,A xor A jp conout ;------------------ ; SET DMA ADDRESS ;----------------- setdma: ld (dmaadr),bc ; shared among all drivers ret ;-------------------- ; SECTOR TRANSLATION ;-------------------- sectran: ld h,b ld l,c ret ;------------- ; SELECT DISK ;------------- hseldsk: ld hl,ddb0 ; get deblocking parameters ld de,dbconst ; move dblk pars to usage area ld bc,13d ; 13 bytes of dblk pars ldir ; move as block ld hl,dph0 ; ret w. dsk parameter hder in hl ret ;------ ; HOME ;------ hhome: call restore ; restore drive heads to trk 0 ret ;----------- ; SET TRACK ;----------- hsettrk: ld (sektrk),bc ; bc contains selected track n. ret ;------------ ; SET SECTOR ;------------ hsetsec: ld (seksec),bc ; bc contains selected sector no. ret ;------------- ; READ SECTOR ;------------- hread: xor a ; clear accumulator ld (rtcnt),a ; reset retry count ld a,1 ; set operation to read ld (oper),a ; save it for when we do xfer call deblk ; deblock phy sec, buf adr, and blk sec call inbuf ; check if new sector is in buf call xfer ; transfer data out of buf into dma ld a,(rtcnt) ; if rtcnt not zero then error ret ;-------------- ; WRITE SECTOR ;-------------- hwrite: ret ;------------------------------------ ; DEBLOCK PHY SEC, BUF ADDR, BLK SEC ;------------------------------------ deblk: ld a,(pdrv) ; get phy drv from dsk deblk parameters ld (sekprv),a ; save it as sek phy drv ld a,(secshf) ; convert sek sec to phy sec ld de,(seksec) ; secshf is log2 cpm sps call shfr16 ; shift de-reg, a-reg times ld a,(hstspt_1) ; de now contains sec rel to cyl and e ; mask for sec rel to platter ld (dsec),a ; save it as deblocked sector ld a,(hdshf) ; convert seksec to phy head ld de,(seksec) ; hdshf is log2 cpm spt call shfr16 ; hd no is high bits, so no msk needed ld a,(hdoff) ; add in head off set for partioning add a,e ; cartriage drv must be part. by hds ld (dhd),a ; save it as deblocked head no. lä a,(cpmsps_1© » converô sekseã tï hsô buæ no. ld de,(seksec) ; mask out low order bits of sec no and e ; since buf no <= 8, need only lsb ld e,a ; mul buf no x128 to get rel adr in buf ld d,0 ; zero out high order of multiplicitan ld a,7 ; convert hst buf no. to hst buf adr call shfl16 ; mult by 128 (shift lf 7) ld hl,hstbuf ; base addr of hst buf add hl,de ; add in offset ld (dadr),hl ; save it as deblocked buf addr ld a,(blkshf) ; convert seksec to blk no. ld de,(seksec) ; blkshf = log2 cpm spb, what we are call shfr16 ; doing is, bl=int(sesc/cpmspb) ld (dblk),de ; save as blk no. on this trk ld a,(hstspb_1) ; convert seksec to hst sec no. in blk ld de,(dsec) ; must use sec just deblocked and e ; and deblk sec w. hst spb ld (dblsec),a ; save it as deblocked block sec ret ;---------------------------- ; CHECK IF NEW SEC IS IN BUF ;---------------------------- inbuf: ld a,(seklrv) ; check if new drv = old drv ld hl,hstlrv ; first check if log drives are same cp (hl) ; compare w. last accessed drv jp nz,difblk ; if drvs are dif, then so is blk ld de,(sektrk) ; check if new trk = old trk ld hl,(hsttrk) ; this is the old trk call cmp16 ; so far drv same jp nz,difblk ; if trks are dif, then so is blk ld a,(dhd) ; check if new head = old head ld hl,hsthd ; so far drv, trk same cp (hl) ; if dif hd, could be jp nz,ckblk ; same blk if blk size > phy trk siz ld a,(dsec) ; check if new sec = old sec ld hl,hstsec ; this is the old sec cp (hl) ; so far drv, trk, hd same jp nz,ckblk ; could be same blk even if dif sec call sethst ; everything same, set buf addr though ret ckblk: ld hl,(dblk) ; check if new sec is in same blk ld de,(hstblk) ; if the new blk equal old blk call cmp16 ; then do not reset usage vars jp nz,difblk ; regardless fall through to prerd samblk: call hflush ; sam blk, but dif blk sec so flush old ld hl,usgblk ; check if this sec free in block ld de,(dblsec) ; look in block usage vector ld d,0 ; index down to correct entry in vector add hl,de ; hl now contains addr of blk usg entry ld b,(hl) ; get blk usage flag ld a,(oper) ; get oper or b ; if (sec not fre) or (oper is read) jp nz,prerd ; then need to pre-read sector nprerd: call sethst ; sector not allocated ret difblk: call hflush call setusg ; sector not in block prerd: call sethst ; sector in blk but alloc, or dif blk call hrdhst ; read in new setor ret ;------------------- ; FLUSH HOST BUFFER ;------------------- hflush: ld a,(wrtpnd) ; check if host buffer active and a ; wrtpnd =0 if inactive, =0ff if active call nz,hwrthst ; physicaly flush buffer if active xor a ; clear write pending ld (wrtpnd),a ; host buffer now in active ret ;--------------------------------- ; SET DEBLOCKED VARS TO HOST VARS ;--------------------------------- sethst: ld hl,sekvars+2 ; blk move sek & dblk vars to hst vars ld de,hstvars ; dont need seksec so sekvars+2 ld bc,14d ; this is how many to move ldir ; set host variables ret ;-------------------------------------- ; TRANSFER DATA TO/FROM BUFFER AND DMA ;-------------------------------------- xfer: ld bc,080h ; transfer 128 bytes ld de,(dmaadr) ; load cpm addr (dma addr storage) ld hl,(hstadr) ; load buf addr ld a,(oper) ; check if read or write operation or a ; oper =0 if read, =1 if write jp nz,transf ; jump if read ex de,hl ; read operation so switch directions transf: ldir ; send 128 byte block ret ;-------------------------------- ; SET OR RESET BLOCK USAGE FLAGS ;-------------------------------- rsetusg: ld b,0 ; set all block sectors in blk to free jp setblk ; sec in blk not allocated if =0 setusg: ld b,0ffh ; set all block sectors in blk to used setblk: ld a,(hstspb_1) ; get no of host sector per block ld hl,usgblk ; get addr of blk sector usage vector setflg: ld (hl),b ; set or reset block usage flag inc hl ; point to next flag loc dec a ; dec count of block sectors to go jp p,setflg ; loop if more to set ret ;------------------------------ ; UPDATE BLOCK USAGE VARIABLES ;------------------------------ update: ld de,(blksec) ; we have just written to a sec in blk ld d,0 ; so set block sec usage flag to used ld hl,usgblk ; first point to flag add hl,de ; de contains sector no. in block ld a,0ffh ; 0ff means sector in block is not free ld (hl),a ; set flag ret ;------------ ; WRITE HOST ;------------ hwrthst: ret ;----------- ; READ HOST ;----------- hrdhst: call settsk ; first set up controller registers ld a,cmdrd ; load a with command to read sector out (hcmd),a ; send read command to command reg call polbsy ; wait until not busy call rxdta ; transfer data from cnt buf to hst buf call retrys ; check for errors jp nz,hrdhst ; retrys sets zero flg if no errors ret ;--------------- ; SET TASK FILE ;--------------- settsk: ld a,(hstprv) ; get physical drive no. ld b,a ; save in b so can use a for mem fetch sla b ; rotate phy drive to correct position sla b ; drive is expected in bits 3 and 4 sla b ; last shift for drive ld a,(hstsdh) ; get sdh sect size setting or b ; or it in w. rotated phy drive no ld b,a ; save result in b ld a,(hsthd) ; get host head no. or b ; or it in w. drv and sec siz out (hsdh),a ; send it siz drv hd register ld bc,(hsttrk) ; host track is really host cylinder ld a,b ; move msb to a-reg for out inst out (hcylhi),a ; send high byte to cylhi reg ld a,c ; move lsb to a-reg out (hcyllow),a ; send to cyl low ld a,(hstsec) ; get host sector no out (hsec),a ; send to sector register ret ;----------- ; SEND DATA ;----------- snddta: ret ;-------------- ; RECIEVE DATA ;-------------- rxdta: ld a,(hstsiz) ; this is how many bytes to move ld b,a ; set up for inir ld c,hdata ; this is where the data comes from ld hl,hstbuf ; this is where the data goes inir ; block move data into hst buf ld a,(hstsiz+1) ; check if moving 512 bytes and 2 ; msb would be 2 if 512 bytes jp z,rxout ; jump over if moveing 128 or 256 only inir ; b should be zero, hl and c set also rxout: ret ;-------------------------------- ; RESTORE DRIVE HEADS TO TRK 000 ;-------------------------------- restore: ld a,(stprte) ; set step rate when doing a restore ld b,cmdrst ; get a restore command or b ; or in step rate out (hcmd),a ; send it to the command register call polbsy ; wait until not busy ret ;----------- ; POLL BUSY ;----------- polbsy: in a,(hstatus) ; read status port and a ; set flags jp m,polbsy ; loop if busy bit set and errbit ; mask for error bit ret ;--------------------- ; SET RETRY CONDITION ;--------------------- retrys: in a,(hstatus) ; read status register and errbit ; mask for error bit jp z,rtout ; jump to exit rtry ld a,(rtcnt) ; get no. of retrys so far inc a ; increment retry count ld (rtcnt),a ; save it for next time cp rtrys ; set not z flg, unless rtcnt = rtrys ret ; return w. flag set or reset rtout: xor a ; clear zero flag ld (rtcnt),a ; clear retry cnt in case had to retry ret ; return w. no errors ;---------------- ; SHIFT RIGHT 16 ;---------------- shfr16: and a ; shift de reg right a-reg times jp z,xr16 ; jump over loop if shift 0 times shfrlp: srl d ; shift msb first, bit 0 into carry rr e ; rotate carry into bit 7 lsb dec a ; decrement shift counter jp nz,shfrlp ; loop util finished xr16: ret ;--------------- ; SHIFT LEFT 16 ;--------------- shfl16: and a ; shift de-reg left a-reg times jp z,xl16 ; check for shift zero times shfllp: sla e ; shf lsb first, c = bit 7, bit 0 = 0 rl d ; shf msb, bit 0 = carry dec a ; decrement shift counter jr nz,shfllp ; loop until a-reg eq zero xl16: ret ;------------------------------ ; COMPARE 16-BIT DE AND HL REG ;------------------------------ cmp16: ld a,e ; compare e-reg w. l-reg xor l ; xor will zero accum. if e = l ret nz ; return if not equal ld a,d ; compare d-reg w. h-reg xor h ; set zero flag if same ret ;------------------------------------------------ ; DATA STORAGE ;------------------------------------------------ dmaadr: dw 0080h ; dma address storage rtcnt: db 0 ; retry counter smapadr: dw 0 ; seek drive map entry address sekvars: ; seek variables seksec: dw 0 ; seek sector seklrv: db 0 ; seek logical drive sekprv: db 0 ; seek physical drive sektrk: dw 0 ; seek track dhd: db 0 ; deblocked head dsec: db 0 ; deblocked sector dadr: dw 0 ; deblocked buffer address dblk: dw 0 ; deblocked block no. in cylinder dblsec: db 0 ; deblocked host sector no. in block dbconst: ; deblocking constants (calc in ddp) secsiz: dw 0 ; host sector size sdhsiz: db 0 ; shd reg sector siz pdrv: db 0 ; physical drive hdoff: db 0 ; head offset stprte: db 0 ; cmd reg step rate hstspt_1: db 0 ; host sector per track hstspb_1: db 0 ; host sectors per block hdshf: db 0 ; log2 cpm spt blkshf: db 0 ; log2 cpm spb hdmsk: db 0 ; heads - 1 secshf: db 0 ; log2 cpm sps cpmsps_1: db 0 ; cpm sps - 1 hstvars: ; host drive variables hstlrv: db 0 ; last logical drive operated on hstprv: db 0 ; physical drive hsttrk: dw 0 ; track (equiv to cylinder) hsthd: db 0 ; head hstsec: db 0 ; sector hstadr: dw 0 ; buffer address hstblk: dw 0 ; block no. in current cylinder blksec: db 0 ; host sector no. in block hstsiz: dw 0 ; physical sector size hstsdh: db 0 ; sdh register sector size setting wrtpnd: db 0 ; write pending (host buffer active) wrttyp: db 0 ; write type (0=use, 1=dir, 2=free) oper: db 0 ; operation (0=write, 1=read) ;------------------------------------------------------------------------------ ; DRIVE PARAMETER DEFINITIONS ;------------------------------------------------------------------------------ ; ; dskdef < drvtyp0, drvtyp1, ... , drvtypm> ; ;------------------------------------------------------------------------------ dskdef endmod equ $ end end