23-389E2-00
;
;TU-58 firmware disassembly
;ROM version: 23-389E2-00
;disssembly version: 0.1
; External RAM References:
FL_XOFF EQU 2000h ;xoff flag
;
;Serial data from host is managed by a state machine.
;The RDF (rst6.5) interrupt reads the UART and then
;jumps to the address in cur_state. The handlers change
;cur_state to implement the protocol.
CUR_STATE EQU 2001h ;current state
;
BYT_DON EQU 2003h ;transfered count
CHK_SAV EQU 2005h ;checksum save
;
;command/response packet storage
;some addresses are duplicated
;since command and response use
;some fields differently
PK_FLAG EQU 2007h ;flag
PK_CMDCT EQU 2008h ;count
PK_OPCD EQU 2009h ;op code
PK_MOD EQU 200Ah ;modifyer
PK_SUCC EQU 200Ah ;success code
PK_UNIT EQU 200Bh ;unit
PK_SWIT EQU 200Ch ;switches
PK_SEQL EQU 200Dh ;sequence low (unused)
PK_SEQH EQU 200Eh ;sequence hi (unused)
PK_CNTL EQU 200Fh ;data count low
PK_CNTH EQU 2010h ;data count hi
PK_BLKL EQU 2011h ;block number low
PK_SUMSL EQU 2011h ;summary status low
PK_BLKH EQU 2012h ;block number hi
PK_SUMSH EQU 2012h ;summary status hi
PK_CHK EQU 2013h ;packet check sum
;
;data buffer (multiuse)
;tape write starts with w_gap1 and
;uses a larger buffer to allow for
;leading bits for AGC and SYNC
;tape read data goes into buffer
;send data to host starts with bf_type
;the type, count and checksum are filled in
;and the block sent without copy
W_GAP1 EQU 2013h ;zero filled gap
W_GAP2 EQU 2015h ;zero filled gap
W_SYNC EQU 2017h ;sync word
BF_TYPE EQU 2017h ;packet type
BF_CNT EQU 2018h ;packet byte count
BUFFER EQU 2019h ;tape read/write buffer
W_BEND EQU 2098h ;end of data buffer
BF_CHKL EQU 2099h ;buffer check sum low
BF_CHKH EQU 209Ah ;buffer check sum hi
;
;tape mark buffer
;the tape mark is the block number
;followed by the inverted block number
ID_HDR1 EQU 209Bh
ID_HDR2 EQU 209Dh
ID_HDR3 EQU 209Eh
;
CHKLO EQU 209Fh ;checksum low
CHKHI EQU 20A0h ;checksum hi
FL_GO EQU 20A2h ;flag GO
DR0_POS EQU 20A3h ;drive 0 cur position
DR1_POS EQU 20A5h ;drive 1 cur pos
TRG_BLL EQU 20A7h ;target block low
TRG_BLH EQU 20A8h ;target block hi
CUR_BLK EQU 20A9h ;current tape block
BTYCNT EQU 20ABh ;byte count (to go)
CASS_IN EQU 20ADh ;cassette in place
PB_IMG EQU 20AEh ;port b image
RTRY_CT EQU 20AFh ;retry count
SEEK_RT EQU 20B0h ;seek retry counter
SW_BITS EQU 20B3h ;drive select bit save
SUCCES EQU 20B4h ;success code
SUMST EQU 20B5h ;summary status
FL_BOOT EQU 20B6h ;init flag
STACK EQU 20FFh ;stack pointer
; IO Port Map:
UART EQU 08h
CSR EQU 20h
PortA EQU 21h
PortB EQU 22h
PortC EQU 23h
TIMERL EQU 24h
TIMERH EQU 25h
ORG 0
0000 31 FF 20 RESET: LXI SP, STACK ;
0003 DB 21 IN PortA ;
0005 E6 40 ANI 40h ;boot sw active?
0007 CA 03 01 JZ BOOT_GO ;then boot
000A CD 45 00 CALL CLR_SW ;reset everything
000D CD 9A 07 CALL SLF_TEST ;do self test
0010 F3 RST2: DI ;
0011 31 FF 20 LXI SP, STACK ;reset stack
0014 CD 49 00 CALL SOFT_RST ;reset protocol
0017 3E 04 SND_INIT: MVI A, 04h ;send init character
0019 CD 31 02 CALL OUTCH ;
001C CD F0 00 CALL CHK_BOOT ;check for boot
001F C3 17 00 JMP SND_INIT ;loop
0022 00 DB 00h ;filler
0023 00 DB 00h ;
;
;TRAP on UART frame error
0024 F3 RST_FRAME_ERR: DI ;
0025 31 FF 20 LXI SP, STACK ;reset stack
0028 DB 08 IN UART ;get character
002A 3E FD MVI A, 0FDh ;all stop
;
;RST5.5 TDRE
002C D3 22 RST_UART_TX: OUT PortB ;stop everything
002E 2E 05 MVI L, 05h ;loop count
0030 C3 77 00 JMP INIT_LOOP ;
0033 00 DB 00h ;filler
;
;RST6.5 RDF
0034 F5 RST_UART_RX: PUSH PSW ;
0035 E5 PUSH H ;
0036 DB 08 IN UART ;get UART character
0038 2A 01 20 LHLD CUR_STATE ;get state pointer
003B E9 PCHL ;jump to it
;
;RST7.5 tape clock edge so shift tape bit in
;bits are accumulated in B
003C 3E 10 RST_RD_STROBE: MVI A, 10h ;reset int 7
003E 30 SIM ;
003F 20 RIM ;
0040 07 RLC ;SID into carry
0041 78 MOV A, B ;save old bits
0042 1F RAR ;shift in input
0043 47 MOV B, A ;return bit in B
0044 C9 RET ;
;
;reset switches, XOFF and state
;initialize 8155 registers
0045 AF CLR_SW: XRA A ;
0046 32 0C 20 STA PK_SWIT ;clear switches
0049 AF SOFT_RST: XRA A ;clear XOFF flag
004A 32 00 20 STA FL_XOFF ;
004D 21 74 01 CLR_STATE: LXI H, STATE_IDLE ;
;
;setup 8155 registers
0050 22 01 20 SETREGS: SHLD CUR_STATE ;set next state
0053 3E 4D MVI A, 4Dh ;en SDE mask 5,7
0055 30 SIM ;
0056 FB EI ;
0057 3E FE SETRG1: MVI A, 0FEh ;
0059 D3 20 OUT CSR ;
005B 3E FD MVI A, 0FDh ;
005D D3 22 OUT PortB ;
005F DB 23 IN PortC ;
0061 F6 01 ORI 01h ;
0063 D3 23 OUT PortC ;
0065 3E 0C MVI A, 0Ch ;
0067 32 AD 20 STA CASS_IN ;set no cass
006A AF XRA A ;
006B 32 A2 20 STA FL_GO ;reset go flag
006E 3A 0C 20 LDA PK_SWIT ;
0071 E6 08 ANI 08h ;
0073 32 0C 20 STA PK_SWIT ;
0076 C9 RET ;
;
;loop waiting for INIT from host
0077 CD F0 00 INIT_LOOP: CALL CHK_BOOT ;check boot swtch
007A 20 RIM ;
007B E6 20 ANI 20h ;mask to RDR
007D CA 77 00 JZ INIT_LOOP ;loop till data ready
0080 2D DCR L ;dec timeout
0081 CA 10 00 JZ RST2 ;start over?
0084 DB 08 IN UART ;read UART
0086 FE 04 CPI 04h ;INIT
0088 C2 77 00 JNZ INIT_LOOP ;loop if not
008B CD 49 00 CALL SOFT_RST ;reset protocol
008E 32 B6 20 STA FL_BOOT ;save
;
;commands return here when done
0091 31 FF 20 IDLE_LOOP: LXI SP, STACK ;reset stack
0094 AF XRA A ;
0095 32 0C 20 STA PK_SWIT ;clear switch
0098 32 A2 20 STA FL_GO ;clear go
009B 21 00 00 LXI H, 0000h ;clear status
009E 22 B4 20 SHLD SUCCES ;clear error bits
00A1 22 03 20 SHLD BYT_DON ;clear bytes sent
00A4 3E 4D MVI A, 4Dh ;en SDE mask 5,7
00A6 30 SIM ;
00A7 FB EI ;
;
;Command loop
;loop till FL_GO sets then dispatch
;to the opcode routine
00A8 CD 18 03 CMD_LOOP: CALL DRV_RDY ;CART in place?
00AB CD F0 00 CALL CHK_BOOT ;check for boot req
00AE 3A A2 20 LDA FL_GO ;command received?
00B1 E6 80 ANI 80h ;
00B3 CA A8 00 JZ CMD_LOOP ;loop if nothing to do
;got packet so check type
00B6 3A 07 20 LDA PK_FLAG ;get flag
00B9 FE 02 CPI 02h ;is eq COMMAND?
00BB C2 10 00 JNZ RST2 ;error?
;check for opcode in range
00BE 3A 09 20 LDA PK_OPCD ;get opcode
00C1 FE 0B CPI 0Bh ;>max command?
00C3 3E D0 MVI A, 0D0h ;bad op code
00C5 D2 75 07 JNC SET_SUCC ;error exit
;make pointer to routine
00C8 3A 09 20 LDA PK_OPCD ;get opcode
00CB 21 D8 00 LXI H, JMPTBL ;point to command table
00CE 07 RLC ;mult X 2
00CF 5F MOV E, A ;index into table
00D0 16 00 MVI D, 00h ;
00D2 19 DAD D ;
00D3 5E MOV E, M ;
00D4 23 INX H ;
00D5 56 MOV D, M ;
00D6 EB XCHG ;
00D7 E9 PCHL ;jump to command
;
;function address table
00D8 46 JMPTBL: DW OP_NOOP ;
00DA 80 DW OP_INIT ;
00DC 1D DW OP_READ ;
00DE C7 DW OP_WRITE ;
00E0 46 DW OP_NOOP ;
00E2 95 DW OP_POS ;
00E4 46 DW OP_NOOP ;
00E6 EC DW OP_DIAG ;
00E8 86 DW OP_GETST ;
00EA 46 DW OP_NOOP ;
00EC 46 DW OP_NOOP ;
00EE 46 DW OP_NOOP ;
;
;check for BOOT request
00F0 DB 21 CHK_BOOT: IN PortA ;read flags
00F2 E6 40 ANI 40h ;mask to boot switch
00F4 3A B6 20 LDA FL_BOOT ;
00F7 CA 00 01 JZ DB_BOOT ;jmp boot sw active
00FA F6 01 ORI 01h ;
00FC 32 B6 20 STA FL_BOOT ;set init flag
00FF C9 RET ;
;debounce BOOT switch
0100 E6 01 DB_BOOT: ANI 01h ;need BOOT twice
0102 C8 RZ ;ret if first
;
;boot Switch really active
0103 31 FF 20 BOOT_GO: LXI SP, STACK ;
0106 21 C3 01 LXI H, RETRN1 ;disable RX data
0109 CD 50 00 CALL SETREGS ;set 8155 regs
010C AF XRA A ;
010D 32 0C 20 STA PK_SWIT ;clear option switch
0110 D3 23 OUT PortC ;clear port C
0112 06 FF MVI B, 0FFh ;delay count
0114 CD 04 04 CALL LNG_DLY ;kill time
0117 CD 9A 07 CALL SLF_TEST ;run self test
;
;boot state handler
;get here via boot switch
;or serial boot command
;state_boot acts different
;depending on how it was invoed
011A 32 0B 20 STATE_BOOT: STA PK_UNIT ;set unit
011D 32 00 20 STA FL_XOFF ;clr XOFF
0120 21 00 00 LXI H, 0000h ;set block num to 0
0123 22 A9 20 SHLD CUR_BLK ;
0126 CD 52 05 ST_BOO1: CALL TAP_READ ;read tape block
0129 CD 0E 04 CALL TAP_STP ;stop tape
012C 21 19 20 LXI H, BUFFER ;buffer
012F 0E 80 MVI C, 80h ;count
;
;send character/byte to host
0131 7E BNXTCH: MOV A, M ;get (next) byte
0132 CD 31 02 CALL OUTCH ;send byte
;
;see how we got here
;check cur_state lo byte for 1ah
0135 3A 01 20 LDA CUR_STATE ;
0138 FE 1A CPI 1Ah ;serial boot?
013A CA 51 01 JZ ST_BOO3 ;
;hardware boot switch
013D 7E MOV A, M ;get character
013E FE 47 CPI 47h ;eq 'G'?
0140 CA 6B 01 JZ SBOOTE ;then done
0143 06 02 MVI B, 02h ;
0145 E6 F8 ANI 0F8h ;
0147 EE 30 XRI 30h ;
0149 CA 4E 01 JZ ST_BOO2 ;
014C 06 14 MVI B, 14h ;delay count
014E CD 04 04 ST_BOO2: CALL LNG_DLY ;dont overrun host
;
0151 23 ST_BOO3: INX H ;inc buffer pointer
0152 0D DCR C ;dec byte count
0153 C2 31 01 JNZ BNXTCH ;loop till done
0156 2A A9 20 LHLD CUR_BLK ;
0159 23 INX H ;inc block number
015A 22 A9 20 SHLD CUR_BLK ;
015D 3E 04 MVI A, 04h ;read 4 blocks
015F BD CMP L ;
0160 C2 26 01 JNZ ST_BOO1 ;loop if more
;
;see how we got here
;check cur_state lo byte for 1ah
0163 3A 01 20 LDA CUR_STATE ;
0166 FE 1A CPI 1Ah ;
0168 C2 26 01 JNZ ST_BOO1 ;if BOOTSW loop
;serial boot end
016B CD 49 00 SBOOTE: CALL SOFT_RST ;reset protocol
016E 32 B6 20 STA FL_BOOT ;
0171 C3 91 00 JMP IDLE_LOOP ;goto idle
;
;idle state handler
;get here with new character in A
;and nothing in progress
0174 FE 08 STATE_IDLE: CPI 08h ;eq BOOT?
0176 21 1A 01 LXI H, STATE_BOOT ;set next state
0179 CA C0 01 JZ RETRN ;
017C FE 13 CPI 13h ;eq XOFF?
017E C2 89 01 JNZ ST_IDL1 ;
0181 3E FF MVI A, 0FFh ;
0183 32 00 20 STA FL_XOFF ;set XOFF flag
0186 C3 C3 01 JMP RETRN1 ;no state change
0189 6F ST_IDL1: MOV L, A ;
018A E6 FE ANI 0FEh ;
018C FE 10 CPI 10h ;eq CONTIN?
018E C2 98 01 JNZ ST_IDL2 ;
0191 AF XRA A ;
0192 32 00 20 STA FL_XOFF ;clear XOFF
0195 C3 C3 01 JMP RETRN1 ;no state change
0198 3E 04 ST_IDL2: MVI A, 04h ;
019A BD CMP L ;eq INIT?
019B CA 58 02 JZ GOT_INIT ;
;
;data or command pkt
019E 3A A2 20 LDA FL_GO ;
01A1 E6 80 ANI 80h ;
01A3 C2 10 00 JNZ RST2 ;error if go is set
01A6 7D MOV A, L ;
01A7 32 07 20 STA PK_FLAG ;save pkt flag
01AA 32 9F 20 STA CHKLO ;add to chksum
01AD 11 19 20 LXI D, BUFFER ;point to DATA buf
01B0 FE 01 CPI 01h ;eq DATA?
01B2 CA BD 01 JZ ST_IDL3 ;
01B5 11 09 20 LXI D, PK_OPCD ;point to CMD buf
01B8 FE 02 CPI 02h ;eq CMD?
01BA C2 10 00 JNZ RST2 ;no is error
01BD 21 C7 01 ST_IDL3: LXI H, STATE_CNT ;
;
;return saving next state
01C0 22 01 20 RETRN: SHLD CUR_STATE ;save next state
;
;return, no state change
01C3 E1 RETRN1: POP H ;return
01C4 F1 POP PSW ;
01C5 FB EI ;
01C6 C9 RET ;
;
;count state handler
01C7 4F STATE_CNT: MOV C, A ;save count
01C8 32 08 20 STA PK_CMDCT ;
01CB 32 A0 20 STA CHKHI ;add to chksum
01CE FE 81 CPI 81h ;count too big?
01D0 D2 10 00 JNC RST2 ;
01D3 06 01 MVI B, 01h ;preset B for add_chk
01D5 21 DB 01 LXI H, STATE_DATI ;set next state
01D8 C3 C0 01 JMP RETRN ;
;
;data/cmd state handler
01DB 12 STATE_DATI: STAX D ;save byte
01DC 1A LDAX D ;
01DD CD 13 02 CALL ADD_CHK ;add to checksum
01E0 0D DCR C ;dec count
01E1 CA E8 01 JZ ST_DAT1 ;done?
01E4 13 INX D ;inc pointer
01E5 C3 C3 01 JMP RETRN1 ;return (same state)
01E8 21 EE 01 ST_DAT1: LXI H, STATE_CK1 ;set next state
01EB C3 C0 01 JMP RETRN ;
;
;checksum1 state handler (1st. char)
01EE 21 9F 20 STATE_CK1: LXI H, CHKLO ;get calc cksum
01F1 96 SUB M ;equal?
01F2 C2 10 00 JNZ RST2 ;chksum error?
01F5 21 FB 01 LXI H, STATE_CK2 ;set next state
01F8 C3 C0 01 JMP RETRN ;
;
;checksum2 state handler (2nd. char)
01FB 21 A0 20 STATE_CK2: LXI H, CHKHI ;get calc cksum
01FE 96 SUB M ;equal?
01FF C2 10 00 JNZ RST2 ;chksum error?
0202 2A 9F 20 LHLD CHKLO ;
0205 22 05 20 SHLD CHK_SAV ;save it
0208 3E 80 MVI A, 80h ;
020A 32 A2 20 STA FL_GO ;set go flag
020D 21 74 01 LXI H, STATE_IDLE ;return to idle
0210 C3 C0 01 JMP RETRN ;
;
;add to check sum
;B is the odd/even byte counter
;must be preserved between calls
0213 E5 ADD_CHK: PUSH H ;
0214 6F MOV L, A ;
0215 78 MOV A, B ;
0216 EE 01 XRI 01h ;
0218 47 MOV B, A ;
0219 C2 24 02 JNZ ADDCK2 ;
;add lo byte
021C 7D ADDCK1: MOV A, L ;
021D 21 9F 20 LXI H, CHKLO ;
0220 8E ADC M ;
0221 77 MOV M, A ;
0222 2E 00 MVI L, 00h ;
;add high byte
0224 7D ADDCK2: MOV A, L ;
0225 21 A0 20 LXI H, CHKHI ;
0228 8E ADC M ;
0229 77 MOV M, A ;
022A 2E 00 MVI L, 00h ;
022C DA 1C 02 JC ADDCK1 ;
022F E1 POP H ;
0230 C9 RET ;
;
;send character to host
;polled output
;stop tape if this takes too long
0231 F5 OUTCH: PUSH PSW ;
0232 E5 PUSH H ;
0233 2E 08 MVI L, 08h ;timeout counter
0235 2D OUTCH1: DCR L ;dec timeout
0236 C5 PUSH B ;
0237 CC 0E 04 CZ TAP_STP ;if 0 stop tape
023A C1 POP B ;
023B 20 RIM ;
023C E6 10 ANI 10h ;mask to TDRE
023E CA 35 02 JZ OUTCH1 ;loop if full
0241 3A 00 20 LDA FL_XOFF ;XOFF set?
0244 3C INR A ;
0245 CA 35 02 JZ OUTCH1 ;loop if cant send
0248 E1 POP H ;
0249 F1 POP PSW ;
024A D3 08 OUT UART ;send character
;switch bit 08H is not documented
;it sets FL_XOFF for each character
024C 3A 0C 20 LDA PK_SWIT ;
024F E6 08 ANI 08h ;
0251 C8 RZ ;ret if not set
0252 3E FF MVI A, 0FFh ;
0254 32 00 20 STA FL_XOFF ;set XOFF
0257 C9 RET ;
;
;got INIT character
0258 31 FF 20 GOT_INIT: LXI SP, STACK ;reset stack
025B CD 49 00 CALL SOFT_RST ;reset protocol
025E CD 4C 05 CALL SND_CONT ;send continue
0261 C3 91 00 JMP IDLE_LOOP ;goto idle
;
;send data packet
0264 21 17 20 SND_DATA: LXI H, BF_TYPE ;point to type
0267 36 01 MVI M, 01h ;type=data
0269 23 INX H ;point to count
;
;generate check sum and send data/response to host
026A 56 SND_RESP: MOV D, M ;get packet byte count
026B 14 INR D ;fix count for cksum
026C 14 INR D ;
026D AF XRA A ;clear checksum
026E 32 9F 20 STA CHKLO ;
0271 32 A0 20 STA CHKHI ;
0274 06 01 MVI B, 01h ;preset B for add_chk
0276 2B DCX H ;point to pkt start
0277 7E SND_RES1: MOV A, M ;get byte
0278 CD 13 02 CALL ADD_CHK ;add to check
027B 7E MOV A, M ;get same byte
027C CD 31 02 CALL OUTCH ;send byte
027F 23 INX H ;inc pointer
0280 15 DCR D ;dec count
0281 C2 77 02 JNZ SND_RES1 ;loop
0284 21 9F 20 LXI H, CHKLO ;point to checksum lo
0287 CD 8B 02 CALL SND_CKSUM ;send it
028A 23 INX H ;point to checksum hi
;
;send check sum
028B 3E 1E SND_CKSUM: MVI A, 1Eh ;delay count
028D CD FB 03 CALL DELAY ;delay
0290 7E MOV A, M ;get chksum
0291 CD 31 02 CALL OUTCH ;send it
0294 C9 RET ;
;
;command: position tape
0295 CD FA 06 OP_POS: CALL SET_BLK ;setup block+count
0298 CD A4 02 CALL SEL_DRV ;select drive
029B CD 24 03 CALL SEEK ;find block
029E CD 0E 04 CALL TAP_STP ;tape stop
02A1 C3 46 07 JMP OP_NOOP ;send response
;
;select drive and track
02A4 2A A9 20 SEL_DRV: LHLD CUR_BLK ;save current block
02A7 EB XCHG ;
02A8 21 AE 20 LXI H, PB_IMG ;point to B image
;select track 0
02AB 36 E9 MVI M, 0E9h ;trk0 fwd read stop
02AD 7A MOV A, D ;block num hi byte
02AE FE 08 CPI 08h ;block too large?
02B0 3E FE MVI A, 0FEh ;partial operation
02B2 D2 75 07 JNC SET_SUCC ;exit if error
02B5 7A MOV A, D ;blknum hi
02B6 FE 04 CPI 04h ;blk >=400?
02B8 3F CMC ;
02B9 7B MOV A, E ;blknum lo
02BA 17 RAL ;
02BB 5F MOV E, A ;save
02BC 7A MOV A, D ;blknum hi
02BD 17 RAL ;
02BE E6 07 ANI 07h ;mask block number
02C0 57 MOV D, A ;
02C1 FE 04 CPI 04h ;bit3 set=track 1
02C3 DA C8 02 JC SEL_UX ;select unit
;select track 1
02C6 36 F9 MVI M, 0F9h ;trk1 fwd read stop
;select unit
02C8 3A 0B 20 SEL_UX: LDA PK_UNIT ;get unit
02CB FE 01 CPI 01h ;
02CD CA D8 02 JZ SEL_U1 ;eq unit 1?
02D0 DA E4 02 JC SEL_U0 ;eq unit 0?
02D3 3E F8 MVI A, 0F8h ;bad unit
02D5 C3 75 07 JMP SET_SUCC ;error exit
;select unit 1 (B)
02D8 7E SEL_U1: MOV A, M ;get port B image
02D9 E6 F7 ANI 0F7h ;sel B low
02DB 77 MOV M, A ;
02DC 3E 04 MVI A, 04h ;b cart switch
02DE 2A A5 20 LHLD DR1_POS ;
02E1 C3 E9 02 JMP SEL_COM ;
;select unit 0 (A)
02E4 3E 08 SEL_U0: MVI A, 08h ;a cart switch
02E6 2A A3 20 LHLD DR0_POS ;
02E9 32 B3 20 SEL_COM: STA SW_BITS ;save cart sw bits
02EC 4F MOV C, A ;
02ED 3A AD 20 LDA CASS_IN ;
02F0 A1 ANA C ;
02F1 CA F6 02 JZ SEL_C1 ;
02F4 6B MOV L, E ;mov blknum to HL
02F5 62 MOV H, D ;
02F6 CD FE 02 SEL_C1: CALL CHK_SEL ;
02F9 EB XCHG ;
02FA 22 A7 20 SHLD TRG_BLL ;set target block
02FD C9 RET ;
;
;check selected drive for cart
02FE CD 18 03 CHK_SEL: CALL DRV_RDY ;CART in place
0301 E5 PUSH H ;
0302 21 B3 20 LXI H, SW_BITS ;drive sel bits
0305 DB 21 IN PortA ;
0307 A6 ANA M ;and switches
0308 3E F7 MVI A, 0F7h ;no cart
030A C2 75 07 JNZ SET_SUCC ;error exit
;cassette in place
030D 3A AD 20 LDA CASS_IN ;
0310 2F CMA ;
0311 B6 ORA M ;
0312 2F CMA ;
0313 32 AD 20 STA CASS_IN ;
0316 E1 POP H ;
0317 C9 RET ;
;
;or cass in bits to status reg
0318 E5 DRV_RDY: PUSH H ;
0319 DB 21 IN PortA ;get cart sw
031B E6 0C ANI 0Ch ;mask bits
031D 21 AD 20 LXI H, CASS_IN ;point to status reg
0320 B6 ORA M ;or bits
0321 77 MOV M, A ;write back
0322 E1 POP H ;
0323 C9 RET ;
;
;seek to block
;returns with tape running forward
;in gap between header and data
0324 3E F8 SEEK: MVI A, 0F8h ;set retry count
0326 32 B0 20 STA SEEK_RT ;
0329 CD FE 02 SEEKNX: CALL CHK_SEL ;
032C 2A A7 20 LHLD TRG_BLL ;get target block
032F 7C MOV A, H ;get hi byte
0330 E6 03 ANI 03h ;mask to 3ffh
0332 67 MOV H, A ;put back
0333 7A MOV A, D ;get hi byte
0334 E6 03 ANI 03h ;mask to 3ffh
0336 57 MOV D, A ;put back
0337 7D MOV A, L ;get target lo
0338 93 SUB E ;sub current lo
0339 6F MOV L, A ;
033A 7C MOV A, H ;get target hi
033B 9A SBB D ;subtract
033C 67 MOV H, A ;
033D D2 66 03 JNC SEEK02 ;jmp if no error
0340 3A B0 20 SEEK01: LDA SEEK_RT ;
0343 3C INR A ;inc retry count
0344 32 B0 20 STA SEEK_RT ;
0347 3E E0 MVI A, 0E0h ;seek error
0349 CA 75 07 JZ SET_SUCC ;if zero exit
;
;retry seek
034C 7D MOV A, L ;blk lo
034D 2F CMA ;negate
034E 6F MOV L, A ;
034F 7C MOV A, H ;blk hi
0350 2F CMA ;negate
0351 67 MOV H, A ;
0352 23 INX H ;add 3
0353 23 INX H ;
0354 23 INX H ;
0355 3A AE 20 LDA PB_IMG ;
0358 F6 04 ORI 04h ;reverse
035A 32 AE 20 STA PB_IMG ;
035D CD 3B 04 CALL FAST_RUN ;backup fast
0360 CD 0E 04 CALL TAP_STP ;stop tape
0363 C3 80 03 JMP TAP_RUN ;run forward
0366 AF SEEK02: XRA A ;
0367 BC CMP H ;hi byte not zero
0368 C2 75 03 JNZ SEEK03 ;room to rev fast
036B BD CMP L ;
036C CA 40 03 JZ SEEK01 ;
036F 3E 04 MVI A, 04h ;
0371 BD CMP L ;small distance?
0372 D2 80 03 JNC TAP_RUN ;then just run slow
0375 2B SEEK03: DCX H ;dec desired block
0376 2B DCX H ;
0377 2B DCX H ;
0378 CD 3B 04 CALL FAST_RUN ;run reverse
037B 06 0F MVI B, 0Fh ;tach count
037D CD 10 04 CALL TAP_DCL ;decellerate motor
;
;set timer and run forward 30ips
0380 3E BE TAP_RUN: MVI A, 0BEh ;setup timer
0382 D3 24 OUT TIMERL ;for 30 ips
0384 3E C0 MVI A, 0C0h ;
0386 D3 25 OUT TIMERH ;
0388 3E CE MVI A, 0CEh ;
038A D3 20 OUT CSR ;
038C 3A AE 20 LDA PB_IMG ;get port b bits
038F F6 80 ORI 80h ;set 30IPS
0391 E6 FA ANI 0FAh ;assert run forward
0393 32 AE 20 STA PB_IMG ;save image
0396 47 MOV B, A ;
0397 DB 22 IN PortB ;
0399 E6 01 ANI 01h ;mask to run bit
039B 78 MOV A, B ;
039C D3 22 OUT PortB ;set port bits
039E 06 1E MVI B, 1Eh ;delay count
03A0 C4 04 04 CNZ LNG_DLY ;delay if not run
03A3 CD 74 04 CALL FND_MRK ;find next tape mark
03A6 FE 09 CPI 09h ;end of tape?
03A8 F2 08 05 JP AT_EOT ;
;
;read ID block
03AB CD A9 04 CALL PLS_RUN ;thump run one-shot
03AE 0E 04 MVI C, 04h ;count
03B0 21 9B 20 LXI H, ID_HDR1 ;buffer
03B3 CD D9 04 CALL READBLK ;read id block
;
;check for good ID read
03B6 3A 9D 20 LDA ID_HDR2 ;get ID lo
03B9 21 9B 20 LXI H, ID_HDR1 ;point to ID header
03BC 2F CMA ;complement bits
03BD BE CMP M ;match?
03BE C2 E1 03 JNZ ID_ERR ;
03C1 3A 9E 20 LDA ID_HDR3 ;get ID hi
03C4 2F CMA ;complement bits
03C5 23 INX H ;
03C6 BE CMP M ;match?
03C7 C2 E1 03 JNZ ID_ERR ;
;
;good id read so set position
03CA CD 20 05 CALL SET_POS ;set cur pos
03CD 3A A7 20 LDA TRG_BLL ;get target
03D0 BB CMP E ;we there?
03D1 C2 29 03 JNZ SEEKNX ;jmp not there
03D4 3A A8 20 LDA TRG_BLH ;get target
03D7 BA CMP D ;we there?
03D8 C2 29 03 JNZ SEEKNX ;jmp not there
03DB 2E 08 MVI L, 08h ;led
03DD CD F2 03 CALL TOG_PC ;toggle it
03E0 C9 RET ;
;
;errror on id read
03E1 2E 10 ID_ERR: MVI L, 10h ;test point 2
03E3 CD F2 03 CALL TOG_PC ;toggle it
03E6 21 B0 20 LXI H, SEEK_RT ;retry counter
03E9 34 INR M ;
03EA C2 80 03 JNZ TAP_RUN ;loop for retry
03ED 3E E0 MVI A, 0E0h ;seek error
03EF C3 75 07 JMP SET_SUCC ;
;
;toggle bit port C
;A=bit to toggle
03F2 DB 23 TOG_PC: IN PortC ;
03F4 AD XRA L ;
03F5 D3 23 OUT PortC ;
03F7 AD XRA L ;
03F8 D3 23 OUT PortC ;
03FA C9 RET ;
;
;short delay A=count
03FB E6 FF DELAY: ANI 0FFh ;
03FD 00 NOP ;
03FE 00 NOP ;
03FF 3D DCR A ;
0400 C2 FB 03 JNZ DELAY ;
0403 C9 RET ;
;
;long delay B=count
0404 3E 60 LNG_DLY: MVI A, 60h ;
0406 CD FB 03 CALL DELAY ;
0409 05 DCR B ;
040A C2 04 04 JNZ LNG_DLY ;
040D C9 RET ;
;
;stop tape
040E 06 2B TAP_STP: MVI B, 2Bh ;tach cnt for stop
;
;decellerate tape
0410 DB 21 TAP_DCL: IN PortA ;
0412 E6 10 ANI 10h ;run_tp
0414 C0 RNZ ;return if stopped
;run motor reverse to stop
0415 3A AE 20 LDA PB_IMG ;get old direction
0418 EE 05 XRI 05h ;flip run+rev bits
041A D3 22 OUT PortB ;change direction
041C EE 01 XRI 01h ;turn on run bit
041E D3 22 OUT PortB ;
0420 E5 PUSH H ;
0421 67 MOV H, A ;
0422 48 TP_DCL1: MOV C, B ;reset timeout count
0423 DB 21 IN PortA ;read port
0425 6F MOV L, A ;save for compare
0426 DB 21 TP_DCL2: IN PortA ;read port
0428 AD XRA L ;compare to last
0429 E6 02 ANI 02h ;velocity (tach) bit?
042B C2 22 04 JNZ TP_DCL1 ;jmp if change
;no tach change
042E 0D DCR C ;so dec timer
042F C2 26 04 JNZ TP_DCL2 ;loop if no timeout
;no tach change for B loops
;motor has slowed to desired speed
0432 3A AE 20 LDA PB_IMG ;
0435 F6 01 ORI 01h ;tape not run
0437 D3 22 OUT PortB ;
0439 E1 POP H ;
043A C9 RET ;
;
;run 60ips
043B 3E 5F FAST_RUN: MVI A, 5Fh ;setup timer
043D D3 24 OUT TIMERL ;for 60 ips
043F 3E C0 MVI A, 0C0h ;
0441 D3 25 OUT TIMERH ;
0443 3E CE MVI A, 0CEh ;
0445 D3 20 OUT CSR ;
0447 3A AE 20 LDA PB_IMG ;
044A E6 7E ANI 7Eh ;run reverse 60ips
044C 32 AE 20 STA PB_IMG ;
044F D3 22 OUT PortB ;go
0451 06 2D MVI B, 2Dh ;delay count
0453 CD 04 04 CALL LNG_DLY ;delay
;
;loop finding tape marks and decrementing
;blocks to go in HL
0456 CD 74 04 FST_RUN1: CALL FND_MRK ;find next mark
0459 FE 04 CPI 04h ;
045B FA 14 05 JM GOT_BOT ;bot
045E FE 09 CPI 09h ;
0460 F2 07 05 JP GOT_EOT ;eot
0463 CD A9 04 CALL PLS_RUN ;thump run one-shot
0466 CD FE 02 CALL CHK_SEL ;
0469 2B DCX H ;dec blocks to go
046A AF XRA A ;
046B BC CMP H ;eq zero?
046C C2 56 04 JNZ FST_RUN1 ;
046F BD CMP L ;eq zero?
0470 C2 56 04 JNZ FST_RUN1 ;
0473 C9 RET ;
;
;find block mark
;returns count between clock edges
0474 16 0C FND_MRK: MVI D, 0Ch ;
0476 1E 00 MVI E, 00h ;clk time
0478 06 05 MVI B, 05h ;wait for clk timeout
;
;loop till mark or motor timeout
047A DB 21 FND_MK1: IN PortA ;
047C E6 90 ANI 90h ;mask mark+runl
047E CA 7A 04 JZ FND_MK1 ;not mark+still running
0481 E6 10 ANI 10h ;mask runl
;
0483 3E DF ERR_STP: MVI A, 0DFh ;motor stopped
0485 C2 75 07 JNZ SET_SUCC ;error exit
;
;tape mark found
;so time the read clock
0488 CD C8 04 BLK_MARK: CALL MRK_CLK ;wait for clock
048B DB 21 IN PortA ;read port A
048D E6 80 ANI 80h ;mask to mark bit
048F C2 99 04 JNZ BLK_MK1 ;hi so time it
0492 05 DCR B ;
0493 CA 74 04 JZ FND_MRK ;
0496 C3 88 04 JMP BLK_MARK ;
0499 20 BLK_MK1: RIM ;read port
049A E6 80 ANI 80h ;mask SID
049C CA A0 04 JZ BLK_MK2 ;
049F 1C INR E ;inc return value
04A0 15 BLK_MK2: DCR D ;
04A1 C2 88 04 JNZ BLK_MARK ;
04A4 3E 1D MVI A, 1Dh ;rst 7 mask 5,7
04A6 30 SIM ;
04A7 7B MOV A, E ;
04A8 C9 RET ;
;
;pulse tape run line
;retrigger motor one-shot
04A9 F5 PLS_RUN: PUSH PSW ;
04AA 3A AE 20 LDA PB_IMG ;get port b bits
04AD F6 01 ORI 01h ;negate tape run
04AF D3 22 OUT PortB ;set port
04B1 00 NOP ;
04B2 E6 FE ANI 0FEh ;assert run
04B4 D3 22 OUT PortB ;set port
04B6 1E 03 PLS_RU1: MVI E, 03h ;
04B8 CD C8 04 PLS_RU2: CALL MRK_CLK ;
04BB DB 21 IN PortA ;
04BD E6 90 ANI 90h ;run_tp+mark
04BF C2 B6 04 JNZ PLS_RU1 ;
04C2 1D DCR E ;
04C3 C2 B8 04 JNZ PLS_RU2 ;
04C6 F1 POP PSW ;
04C7 C9 RET ;
;
;wait for clock in tape mark
04C8 3E 1D MRK_CLK: MVI A, 1Dh ;rst 7 mask 5,7
04CA 30 SIM ;
04CB DB 21 MRK_CK1: IN PortA ;
04CD E6 10 ANI 10h ;run_tp
04CF C2 83 04 JNZ ERR_STP ;error stopped?
04D2 20 RIM ;read int status
04D3 E6 40 ANI 40h ;mask tape clock
04D5 CA CB 04 JZ MRK_CK1 ;
04D8 C9 RET ;
;
;read block from tape
;tape is running positioned in gap
;between header and data
04D9 3E 1B READBLK: MVI A, 1Bh ;rst 7 mask 5,6
04DB 30 SIM ;
;
;Tape read loop syncronizes to data by waiting for
;rst7.5 interrupt generated by tape read clock.
;Data is shifted into the B reg via interupt.
;The housekeeping code is spread between the HLTs
;to fit the bit time window.
04DC FB TAP_RD: EI ;get bit
04DD 76 HLT ;
04DE E6 80 ANI 80h ;
04E0 CA DC 04 JZ TAP_RD ;wait for sync bit
;
;sync bit found now assemble bytes
;and write to buffer
04E3 FB EI ;get bit
04E4 76 HLT ;
04E5 FB EI ;
04E6 76 HLT ;
04E7 FB EI ;
04E8 76 HLT ;
04E9 FB TAP_RD1: EI ;
04EA 76 HLT ;
04EB FB EI ;
04EC 76 HLT ;
04ED FB EI ;
04EE 76 HLT ;
04EF FB EI ;
04F0 76 HLT ;
04F1 FB EI ;
04F2 76 HLT ;
04F3 70 MOV M, B ;save byte
04F4 FB EI ;get bit
04F5 76 HLT ;
04F6 0D DCR C ;dec byte count
04F7 CA 02 05 JZ TAP_RD2 ;exit if done
04FA FB EI ;get bit
04FB 76 HLT ;
04FC 23 INX H ;inc pointer
04FD FB EI ;get bit
04FE 76 HLT ;
04FF C3 E9 04 JMP TAP_RD1 ;loop for 5 more bits
0502 3E 0D TAP_RD2: MVI A, 0Dh ;mask 5,7
0504 30 SIM ;
0505 FB EI ;
0506 C9 RET ;
;
;eot while running fast forward
0507 F1 GOT_EOT: POP PSW ;clean up stack
;
;eot while seeking
0508 21 FF 03 AT_EOT: LXI H, 03FFh ;last block num
050B 22 9B 20 SHLD ID_HDR1 ;
050E CD 20 05 CALL SET_POS ;make current
0511 C3 29 03 JMP SEEKNX ;seek target
;
;bot while running fast reverse
0514 F1 GOT_BOT: POP PSW ;clean up stack
0515 06 28 MVI B, 28h ;delay count
0517 CD 04 04 CALL LNG_DLY ;delay
051A CD 0E 04 CALL TAP_STP ;stop tape
051D C3 80 03 JMP TAP_RUN ;run forward
;
;set current block position for drive
0520 2A 9B 20 SET_POS: LHLD ID_HDR1 ;get tape position
0523 EB XCHG ;
0524 21 A3 20 LXI H, DR0_POS ;point to drv 0 pos
0527 3A 0B 20 LDA PK_UNIT ;
052A 3D DCR A ;
052B FA 31 05 JM SET_PO1 ;
052E 21 A5 20 LXI H, DR1_POS ;point to drv 1 pos
0531 73 SET_PO1: MOV M, E ;save position
0532 23 INX H ;
0533 72 MOV M, D ;
0534 C9 RET ;
;
;calculate chksum for data in buffer
0535 2A A7 20 CALC_CK: LHLD TRG_BLL ;
0538 22 9F 20 SHLD CHKLO ;
053B 11 19 20 CCK_01: LXI D, BUFFER ;point to data
053E 0E 80 CCK_02: MVI C, 80h ;count
0540 06 01 MVI B, 01h ;preset B for add_chk
0542 1A CCK_03: LDAX D ;get byte
0543 CD 13 02 CALL ADD_CHK ;add to chksum
0546 13 INX D ;point next
0547 0D DCR C ;dec count
0548 C8 RZ ;exit if done
0549 C3 42 05 JMP CCK_03 ;loop
;
;send continue character
054C 3E 10 SND_CONT: MVI A, 10h ;
054E CD 31 02 CALL OUTCH ;
0551 C9 RET ;
;
;read tape block
0552 3E F8 TAP_READ: MVI A, 0F8h ;retry=8
0554 32 AF 20 STA RTRY_CT ;
0557 CD A4 02 TAP_NXT: CALL SEL_DRV ;
055A 3A AF 20 LDA RTRY_CT ;
055D E6 01 ANI 01h ;
055F C2 6A 05 JNZ TAP_R01 ;
0562 3A 0A 20 LDA PK_MOD ;
0565 E6 01 ANI 01h ;reduce gain?
0567 CA 72 05 JZ TAP_R02 ;
056A 3A AE 20 TAP_R01: LDA PB_IMG ;get B bits
056D E6 DF ANI 0DFh ;gain reduce=0
056F 32 AE 20 STA PB_IMG ;put back
0572 CD 24 03 TAP_R02: CALL SEEK ;seek to block
0575 3E A2 MVI A, 0A2h ;delay count
0577 CD FB 03 CALL DELAY ;delay
057A 0E 82 MVI C, 82h ;block size
057C 21 19 20 LXI H, BUFFER ;buffer pointer
057F CD D9 04 CALL READBLK ;read block
0582 CD 35 05 CALL CALC_CK ;calc chksum
;
;check chksum match
0585 2A 9F 20 CK_MATCH: LHLD CHKLO ;get calculated sum
0588 3A 99 20 LDA BF_CHKL ;compare to read sum
058B BD CMP L ;
058C C2 94 05 JNZ CK_BAD ;error?
058F 3A 9A 20 LDA BF_CHKH ;same for hi byte
0592 BC CMP H ;
0593 C8 RZ ;exit if good
;
;chksum was bad
0594 2E 02 CK_BAD: MVI L, 02h ;test point 3
0596 CD F2 03 CALL TOG_PC ;toggle it
0599 CD 0E 04 CALL TAP_STP ;stop tape
059C 2A 9B 20 LHLD ID_HDR1 ;get block
059F 23 INX H ;fake next block
05A0 CD 20 05 CALL SET_POS ;backup
05A3 3A 0C 20 LDA PK_SWIT ;maint switch
05A6 E6 10 ANI 10h ;send bad data
05A8 C2 BA 05 JNZ SND_BAD ;
05AB 21 AF 20 LXI H, RTRY_CT ;
05AE 34 INR M ;inc retry count
05AF 3E 01 MVI A, 01h ;set retry required
05B1 32 B4 20 STA SUCCES ;return code
05B4 C2 57 05 JNZ TAP_NXT ;out of retries?
05B7 C3 C2 05 JMP ERR_DCK ;then data chk error
;
;send bad data to host
05BA 3E 80 SND_BAD: MVI A, 80h ;count
05BC 32 18 20 STA BF_CNT ;set count
05BF CD 64 02 CALL SND_DATA ;send data
;
;data check error
05C2 3E EF ERR_DCK: MVI A, 0EFh ;data check error
05C4 C3 75 07 JMP SET_SUCC ;
;
;command: write bock(s)
05C7 CD FA 06 OP_WRITE: CALL SET_BLK ;setup block num
05CA AF WR_NEXB: XRA A ;clear go flag
05CB 32 A2 20 STA FL_GO ;
05CE CD 4C 05 CALL SND_CONT ;send continue
05D1 D5 PUSH D ;
;
05D2 CD 18 03 WR_WAIT: CALL DRV_RDY ;cartridge in place?
05D5 CD F0 00 CALL CHK_BOOT ;boot request?
05D8 3A A2 20 LDA FL_GO ;
05DB E6 80 ANI 80h ;
05DD CA D2 05 JZ WR_WAIT ;loop till go sets
;
05E0 3A 07 20 LDA PK_FLAG ;
05E3 FE 01 CPI 01h ;did we get a data packet
05E5 C2 10 00 JNZ RST2 ;no then reset
05E8 D1 POP D ;
;
;zero fill buffer if not full block
05E9 CD A4 02 Z_FILL: CALL SEL_DRV ;
05EC E5 PUSH H ;
05ED D5 PUSH D ;
05EE 3A 08 20 LDA PK_CMDCT ;get count
05F1 D6 80 SUI 80h ;subtract full count
05F3 CA 01 06 JZ W_SETUP ;no fill?
05F6 4F MOV C, A ;save count
05F7 21 98 20 LXI H, W_BEND ;point to buf end
05FA AF XRA A ;zero byte
05FB 77 Z_FIL1: MOV M, A ;put in buffer
05FC 2B DCX H ;dec pointer
05FD 0C INR C ;inc count
05FE C2 FB 05 JNZ Z_FIL1 ;loop
;
;setup gap, sync and chksum
0601 CD 35 05 W_SETUP: CALL CALC_CK ;
0604 2A 9F 20 LHLD CHKLO ;get checksum
0607 22 99 20 SHLD BF_CHKL ;save in buffer
;
;write requires 47 zero bits followed
;by a single 1 bit before the data
060A 21 00 00 LXI H, 0000h ;zero gap
060D 22 13 20 SHLD W_GAP1 ;
0610 22 15 20 SHLD W_GAP2 ;
0613 21 00 80 LXI H, 8000h ;single 1 bit
0616 22 17 20 SHLD W_SYNC ;set start of record
;
0619 3A AE 20 LDA PB_IMG ;get port b bits
061C D3 22 OUT PortB ;set port
061E DB 21 IN PortA ;read port a
0620 E6 01 ANI 01h ;write permit
0622 3E F5 MVI A, 0F5h ;write protect
0624 C2 75 07 JNZ SET_SUCC ;error exit
0627 D1 POP D ;
0628 E1 POP H ;
0629 CD 24 03 CALL SEEK ;find block
062C F3 DI ;
;
;delay past gap
062D 3E 0F MVI A, 0Fh ;delay count
062F CD FB 03 CALL DELAY ;delay
0632 21 13 20 LXI H, W_GAP1 ;point to write buf
0635 06 86 MVI B, 86h ;byte count
0637 16 8A MVI D, 8Ah ;byte count+trailer
;
;turn on write
0639 3A AE 20 LDA PB_IMG ;get port B bits
063C F6 02 ORI 02h ;turn on write
063E 5F MOV E, A ;
063F E6 BF ANI 0BFh ;erase enable
0641 D3 22 OUT PortB ;set port
0643 0E 08 MVI C, 08h ;bit count
;write loop
0645 3E FF WR_LOOP: MVI A, 0FFh ;set SOD hi
0647 30 SIM ;
0648 7E MOV A, M ;get byte
0649 0F RRC ;shift data to next bit
064A 77 MOV M, A ;save shifted byte
064B F6 7F ORI 7Fh ;set SOD lo if data=0
064D 30 SIM ;
064E 0D DCR C ;dec bit count
064F CA 62 06 JZ WR_LO02 ;
0652 05 DCR B ;dec byte count
0653 C2 71 06 JNZ WR_LO03 ;
0656 7B MOV A, E ;
0657 D3 22 OUT PortB ;
0659 00 NOP ;
;
;byte count=0 so write trailer
065A 3E 7F WR_LO01: MVI A, 7Fh ;set SOD lo
065C 30 SIM ;
065D 00 NOP ;
065E 00 NOP ;
065F C3 45 06 JMP WR_LOOP ;
;next byte
0662 15 WR_LO02: DCR D ;dec trailer count
0663 CA 75 06 JZ WR_DONE ;exit if done
0666 23 INX H ;point to next byte
0667 3E 7F MVI A, 7Fh ;SOD lo
0669 0E 08 MVI C, 08h ;set bit count
066B 30 SIM ;
066C 05 DCR B ;dec byte count
066D 00 NOP ;
066E C3 45 06 JMP WR_LOOP ;
;
0671 04 WR_LO03: INR B ;
0672 C3 5A 06 JMP WR_LO01 ;
;write done
0675 3A AE 20 WR_DONE: LDA PB_IMG ;get port b bits
0678 D3 22 OUT PortB ;turn off write
067A 3E 0D MVI A, 0Dh ;mask 5,7
067C 30 SIM ;
067D FB EI ;enable irq
067E CD 0E 04 CALL TAP_STP ;stop tape
0681 3E FF MVI A, 0FFh ;disable retry
0683 32 AF 20 STA RTRY_CT ;
0686 CD 85 05 CALL CK_MATCH ;
0689 2A 07 20 LHLD PK_FLAG ;
068C 22 9F 20 SHLD CHKLO ;
068F CD 3B 05 CALL CCK_01 ;calc check sum
0692 2A 05 20 LHLD CHK_SAV ;get RSP check
0695 22 99 20 SHLD BF_CHKL ;put in buffer
0698 CD 85 05 CALL CK_MATCH ;match?
069B 3A 08 20 LDA PK_CMDCT ;get count
069E CD EF 06 CALL ADD_DON ;add to bytes done
06A1 CD DD 06 CALL REMAIN ;dec remaining
06A4 DA CA 05 JC WR_NEXB ;more to do?
;
;zero fill rest of 512 byte block
06A7 3A A9 20 LDA CUR_BLK ;get block
06AA E6 03 ANI 03h ;last tape block?
06AC 3A 0A 20 LDA PK_MOD ;get mod flag
06AF CA C6 06 JZ WR_VERF ;
06B2 FE 00 CPI 00h ;
06B4 FA C6 06 JM WR_VERF ;verify set?
;
;zero fill and write next tape block
06B7 21 00 00 LXI H, 0000h ;zero out count
06BA 22 07 20 SHLD PK_FLAG ;and flags
06BD 22 AB 20 SHLD BTYCNT ;
06C0 22 05 20 SHLD CHK_SAV ;
06C3 C3 E9 05 JMP Z_FILL ;and write it
;
;write verify if flag set
06C6 E6 01 WR_VERF: ANI 01h ;read after write
06C8 CA D7 06 JZ WR_VER2 ;skip?
06CB CD FA 06 CALL SET_BLK ;reset block number
06CE CD 52 05 WR_VER1: CALL TAP_READ ;read verify
06D1 CD DD 06 CALL REMAIN ;update bytes remaining
06D4 DA CE 06 JC WR_VER1 ;more to go?
06D7 CD 0E 04 WR_VER2: CALL TAP_STP ;stop tape
06DA C3 46 07 JMP OP_NOOP ;send response
;
; inc block and calc bytes remaining
06DD 2A A9 20 REMAIN: LHLD CUR_BLK ;inc cur tape block
06E0 23 INX H ;
06E1 22 A9 20 SHLD CUR_BLK ;
06E4 2A AB 20 LHLD BTYCNT ;get byte count
06E7 11 80 FF LXI D, 0FF80h ;subtract block size
06EA 19 DAD D ;
06EB 22 AB 20 SHLD BTYCNT ;save bytes remaining
06EE C9 RET ;
;
;add current transfer to total
06EF 21 03 20 ADD_DON: LXI H, BYT_DON ;
06F2 86 ADD M ;
06F3 77 MOV M, A ;
06F4 23 INX H ;
06F5 7E MOV A, M ;
06F6 CE 00 ACI 00h ;
06F8 77 MOV M, A ;
06F9 C9 RET ;
;
;setup count,block and modifyer
06FA 2A 0F 20 SET_BLK: LHLD PK_CNTL ;get count
06FD 2B DCX H ;correct count
06FE 22 AB 20 SHLD BTYCNT ;save count
0701 2A 11 20 LHLD PK_BLKL ;get block num
0704 3A 0A 20 LDA PK_MOD ;get modifyer
0707 FE 00 CPI 00h ;special address
0709 FA 11 07 JM SET_BL1 ;mode?
;
;not special address mode so
;convert block number to 0-2047
070C 5D MOV E, L ;
070D 54 MOV D, H ;
070E 19 DAD D ;
070F 19 DAD D ;
0710 19 DAD D ;
0711 3E F8 SET_BL1: MVI A, 0F8h ;range check
0713 A4 ANA H ;
0714 3E C9 MVI A, 0C9h ;bad block number
0716 C2 75 07 JNZ SET_SUCC ;error exit
0719 22 A9 20 SHLD CUR_BLK ;set block number
071C C9 RET ;
;
;command: read block (s)
071D CD FA 06 OP_READ: CALL SET_BLK ;setup starting block
0720 CD 52 05 OP_RD1: CALL TAP_READ ;read block
0723 CD DD 06 CALL REMAIN ;calc bytes remaining
0726 D2 37 07 JNC OP_RD2 ;jmp if not 128 bytes
;
;128 byte transfer
0729 3E 80 MVI A, 80h ;count
072B 32 18 20 STA BF_CNT ;set count
072E CD EF 06 CALL ADD_DON ;
0731 CD 64 02 CALL SND_DATA ;send to host
0734 C3 20 07 JMP OP_RD1 ;loop
;
;less than 128 bytes left
0737 CD 0E 04 OP_RD2: CALL TAP_STP ;
073A 7D MOV A, L ;
073B C6 81 ADI 81h ;
073D 32 18 20 STA BF_CNT ;set count
0740 CD EF 06 CALL ADD_DON ;
0743 CD 64 02 CALL SND_DATA ;send to host
;fall through to send response packet
;
;command: no operation
;format and return response packet
0746 21 02 0A OP_NOOP: LXI H, 0A02h ;flag+count
0749 22 07 20 SHLD PK_FLAG ;
074C 3E 40 MVI A, 40h ;end packet
074E 32 09 20 STA PK_OPCD ;
0751 3A B4 20 LDA SUCCES ;
0754 32 0A 20 STA PK_SUCC ;success code
0757 AF XRA A ;
0758 32 11 20 STA PK_SUMSL ;summary status
075B 3A B5 20 LDA SUMST ;
075E 32 12 20 STA PK_SUMSH ;summary status
0761 2A 03 20 LHLD BYT_DON ;
0764 22 0F 20 SHLD PK_CNTL ;actual count
0767 06 05 MVI B, 05h ;delay count
0769 CD 04 04 CALL LNG_DLY ;delay
076C 21 08 20 LXI H, PK_CMDCT ;point to packet
076F CD 6A 02 CALL SND_RESP ;send it
0772 C3 91 00 JMP IDLE_LOOP ;
;
;set error in summary status and success code
;fall through to init and return packet (OP_NOOP)
0775 32 B4 20 SET_SUCC: STA SUCCES ;
0778 3E 80 MVI A, 80h ;error bit
077A 32 B5 20 STA SUMST ;
077D 31 FF 20 LXI SP, STACK ;reset stack
;
;command: initialize
0780 CD 4D 00 OP_INIT: CALL CLR_STATE ;reset protocol
0783 C3 46 07 JMP OP_NOOP ;send response
;
;command: get status
0786 3A 0A 20 OP_GETST: LDA PK_MOD ;
0789 E6 80 ANI 80h ;
078B CA 46 07 JZ OP_NOOP ;send response
078E 3A AD 20 LDA CASS_IN ;
0791 E6 0C ANI 0Ch ;
0793 0F RRC ;
0794 32 B5 20 STA SUMST ;
0797 C3 46 07 JMP OP_NOOP ;send response
;
;Self test
079A 3E 01 SLF_TEST: MVI A, 01h ;set boot
079C D3 23 OUT PortC ;
079E AF XRA A ;clear result code
079F 32 B4 20 STA SUCCES ;
07A2 06 C8 MVI B, 0C8h ;delay count
07A4 CD 04 04 CALL LNG_DLY ;kill time
;
;Test ROM
07A7 21 00 00 LXI H, 0000h ;point to ROM
07AA 22 9F 20 SHLD CHKLO ;
07AD EB XCHG ;
07AE CD 3E 05 TST_01: CALL CCK_02 ;calc sum for 256 bytes
07B1 3E 08 MVI A, 08h ;number of blocks
07B3 BA CMP D ;
07B4 C2 AE 07 JNZ TST_01 ;loop if not done
07B7 2A 9F 20 LHLD CHKLO ;get checksum
07BA 2C INR L ;inc
07BB C2 E5 07 JNZ TST_04 ;not zero=error
07BE 24 INR H ;inc
07BF C2 E5 07 JNZ TST_04 ;not zero=error
;
;Test RAM
07C2 21 10 20 LXI H, PK_CNTH ;point to ram
07C5 75 TST_02: MOV M, L ;write to RAM
07C6 2C INR L ;next
07C7 3E F0 MVI A, 0F0h ;end count
07C9 BD CMP L ;at end?
07CA C2 C5 07 JNZ TST_02 ;loop if not
07CD 2D TST_03: DCR L ;point to previous
07CE 7E MOV A, M ;get RAM
07CF BD CMP L ;pattern match?
07D0 C2 E5 07 JNZ TST_04 ;RAM error
07D3 FE 10 CPI 10h ;end of test?
07D5 C2 CD 07 JNZ TST_03 ;loop if not
;
;Reset IO
07D8 CD 57 00 CALL SETRG1 ;
07DB 3E 05 MVI A, 05h ;
07DD D3 23 OUT PortC ;
07DF AF XRA A ;
07E0 67 MOV H, A ;
07E1 6F MOV L, A ;
07E2 C3 E8 07 JMP TST_05 ;
07E5 21 FF 80 TST_04: LXI H, 80FFh ;failled self test
07E8 22 B4 20 TST_05: SHLD SUCCES ;set result
07EB C9 RET ;
;
;command: diagnostics
07EC CD 9A 07 OP_DIAG: CALL SLF_TEST ;
07EF C3 46 07 JMP OP_NOOP ;send response
;
;ROM check sum
;the following bytes should be calculated
;so the sum of all the ROM bytes is $FFFF
07F2 CD DB 0CDh ;
07F3 79 DB 79h ;
07F4 00 DB 00h ;
07F5 00 DB 00h ;
07F6 00 DB 00h ;
07F7 00 DB 00h ;
07F8 00 DB 00h ;
07F9 00 DB 00h ;
07FA 00 DB 00h ;
07FB 00 DB 00h ;
07FC 00 DB 00h ;
07FD 00 DB 00h ;
07FE 00 DB 00h ;
07FF 00 DB 00h ;
END