; ;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