mirror of
https://github.com/tebl/RC6502-Apple-1-Replica.git
synced 2024-11-22 14:31:56 +00:00
241 lines
18 KiB
Plaintext
241 lines
18 KiB
Plaintext
0000- 4 ;-------------------------------------------------------------------------
|
|
0000- 5 ;
|
|
0000- 6 ; The WOZ Apple Cassette Interface for the Apple 1
|
|
0000- 7 ; Written by Steve Wozniak somewhere around 1976
|
|
0000- 8 ;
|
|
0000- 9 ;-------------------------------------------------------------------------
|
|
0000- 10
|
|
0000- 11
|
|
0000- 12 ;-------------------------------------------------------------------------
|
|
0000- 13 ; Memory declaration
|
|
0000- 14 ;-------------------------------------------------------------------------
|
|
0000- 15
|
|
0024- 16 HEX1L .EQ $24 End address of dump block
|
|
0025- 17 HEX1H .EQ $25
|
|
0026- 18 HEX2L .EQ $26 Begin address of dump block
|
|
0027- 19 HEX2H .EQ $27
|
|
0028- 20 SAVEINDEX .EQ $28 Save index in input buffer
|
|
0029- 21 LASTSTATE .EQ $29 Last input state
|
|
0000- 22
|
|
0200- 23 IN .EQ $0200 Input buffer
|
|
C000- 24 FLIP .EQ $C000 Output flip-flop
|
|
C081- 25 TAPEIN .EQ $C081 Tape input
|
|
D010- 26 KBD .EQ $D010 PIA.A keyboard input
|
|
D011- 27 KBDCR .EQ $D011 PIA.A keyboard control register
|
|
FF1A- 28 ESCAPE .EQ $FF1A Escape back to monitor
|
|
FFEF- 29 ECHO .EQ $FFEF Echo character to terminal
|
|
0000- 30
|
|
0000- 31 ;-------------------------------------------------------------------------
|
|
0000- 32 ; Constants
|
|
0000- 33 ;-------------------------------------------------------------------------
|
|
0000- 34
|
|
008D- 35 CR .EQ $8D Carriage Return
|
|
009B- 36 ESC .EQ $9B ASCII ESC
|
|
0000- 37
|
|
0000- 38 ;-------------------------------------------------------------------------
|
|
0000- 39 ; Let's get started
|
|
0000- 40 ;-------------------------------------------------------------------------
|
|
C100- 41 .OR $C100
|
|
C100-A9 AA 42 ( 2) WOZACI LDA #"*" Print the Tape prompt
|
|
C102-20 EF FF 43 ( 6) JSR ECHO
|
|
C105-A9 8D 44 ( 2) LDA #CR And drop the cursor one line
|
|
C107-20 EF FF 45 ( 6) JSR ECHO
|
|
C10A- 46
|
|
C10A-A0 FF 47 ( 2) LDY #-1 Reset the input buffer index
|
|
C10C-C8 48 ( 2) NEXTCHAR INY
|
|
C10D-AD 11 D0 49 ( 4) KBDWAIT LDA KBDCR Wait for a key
|
|
C110-10 FB 50 (2**) BPL KBDWAIT Still no key!
|
|
C112- 51
|
|
C112-AD 10 D0 52 ( 4) LDA KBD Read key from keyboard
|
|
C115-99 00 02 53 ( 5) STA IN,Y Save it into buffer
|
|
C118-20 EF FF 54 ( 6) JSR ECHO And type it on the screen
|
|
C11B-C9 9B 55 ( 2) CMP #ESC
|
|
C11D-F0 E1 56 (2**) BEQ WOZACI Start from scratch if ESC!
|
|
C11F-C9 8D 57 ( 2) CMP #CR
|
|
C121-D0 E9 58 (2**) BNE NEXTCHAR Read keys until CR
|
|
C123- 59
|
|
C123-A2 FF 60 ( 2) LDX #-1 Initialize parse buffer pointer
|
|
C125- 61
|
|
C125- 62 ;-------------------------------------------------------------------------
|
|
C125- 63 ; Start parsing first or a new tape command
|
|
C125- 64 ;-------------------------------------------------------------------------
|
|
C125- 65
|
|
C125-A9 00 66 ( 2) NEXTCMD LDA #0 Clear begin and end values
|
|
C127-85 24 67 ( 2) STA HEX1L
|
|
C129-85 25 68 ( 2) STA HEX1H
|
|
C12B-85 26 69 ( 2) STA HEX2L
|
|
C12D-85 27 70 ( 2) STA HEX2H
|
|
C12F- 71
|
|
C12F-E8 72 ( 2) NEXTCHR INX Increment input pointer
|
|
C130-BD 00 02 73 ( 4*) LDA IN,X Get next char from input line
|
|
C133-C9 D2 74 ( 2) CMP #"R" Read command?
|
|
C135-F0 56 75 (2**) BEQ READ Yes!
|
|
C137-C9 D7 76 ( 2) CMP #"W" Write command?
|
|
C139-F0 35 77 (2**) BEQ WRITE Yes! (note: CY=1)
|
|
C13B-C9 AE 78 ( 2) CMP #"." Separator?
|
|
C13D-F0 27 79 (2**) BEQ SEP Yes!
|
|
C13F-C9 8D 80 ( 2) CMP #CR End of line?
|
|
C141-F0 20 81 (2**) BEQ GOESC Escape to monitor! We're done
|
|
C143-C9 A0 82 ( 2) CMP #" " Ignore spaces
|
|
C145-F0 E8 83 (2**) BEQ NEXTCHR
|
|
C147-49 B0 84 ( 2) EOR #"0" Map digits to 0-9
|
|
C149-C9 0A 85 ( 2) CMP #9+1 Is it a decimal digit?
|
|
C14B-90 06 86 (2**) BCC DIG Yes!
|
|
C14D-69 88 87 ( 2) ADC #$88 Map letter "A"-"F" to $FA-$FF
|
|
C14F-C9 FA 88 ( 2) CMP #$FA Hex letter?
|
|
C151-90 AD 89 (2**) BCC WOZACI No! Character not hex!
|
|
C153- 90
|
|
C153-0A 91 ( 2) DIG ASL Hex digit to MSD of A
|
|
C154-0A 92 ( 2) ASL
|
|
C155-0A 93 ( 2) ASL
|
|
C156-0A 94 ( 2) ASL
|
|
C157- 95
|
|
C157-A0 04 96 ( 2) LDY #4 Shift count
|
|
C159-0A 97 ( 2) HEXSHIFT ASL Hex digit left, MSB to carry
|
|
C15A-26 24 98 ( 5) ROL HEX1L Rotate into LSD
|
|
C15C-26 25 99 ( 5) ROL HEX1H Rotate into MSD
|
|
C15E-88 100 ( 2) DEY Done 4 shifts?
|
|
C15F-D0 F8 101 (2**) BNE HEXSHIFT No! Loop
|
|
C161-F0 CC 102 (2**) BEQ NEXTCHR Handle next character
|
|
C163- 103
|
|
C163- 104 ;-------------------------------------------------------------------------
|
|
C163- 105 ; Return to monitor, prints \ first
|
|
C163- 106 ;-------------------------------------------------------------------------
|
|
C163- 107
|
|
C163-4C 1A FF 108 ( 3) GOESC JMP ESCAPE Escape back to monitor
|
|
C166- 109
|
|
C166- 110 ;-------------------------------------------------------------------------
|
|
C166- 111 ; Separating . found. Copy HEX1 to Hex2. Doesn't clear HEX1!!!
|
|
C166- 112 ;-------------------------------------------------------------------------
|
|
C166- 113
|
|
C166-A5 24 114 ( 3) SEP LDA HEX1L Copy hex value 1 to hex value 2
|
|
C168-85 26 115 ( 2) STA HEX2L
|
|
C16A-A5 25 116 ( 3) LDA HEX1H
|
|
C16C-85 27 117 ( 2) STA HEX2H
|
|
C16E-B0 BF 118 (2**) BCS NEXTCHR Always taken!
|
|
C170- 119
|
|
C170- 120 ;-------------------------------------------------------------------------
|
|
C170- 121 ; Write a block of memory to tape
|
|
C170- 122 ;-------------------------------------------------------------------------
|
|
C170- 123
|
|
C170-A9 40 124 ( 2) WRITE LDA #64 Write 10 second header
|
|
C172-20 CC C1 125 ( 6) JSR WHEADER
|
|
C175- 126
|
|
C175-88 127 ( 2) WRNEXT DEY Compensate timing for extra work
|
|
C176-A2 00 128 ( 2) LDX #0 Get next byte to write
|
|
C178-A1 26 129 ( 6) LDA (HEX2L,X)
|
|
C17A- 130
|
|
C17A-A2 10 131 ( 2) LDX #8*2 Shift 8 bits (decremented twice)
|
|
C17C-0A 132 ( 2) WBITLOOP ASL Shift MSB to carry
|
|
C17D-20 DB C1 133 ( 6) JSR WRITEBIT Write this bit
|
|
C180-D0 FA 134 (2**) BNE WBITLOOP Do all 8 bits!
|
|
C182- 135
|
|
C182-20 F1 C1 136 ( 6) JSR INCADDR Increment address
|
|
C185-A0 1E 137 ( 2) LDY #30 Compensate timer for extra work
|
|
C187-90 EC 138 (2**) BCC WRNEXT Not done yet! Write next byte
|
|
C189- 139
|
|
C189-A6 28 140 ( 3) RESTIDX LDX SAVEINDEX Restore index in input line
|
|
C18B-B0 98 141 (2**) BCS NEXTCMD Always taken!
|
|
C18D- 142
|
|
C18D- 143 ;-------------------------------------------------------------------------
|
|
C18D- 144 ; Read from tape
|
|
C18D- 145 ;-------------------------------------------------------------------------
|
|
C18D- 146
|
|
C18D-20 BC C1 147 ( 6) READ JSR FULLCYCLE Wait until full cycle is detected
|
|
C190-A9 16 148 ( 2) LDA #22 Introduce some delay to allow
|
|
C192-20 CC C1 149 ( 6) JSR WHEADER the tape speed to stabilize
|
|
C195-20 BC C1 150 ( 6) JSR FULLCYCLE Synchronize with full cycle
|
|
C198- 151
|
|
C198-A0 1F 152 ( 2) NOTSTART LDY #31 Try to detect the much shorter
|
|
C19A-20 BF C1 153 ( 6) JSR CMPLEVEL start bit
|
|
C19D-B0 F9 154 (2**) BCS NOTSTART Start bit not detected yet!
|
|
C19F- 155
|
|
C19F-20 BF C1 156 ( 6) JSR CMPLEVEL Wait for 2nd phase of start bit
|
|
C1A2- 157
|
|
C1A2-A0 3A 158 ( 2) LDY #58 Set threshold value in middle
|
|
C1A4-A2 08 159 ( 2) RDBYTE LDX #8 Receiver 8 bits
|
|
C1A6-48 160 ( 3) RDBIT PHA
|
|
C1A7-20 BC C1 161 ( 6) JSR FULLCYCLE Detect a full cycle
|
|
C1AA-68 162 ( 4) PLA
|
|
C1AB-2A 163 ( 2) ROL Roll new bit into result
|
|
C1AC-A0 39 164 ( 2) LDY #57 Set threshold value in middle
|
|
C1AE-CA 165 ( 2) DEX Decrement bit counter
|
|
C1AF-D0 F5 166 (2**) BNE RDBIT Read next bit!
|
|
C1B1-81 26 167 ( 6) STA (HEX2L,X) Save new byte
|
|
C1B3- 168
|
|
C1B3-20 F1 C1 169 ( 6) JSR INCADDR Increment address
|
|
C1B6-A0 35 170 ( 2) LDY #53 Compensate threshold with workload
|
|
C1B8-90 EA 171 (2**) BCC RDBYTE Do next byte if not done yet!
|
|
C1BA-B0 CD 172 (2**) BCS RESTIDX Always taken! Restore parse index
|
|
C1BC- 173
|
|
C1BC-20 BF C1 174 ( 6) FULLCYCLE JSR CMPLEVEL Wait for two level changes
|
|
C1BF-88 175 ( 2) CMPLEVEL DEY Decrement time counter
|
|
C1C0-AD 81 C0 176 ( 4) LDA TAPEIN Get Tape In data
|
|
C1C3-C5 29 177 ( 3) CMP LASTSTATE Same as before?
|
|
C1C5-F0 F8 178 (2**) BEQ CMPLEVEL Yes!
|
|
C1C7-85 29 179 ( 2) STA LASTSTATE Save new data
|
|
C1C9- 180
|
|
C1C9-C0 80 181 ( 2) CPY #128 Compare threshold
|
|
C1CB-60 182 ( 6) RTS
|
|
C1CC- 183
|
|
C1CC- 184 ;-------------------------------------------------------------------------
|
|
C1CC- 185 ; Write header to tape
|
|
C1CC- 186 ;
|
|
C1CC- 187 ; The header consists of an asymmetric cycle, starting with one phase of
|
|
C1CC- 188 ; approximately (66+47)x5=565us, followed by a second phase of
|
|
C1CC- 189 ; approximately (44+47)x5=455us.
|
|
C1CC- 190 ; Total cycle duration is approximately 1020us ~ 1kHz. The actual
|
|
C1CC- 191 ; frequencywill be a bit lower because of the additional workload between
|
|
C1CC- 192 ; the twoloops.
|
|
C1CC- 193 ; The header ends with a short phase of (30+47)x5=385us and a normal
|
|
C1CC- 194 ; phase of (44+47)x5=455us. This start bit must be detected by the read
|
|
C1CC- 195 ; routine to trigger the reading of the actual data.
|
|
C1CC- 196 ;-------------------------------------------------------------------------
|
|
C1CC- 197
|
|
C1CC-86 28 198 ( 3) WHEADER STX SAVEINDEX Save index in input line
|
|
C1CE-A0 42 199 ( 2) HCOUNT LDY #66 Extra long delay
|
|
C1D0-20 E0 C1 200 ( 6) JSR WDELAY CY is constantly 1, writing a 1
|
|
C1D3-D0 F9 201 (2**) BNE HCOUNT Do this 64 * 256 time!
|
|
C1D5-69 FE 202 ( 2) ADC #-2 Decrement A (CY=1 all the time)
|
|
C1D7-B0 F5 203 (2**) BCS HCOUNT Not all done!
|
|
C1D9-A0 1E 204 ( 2) LDY #30 Write a final short bit (start)
|
|
C1DB- 205
|
|
C1DB- 206 ;-------------------------------------------------------------------------
|
|
C1DB- 207 ; Write a full bit cycle
|
|
C1DB- 208 ;
|
|
C1DB- 209 ; Upon entry Y contains a compensated value for the first phase of 0
|
|
C1DB- 210 ; bit length. All subsequent loops don't have to be time compensated.
|
|
C1DB- 211 ;-------------------------------------------------------------------------
|
|
C1DB- 212
|
|
C1DB-20 E0 C1 213 ( 6) WRITEBIT JSR WDELAY Do two equal phases
|
|
C1DE-A0 2C 214 ( 2) LDY #44 Load 250us counter - compensation
|
|
C1E0- 215
|
|
C1E0-88 216 ( 2) WDELAY DEY Delay 250us (one phase of 2kHz)
|
|
C1E1-D0 FD 217 (2**) BNE WDELAY
|
|
C1E3-90 05 218 (2**) BCC WRITE1 Write a '1' (2kHz)
|
|
C1E5- 219
|
|
C1E5-A0 2F 220 ( 2) LDY #47 Additional delay for '0' (1kHz)
|
|
C1E7-88 221 ( 2) WDELAY0 DEY (delay 250us)
|
|
C1E8-D0 FD 222 (2**) BNE WDELAY0
|
|
C1EA- 223
|
|
C1EA-BC 00 C0 224 ( 4*) WRITE1 LDY FLIP,X Flip the output bit
|
|
C1ED-A0 29 225 ( 2) LDY #41 Reload 250us cntr (compensation)
|
|
C1EF-CA 226 ( 2) DEX Decrement bit counter
|
|
C1F0-60 227 ( 6) RTS
|
|
C1F1- 228
|
|
C1F1- 229 ;-------------------------------------------------------------------------
|
|
C1F1- 230 ; Increment current address and compare with last address
|
|
C1F1- 231 ;-------------------------------------------------------------------------
|
|
C1F1- 232
|
|
C1F1-A5 26 233 ( 3) INCADDR LDA HEX2L Compare current address with
|
|
C1F3-C5 24 234 ( 3) CMP HEX1L end address
|
|
C1F5-A5 27 235 ( 3) LDA HEX2H
|
|
C1F7-E5 25 236 ( 3) SBC HEX1H
|
|
C1F9-E6 26 237 ( 5) INC HEX2L And increment current address
|
|
C1FB-D0 02 238 (2**) BNE NOCARRY No carry to MSB!
|
|
C1FD-E6 27 239 ( 5) INC HEX2H
|
|
C1FF-60 240 ( 6) NOCARRY RTS
|
|
C200- 241
|
|
C200- 242 ;-------------------------------------------------------------------------
|
|
C200- 243
|