Published Friday, January 18 2013
Good progress tonight! I think the code to WRITE data to tape is fully complete. I’m not particularly impressed with my own 6502 assembly, but by golly it works.
Note that there is no checksum yet. I’m calling this “Optional” for now. I may regret that later.
The next step is the opposite process: READING THE DATA! I’ll have more on that when I’m a little less tired.
.alias TAPEST $40
.alias A1L $41 ; Start address low byte
.alias A1H $42 ; Start address high byte
.alias A2L $43 ; End address low byte
.alias A2H $44 ; End address high byte
.alias IOB $8000
.alias IOA $8001
.alias DDRB $8002
.alias DDRA $8003
.org $0300
INIT: LDA #$FF ; Make all Port-A IO lines outputs
STA DDRA
LDA #$00 ; Initialize tape state scratch space
STA TAPEST
STA IOA
;*******************************************************************************
; Write Memory to Tape
; Start Address: A1L,A1H
; End Address: A2L,A2H
;*******************************************************************************
WRITE: JSR HEADR
JSR WRSYNC
JSR WRDATA
; END
BRK
; END
;*******************************************************************************
; Write the Tape Header.
; This outputs 10 seconds of 750 Hz square wave.
;
; NB: Measured values for cycle widths at 1MHz PHI2:
;
; $79 = 776.4Hz 1.288ms
; $7A = 766.9Hz 1.304ms
; $7B = 757.6Hz 1.320ms
;*******************************************************************************
HEADR: LDX #$3C ; 60 times thru inner loop
HD0: LDY #$FF ; (60 * 255 = 15,300 half cycles)
HD1: JSR TOGTAP
LDA #$7A ; (122 * 5 uS) + overhead = 650 uS width
HD3: SBC #$01 ; Delay (using A, because X and Y are busy)
BNE HD3
DEY
BNE HD1 ; Inner Loop
DEX
BNE HD0 ; Outer Loop
RTS
;*******************************************************************************
; Write a single Sync Bit.
;*******************************************************************************
WRSYNC: LDX #$24
JSR WS0 ; Recursive call to toggle bit twice
WS0: JSR TOGTAP
WS1: DEX
BNE WS1
LDX #$28
RTS
;*******************************************************************************
; Read the memory between A1L,A1H and A2L,A2H, one byte at a
; time, and send it to tape.
;
; Values #$34 was chosen as a perfect match for a 250uS
; delay. #$2A is the same delay, but compensated.
;*******************************************************************************
WRDATA: LDX #$00
LDA (A1L,X) ; Get first byte to send to tape.
LDY #$08 ; 8 bits to do
WRBIT: ROL ; Shift leftmost bit into C
PHA ; Save the accumulator.
WD0: JSR TOGTAP ; Toggle output state
BCC ZERDLY ; Is C a '0'? Skip '1' delay
LDX #$34
ONEDLY: DEX ; Delay for 260 clock cycles.
BNE ONEDLY
ZERDLY: LDX #$2A
ZD0: DEX ; Delay for 210 clock cycles.
BNE ZD0
; Bit test does not affect 'Carry' flag, so it will
; still be set from the ROL
BIT TAPEST ; Check to see if the cycle is done.
BNE WD0 ; If not, write second half.
PLA ; If so, restore the input byte
DEY ; If not done with bits, do
BNE WRBIT ; next bit...
JSR INCADR ; Increment read address,
BCC WRDATA ; and get the next byte
; Done. At this point, the entire block of memory to
; dump to tape has been sent. A1L,A1H have been
; incremented to be > A2L,A2H
RTS
;*******************************************************************************
; Toggle the current tape output state. Modifies Accumulator.
;*******************************************************************************
TOGTAP: LDA TAPEST ; Load current tape state
EOR #$01 ; Toggle it
STA TAPEST ; Store back into tape state,
STA IOA ; and out to tape.
RTS
;*******************************************************************************
; Increment the tape memory buffer pointer.
;
; Carry will be left set iff A1L == A2L and A1H == A2H
; Blatently stolen from Woz's Apple 1 Monitor
;*******************************************************************************
INCADR: LDA A1L ; Compare current addr with end addr.
CMP A2L ; Sets carry if A1L >= A2L.
LDA A1H
SBC A2H ; Clears carry if A2H < A1H.
INC A1L
BNE NOCARY ; If A1L is now 00, inc A1H as well.
INC A1H
NOCARY: RTS
Comments