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
/
CPM
/
PACKET
/
RLI120.ARK
/
CBIOS.MAC
< prev
next >
Wrap
Text File
|
1986-08-12
|
24KB
|
1,200 lines
; CBIOS.MAC - 3/9/86 The real BIOS for the Xerox.
; This loads itself using the SBIOS.
; It takes the place of the Xerox PROM code.
; Xerox CBIOS Version 10.6 (For MailBox/GateWay version 10.x).
; Thanks to k1bc, ke1g, ki4xo for help with the bios code.
; Bigboard I mods from n6fqr
.z80
.xlist
maclib TNC.LIB
timdef
asciictl
.list
false equ 0
true equ not false
maclib BIOSCPM.INC ; CP/M addresses
maclib BIOSDSKE.INC ; Disk equates
; Parallel keyboard port:
; Set keyreg to true to use a "normal" keyboard.
; Set to false and set keyxor if:
; the high order bit is set to one for control shift,
; then use ffh, if it is set to zero then use 7fh
keyreg equ true ; I have funny keyboards.
keyxor equ 0ffh ; 7fh for Sperry, 0ffh for Honeywell kbd
; What to do with the PRINTER port.
; Set ONE of these tags to true.
pistnc equ true ; Second TNC, 4800 baud, 8 bit, no parity.
piscon equ false ; Console, 9600 baud, 8 bit, no parity.
pispr equ false ; Printer, 9600 baud, 7 bit, even parity.
; How to handshake the serial ports.
hdwhnd equ false ; True if hdw handshake works
xon equ dc1 ; dc1 or bs
xoff equ dc3 ; dc3 or ' '
; What to do with the parallel user port.
parlst equ true ; True to use par port for list device.
clk4 equ false ; Set true if 4 Mhz system clock
; Ram Allocation
ivec equ 0ff00h ; Interrupt vector page.
defbuf equ 80h ; Default CPM Disk buffer area
nmivec equ 66h ; Where Z80 traps on non-maskable interrupt
; I/O ports:
; COMM port (SIO A)
pu1st equ 6
pu1dat equ 4
pu1cts equ 20h
pu1dcd equ 8
pu1tbe equ 4
pu1spd equ 0 ; Baud rate generator for channel A
pu1buf equ bufbas ; Must be on page boundary
pu1siz equ 256 ; Input buffer size
; PRINTER port (SIO B)
pu2st equ 7
pu2dat equ 5
pu2cts equ 20h
pu2dcd equ 8
pu2tbe equ 4
pu2spd equ 0ch ; Baud rate generator for channel B
pu2buf equ pu1buf+pu1siz ; Must be on page boundary
pu2siz equ 256 ; Input buffer size
; Keyboard port.
pu3dat equ 1eh ; Keyboard data port of PIO
pu3st equ 1fh ; Keyboard control port of PIO
pu3buf equ pu2buf+pu2siz ; Must be on page boundary
pu3siz equ 16 ; Must be pwr of 2 and <= 256
; Misc system ports.
pio.ad equ 8 ; PIO channel A, Data port
pio.as equ 9 ; PIO channel A, Sts/Ctrl port
pio.bd equ 0ah ; PIO channel B, Data port
pio.bs equ 0bh ; PIO channel B, Sts/Ctrl port
fdc.cs equ 10h ; 1771 Disc Controller: Ctrl/Status
fdc.tk equ 11h ; 1771 Disc Controller: Cylinder/track
fdc.se equ 12h ; 1771 Disc Controller: Sector
fdc.da equ 13h ; 1771 Disc Controller: Data
crt.sc equ 14h ; CRT Scroll control register
ctc.c0 equ 18h ; Counter/Timer Chip Channel 0
ctc.c1 equ 19h ; Counter/Timer Chip Channel 1
ctc.c2 equ 1ah ; Counter/Timer Chip Channel 2
ctc.c3 equ 1bh ; Counter/Timer Chip Channel 3
pio.sd equ 1ch ; Data port of system PIO
pio.sc equ 1dh ; Control port of system PIO
; Bit numbers for bit, res,and set instructions
b0 equ 0
b1 equ 1
b2 equ 2
b3 equ 3
b4 equ 4
b5 equ 5
b6 equ 6
b7 equ 7
; This section is the loader code. It runs as a normal .COM file.
; It sets up the interrupt vectors, then moves the BIOS
; code to upper memory where it belongs.
aseg
org 100h
; Initialize the I/O devices.
di ; Start with interrupts off
ld hl,inivio ; Set up initial I/O variables
initio: ld b,(hl) ; Get count of I/O setup data bytes
inc hl
ld c,(hl) ; To be stuffed into this I/O port
inc hl ; Point at data bytes
otir ; Set up the I/O device
bit b7,(hl) ; Check for end of setup blocks
jr z,initio ; Loop over all I/O setups
; Set the processor to proper interrupt state.
ld a,ivec shr 8 ; I/O vector page
ld i,a ; Set processor for vectored interrupts
im 2
; Set up the interrupt vectors.
ld hl,livec ; Point to local copy
ld de,ivec ; Point to where they go
ld bc,livecl ; How many bytes
ldir ; Move them there
; Move the BIOS code to its execution area.
ld hl,bsbgn
ld de,bios
ld bc,bslen
ldir
ei
jp bios ; Go do it.
; I/O port initialization values.
; Organized for copying loop above, these are in the form:
; one byte count
; one byte port number
; n bytes of port initialization values
; followed by another block, or "FF" to mark the end of the list
inivio:
if parlst
db 1,pio.as
db 0fh ; Output mode on PIO port A
db 2,pio.bs
db 0cfh ; BIT mode on PIO port B
db 0fh ; BITS 7..4 outputs, BITS 3..0 inputs
db 1,pio.ad
db 0d0h ; Strobe bit negated
endif
db 3,pio.sc ; PIO for system control port
db 0cfh,38h,40h ; Change 38 to 18 for bell
db 1,pio.sd
db 0 ; Init system control port data
db 3,pu3st ; PIO control for keyboard
db 4fh
db ivkbd and 0ffh ; Vector location
db 83h
db 1,ctc.c0 ; Chan 0 of CTC
db ivctc and 0ffh
db 2,ctc.c2 ; Chan 2 of CTC
if clk4
db 27h,168 ; Each tick = 10.752 Ms.
else
db 27h,105 ; Each tick = 10.752 Ms.
endif
db 2,ctc.c3 ; Chan 3 of CTC
db 0c7h,93 ; Counts of ch 2 = 1 sec.
; Baud rates for the SIO ports.
db 1,pu1spd ; SIO port A baud rate
db 12 ; 4800 baud for COMM port.
db 1,pu2spd ; SIO port B baud rate
if pistnc
db 12 ; 4800 baud for PRINTER port.
else
db 14 ; 9600 baud
endif
; SIO port A (COMM port).
db pu1inl,pu1st ; Count, port
pu1ini: db 18h ; Reset
db 14h,44h ; A reg 4 - x16, 1 stop, no par
db 13h,0c1h ; A reg 3 - 8 bit, rx enable
db 15h,0eah ; A reg 5 - DTR, RTS, 8 bit, tx enable
db 11h,19h ; A reg 1 - rx int all char, external
pu1inl equ $-pu1ini
; SIO port B (PRINTER port).
db pu2inl,pu2st ; Count, port
pu2ini:
if pispr
db 18h ; Reset
db 14h,43h ; B reg 4 - x16, 1 stop, even par
db 13h,40h ; B reg 3 - 7 bit, no rx
db 15h,0aah ; B reg 5 - DTR, RTS, 7 bit, tx enable
db 12h,(ivsio and 0ffh) ; B reg 2 - Int addr
db 11h,5h ; B reg 1 - rx off, ext, status affects vect
else
db 18h ; Reset
db 14h,44h ; B reg 4 - x16, 1 stop, no par
db 13h,0c1h ; B reg 3 - 8 bit, rx enable
db 15h,0eah ; B reg 5 - DTR, RTS, 8 bit, tx enable
db 12h,(ivsio and 0ffh) ; B reg 2 - Int addr
db 11h,1dh ; B reg 1 - rx all, ext, status affects vect
endif
pu2inl equ $-pu2ini
db 0ffh ; End of I/O initializer list
; Local copy of the interrupt vectors.
; Moved to the interrupt page at initialization time.
livec:
; SIO vectors.
ivsio equ ivec+($-livec)
dw 0
dw pu2ext
dw pu2ihd
dw pu2err
dw 0
dw pu1ext
dw pu1ihd
dw pu1err
; CTC interrupt vectors.
ivctc equ ivec+($-livec)
dw 0 ; CTC 0, not used.
dw ctcint ; Handler for timer (1 Ms ticks)
dw 0 ; CTC 2, prescale for clock.
dw clkint ; Handler for clock (seconds tick)
; Keyboard PIO vectors.
ivkbd equ ivec+($-livec)
dw pu3ihd ; Handler for keyboard
dw 0
dw 0
dw 0
livecl equ $-livec
; Here is the bios code. It is moved to its real location
; by the loader code above.
bsbgn equ $ ; Start of BIOS code
.phase bios ; Assemble correct addresses
maclib BIOSJMP.INC ; Makes the BIOS jump table
; Console.
; pu0 is keyboard/video + PRINTER, controled by pistnc/piscon/pispr
; pu1 is COMM port (SIO A)
; pu2 is PRINTER port (SIO B)
; pu3 is keyboard/video
; pu4 is parallel port on PIO
; Console status
const: ld a,(3) ; Iobyte
or a
jr z,pu0ist
dec a
jr z,pu1ist
if pistnc
pu2ist: ld a,(pu2ict)
or a
jr z,pu2isu
ld a,0ffh
ret
pu2isu: ld a,(pu2off)
or a
ret z ; Not off
if hdwhnd
di
ld a,5
out (pu2st),a
ld a,0eah
out (pu2st),a ; Turn TNC on
else
push bc
ld c,xon
call pu2ot ; Send the xon to the tnc
pop bc
di
endif
xor a
ld (pu2off),a
ei
ret ; With zero set
else
pu2ist: ld a,(pu2ict)
or a
ret z
ld a,0ffh
ret
endif
pu1ist: ld a,(pu1ict)
or a
jr z,pu1isu
ld a,0ffh
ret
pu1isu: ld a,(pu1off)
or a
ret z ; Not off
if hdwhnd
di
ld a,5
out (pu1st),a
ld a,0eah
out (pu1st),a ; Turn TNC on
else
push bc
ld c,xon
call pu1ot
pop bc
di
endif
xor a
ld (pu1off),a
ei
ret
pu0ist: if piscon
call pu2ist
ret nz
endif
pu3ist: ld a,(pu3ict) ; Anything in ring buffer?
or a
ret z ; Return Z if not
ld a,0ffh ; Yes, return non-Z and A/ FF
ret
; Console input
conin: ld a,(3) ; Iobyte
or a
jr z,pu0inp
dec a
jr z,pu1inp
pu2inp: call pu2ist
jr z,pu2inp
ld hl,(pu2gpt)
ld a,(hl)
inc l
ld (pu2gpt),hl
ld hl,pu2ict
dec (hl)
ret
pu1inp: call pu1ist
jr z,pu1inp
ld hl,(pu1gpt)
ld a,(hl)
inc l
ld (pu1gpt),hl
ld hl,pu1ict
dec (hl)
ret
pu0inp: if piscon
call pu2ist
jr nz,pu2inp
endif
call pu3ist
jr z,pu0inp
; Return character from keyboard. Wait if needed.
pu3inp: call pu3ist ; Anything there yet?
jr z,pu3inp ; Wait if not
push hl ; Yes, save hl pair
ld hl,pu3ict ; One less char in ring
dec (hl)
ld hl,pu3gpt ; Point at ring taker
call pu3ibp ; Get the char
pop hl ; Restore regs
ret ; Return char in A
; Console output
conout: ld a,(3) ; Iobyte
or a
jr z,pu0ot
dec a
jr z,pu1ot
if pistnc
pu2ot: in a,(pu2st)
and pu2dcd
ret z ; TNC is off
pu2ota: in a,(pu2st)
and pu2tbe
jr z,pu2ota
pu2otb: in a,(pu2st)
and pu2cts
jr z,pu2otb
ld a,c
out (pu2dat),a
ret
else
pu2ot: call pu2ost
jr z,pu2ot
ld a,c
out (pu2dat),a
ret
pu2ost: in a,(pu2st)
and pu2tbe
ret z
ld a,0ffh
ret
endif
pu1ot: in a,(pu1st)
and pu1dcd
ret z ; TNC is off
pu1ota: in a,(pu1st)
and pu1tbe
jr z,pu1ota
pu1otb: in a,(pu1st)
and pu1cts
jr z,pu1otb
ld a,c
out (pu1dat),a
ret
pu0ot: call pu3ot
if piscon
jr pu2ot
else
ret
endif
if parlst
pu4ot: in a,(pio.bd)
and 2
jr nz,pu4ot
ld a,c
out (pio.ad),a
push af
di
in a,(pio.bd)
res 4,a
out (pio.bd),a
set 4,a
out (pio.bd),a
ei
pop af
ret
pu4ost: in a,(pio.bd)
and 2
jr nz,pu4osa
ld a,0ffh
or a
ret
pu4osa: xor a
ret
endif
; CP/M list device.
if pispr
list equ pu2ot
listst equ pu2ost
endif
if parlst
list equ pu4ot
listst equ pu4ost
endif
if (not pispr) and (not parlst)
list equ pu0ot
listst: ld a,0ffh ; Return always ready
or a
ret
endif
; Punch and reader are not used.
punch equ conout
reader equ conin
; Increment pu3inp buffer pointer.
pu3ibp: ld a,(hl) ; Pick up putter or taker low bits
inc a ; Step the pointer
and pu3siz-1 ; Wrap within ring
ld (hl),a ; Update pointer
ld hl,pu3buf ; Now find the char it points to
add a,l
ld l,a
ld a,(hl) ; Pick up the character, for taker case
ret
; The interrupt code.
pu1no: ld a,(pu1off)
or a
ret nz ; Already off
cpl
ld (pu1off),a
if hdwhnd
ld a,5
out (pu1st),a
ld a,0e8h
out (pu1st),a
else
ld c,xoff
call pu1ot
endif
ret
pu2no: ld a,(pu2off)
or a
ret nz ; Already off
cpl
ld (pu2off),a
if hdwhnd
ld a,5
out (pu2st),a
ld a,0e8h
out (pu2st),a
else
ld c,xoff
call pu2ot
endif
ret
pu1err: ex af,af'
in a,(pu1dat)
ld a,30h
jr pu1xx
pu1ext: ex af,af'
in a,(pu1st)
ld a,10h
pu1xx: out (pu1st),a
jr iret2
pu1ihd: ex af,af'
exx
ld hl,(pu1ppt)
in a,(pu1dat)
ld (hl),a
inc l
ld (pu1ppt),hl
ld hl,pu1ict
inc (hl)
ld a,(hl)
cp pu1siz-8
call z,pu1no
jr iret1
pu2err: ex af,af'
in a,(pu2dat)
ld a,30h
jr pu2xx
pu2ext: ex af,af'
in a,(pu2st)
ld a,10h
pu2xx: out (pu2st),a
jr iret2
pu2ihd: ex af,af'
exx
ld hl,(pu2ppt)
in a,(pu2dat)
ld (hl),a
inc l
ld (pu2ppt),hl
ld hl,pu2ict
inc (hl)
ld a,(hl)
cp pu2siz-8
call z,pu2no
jr iret1
; Keyboard interrupt handler.
pu3ihd: exx ; Save registers
ex af,af'
in a,(pu3dat) ; Get the keyboard data
if keyreg
cpl ; Invert inverted data
and 7fh ; Bit 7 = 0
else
; Fix for control chars from keyboard
xor keyxor
jp p,xx
and 1fh
endif
xx: ld c,a ; Char to add to ring
ld hl,pu3ict ; Ring fullness count
ld a,(hl) ; Pick up count
inc a ; Add one more character
cp pu3siz ; Ring full?
jr nc,iret1 ; Don't add another char, if full
ld (hl),a ; OK, add this one
ld hl,pu3ppt ; Point at ring putter
call pu3ibp ; Compute address and wrap
ld (hl),c ; Put char in ring
iret1: exx
iret2: ex af,af'
ei
reti
pu1ppt: dw pu1buf
pu1gpt: dw pu1buf
pu1ict: db 0
pu1off: db 0
pu2ppt: dw pu2buf
pu2gpt: dw pu2buf
pu2ict: db 0
pu2off: db 0
pu3ppt: db 0
pu3gpt: db 0
pu3ict: db 0
; Disk handler.
maclib BIOSDPB.INC
; Sector translate
sectrn: ex de,hl
add hl,bc
ld l,(hl)
ld h,0
ret
; Select drive
seldsk: ld hl,0 ; Assume bad staus
ld a,c
cp mxdrv
ret nc ; No such drive
ld (drive),a
ld l,c
add hl,hl
add hl,hl
add hl,hl
add hl,hl
ld de,dpe0
add hl,de
ret
; Do the actual select.
select: ld a,(drive) ; Get drive wanted
ld hl,ldrive ; Point at last drive used
cp (hl) ; Same one?
ret z ; Yes, do nothing.
cp 4 ; Is it 4 or more?
ret nc ; Return if so, no good.
ld e,(hl) ; Get the old one
ld (hl),a ; Save current, committed now
ld c,a ; Save a copy
ld a,e ; The previous drive.
cp 0ffh ; was there really one?
jr z,selec1 ; No, no need to save the track.
ld hl,trkvec ; Point at track slot
if xrxsds
ld a,e
and 1 ; make the two sides of the same
ld e,a ; point to the same track save
endif
ld d,0
add hl,de ; for the old drive
in a,(fdc.tk) ; Read old track number
ld (hl),a ; Put it in vector for next use of drive
selec1: in a,(pio.sd) ; Turn off the drive/side select bits so that
and 0f8h ; first call to diskup will set them.
if bigbrd
or 4 ; Deselct the drive
endif
out (pio.sd),a
ld hl,trkvec ; Now get track of new drive
if xrxsds
ld a,c
and 1 ; make the two sides of the same
ld c,a ; point to the same track save
endif
ld b,0
add hl,bc
ld a,(hl)
cp 0ffh ; If unknown, home this drive
jr z,homea
out (fdc.tk),a ; Else tell 1771 where the head is
xor a ; Return Z, success
ret
; Home the drive
home: call select
homea: call diskup ; Get the drive up to speed first
ret nz ; Return if can't
xor a ; OK, set cylinder to zero
ld (track),a
homeb: ld b,0ch ; Set seek track 0 command
call fdcsek ; Go do it
xor 4 ; Set up error bits for return
and 9ch
ret
; Set track.
settrk: ld a,c
ld (track),a
ret
; Set sector.
setsec: ld a,c
ld (sect),a
ret
; Set dma address.
setdma: ld (dmaadr),bc
ret
; Read a sector.
read: call setup
call z,rdsec
ret
; Write a sector.
write: call setup
call z,wtsec
ret
setup:
if pistnc
call pu2no
endif
call pu1no
call select
jp seek
; Reload CCP + BDOS.
; Set up stuff in low memory for CP/M.
; loadit is the entry point
lderrm: db ff,'Disk error loading DOS, type any character to retry.',0
lderr: ld hl,lderrm
call putstr
call pu3inp ; May want to be pu0inp
loadit: ld a,0c3h
ld (0),a
ld (5),a
ld hl,bios+3
ld (1),hl
ld hl,bdos+6
ld (6),hl
xor a
ld (drive),a
; ld e,1 ; To force loggin of disk.
call home
or a ; check for errors
jr nz,lderr ; woops!
ld a,cpmsec
ld (sect),a
ld hl,ccp
ld (dmaadr),hl
ld b,44 ; # sectors to read.
load: push bc
call rdsec
pop bc
or a ; check for errors
jr nz,lderr ; woops!
dec b ; Count sectors read
ret z ; Read em all, done
call pokefd ; Prevent motor timeout
ld de,secsiz
ld hl,(dmaadr)
add hl,de
ld (dmaadr),hl
ld a,(sect)
inc a
ld (sect),a
sub spt+1 ; Done with track?
jr nz,load ; No, continue reading
ld a,1
ld (sect),a
ld hl,track
inc (hl)
push bc
call seek
or a ; check for errors
jr nz,lderr ; woops!
pop bc
jr load
; Do a warm boot.
bootw: ld sp,80h
call loadit
ld bc,80h
call setdma
ld a,(4)
ld c,a
jp ccp+3
; Finish the cold boot.
bootc: di
ld sp,80h
call loadit
ld bc,80h
call setdma
xor a
ld (yr),a ; Flag for "no date entered"
ei
; Print the id message.
ld hl,idmsg
call putstr
jp ccp
idmsg: db ff,'DOS 2.2 BIOS 10.6',0
putstr: ld c,(hl)
inc hl
ld a,c
or a
ret z
call pu3ot ; May want to be pu0ot
jr putstr
mos: db 31,28,31,30,31,30,31,31,30,31,30,31
clkint: exx ; CTC chan 3 comes here once a second
ex af,af'
; Tick the timer.
ld hl,(timer)
dec hl
ld (timer),hl
ld a,(sec)
inc a
cp 60
jr nz,tiksec
ld a,(min)
inc a
cp 60
jr nz,tikmin
ld a,(hr)
inc a
cp 24
jr nz,tikhr
ld a,(day)
ld hl,mo
ld e,(hl)
dec e ; Months 0-11 to index table
ld d,0
ld hl,mos
add hl,de
cp (hl)
jr nz,tikday ; Not first day of new month
ld a,(mo)
cp 12
jr nz,tikmon ; Not a new year
ld hl,yr
inc (hl)
xor a
tikmon: inc a
ld (mo),a
xor a
tikday: inc a
ld (day),a
xor a
tikhr: ld (hr),a
xor a
tikmin: ld (min),a
xor a
tiksec: ld (sec),a
ld hl,fdrunt ; Count down run time of floppy motor
dec (hl)
jr nz,tikdon ; Time not up yet
in a,(pio.sd) ; Time up, deselect the drive
and 0f8h
if bigbrd
or 44h ; Turn off motor and deselect
endif
out (pio.sd),a
tikdon: ex af,af'
exx
ei
reti
ctcint: exx ; Channel 1 of CTC comes here
ex af,af'
ld hl,(dsktmr)
dec hl
ld (dsktmr),hl
ex af,af'
exx
ei
reti
maclib BIOSVID.INC ; Include video handler (pu3ot)
; Seek to requested track.
seek: call diskup ; Make sure disk is spinning
ret nz ; It won't. Fail.
ld a,(track) ; Desired track
cp tracks ; In range?
ret nc ; Fail if not.
out (fdc.da),a ; Tell the 1771 where to go
ld b,1ch ; Seek op
call fdcsek ; Plug in step rate and do it
and 98h ; Check for any errors
ret z ; Done if OK
call homeb ; Seek failed. Try recalibrating
ret nz ; That failed too?
ld a,(track) ; Try the seek again if recal worked
out (fdc.da),a
ld b,1ch
call fdcsek
and 98h ; Return success or fail this time
ret
; Sector Read and Write routines
wtsec: call fdcsts ; See if disk is write locked
bit b6,a
ret nz ; Don't try writing if locked
ld b,0a8h ; Write opcode
jr rdsec1 ; Much like read from here on
rdsec: ld b,88h ; Read opcode
rdsec1: ld hl,fdop ; Save the opcode in fdop
ld (hl),b
ld hl,retryc ; Point at retryc
ld (hl),11 ; Set initial retry count
again1: di ; Turn off interrupts during transfer
ld hl,nmivec ; Use NMI mechanism for the data xfer
ld d,(hl) ; Hold old contents of 0066H
ld (hl),0c9h ; Put a "ret" there for now
ld b,secsiz ; # bytes/sector set for ini/outi
ld c,fdc.da ; I/O port for read and write data
ld hl,(dmaadr) ; Memory address for the sector
ld a,(sect) ; Tell it what sector we want
out (fdc.se),a
call fdcsts ; Stop old op, get status
bit b5,a ; Head loaded yet?
ld a,(fdop) ; Pick up the read or write
jr nz,noload ; Go if no need to load it
or 4 ; Tell it to load head
noload: call fdcdo ; Do the read or write
bit b5,a ; Is this a read or a write?
jr nz,wrwait ; Go handle write
rdwait: halt ; Wait for NMI
ini ; Read a byte
jp nz,rdwait ; Loop if not done, JP not JR, faster
call fdcskw ; Wait for it to finish CRC
and 9ch ; Error bits for read
jr rwwat1 ; Go clean up at end
wrwait: halt ; Wait for NMI, write case
outi ; Output a byte
jp nz,wrwait ; Loop till sector done, JP not JR
call fdcskw ; Wait for CRC to go out, get status
and 0bch ; Error bits for write case.
rwwat1: ld hl,nmivec ; Restore the contents of 0066H
ld (hl),d
ei ; Allow interrupts again
ret z ; Return if no errors
ld hl,retryc ; Nuts, there were errors.
dec (hl) ; Count the retries
jr nz,again ; If some left, try it all again
or a ; Else set NZ with error bits
ret ; and fail the read/write.
again: call seek
jr again1 ; And re-do the read or write.
fdcsek: ld a,stept ; Pick up step rate bits
or b ; Put in seek/home operation
call fdcdo ; Hand it to the chip
fdcskw: in a,(fdc.cs) ; Wait for it to finish
bit b0,a
jr nz,fdcskw
ret
fdcdo: out (fdc.cs),a ; Do the requested op in 1771
call fdcdow ; And wait a little while
fdcdow: ex (sp),hl ; since 1771 is a bit slow on
ex (sp),hl ; getting the status right
ret
fdcsts: ld a,0d0h ; Reset current op
call fdcdo ; Do that and delay
in a,(fdc.cs) ; See what status is
ret
pokefd: ld a,whirtm ; Restart motor timer at max
ld (fdrunt),a
call pokef1 ; A little delay
in a,(pio.sd) ; Get system PIO for drive bits
pokef1: ret
diskup: call pokefd ; Restart timer, get drive bits
ld e,0 ; A success code in case allready up.
if xerox
and 7
jr nz,dskupx ; Return if one is selected
endif
if bigbrd
and 4
jr z,dskupx ; Return if one is selected
endif
push hl ; Save two reg pairs
push bc
ld a,(ldrive) ; Get desired drive
ld c,a ; Make a copy
if xerox
and 2 ; If 2 or 3 get a 2 to add to turn that 2 bit
add a,c ; into a 4 bit for side select.
inc a ; If 0 or 4 turn on bit 1 to select drive A/C,
ld c,a ; if 1 or 5 turn that 1 bit to a 2 bit to
; select drive B/D.
endif
if bigbrd
; Nothing to do here
endif
in a,(pio.sd) ; Get other bits, we know that drive/side bits
or c ; are allready zero or we wouldn't be here,
if bigbrd
and 0bbh ; Turn on drive motor and select
endif
out (pio.sd),a ; so we don't have to mask them.
ld a,87h ; Tell CTC 1 to time us
out (ctc.c1),a
if clk4
tkpms equ 250 ; processor clocks per ms / 16
else
tkpms equ 156
endif
ld a,tkpms ; for a while (1 Ms ticks).
out (ctc.c1),a
ld hl,2000 ; This many Ms. says disk doesn't turn
ld (dsktmr),hl
call fdcsts ; See if index bit is on
and 2
ld b,a
call idxwat ; Wait for index bit to change
jr c,offlin ; If it didn't, give up on drive
dskup2: ld hl,(dsktmr) ; It changed. Now wait for up to speed
call idxwat
jr c,offlin ; Go if failed
call idxwat ; Wait for two half square-waves
jr c,offlin ; Go if failed
ld de,(dsktmr) ; Now see if it's fast enough
sbc hl,de
ld (idxtim),hl ; Save rotation time
ld de,msprev
or a ; Clear CY for sbc
sbc hl,de ; Is it this fast yet?
jr nc,dskup2 ; If not, let it turn some more
ld e,0 ; Fast enough.Success code. Go accept it
jr oflin1
offlin: in a,(pio.sd) ; Disconnect from this drive. It's bad
and 0f8h
if bigbrd
or 4 ; Deselect
endif
out (pio.sd),a
ld e,80h ; Failure code
oflin1: ld a,3 ; Through with this CTC channel
di ; Because of CTC chip bug
out (ctc.c1),a
ei
pop bc ; Restore registers
pop hl
dskupx: ld a,e ; Success/fail code
or a ; Non-Z says OK
ret
idxwat: call fdcsts ; Get Index hole bit
and 2
xor b ; Compare to old bit
jr nz,idxchg ; Go when it changes
ld a,(dsktmr+1) ; See if time to give up
bit b7,a
jr z,idxwat ; No, keep waiting
scf ; Failed. This thing isn't turning
ret
idxchg: ld a,b ; Aha. It changed.
xor 2 ; Remember the new Index value
ld b,a
ret ; Return from idxwat
drive: ds 1 ; Drive wanted, 0-3
ldrive: db 0ffh ; Previous drive wanted, 0-3
track: ds 1
trkvec: db 0ffh,0ffh,0ffh,0ffh
sect: ds 1
dmaadr: ds 2
fdrunt: db whirtm ; Seconds to let motor run.
fdop: db 0 ; Opcode for current floppy op
retryc: db 0 ; Retry count for read or write on floppy
dsktmr: dw 0 ; Time counter for disk up to speed test
idxtim: dw 0 ; Time for disk to turn
dirbuf: ds 128
alv0: ds 31
csv0: ds 16
if mxdrv gt 1
alv1: ds 31
csv1: ds 16
endif
if mxdrv gt 2
alv2: ds 31
csv2: ds 16
endif
if mxdrv gt 3
alv3: ds 31
csv3: ds 16
endif
bufbas equ 256*(($ shr 8)+1)
bslen equ $-bios ; Length of the bios load
end