C64 ROM | Routines |
Prev: FBC8 | Up: Map | Next: FC6A |
this is the routine that writes the bits to the tape. it is called each time VIA 2 T2 times out and checks if the start bit is done, if so checks if the data bits are done, if so it checks if the byte is done, if so it checks if the synchronisation bytes are done, if so it checks if the data bytes are done, if so it checks if the checksum byte is done, if so it checks if both the load and verify copies have been done, if so it stops the tape
|
||||
FBCD | A5 A8 | LDA $A8 | get start bit first cycle done flag | |
FBCF | D0 12 | BNE $FBE3 | if first cycle done go do rest of byte | |
each byte sent starts with two half cycles of $0110 system clocks and the whole block ends with two more such half cycles
|
||||
FBD1 | A9 10 | LDA #$10 | set first start cycle time constant low byte | |
FBD3 | A2 01 | LDX #$01 | set first start cycle time constant high byte | |
FBD5 | 20 B1 FB | JSR $FBB1 | write time constant and toggle tape | |
FBD8 | D0 2F | BNE $FC09 | if first half cycle go restore registers and exit interrupt | |
FBDA | E6 A8 | INC $A8 | set start bit first start cycle done flag | |
FBDC | A5 B6 | LDA $B6 | get buffer address high byte | |
FBDE | 10 29 | BPL $FC09 | if block not complete go restore registers and exit interrupt. the end of a block is indicated by the tape buffer high byte b7 being set to 1 | |
FBE0 | 4C 57 FC | JMP $FC57 | else do tape routine, block complete exit | |
continue tape byte write. the first start cycle, both half cycles of it, is complete so the routine drops straight through to here
|
||||
FBE3 | A5 A9 | LDA $A9 | get start bit check flag | |
FBE5 | D0 09 | BNE $FBF0 | if the start bit is complete go send the byte bits | |
after the two half cycles of $0110 ststem clocks the start bit is completed with two half cycles of $00B0 system clocks. this is the same as the first part of a 1 bit
|
||||
FBE7 | 20 AD FB | JSR $FBAD | set time constant for bit = 1 and toggle tape | |
FBEA | D0 1D | BNE $FC09 | if first half cycle go restore registers and exit interrupt | |
FBEC | E6 A9 | INC $A9 | set start bit check flag | |
FBEE | D0 19 | BNE $FC09 | restore registers and exit interrupt, branch always | |
continue tape byte write. the start bit, both cycles of it, is complete so the routine drops straight through to here. now the cycle pairs for each bit, and the parity bit, are sent
|
||||
FBF0 | 20 A6 FB | JSR $FBA6 | send lsb from tape write byte to tape | |
FBF3 | D0 14 | BNE $FC09 | if first half cycle go restore registers and exit interrupt | |
else two half cycles have been done
|
||||
FBF5 | A5 A4 | LDA $A4 | get tape bit cycle phase | |
FBF7 | 49 01 | EOR #%00000001 | toggle b0 | |
FBF9 | 85 A4 | STA $A4 | save tape bit cycle phase | |
FBFB | F0 0F | BEQ $FC0C | if bit cycle phase complete go setup for next bit | |
each bit is written as two full cycles. a 1 is sent as a full cycle of $0160 system clocks then a full cycle of $00C0 system clocks. a 0 is sent as a full cycle of $00C0 system clocks then a full cycle of $0160 system clocks. to do this each bit from the write byte is inverted during the second bit cycle phase. as the bit is inverted it is also added to the, one bit, parity count for this byte
|
||||
FBFD | A5 BD | LDA $BD | get tape write byte | |
FBFF | 49 01 | EOR #%00000001 | invert bit being sent | |
FC01 | 85 BD | STA $BD | save tape write byte | |
FC03 | 29 01 | AND #%00000001 | mask b0 | |
FC05 | 45 9B | EOR $9B | EOR with tape write byte parity bit | |
FC07 | 85 9B | STA $9B | save tape write byte parity bit | |
This entry point is used by the routine at FBC8.
|
||||
FC09 | 4C BC FE | JMP $FEBC | restore registers and exit interrupt | |
the bit cycle phase is complete so shift out the just written bit and test for byte end
|
||||
FC0C | 46 BD | LSR $BD | shift bit out of tape write byte | |
FC0E | C6 A3 | DEC $A3 | decrement tape write bit count | |
FC10 | A5 A3 | LDA $A3 | get tape write bit count | |
FC12 | F0 3A | BEQ $FC4E | if all the data bits have been written go setup for sending the parity bit next and exit the interrupt | |
FC14 | 10 F3 | BPL $FC09 | if all the data bits are not yet sent just restore the registers and exit the interrupt | |
This entry point is used by the routine at FC6A.
do next tape byte
the byte is complete. the start bit, data bits and parity bit have been written to the tape so setup for the next byte
|
||||
FC16 | 20 97 FB | JSR $FB97 | new tape byte setup | |
FC19 | 58 | CLI | enable the interrupts | |
FC1A | A5 A5 | LDA $A5 | get cassette synchronization character count | |
FC1C | F0 12 | BEQ $FC30 | if synchronisation characters done go do block data | |
at the start of each block sent to tape there are a number of synchronisation bytes that count down to the actual data. the commodore tape system saves two copies of all the tape data, the first is loaded and is indicated by the synchronisation bytes having b7 set, and the second copy is indicated by the synchronisation bytes having b7 clear. the sequence goes $09, $08, ..... $02, $01, data bytes
|
||||
FC1E | A2 00 | LDX #$00 | clear X | |
FC20 | 86 D7 | STX $D7 | clear checksum byte | |
FC22 | C6 A5 | DEC $A5 | decrement cassette synchronization byte count | |
FC24 | A6 BE | LDX $BE | get cassette copies count | |
FC26 | E0 02 | CPX #$02 | compare with load block indicator | |
FC28 | D0 02 | BNE $FC2C | branch if not the load block | |
FC2A | 09 80 | ORA #$80 | this is the load block so make the synchronisation count go $89, $88, ..... $82, $81 | |
FC2C | 85 BD | STA $BD | save the synchronisation byte as the tape write byte | |
FC2E | D0 D9 | BNE $FC09 | restore registers and exit interrupt, branch always | |
the synchronization bytes have been done so now check and do the actual block data
|
||||
FC30 | 20 D1 FC | JSR $FCD1 | check read/write pointer, return Cb = 1 if pointer >= end | |
FC33 | 90 0A | BCC $FC3F | if not all done yet go get the byte to send | |
FC35 | D0 91 | BNE $FBC8 | if pointer > end go flag block done and exit interrupt | |
else the block is complete, it only remains to write the checksum byte to the tape so setup for that
|
||||
FC37 | E6 AD | INC $AD | increment buffer pointer high byte, this means the block done branch will always be taken next time without having to worry about the low byte wrapping to zero | |
FC39 | A5 D7 | LDA $D7 | get checksum byte | |
FC3B | 85 BD | STA $BD | save checksum as tape write byte | |
FC3D | B0 CA | BCS $FC09 | restore registers and exit interrupt, branch always | |
the block isn't finished so get the next byte to write to tape
|
||||
FC3F | A0 00 | LDY #$00 | clear index | |
FC41 | B1 AC | LDA ($AC),Y | get byte from buffer | |
FC43 | 85 BD | STA $BD | save as tape write byte | |
FC45 | 45 D7 | EOR $D7 | XOR with checksum byte | |
FC47 | 85 D7 | STA $D7 | save new checksum byte | |
FC49 | 20 DB FC | JSR $FCDB | increment read/write pointer | |
FC4C | D0 BB | BNE $FC09 | restore registers and exit interrupt, branch always | |
set parity as next bit and exit interrupt
|
||||
FC4E | A5 9B | LDA $9B | get parity bit | |
FC50 | 49 01 | EOR #%00000001 | toggle it | |
FC52 | 85 BD | STA $BD | save as tape write byte | |
FC54 | 4C BC FE | JMP $FEBC | restore registers and exit interrupt | |
tape routine, block complete exit
|
||||
FC57 | C6 BE | DEC $BE | decrement copies remaining to read/write | |
FC59 | D0 03 | BNE $FC5E | branch if more to do | |
FC5B | 20 CA FC | JSR $FCCA | stop the cassette motor | |
FC5E | A9 50 | LDA #$50 | set tape write leader count | |
FC60 | 85 A7 | STA $A7 | save tape write leader count | |
FC62 | A2 08 | LDX #$08 | set index for write tape leader vector | |
FC64 | 78 | SEI | disable the interrupts | |
FC65 | 20 BD FC | JSR $FCBD | set the tape vector | |
FC68 | D0 EA | BNE $FC54 | restore registers and exit interrupt, branch always |
Prev: FBC8 | Up: Map | Next: FC6A |