mirror of
https://github.com/tebl/RC6502-Apple-1-Replica.git
synced 2024-11-29 14:50:56 +00:00
245 lines
11 KiB
NASM
245 lines
11 KiB
NASM
|
.CR 6502
|
|||
|
.TF wozaci.hex,HEX,8
|
|||
|
.LF wozaci.list
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; The WOZ Apple Cassette Interface for the Apple 1
|
|||
|
; Written by Steve Wozniak somewhere around 1976
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Memory declaration
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
HEX1L .EQ $24 End address of dump block
|
|||
|
HEX1H .EQ $25
|
|||
|
HEX2L .EQ $26 Begin address of dump block
|
|||
|
HEX2H .EQ $27
|
|||
|
SAVEINDEX .EQ $28 Save index in input buffer
|
|||
|
LASTSTATE .EQ $29 Last input state
|
|||
|
|
|||
|
IN .EQ $0200 Input buffer
|
|||
|
FLIP .EQ $C000 Output flip-flop
|
|||
|
TAPEIN .EQ $C081 Tape input
|
|||
|
KBD .EQ $D010 PIA.A keyboard input
|
|||
|
KBDCR .EQ $D011 PIA.A keyboard control register
|
|||
|
ESCAPE .EQ $FF1A Escape back to monitor
|
|||
|
ECHO .EQ $FFEF Echo character to terminal
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Constants
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
CR .EQ $8D Carriage Return
|
|||
|
ESC .EQ $9B ASCII ESC
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Let's get started
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
.OR $C100
|
|||
|
WOZACI LDA #"*" Print the Tape prompt
|
|||
|
JSR ECHO
|
|||
|
LDA #CR And drop the cursor one line
|
|||
|
JSR ECHO
|
|||
|
|
|||
|
LDY #-1 Reset the input buffer index
|
|||
|
NEXTCHAR INY
|
|||
|
KBDWAIT LDA KBDCR Wait for a key
|
|||
|
BPL KBDWAIT Still no key!
|
|||
|
|
|||
|
LDA KBD Read key from keyboard
|
|||
|
STA IN,Y Save it into buffer
|
|||
|
JSR ECHO And type it on the screen
|
|||
|
CMP #ESC
|
|||
|
BEQ WOZACI Start from scratch if ESC!
|
|||
|
CMP #CR
|
|||
|
BNE NEXTCHAR Read keys until CR
|
|||
|
|
|||
|
LDX #-1 Initialize parse buffer pointer
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Start parsing first or a new tape command
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
NEXTCMD LDA #0 Clear begin and end values
|
|||
|
STA HEX1L
|
|||
|
STA HEX1H
|
|||
|
STA HEX2L
|
|||
|
STA HEX2H
|
|||
|
|
|||
|
NEXTCHR INX Increment input pointer
|
|||
|
LDA IN,X Get next char from input line
|
|||
|
CMP #"R" Read command?
|
|||
|
BEQ READ Yes!
|
|||
|
CMP #"W" Write command?
|
|||
|
BEQ WRITE Yes! (note: CY=1)
|
|||
|
CMP #"." Separator?
|
|||
|
BEQ SEP Yes!
|
|||
|
CMP #CR End of line?
|
|||
|
BEQ GOESC Escape to monitor! We're done
|
|||
|
CMP #" " Ignore spaces
|
|||
|
BEQ NEXTCHR
|
|||
|
EOR #"0" Map digits to 0-9
|
|||
|
CMP #9+1 Is it a decimal digit?
|
|||
|
BCC DIG Yes!
|
|||
|
ADC #$88 Map letter "A"-"F" to $FA-$FF
|
|||
|
CMP #$FA Hex letter?
|
|||
|
BCC WOZACI No! Character not hex!
|
|||
|
|
|||
|
DIG ASL Hex digit to MSD of A
|
|||
|
ASL
|
|||
|
ASL
|
|||
|
ASL
|
|||
|
|
|||
|
LDY #4 Shift count
|
|||
|
HEXSHIFT ASL Hex digit left, MSB to carry
|
|||
|
ROL HEX1L Rotate into LSD
|
|||
|
ROL HEX1H Rotate into MSD
|
|||
|
DEY Done 4 shifts?
|
|||
|
BNE HEXSHIFT No! Loop
|
|||
|
BEQ NEXTCHR Handle next character
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Return to monitor, prints \ first
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
GOESC JMP ESCAPE Escape back to monitor
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Separating . found. Copy HEX1 to Hex2. Doesn't clear HEX1!!!
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
SEP LDA HEX1L Copy hex value 1 to hex value 2
|
|||
|
STA HEX2L
|
|||
|
LDA HEX1H
|
|||
|
STA HEX2H
|
|||
|
BCS NEXTCHR Always taken!
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Write a block of memory to tape
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
WRITE LDA #64 Write 10 second header
|
|||
|
JSR WHEADER
|
|||
|
|
|||
|
WRNEXT DEY Compensate timing for extra work
|
|||
|
LDX #0 Get next byte to write
|
|||
|
LDA (HEX2L,X)
|
|||
|
|
|||
|
LDX #8*2 Shift 8 bits (decremented twice)
|
|||
|
WBITLOOP ASL Shift MSB to carry
|
|||
|
JSR WRITEBIT Write this bit
|
|||
|
BNE WBITLOOP Do all 8 bits!
|
|||
|
|
|||
|
JSR INCADDR Increment address
|
|||
|
LDY #30 Compensate timer for extra work
|
|||
|
BCC WRNEXT Not done yet! Write next byte
|
|||
|
|
|||
|
RESTIDX LDX SAVEINDEX Restore index in input line
|
|||
|
BCS NEXTCMD Always taken!
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Read from tape
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
READ JSR FULLCYCLE Wait until full cycle is detected
|
|||
|
LDA #22 Introduce some delay to allow
|
|||
|
JSR WHEADER the tape speed to stabilize
|
|||
|
JSR FULLCYCLE Synchronize with full cycle
|
|||
|
|
|||
|
NOTSTART LDY #31 Try to detect the much shorter
|
|||
|
JSR CMPLEVEL start bit
|
|||
|
BCS NOTSTART Start bit not detected yet!
|
|||
|
|
|||
|
JSR CMPLEVEL Wait for 2nd phase of start bit
|
|||
|
|
|||
|
LDY #58 Set threshold value in middle
|
|||
|
RDBYTE LDX #8 Receiver 8 bits
|
|||
|
RDBIT PHA
|
|||
|
JSR FULLCYCLE Detect a full cycle
|
|||
|
PLA
|
|||
|
ROL Roll new bit into result
|
|||
|
LDY #57 Set threshold value in middle
|
|||
|
DEX Decrement bit counter
|
|||
|
BNE RDBIT Read next bit!
|
|||
|
STA (HEX2L,X) Save new byte
|
|||
|
|
|||
|
JSR INCADDR Increment address
|
|||
|
LDY #53 Compensate threshold with workload
|
|||
|
BCC RDBYTE Do next byte if not done yet!
|
|||
|
BCS RESTIDX Always taken! Restore parse index
|
|||
|
|
|||
|
FULLCYCLE JSR CMPLEVEL Wait for two level changes
|
|||
|
CMPLEVEL DEY Decrement time counter
|
|||
|
LDA TAPEIN Get Tape In data
|
|||
|
CMP LASTSTATE Same as before?
|
|||
|
BEQ CMPLEVEL Yes!
|
|||
|
STA LASTSTATE Save new data
|
|||
|
|
|||
|
CPY #128 Compare threshold
|
|||
|
RTS
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Write header to tape
|
|||
|
;
|
|||
|
; The header consists of an asymmetric cycle, starting with one phase of
|
|||
|
; approximately (66+47)x5=565us, followed by a second phase of
|
|||
|
; approximately (44+47)x5=455us.
|
|||
|
; Total cycle duration is approximately 1020us ~ 1kHz. The actual
|
|||
|
; frequencywill be a bit lower because of the additional workload between
|
|||
|
; the twoloops.
|
|||
|
; The header ends with a short phase of (30+47)x5=385us and a normal
|
|||
|
; phase of (44+47)x5=455us. This start bit must be detected by the read
|
|||
|
; routine to trigger the reading of the actual data.
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
WHEADER STX SAVEINDEX Save index in input line
|
|||
|
HCOUNT LDY #66 Extra long delay
|
|||
|
JSR WDELAY CY is constantly 1, writing a 1
|
|||
|
BNE HCOUNT Do this 64 * 256 time!
|
|||
|
ADC #-2 Decrement A (CY=1 all the time)
|
|||
|
BCS HCOUNT Not all done!
|
|||
|
LDY #30 Write a final short bit (start)
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Write a full bit cycle
|
|||
|
;
|
|||
|
; Upon entry Y contains a compensated value for the first phase of 0
|
|||
|
; bit length. All subsequent loops don't have to be time compensated.
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
WRITEBIT JSR WDELAY Do two equal phases
|
|||
|
LDY #44 Load 250us counter - compensation
|
|||
|
|
|||
|
WDELAY DEY Delay 250us (one phase of 2kHz)
|
|||
|
BNE WDELAY
|
|||
|
BCC WRITE1 Write a '1' (2kHz)
|
|||
|
|
|||
|
LDY #47 Additional delay for '0' (1kHz)
|
|||
|
WDELAY0 DEY (delay 250us)
|
|||
|
BNE WDELAY0
|
|||
|
|
|||
|
WRITE1 LDY FLIP,X Flip the output bit
|
|||
|
LDY #41 Reload 250us cntr (compensation)
|
|||
|
DEX Decrement bit counter
|
|||
|
RTS
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
; Increment current address and compare with last address
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
INCADDR LDA HEX2L Compare current address with
|
|||
|
CMP HEX1L end address
|
|||
|
LDA HEX2H
|
|||
|
SBC HEX1H
|
|||
|
INC HEX2L And increment current address
|
|||
|
BNE NOCARRY No carry to MSB!
|
|||
|
INC HEX2H
|
|||
|
NOCARRY RTS
|
|||
|
|
|||
|
;-------------------------------------------------------------------------
|
|||
|
|
|||
|
.LI OFF
|
|||
|
|