 lib environment
 lib bfhdr
 lib dtab
 lib macdefs
 data
 sttl Archive Tape Driver
 pag
 name atdrvr

 global atopen,atclose,atread,atwrite,atspcl
 global ATinit,ATint,ATio,ATerr

ATPRIOR equ -15 tape sleep priority
*
*  Output lines presented on B Data Register
*
online equ %00000001 0 => ONLINE presented
request equ %00000010 0 => REQUEST presented
*
*  Input lines presented to B Data Register
*

ready  equ %00010000 0 => Tape drive Ready
except equ %00100000 0 => Tape drive Exception
*
*  tape controller command words
*
c_unlock  equ %00000001 unlock the tape in drive zero
c_lock equ %00010001 lock the tape in drive zero
c_posit equ %00100000 position the tape to certain place
c_write equ %01000000 write data blocks to the tape
c_wfm  equ %01100000 write file mark on the tape
c_rfm  equ %10100000 read file mark on the tape
c_read equ %10000000 read data blocks on the tape
c_test equ %10110000 initiate diagnostic read of tape
c_status  equ %11000000 read status bytes from the drive
*
BLKSIZ equ 512 Tape always reads/writes 512 bytes
*
*  read/write flag definitions
*
T_idle equ 0 tape is now idle
T_ioerr equ 1 tape has I/O error
T_wterm equ 2 terminated write operation
T_write equ 3 active write operation
T_rterm equ 4 terminated read operation
T_read equ 5 active read operation

 pag
*
* Open Archive Tape
*
atopen
 tst atflag is device open
 bne in_use yes, croak dude
 lda #!(online)
 sta AT_DTB bring drive online

*
* Do a hardware Archive reset for some reason
*
 lbsr atreset
 jsr getstat

 ldb #c_lock load a lock command
 lbsr dotape crank out the tape stuff
 lbsr getstat then read status
 ldd byteit
 bita #%01100110 check for no tape
 lbne ATerr
 bitb #%01110000 check for perm I/O err
 lbne ATerr
*
*   validated open - lock tape, rewind, etc.
*
 ldb #c_posit+%001
 lbsr dotape rewind to beginning of tape
 inc atflag no - set open flag
 clr rwflag
 rts
in_use lda #EBSY set error (Device busy)
 sta uerror
 rts

*
* Close Archive Tape
*
atclose
 tst atflag is device open
 lbeq ATerr
 lda #!(0) drive offline
 sta AT_DTB
 lbsr getstat
 lda #%00000011 shut down CA1 CA2 stuff
 sta AT_IER
 lda AT_PTY and shut down dmas
 anda #%11110011
 sta AT_PTY
*
*  when operation terminates, rewind and unlock tape
*
 ldb #c_posit+%001 rewind the tape
 lbsr dotape
 ldb #c_unlock load the unlock command
 lbsr dotape
 clr atflag reset open flag
 clr rwflag
 clr at_dt+dtbusy
 rts

*
*  Write data to Archive Tape
*
atwrite
 lda rwflag
 cmpa #T_write
 beq wiochk if write mode, ok
 lbsr getstat clear exception
 tst uerror
 beq wiochk exit if error
 rts
*
*  validate the I/O request
*
wiochk
 lda byteit check drive status
 bita #$70 no tape/no drive/write protected
 bne ATerr
 lbsr chkio validate I/O request
 beq 0f jump if OK
 lda #EBARG Illegal argument
 sta uerror
 rts
0 pshs d save device number
 jsr fchgb get buffer header
 puls d
 bsr at_cnf configure buffer
 tst uerror any errors?
 beq at_cio
 rts error return
*
*  perform I/O using character block header
*
at_cio bsr at_fio do floppy disk io
 ldd bfxfc,y
 std uicnt restore xfer count
 rts

at_fio pshs a save task status
 jmp fchio same as floppies

*
*  Read data from Archive Tape
*
atread
 lda rwflag
 beq riochk if no mode, ok
 cmpa #T_rterm
 bhs riochk
 cmpa #T_ioerr
 beq ATerr
 lbsr getstat clear exception
 clr rwflag reset read/write flag
 tst uerror
 beq riochk exit if error
 rts
*
*  validate the I/O request
*
riochk
 lda byteit check status
 bita #$60 check bad status bits
 bne ATerr can't do I/O
 bsr chkio validate I/O request
 beq 0f jump if OK
 lda #EBARG Illegal argument
 sta uerror
 rts
0 pshs d save device number
 jsr fchgb get buffer header
 puls d reset dev number
 bsr at_cnf go configure header
 orb #BFRWF set read mode
 stb bfflag,y save in buffer
 tst uerror any errors?
 beq at_cio
 rts error return

*
*   permanent error on archive device
*
ATerr
 ldb #c_unlock load the unlock command
 lbsr dotape
 clr atflag reset open flag
 clr rwflag
 lda #EIO set error - can't open
 sta uerror return error code
 rts

*
* configure character header
*

at_cnf ldd #AT_DVN get archive tape device #
 std bfdvn,y set up device number
 ldd uicnt get transfer count
 std bfxfc,y set in header
 jsr fchcn2 same as floppies
 pshs d save registers
 ldd uistrt restore unmapped address
 std bfadr,y
 ldb sysmap+USRLOC save user block address
 stb bfxadr,y
 puls d,pc return

*
*   chkio - Validate I/O request
*     1. Transfer count must be a multiple of 512
*     2. Buffer must lie on a 512 byte boundary to
*        avoid problems of large buffers crossing
*        page boundaries.
*
chkio pshs d save registers
 ldd uicnt get transfer count
 anda #$01
 cmpd #0 check for multiple of 512 bytes
 bne 90f
 ldd uistrt get buffer starting address
 anda #$01
 cmpd #0 check buffer alignment
 beq 95f
90 lda #1 return - Illegal argument
95 puls d,pc

*
* Perform Archive Tape I/O Operation
*
ATio stx BDtable save Block Device Table address
*
* decide whether we are doing a read or write
*
 ldb bfflag,y get buffer flags
 bitb #BFRWF are we reading?
 beq at_wrt go do write
 bra at_rd go do read
*
* error routine - give up forever
*
at_ers
 jsr getstat clear exception
at_er
 lda #T_ioerr indicate I/O error
 sta rwflag
 ldd byteit get exception status
 anda #$EF clear write protect
 cmpd #$8100 check for end of file
 beq A_IOend
 ldy at_dt+dtqfl
 beq A_IOend
 lda bfflag,y get buffer flag
 ora #BFERR indicate failure
 sta bfflag,y stuff back in el flago
 lda #EIO set error code
 sta uerror
A_IOend clr at_dt+dtbusy set not busy
 clr AT_PTY shut down DMA
 clr AT_ICR
 ldx BDtable restore Block Device Table address
 jmp BDioend end of operation

*
*   Perform actual READ
*
at_rd
 ldd bfxfc,y get read count
 beq A_IOend exit when no more left
 jmp uread read block
*
*   take interrupt off read completion
*
R_int tsta check error flag
 bne at_er jump on error
 ldx bfadr,y update address
 leax BLKSIZ,x
 stx bfadr,y
 ldd bfxfc,y fix up count
 subd #BLKSIZ
 std bfxfc,y
 bra at_rd

*
*   Perform actual WRITE
*
at_wrt
 ldd bfxfc,y get write count
 beq A_IOend exit when no more
 jmp uwrite
*
*   take interrupt off write completion
*
W_int tsta check interrupt response
 bne at_er jump on error
 ldx bfadr,y update address
 leax BLKSIZ,x
 stx bfadr,y
 ldd bfxfc,y fix up count
 subd #BLKSIZ
 std bfxfc,y
 bra at_wrt

*
*   Special handler for Archive Tape (ttyset/ttyget)
*
atspcl
 cmpx #0 ttyget?
 beq ioctl
*
*  ttyget returns last archive status
*
 ldb #6 copy six bytes
 ldy #byteit point at status buffer
atsout lda 0,y+ copy status info
 sta 0,x+
 decb done?
 bne atsout
 rts
*
*   ttyset is I/O control call
*
ioctl ldd usarg0
 bita #1 see if active
 bne badctl
 cmpb #c_wfm write file mark
 beq do_ctl
 cmpb #c_rfm read file mark
 beq do_ctl
 cmpb #c_posit+%001 rewind to BOT
 beq do_ctl
 cmpb #c_posit+%010 erase entire tape
 beq do_ctl
 cmpb #c_posit+%100 retension tape
 beq do_ctl
 cmpb #c_status status command
 beq do_stat
badctl lda #EBDCL Illegal (Bad) System Call
 sta uerror
 rts

do_ctl pshs a
 bsr dotape issue tape command
 puls a
do_stat sta rwflag
 bsr getstat get drive status
 lda byteit+1
 bita #%01000000 check illegal command
 bne badctl
 rts


*
*  issue status command to the drive
*
getstat tst AT_DMC clear XFER line
 lda #-1
 sta AT_DXA bring data lines high
statlp lbsr waiteith wait for status or exception
gostat
 ldb #c_status load a status command
 bsr dotcmd send command out to drive
 ldb #6  set count to 6 bytes
 ldx #byteit point to data buffer
*
*  wait for ready strobe indicating byte is ready
*
grabone
 lbsr waitrdy
*
*  read the data bus and assert request to tell archive
*
 lda AT_DXA read data byte from drive
 sta 0,x+ stuff into the buffer
 lda AT_DTB strobe the request line low
 anda #!(request) while leaving on line alone
 sta AT_DTB
 lda #10
grabtwo deca delay at least 20 uSec
 bne grabtwo
*
*  wait for archive to respond by dropping ready
*
grabbed lda AT_DTB read the flags byte
 bita #ready check for ready flag bit
 beq grabbed if still set, loop
 lda #8 delay 20 uS for Archive spec
gx deca
 bne gx
 lda AT_DTB turn request line off
 ora #request and leave on line alone
 sta AT_DTB
 decb  decrement byte counter
 bne grabone if not done, continue
 rts
*
*  issue a command to the archive
*
dotape tst AT_DMC insure DMA preset inactive
 lda AT_DTB
 anda #!(online) bring drvie online
 sta AT_DTB

 lbsr waitrdy


*
*   send command word to archive
*
dotcmd stb AT_DXA put command on data bus
 lda AT_DTB bring the request line low
 anda #!(request) and leave online alone
 sta AT_DTB
 lda #10
dotdly deca insure 30 uSec delay
 bne dotdly
dotwat
 lbsr waitrdy
 lda AT_DTB drop the request strobe
 ora #request and leave online alone
 sta AT_DTB
 lda #-1
 sta AT_DXA remove command byte
dotcma lda AT_DTB
 bita #ready
 beq dotcma wait for ready dropped
 rts

*
*  write a block to the tape
*
uwrite lda rwflag check for write in progress
 cmpa #T_write see if already writing
 beq wrtmore
 cmpa #T_ioerr check for I/O error
 lbeq at_er
*
*  fire up a write command to the tape
*
do_write
 pshs cc
 clri mask
 ldb #c_write  load the write command
 bsr dotape stuff write command to drive
 puls cc
 lda #T_write
 sta rwflag indicate write in progress
wrtmore lda AT_DTB
 bita #except
 lbeq at_ers oops, croak the write
*
*  set up the VIA and DMA for handshake mode
*
 lda #%00101110 force CA2 to output high to stop lockup (black magic!)
 sta AT_PCR stuff Peripheral Control Reg
 lda #%00101000 turn CA2 back into handshake input
 sta AT_PCR stuff Peripheral Control Reg
 clr AT_DMC clear any pending DMA
 lda #%00000001 select a DMA write to archive
 sta CAT_C3 stuff channel 3 control register
 lda #%00001000 select DMA 4 channel mode
 sta AT_DCR stuff data chain register
*
*  set up rest of DMA for the block
*
 pshs cc
 seti mask disable interrupts here
 lda #%00001000 enable dma write interrupt
 sta AT_ICR
 lbsr xlate  perform address translation
 ora #%00110000 select channel 3 on latch
 sta AT_XAL stuff extended address latch
 stx AT_C3A stuff channel 3 address register
 ldd #BLKSIZ set block size for DMA
 std AT_C3C stuff channel 3 count register
 lda #%00001000 set request enable on channel 3
 sta AT_PTY stuff priority control
 sta AT_DMP fire up the DMA
*
*  wait for the DMA to complete
*
 lda #$20 set up busy flag
 sta at_dt+dtbusy
 puls cc,pc
*
*   Archive Tape Interrupt Handler
*   Enter with A=IFR from 6522
*
ATint
 clr 0,-s set exception flag to zero
 lda AT_DTB check for exception
 bita #except
 bne normal jump if no exception
* Something nasty happened - got an exception
 inc 0,s set exception flag
 lda AT_PTY clear dma's this device
 anda #%11110011
 sta AT_PTY
 ldy at_dt+dtqfl get transaction pointer
 beq nores jump if no transaction in progress
 ldb bfdvn+1,y check for archive transaction
 cmpb #ATminor
 bne nores
 ldb at_dt+dtbusy check busy flag
 cmpb #$10 Reading?
 beq nores
 lda #!(0) take drive offline
 sta AT_DTB
 ldb #%11000000
 lda #6
0 stb AT_RES
 deca
 bne 0b
 sta AT_RES
nores
 jsr getstat read status


*
*   check for active transaction
*
normal puls a get exception flag
 ldy at_dt+dtqfl get transaction pointer
 beq nullint jump if no transaction in progress
 ldb bfdvn+1,y check for archive transaction
 cmpb #ATminor
 bne nullint not archive - just get out
 clr AT_PTY disable DMA request
 ldb at_dt+dtbusy check busy flag
 cmpb #$20 Writing?
 lbeq W_int yes - jump
 cmpb #$10 Reading?
 lbeq R_int yes - jump
nullint rts

*
*  set up timers for ARCHIVE tape
*
ATinit pshs cc
 seti mask
 ldd #2000  set up time for 2 MHz
 stb AT_T1C
 sta AT_T1C+1  write timer 1 counter
 clr AT_T2C
 clr AT_T2C+1  clear out timer 2 counter
 lda #%11100000
 sta AT_ACR enable timers
*
*  reset archive tape on boot
*
 clr AT_DMC clear any archive DMA present
 lbsr atreset
 clr rwflag
*
*  if no exception, tape not connected
*
 lda AT_DTB
 bita #except check for exception
 bne noarch
 jsr getstat read archive status
 puls cc,pc
noarch clr atflag indicate closed
 puls cc,pc

*
*  read a block into the buffer
*
uread  lda rwflag check for read in process
 cmpa #T_read see if already reading
 beq readmor
 cmpa #T_ioerr check for I/O error
 lbeq at_er
*
*  set up handshake mode on VIA
*
do_read
 tst AT_DMC clear preset if glitched
 lda #%00101000 set up handshake on CA2
 sta AT_PCR stuff peripheral control reg
 lda #%00000000 select a DMA read from archive
 sta CAT_C2 stuff channel 2 control register
 lda #%00001000 select DMA 4 channel mode
 sta AT_DCR stuff data chain register
*
*  fire up a read command to archive
*
 pshs cc
 clri mask
 ldb #c_read
 lbsr dotape issue read to controller
 puls cc
 lda #T_read
 sta rwflag indicate read in progress
readmor
 lda AT_DTB any croaks?
 bita #except
 lbeq at_ers croak if so
 bra rdyok


rdyint
 tsta
 lbne at_er
rdyok

*
*  set up rest of DMA for the block
*
 pshs cc save i,f flags
 seti mask disable interrupts
 bsr xlate  perform address untranslation
 ora #%01100000 select channel 2 on latch
 sta AT_XAL stuff extended address latch
 stx AT_C2A stuff channel 2 address register
 ldd #BLKSIZ load length of block
 std AT_C2C stuff channel 2 count register
*
*  fire up DMA and wait for complete
*
 lda #%00000100 enable DMA interrupt
 sta AT_ICR
 lda #%00000100 set request enable on channel 2
 sta AT_PTY stuff priority control
 lda #$10 set reading mode
 sta at_dt+dtbusy
 puls cc,pc

*
*  delay number of milliseconds in D register
*
delay  pshs d  save registers on stack
 stb AT_T2C
 sta AT_T2C+1  start up timer 2 with count
deloop lda AT_IFR
 anda #%00100000 check for timer 2 expired
 beq deloop
 puls d,pc

*
* xlate - map logical address into physical address
*
xlate jmp at_map perform mapping

*
* Wait for the ready line to become active
*
waitrdy
 lda AT_DTB load the status
 bita #ready
 bne waitrdy
 rts


waiteith
 pshs x,y,d retain all registers
waitlon ldb #$ff set up loop counter
waitlpe lda AT_DTB load status
 bita #ready check for tape ready
 beq already Unit is ready - exit
 bita #except excepton?
 beq already
 decb decrement the counter
 bne waitlpe loop more if not expired
 bsr beddown sleep on the subject if possible
 bra waitlon


already puls x,y,d
 rts


*
* Go to sleep if interrupts are not masked
*
beddown
 tfr cc,a see if interrupts are enabled
 bita #%00010000 check the I mask
 bne kickout if masked, just have to wait
 ldb #ATPRIOR load up priority
 ldy #lbolt and sleep on lightning bolt
 lbsr sleep
kickout rts

*
* Archive tape reset code
*
atreset pshs cc
 seti mask
 tst AT_RES set the reset latch
 ldb #6 delay for at least 13 uS
rslp decb
 bne rslp
 tst AT_DMC clear reset latch
 puls cc,pc

byteit fcb 0,0,0,0,0,0 6-byte status

BDtable fdb 0 Block Device Table pointer
atflag fcb 0 device open flag
rwflag fcb 0 read/write status flag
