Setup, Claim, and Reset ACIA; Cancel tape operation; Activate / deactivate RTS; Zero checksum; Copy filename; Motor on/off; Check file is open; Send data to second processor; Setup for cassette write - 280 bytes (1.7%)
- §1. beepAndCancelTapeOperation
- §2. cancelTapeOperationAndMotor
- §3. setupACIA
- §4. checkForEscapeFlag
- §5. claimSerialSystemForSequentialAccess
- §6. claimSerialSystemForLoadSave
- §7. resetACIA
- §8. activateRequestToSend
- §9. flipRelayOffAndOnThenSetToReadFromTape
- §10. incrementBlockNumbers
- §11. zeroChecksumAndFSFlag
- §12. setChecksumBytesToY
- §13. Copy zero terminated string to .filenameToSearchFor
- §14. zeroFileHandleAndMotorOn
- §15. storeFileHandleAndMotorOn
- §16. controlMotor
- §17. Check file is open
- §18. startSendToSecondProcessor
- §19. Check load address for destination
- §21. setupForCassetteWrite
§1. beepAndCancelTapeOperation.
.beepAndCancelTapeOperation = $fae8 JSR .shouldPrintMessage check if free to print message BEQ .cancelTapeOperationAndMotor LDA #.charBELL beep JSR .OSWRCH fall through...
§2. cancelTapeOperationAndMotor.
Cancel the tape operation: relinquish the Tube switch off the cassette motor reset ACIA
.cancelTapeOperationAndMotor = $faf2 LDA #$80 JSR .secondProcessorTransfer relinquish the Tube (NAUG Section 18.8, Page 339) LDX #0 JSR .controlMotor switch off motor .cancelTapeOperation = $fafc PHP save flags on stack SEI prevent IRQ interrupts LDA .serialULARegisterCopy get serial ULA control register setting STA .serialULAControlRegister write to serial ULA control register setting LDA #0 A=0 STA .rs423TimeoutCounter zero RS-423 timeout counter BEQ + ALWAYS branch
.setupACIA = $fb0a PHP save flags on stacksave flags + JSR .resetACIA reset the ACIA LDA .rs423ControlRegisterCopy get last setting of ACIA JMP .storeACIAAndPull set ACIA and OS Copy from A before exit
.checkForEscapeFlag = $fb14 PLP get back flags BIT .escapeFlag check bit 7 of ESCAPE flag BPL .waitForRS423ToTimeout if (ESCAPE flag not set) then branch RTS return (ESCAPE is pending)
§5. claimSerialSystemForSequentialAccess.
.claimSerialSystemForSequentialAccess = $fb1a LDA .tapeOptionsByte get cassette filing system options byte high nybble used for LOAD and SAVE operations low nybble used for sequential access See .tapeOptByteTable ASL } ASL } ASL } move low nybble into high nybble ASL } STA .tapeCurrentOptionsByte save current OPTions LDA .tapeSequentialAccessInterBlockGap get sequential block gap (>0) BNE .claimSerialSystem ALWAYS branch
§6. claimSerialSystemForLoadSave.
.claimSerialSystemForLoadSave = $fb27 LDA .tapeOptionsByte get cassette filing system options byte high nybble used for LOAD and SAVE operations low nybble used for sequential access See .tapeOptByteTable AND #%11110000 clear low nybble STA .tapeCurrentOptionsByte store as current OPTions LDA #6 set current interblock gap to 6/10ths of a second .claimSerialSystem = $fb2f STA .tapeInterBlockGap set current interblock gap wait for the RS-423 system to timeout, so that the cassette system can take over .waitForRS423ToTimeout = $fb31 CLI allow interrupts briefly PHP save flags on stack (with interrupts enabled) SEI disable interrupts BIT .rs423ReadyFlag BPL .checkForEscapeFlag if (RS-423 is busy) then branch (check escape flag and try again) LDA .rs423TimeoutCounter BMI .checkForEscapeFlag if (RS-423 has NOT timed out) then branch (check for escape flag and try again) LDA #1 } store RS-423 timeout counter with STA .rs423TimeoutCounter } one to indicate that cassette has } control of the ACIA 6850 JSR .resetACIA reset ACIA PLP get back flags (enabling interrupts) RTS
.resetACIA = $fb46 LDA #%00000011 A=3 (bits CR0 and CR1 set means 'master reset') BNE .storeAToACIARegister ALWAYS branch (to reset ACIA)
.activateRequestToSend = $fb4a LDA #%00110000 set current ACIA control register 8 bit word, 2 stop bits, RTS low (this is the active state), transmit interrupt enabled STA .tapeSendingFlag set non-zero value to indicate sending to tape BNE .setACIA6850ControlRegister ALWAYS branch
§9. flipRelayOffAndOnThenSetToReadFromTape.
.flipRelayOffAndOnThenSetToReadFromTape = $fb50 LDA #%00000101 set .serialULAControlRegister STA .serialULAControlRegister which sets transmit to 300 baud receive to 19200 baud tape system in use motor off LDX #$FF loop counter - DEX } delay loop BNE - } STX .tapeSendingFlag .tapeSendingFlag = 0 LDA #%10000101 transmit baud rate 300 baud receive to 19200 baud tape system in use motor on STA .serialULAControlRegister LDA #%11010000 A=%11010000 bit 7 - enable interrupts bit 6/5 - RTS high, transmit interrupt disabled bit 4/3/2 - 8 bit word, 2 stop bits bit 1/0 - divide counter by 1 .setACIA6850ControlRegister = $fb63 ORA .tapeBaudRate set bits for baud rate: 5 = %101 means 1200 baud (divide by 16; 1 stop bit) 6 = %110 means 300 baud (divide by 64; 1 stop bit) .storeAToACIARegister = $fb65 STA .acia6850ControlRegister set up ACIA control register RTS
.incrementBlockNumbers = $fb69 LDX .fsBlockNumberLow block number LDY .fsBlockNumberHigh block number high INX X=X+1 STX .currentBlockNumberLow current block number low BNE + INY Y=Y+1 + STY .currentBlockNumberHigh current block number high RTS
.zeroChecksumAndFSFlag = $fb78 LDY #0 STY .fsGotACharacterToReadOrWriteFlag clear 'just read character' flag fall through...
Set (zero) checksum bytes On Entry: Y = value to store (always zero in practice)
.setChecksumBytesToY = $fb7c STY .tapeChecksumLow STY .tapeChecksumHigh RTS
§13. Copy zero terminated string to .filenameToSearchFor.
On Entry: X is offset from $301 for source string
.copyToSoughtFilename = $fb81 LDY #$FF Y=$FF - INY Y=Y+1 INX X=X+1 LDA .vduVariablesStart,X STA .filenameToSearchFor,Y sought filename BNE - until end of filename (0) RTS
§14. zeroFileHandleAndMotorOn.
.zeroFileHandleAndMotorOn = $fb8e LDY #0 Y=0 fall through...
§15. storeFileHandleAndMotorOn.
.storeFileHandleAndMotorOn = $fb90 CLI enable interrupts LDX #1 X=1 (relay on) STY .tapeCurrentFileHandle store Y as current file handle fall through...
Control Tape Relay (On / Off) On Entry: X = 0 for relay off X = 1 for relay on
.controlMotor = $fb95 LDA #137 do OSBYTE 137 LDY .tapeCurrentFileHandle get back file handle (preserved through OSBYTE) JMP .OSBYTE turn on motor
On Entry: A = 1 means check file is open for reading (check bit 0 of tape status byte) A = 2 means check file is open for writing (check bit 1 of tape status byte) A = 3 means check file is open for reading or writing Y = file handle ('channel') On Exit: If file is not open then a 'Channel' error occurs
.checkFileIsOpen = $fb9c STA .fsTempStorage remember action type (1-3) TYA A=Y=channel: 1 = input file on tape 2 = output file on tape 3 = input file from ROMFS EOR .tapeOrROMSwitch EOR with filing system flag TAY Y=A now, Y = 1 for input Y = 2 for output LDA .fsStatusByte tape / ROM FS status byte AND .fsTempStorage file status or temporary store LSR set carry if open for input DEY Y = Y - 1 BEQ + if (checking open for input) then branch LSR set carry if open for output DEY Y = Y - 1 BNE .channelError if (not checking open for output) then branch + BCS .exit36 if (file is open as expected) then branch (exit) .channelError = $fbb1 BRK !byte $DE error number !text "Channel" message !byte 0 terminator
§18. startSendToSecondProcessor.
See NAUG Section 18.8, Page 340
.startSendToSecondProcessor = $fbbb LDA #1 A=1 (Multiple single byte transfer: main processor to second processor) .secondProcessorTransfer = $fbbd JSR .checkLoadAddressIsForSecondProcessor check if load address is valid BEQ .exit36 if (load address is for main processor) then branch (exit) TXA A=1 LDX #<.loadAddressLow } LDY #>.loadAddressLow } set up parameter block address .secondProcessorCall = $fbc7 PHA save A=1 on stack LDA #.tubeClaimReasonCode + .tubeCallerIDCassetteFS Claim the Tube, caller is the Cassette Filing System - JSR .tubeTransferData call out to Tube BCC - keep trying to claim until claim is done PLA pull A=1 (Multiple single byte transfer: main processor to second processor) JMP .tubeTransferData
§19. Check load address for destination.
Check the top two bytes of the 32 bit load address. If they are both $FF, then it is for the main processor and we return with Z set. If the Tube is not present, then we also return with Z set. Otherwise it's for the Tube, we return with Z clear. On Exit: Z set if load address is for the second processor X is value of A on entry
.checkLoadAddressIsForSecondProcessor = $fbd3 TAX X=A LDA .loadAddressMid2 current load address high word AND .loadAddressHigh current load address high word CMP #$FF BEQ + if ($FF, i.e. it's for base processor) then branch LDA .tubePresentFlag $FF if Tube is present AND #%10000000 Set bit 7 alone if Tube is present + RTS
This routine is actually a bugfix. Commented from the original source code: BUGFIX When the 6850 counter divide bits are reset, it is possible for the SERPROC to get out of synch. for a few bits. This has the effect of corrupting the first character of the first block of a SAVE, or the first character of ANY block during sequential access (since the 6850 is reset for every block during putbytes). The cure is to write a dummy byte to tape at the start of a SAVE, and at the start of every block during putbytes. This must be done by polling, since there must be a period of high-tone after the dummy byte, which is difficult to accomplish if the 6850 is interrupting all the time. BUGFIX is thus called after the SERPROC is set and before the 6850 is set to interrupt during a block write operation. ["SERPROC" refers to .serialULAControlRegister, and "BUGFIX" is this routine]
.setupForCassetteWrite = $fbe2 LDA #%10000101 } switch on the cassette motor and } relay STA .serialULAControlRegister } and set 300 baud JSR .resetACIA reset ACIA LDA #%00010000 } even parity } 2 stop bits } 8 bit word } 'Request To Send' ('RTS') low } (active) } disable interrupts JSR .setACIA6850ControlRegister set ACIA to tape filing system baud rate - JSR .checkForEscapeDuringCassetteOperation check for ESCAPE LDA .acia6850StatusRegister read ACIA status register AND #%00000010 check bit 1 (transmit interrupt generated) BEQ - if (bit 1 clear, i.e. transmit interrupt generated) then branch (loop back and try again) LDA #%10101010 A=$AA STA .acia6850DataRegister send byte to tape .exit36 = $fbfe RTS !byte 0 [unused]