home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
MBUG
/
MBUG097.ARC
/
FL512.MAC
< prev
next >
Wrap
Text File
|
1979-12-31
|
12KB
|
535 lines
.Z80
; DOUBLE DENSITY disk package for 512k BIOS
MILLISEC equ 122 ;3.375 Mhz only
; This should be the value to set the number of retries.
RTCNT equ 25 ;50 ;retry count (or 25)
DS_RETRY equ 4 ;# times to try read addr.
CMND equ 044H ;WD1793/97 FDC
STATUS equ cmnd
TRACK equ cmnd+1
SECTOR equ cmnd+2
DATA equ cmnd+3
DRQ equ 048H
DRIVES equ drq
DDEN_SEL equ 3 ;bits on the (drives) port
SIDE_SEL equ 2
TTD equ 3 ;30 Ms for restore only
TRKPD equ 40 ;40 cylinders
INT_CMND equ 0D0H ;force interrupt
RA_CMND equ 0C0H ;read address command
SEEK_CMND equ 01cH ;seek, hld, verify
STPIN_CMND equ 058H ;stpin, update, hld, no verify
; the read and write commmands assume disks formatted with
; the side byte zero on both sides - this allows both
; 1/2793 and 1/2797 controller chips to be used
RD_CMND equ 088H ;read 1 sector, no HLD wait
WR_CMND equ 0A8H ;write 1 sector, no HLD wait
;
; assuming c=drq, this macro will wait for the DRQ
; flag from the FDC
idrqwait macro
zdrqwait defl $
in a,(c)
jp p,zdrqwait
endm
;
odrqwait macro
zdrqwait defl $
in d,(c)
jp p,zdrqwait
endm
;
; select drive (A), and set (sec_length) and (dden_byte)
; according to what type of disk is in the drive
; also correct track register
; return Z if O.K., NZ if drive won't select (no disk
; or no drive if unused drive_sels are connected to IP)
SEL_FLOPPY:
push bc
ld (disk),a
ld c,a ;what is desired
ld a,(dden_byte)
or c
out (drives),a ;select drive,density
;
; don't bother checking whether there is a disk in the drive,
; because if we return an error, we would have to bomb the
; program anyway
call d_int ;force type I status
call dense_sense ;fix track, density, size
jr z,fzz_aam
call d_restore ;in case off track, restore
call dense_sense ;and try again
fzz_aam:
pop bc
ret
; sense the density and sector length of the currently
; selected disk by retrying up to ds_retry times until a correct
; read is obtained (update track register if it is ok)
DENSE_SENSE:
push bc
ld b,ds_retry ;ds_retry goes to get it right
fz_a defl $
call try_ra ;read address, return Z/NZ
jr z,fz_aaav
push hl
ld hl,dden_byte
ld a,1 shl dden_sel
xor (hl) ;invert dden bit (swap modes)
ld (hl),a
ld a,(disk)
or (hl)
out (drives),a ;tell controller
pop hl
or -1 ;set nz=error
djnz fz_a
fz_aaav:
pop bc
ret
; try_ra tries to do a READ ADDRESS command and
; if successful, updates the sector length bytes and
; track register (in case of misseek)
TRY_RA:
push bc
push de
fz_a defl $
di ;disable RS232 interrupts
out (vwait_off),a ;kill colour board
ld a,ra_cmnd
call cmnd_delay ;give command, load head if necc.
ld c,drq
idrqwait
in a,(data) ;get possible track number
ld d,a
ld b,3 ;read through side,sector,length
fz_b defl $
idrqwait
in a,(data)
djnz fz_b
fz_baaa:
ld e,a ;get poss. sector length byte
call wbsy ;wait till unbusy, get status
ei
and 098H
jr nz,ra_ex ;bad read, so exit early
ld a,d ;track number read from disk
out (track),a ;correct track register
cp 3 ;if >= track 3, continue
jr nc,fz_aaaw
; step in a track to determine type correctly for foreign formats
ld a,stpin_cmnd
call cm_wrdy
jr fz_a
fz_aaaw:
; no problems, so update track, sec_length, and # pair of bytes
ld a,e
ld (sec_length),a ;sector length 0=128, 2=512
; this does not work for 1024 byte sectors ..
ld a,1 shl 5
fz_a defl $
rla
dec e
jp p,fz_a
fz_aaax:
ld (num_pairs),a
cp a
; .. Z flag is true
RA_EX:
pop de
pop bc
ret
; setup for read or write ...
; given d=track with b7=1 for side 1, e=sector,
; try to seek to correct position, if O.K., return
; Z, otherwise return NZ if seek error
; also return b=# pairs of bytes to read, c=drq
SETUP:
out (vwait_off),a ;disable screen waiting each line
push de
ld a,(disk)
ld e,a
ld a,(dden_byte)
or e
ld e,a ;e = disk | dden_byte
bit 7,d
jr z,side0
res 7,d ;and for physical track number
set side_sel,e ;set for side 1
SIDE0:
ld a,e
out (drives),a ;set drive, side, density
;
in a,(track)
cp d ;already there?
jr z,fzz_aan
ld a,d
out (data),a ;desired track
ld a,seek_cmnd ;seek with verify and hld at 6ms
call cm_wrdy ;and return status in a
ld b,10
call dely1 ;10 Ms head settle time
in a,(status)
and 018H ;did verify fail?
fzz_aan:
; get # pairs of bytes to read or write in B
ld a,(num_pairs) ;quickest way to get it
ld b,a
;
ld c,drq ;for ED70 loop
pop de
ld a,e ;required sector
out (sector),a
ret
;
;
; Read 'host' sector
; given ...
; drive number in 'drive'
; sector length in (sec_length)
; d=track, e=sector
; hl=data transfer address
;
; returns ..
; data at (hl) for 128*2^(sec_length) bytes
; hl=hl+128*2^(sec_length)
; a=0 (and Z) if no errors, else returns 1 (and NZ)
;
RD_FLOPPY:
push bc
ld b,rtcnt
fz_a defl $
push hl ;save transfer address
push bc ;save error count-down
call setup ;seek, set sector, b=# pairs, c=drq
jr nz,fzz_aao
di
ld a,rd_cmnd ;read, no wait cmnd
call cmnd_delay ;give command, wait for status valid
fz_b defl $
idrqwait
in a,(data)
ld (hl),a
inc hl
idrqwait
in a,(data)
ld (hl),a
inc hl
djnz fz_b
fz_baab:
ei
call wbsy ;wait for unbusy, get status
and 09CH ;relevant bits only
jr nz,fzz_aao
pop bc ;pop off error count
pop bc ;pop off transfer address
pop bc
ret ;successful read exit
fzz_aao:
pop bc ;reget error count in b
pop hl ;reget transfer address
call erchk ;do dense_sense and restore sometimes
djnz fz_a
fz_aaay:
pop bc
xor a
inc a
ret ;unrecoverable error
;
;
; Write 'host' sector
; given ...
; drive number in 'drive'
; sector length in (sec_length)
; d=track, e=sector
; hl=data transfer address
;
; returns ..
; hl=hl+128*2^(sec_length)
; a=0 (and Z) if no errors, else returns 1 (and NZ)
;
; Write a sector
WR_FLOPPY:
push bc
ld b,rtcnt
fz_a defl $
push hl ;save transfer address
push bc ;save error count-down
call setup ;seek, set sector, b=# pairs, c=drq
jr nz,fzz_aap
di
push de ;save de since we must "in ?,(c)"
ld a,wr_cmnd ;write, no wait cmnd
call cmnd_delay ;give command, wait for status valid
fz_b defl $
ld a,(hl)
odrqwait
out (data),a
inc hl
ld a,(hl)
odrqwait
out (data),a
inc hl
djnz fz_b
fz_baac:
ei
pop de
call wbsy ;wait for unbusy, get status
and 0FDH ;relevant bits only
jr nz,fzz_aap
pop bc ;pop off error count
pop bc ;pop off transfer address
pop bc
ret ;successful write exit
fzz_aap:
pop bc ;reget error count in b
pop hl ;reget transfer address
call erchk ;do dense_sense and restore sometimes
djnz fz_a
fz_aaaz:
pop bc
xor a
inc a
ret ;unrecoverable error
;
; an error has occured, so
; home the head after every 8 retrys (b is counter)
; also STATUS is type I after this subroutine
; also update error count
ERCHK:
push af
call try_ra ;try to read address, fix track reg ..
ld a,7
and b ;restore every 8 retrys
call z,d_restore ;do a restore
call d_int ;force type I status (not read status)
; keep a count of total errors, stopping at 255
ld a,(total_errs)
inc a
jr z,fzz_aaq
ld (total_errs),a
fzz_aaq:
pop af
ret
;
CMND_DELAY:
out (cmnd),a
; greater than 60uS delay at 2.25Mhz
D_DELAY:
ld a,16
fz_a defl $
dec a
jr nz,fz_a
fz_aaba:
ret
;
; interrupt the FDC
D_INT:
ld a,int_cmnd
jr cm_wrdy
; restore to track zero
D_RESTORE:
ld a,8+ttd ;restore (slowly always)
CM_WRDY:
out (cmnd),a
DWRDY:
call d_delay
WBSY:
in a,(status)
bit 0,a ;check busy flag
jr nz,wbsy ;wait till not busy
ret
;
; delay for b milliseconds
DELY1:
push hl
DLY1LP:
ld hl,millisec
DLY:
dec hl
ld a,h
or l
jr nz,dly
djnz dly1lp
pop hl
ret
;
;
; a routine which loads consecutive sectors into memory for
; a specified number of bytes
;
; Requires no. bytes to load in BC
; destination of load in HL
; D=starting track no 0-79
; E=starting sector no 1-?
; returns Z if OK, NZ if a bad read occured
;
;OFFLOAD:
; push ix
; push iy
;;
; push hl
; pop ix
; add ix,bc
; call get_tab ;address of sectors per track in iy
; ld b,5 ;number of retries
;fz_a defl $
; push bc ;save #retries left
; push de ;save initial track/sector
; push hl ;save initial address
;fz_b defl $
; call setup ;seek and set init. sector reg.
; jr nz,fz_baad
; di ;kill RS232 ints
; ld a,rd_cmnd+010H ;multiple sec read
; call cmnd_delay ;ensure head loaded (& motor)
;fz_c defl $
; ld a,(num_pairs)
; ld b,a
; ld c,drq ;port with drq bit 7
;fz_d defl $
; idrqwait
; in a,(data)
; ld (hl),a
; inc hl
; idrqwait
; in a,(data)
; ld (hl),a
; inc hl
; djnz fz_d
;fz_daaa:
; push ix
; pop bc
; push hl
; and a ;clear carry
; sbc hl,bc
; pop hl
; jr nc,qr_exit ;don't need any more sectors
;;
; ld a,e
; inc e
; cp (iy+0) ;number of sectors per track
; jr nz,fz_c
;fz_caaa:
; ld b,3
; call dely1 ;wait for busy status valid
; in a,(status)
; cpl
; bit 0,a
; jr nz,fz_baad
;;
; call d_int ;kill track read
; ld e,1
; inc d ;next track
; jr fz_b
;fz_baad:
; pop hl ;start address
; pop de ;starting track, sector
; pop bc ;number of retries
; djnz fz_a
;fz_aabb:
;QR_PX:
; ei
; pop iy
; pop ix
; ret nz ;if stopped for error
; call d_int ;kill multi-sector read
; and 09CH ;relevant bits only
; ret
;QR_EXIT:
; pop hl
; pop de
; pop bc
; xor a ;set z flag -> check status reg.
; jr qr_px
;;
;
; a routine which stores consecutive sectors onto disk for
; a specified number of bytes (taken up to next sector length)
;
; Requires no. bytes to save in BC
; source of load in HL
; D=starting track no 0-79
; E=starting sector no 1-?
; returns Z if OK, NZ if a bad write occured
;blockwrite
; push iy
; push hl
; add hl,bc
; ld b,h ;bc=byte after last byte to read
; ld c,l
; call get_tab ;get address of sectors per track
; pop hl
; {
; call wr_floppy
; #if nz,brk ;bad sector read
; ld a,e
; inc e
; cp (iy+0) ;overflow off track?
; #if c,nxt
; inc d ;next track
; ld e,1 ;first sector
; #mark
; push hl
; and a ;clear carry
; sbc hl,bc
; pop hl
; #if c,cont
; cp a ;set Z flag
; }
; pop iy
; ret
;
;
; return iy pointing to byte containing the number
; of sectors per track for a disk formatted in the
; current format
GET_TAB:
push hl
ld hl,dden_byte
ld a,(sec_length) ;0=128, 1=256, 2=512
rlca ;*2
bit dden_sel,(hl) ;is it single density?
pop hl
jr z,fzz_aar
dec a ;double density
fzz_aar:
ld iy,max_sects ;default to 18 if too big or small
ret m ;and NZ if 128 byte DD !
bit 2,a ;too big if 512 SD, or 1024 SD&DD
ret nz
push de
ld d,0
ld e,a
add iy,de
pop de
ret
;
;
; a table of the maximum number of sectors per
; track for the 4 supported formats
MAX_SECTS:
defb 18 ;SD 128 bytes (old sd format)
defb 18 ;DD 256 bytes (mos)
defb 10 ;SD 256 bytes (osborne)
defb 10 ;DD 512 bytes (main DD format)
DISK: defb 0 ;currently selected disk
SEC_LENGTH: defb 2 ;0=128, 1=256, 2=512
NUM_PAIRS: defb 1 ;# pairs of byte to xfer
TOTAL_ERROR: defb 0 ;total r/w errors so far
DDEN_BYTE: defb 08H ;=08H if double density selected