ca65 V2.15 Main file : Acorn_201_606_ROM_ca65.txt Current file: Acorn_201_606_ROM_ca65.txt 000000r 1 000000r 1 ; Copied from http://stardot.org.uk/forums/viewtopic.php?t=8852$f=44 000000r 1 000000r 1 ; Has to have CRLF so it can be pasted into BeebEm 000000r 1 000000r 1 ; NB not all bytes are shown in listing for text messages 000000r 1 000000r 1 ; >Client/src 000000r 1 ; Source for 6502 Tube Client 000000r 1 ; As supplied with External 6502 Second Processor 000000r 1 ; Code copyright Acorn Computer 000000r 1 ; Commentary copyright J.G.Harston 000000r 1 000000r 1 ; IF PAGE>$8000 000000r 1 ; LOADATN OS_GetEnvTOA$ 000000r 1 ; IFLEFT$(A$,5)<>"B6502" 000000r 1 ; OSCLI"B6502"+MID$(A$,INSTR(A$," )) 000000r 1 ; 000000r 1 ; Uncomment the next line to get 000000r 1 ; the original source as a reference 000000r 1 000000r 1 ; reference_code 000000r 1 000000r 1 LF =$0A 000000r 1 CR =$0D 000000r 1 000000r 1 vector_table =$200 000000r 1 000000r 1 USERV =$200 000000r 1 BRKV =$202 000000r 1 IRQ1V =$204 000000r 1 IRQ2V =$206 000000r 1 CLIV =$208 000000r 1 BYTEV =$20A 000000r 1 WORDV =$20C 000000r 1 WRCHV =$20E 000000r 1 RDCHV =$210 000000r 1 FILEV =$212 000000r 1 ARGSV =$214 000000r 1 BGetV =$216 000000r 1 BPutV =$218 000000r 1 GBPBV =$21A 000000r 1 FINDV =$21C 000000r 1 FSCV =$21E 000000r 1 EVNTV =$220 000000r 1 UPTV =$222 000000r 1 NETV =$224 000000r 1 VduV =$226 000000r 1 KEYV =$228 000000r 1 INSV =$22A 000000r 1 RemV =$22C 000000r 1 CNPV =$22E 000000r 1 IND1V =$230 000000r 1 IND2V =$232 000000r 1 IND3V =$234 000000r 1 000000r 1 ERRBUF =$236 000000r 1 INPBUF =$236 000000r 1 000000r 1 vector_table_size = VECDEF-vector_table_defaults 000000r 1 000000r 1 ; Memory addresses 000000r 1 pointer_to_current_program =$EE ; $EE/F = PROG 0 Current program 000000r 1 hex_accumulator =$F0 ; $F0/1 = NUM 0 hex accumulator 000000r 1 pointer_to_top_of_memory =$F2 ; $F2/3 = MEMTOP 0 top of memory 000000r 1 address_of_byte_transfer_address =$F4 ; $F4/5 = address of byte transfer address, NMIAddr or ADDR 000000r 1 pointer_to_transfer =$F6 ; $F6/7 = ADDR 0 Data transfer address 000000r 1 string_pointer =$F8 ; $F8/9 = String pointer, OSWORD control block 000000r 1 pointer_at_FA =$FA ; $FA/B = CTRL 0 OSFILE, OSGBPB control block, PrText string pointer 000000r 1 IRQ_A_store =$FC ; $FC = IRQ A store 000000r 1 error_510_last_error =$FD ; $FD/E Err 510 last error 000000r 1 escape_flag =$FF ; $FF = Escape flag 000000r 1 000000r 1 000000r 1 ; Status register bits: 000000r 1 ; bit 7 - data available/IRQ 000000r 1 ; bit 6 - not full 000000r 1 ; 000000r 1 ; I/O Co-proc 000000r 1 ; addr addr 000000r 1 ; Register number 1 000000r 1 ; 000000r 1 ; &FEE0 &FEF8 status write/read (clears IRQ) 000000r 1 ; &FEE1 &FEF9 data 000000r 1 ; Parasite to Host: Carries the OSWRCH call. 000000r 1 ; Data register is a FIFO that can handle 000000r 1 ; a VDU command length (10 bytes). 000000r 1 ; Host to Parasite: There is a 1 byte buffer. 000000r 1 ; It is used to generate IRQ's in the parasite 000000r 1 ; from events in the host. 000000r 1 ; 000000r 1 ; Register number 2 000000r 1 ; 000000r 1 ; &FEE2 &FEFA status write/read 000000r 1 ; &FEE3 &FEFB data 000000r 1 ; Used to implement OS calls that take a long time 000000r 1 ; or that cannot interrupt Host tasks. 000000r 1 ; The parasite passes a byte describing the required task. 000000r 1 ; The two processors then exchange data until the task is complete. 000000r 1 ; OS calls handled through this register include: 000000r 1 ; OSRDCH, OSCLI, OSBYTE, OSWORD, OSBPUT, 000000r 1 ; OSBGET, OSFIND, OSARGS, OSFILE, OSGBPB. 000000r 1 ; 000000r 1 ; Register number 3 000000r 1 ; 000000r 1 ; &FEE4 &FEFC status write/read (clears IRQ) 000000r 1 ; &FEE5 &FEFD data available/NMI 000000r 1 ; Used for the background task of fast data transfer between the two processors. 000000r 1 ; 000000r 1 ; Register number 4 000000r 1 ; 000000r 1 ; &FEE6 &FEFE write (sets IRQ)/read (clears IRQ) 000000r 1 ; bit 7 - data available/IRQ 000000r 1 ; bit 6 - not full/IRQ 000000r 1 ; &FEE7 &FEFF data available/NMI 000000r 1 ; Used for the background task of fast data transfer between the two processors. 000000r 1 ; Used as the control channel for block transfers going through Register 3, 000000r 1 ; and also the transfer register for error strings from host to parasite. 000000r 1 ; In both cases, the host interrupts the parasite by placing a byte into the Register. 000000r 1 ; In the former case it is a byte describing the required action, 000000r 1 ; in the latter it is an error code. 000000r 1 ; 000000r 1 ; Tube macros use the BIT instruction to test the handshake flags. 000000r 1 ; The USB module FIFO can be made to look exactly 000000r 1 ; like a Tube FIFO, lucky for us! 000000r 1 ; USB_BASE+0 000000r 1 ; bit 7 = data available 000000r 1 ; bit 6 = not full 000000r 1 ; USB_BASE+1 000000r 1 ; bit 7 = 000000r 1 ; bit 6 = 000000r 1 ; The BIT instruction copies bits 7 and 6 to the flag register 000000r 1 ; The S and V flags are set to match bits 7 and 6 respectively in the value stored at the tested address. 000000r 1 ; So 000000r 1 ; BIT status 000000r 1 ; BPL branch_here_if_bit_7_is_0 ; no data available, so wait 000000r 1 ; BMI branch_here_if_bit_7_is_1 ; okay to read 000000r 1 ; BVC branch_here_if_bit_6_is_0 ; full, so wait 000000r 1 ; BVS branch_here_if_bit_6_is_1 ; okay to write 000000r 1 ; 000000r 1 ; In my VHDL code for the Atom, the bits are in the right position, 000000r 1 ; 000000r 1 ; -- cpu reads the usb status for handshaking 000000r 1 ; s_status_d(7) <= usb_rd_wait; 000000r 1 ; s_status_d(6) <= usb_wr_wait; 000000r 1 ; 000000r 1 ; # external USB module control signals 000000r 1 ; ############################################ 000000r 1 ; NET "usb_rd_wait" LOC = "P192"; # rxf 000000r 1 ; NET "usb_wr_wait" LOC = "P194"; # txe 000000r 1 ; NET "usb_n_rd_strobe" LOC = "P193"; # n_rd 000000r 1 ; NET "usb_wr_strobe" LOC = "P198"; # n_wr 000000r 1 ; 000000r 1 ; This is the module I have: 000000r 1 ; http://www.ftdichip.com/Support/Documents/DataSheets/DLP/dlp2232ml-v21-ds.pdf 000000r 1 ; using the FT2232 chip 000000r 1 ; http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232D.pdf 000000r 1 ; in "245 FIFO" mode, 000000r 1 ; pin 13 = TXE# so 1 = tx empty, okay to write (same sense as the tube?) 000000r 1 ; pin 15 = RXF# so 0 = rx full, data available 000000r 1 ; pins 000000r 1 ; A B 000000r 1 ; 15 30 RXF# OUTPUT When high, do not read data from the FIFO. 000000r 1 ; When low, there is data available in the FIFO 000000r 1 ; 13 29 TXE# OUTPUT When high, do not write data into the FIFO. 000000r 1 ; When low, data can be written into 000000r 1 ; 000000r 1 ; so these both work as "wait while high" 000000r 1 ; this is the opposite of the Tube, 000000r 1 ; so one can either modify the code 000000r 1 ; or use inverting buffers in hardware 000000r 1 ; 000000r 1 ; We can make the one USB FIFO look like all four Tube FIFOs 000000r 1 ; by just partially decoding the address, 000000r 1 ; i.e. it appears in four locations. 000000r 1 ; 000000r 1 ; Pimp BBC micro to 8 MHz? 000000r 1 ; 000000r 1 ; Idea for testing: 000000r 1 ; Use BBC micro as ready-wired 6502 system, 000000r 1 ; add USB module as a Tube! 000000r 1 ; Add socket for Flash ROM 000000r 1 ; 000000r 1 ; 000000r 1 000000r 1 .if 1 000000r 1 .include "Acorn_macros_for_6502.txt" 000000r 2 000000r 2 .macro pull_var16_via_A var 000000r 2 PLA 000000r 2 STA var 000000r 2 PLA 000000r 2 STA var+1 000000r 2 .endmacro 000000r 2 000000r 2 000000r 2 000000r 2 .macro inc16 addr 000000r 2 .local skip 000000r 2 inc addr 000000r 2 bne skip 000000r 2 inc addr+1 000000r 2 skip: 000000r 2 .endmacro 000000r 2 000000r 2 .macro load_ax arg 000000r 2 .if (.match (.left (1, {arg}), #)) 000000r 2 ; immediate mode 000000r 2 LDA #<(.right (.tcount ({arg})-1, {arg})) 000000r 2 LDX #>(.right (.tcount ({arg})-1, {arg})) 000000r 2 .else 000000r 2 ; assume absolute or zero page 000000r 2 LDA arg 000000r 2 LDX 1+(arg) 000000r 2 .endif 000000r 2 .endmacro 000000r 2 000000r 2 .macro load_xy arg 000000r 2 .if (.match (.left (1, {arg}), #)) 000000r 2 ; immediate mode 000000r 2 LDX #<(.right (.tcount ({arg})-1, {arg})) 000000r 2 LDY #>(.right (.tcount ({arg})-1, {arg})) 000000r 2 .else 000000r 2 ; assume absolute or zero page 000000r 2 LDX arg 000000r 2 LDY 1+(arg) 000000r 2 .endif 000000r 2 .endmacro 000000r 2 000000r 2 ; .macro load_xy value 000000r 2 ; LDX #value ; Y := bits 8 to 16 000000r 2 ; .endmacro 000000r 2 000000r 2 .macro load_vector_with_address_via_A address, value 000000r 2 LDA #value 000000r 2 STA address+1 000000r 2 .endmacro 000000r 2 000000r 2 .macro copy_word_from_src_to_dst_via_A src, dst 000000r 2 LDA src 000000r 2 STA dst 000000r 2 LDA src+1 000000r 2 STA dst+1 000000r 2 .endmacro 000000r 2 000000r 2 000000r 2 ; Tube macros use the BIT instruction to test the handshake flags. 000000r 2 ; The USB module FIFO can be made to look exactly 000000r 2 ; like a Tube FIFO, lucky for us! 000000r 2 ; USB_BASE+0 000000r 2 ; bit 7 = data available 000000r 2 ; bit 6 = not full 000000r 2 ; USB_BASE+1 000000r 2 ; bit 7 = 000000r 2 ; bit 6 = 000000r 2 ; The BIT instruction copies bits 7 and 6 to the flag register 000000r 2 ; The S and V flags are set to match bits 7 and 6 respectively in the value stored at the tested address. 000000r 2 ; So 000000r 2 ; BIT status 000000r 2 ; BPL branch_here_if_bit_7_is_0 ; no data available, so wait 000000r 2 ; BMI branch_here_if_bit_7_is_1 ; okay to read 000000r 2 ; BVC branch_here_if_bit_6_is_0 ; full, so wait 000000r 2 ; BVS branch_here_if_bit_6_is_1 ; okay to write 000000r 2 ; 000000r 2 ; In my VHDL code for the Atom, the bits are in the right position, 000000r 2 ; 000000r 2 ; -- cpu reads the usb status for handshaking 000000r 2 ; s_status_d(7) <= usb_rd_wait; 000000r 2 ; s_status_d(6) <= usb_wr_wait; 000000r 2 ; 000000r 2 ; # external USB module control signals 000000r 2 ; ############################################ 000000r 2 ; NET "usb_rd_wait" LOC = "P192"; # rxf 000000r 2 ; NET "usb_wr_wait" LOC = "P194"; # txe 000000r 2 ; NET "usb_n_rd_strobe" LOC = "P193"; # n_rd 000000r 2 ; NET "usb_wr_strobe" LOC = "P198"; # n_wr 000000r 2 ; 000000r 2 ; This is the module I have: 000000r 2 ; http://www.ftdichip.com/Support/Documents/DataSheets/DLP/dlp2232ml-v21-ds.pdf 000000r 2 ; using the FT2232 chip 000000r 2 ; http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232D.pdf 000000r 2 ; in "245 FIFO" mode, 000000r 2 ; pin 13 = TXE# so 1 = tx empty, okay to write (same sense as the tube?) 000000r 2 ; pin 15 = RXF# so 0 = rx full, data available 000000r 2 ; pins 000000r 2 ; A B 000000r 2 ; 15 30 RXF# OUTPUT When high, do not read data from the FIFO. 000000r 2 ; When low, there is data available in the FIFO 000000r 2 ; 13 29 TXE# OUTPUT When high, do not write data into the FIFO. 000000r 2 ; When low, data can be written into 000000r 2 ; 000000r 2 ; so these both work as "wait while high" 000000r 2 ; this is the opposite of the Tube, 000000r 2 ; so one can either modify the code 000000r 2 ; or use inverting buffers in hardware 000000r 2 ; 000000r 2 ; We can make the one USB FIFO look like all four Tube FIFOs 000000r 2 ; by just partially decoding the address, 000000r 2 ; i.e. it appears in four locations. 000000r 2 ; 000000r 2 ; Pimp BBC micro to 8 MHz? 000000r 2 ; 000000r 2 ; Idea for testing: 000000r 2 ; Use BBC micro as ready-wired 6502 system, 000000r 2 ; add USB module as a Tube! 000000r 2 ; Add socket for Flash ROM 000000r 2 ; 000000r 2 ; 000000r 2 ;============================= 000000r 2 ; 000000r 2 ; These macros hide the polarity of the status flags 000000r 2 ; 000000r 2 ; 000000r 2 .macro wait_to_write_FIFO n 000000r 2 .local wait 000000r 2 wait: 000000r 2 BIT TUBE_BASE+n*2-2 ; S = (n-1)*2 == n*2-2 000000r 2 BVC wait ; writing tests using BVC 000000r 2 .endmacro 000000r 2 000000r 2 .macro wait_to_read_FIFO n 000000r 2 .local wait 000000r 2 wait: 000000r 2 BIT TUBE_BASE+n*2-2 000000r 2 BPL wait ; reading tests using BPL 000000r 2 .endmacro 000000r 2 000000r 2 000000r 2 ;========================= 000000r 2 .macro STA_FIFO n 000000r 2 wait_to_write_FIFO n 000000r 2 STA TUBE_BASE+n*2-1 ; S = (n-1)*2 == n*2-2 000000r 2 .endmacro 000000r 2 000000r 2 .macro STX_FIFO n 000000r 2 wait_to_write_FIFO n 000000r 2 STX TUBE_BASE+n*2-1 000000r 2 .endmacro 000000r 2 000000r 2 .macro STY_FIFO n 000000r 2 wait_to_write_FIFO n 000000r 2 STY TUBE_BASE+n*2-1 000000r 2 .endmacro 000000r 2 000000r 2 000000r 2 000000r 2 .macro LDA_FIFO n 000000r 2 wait_to_read_FIFO n 000000r 2 LDA TUBE_BASE+n*2-1 000000r 2 .endmacro 000000r 2 000000r 2 .macro LDX_FIFO n 000000r 2 wait_to_read_FIFO n 000000r 2 LDX TUBE_BASE+n*2-1 000000r 2 .endmacro 000000r 2 000000r 2 .macro LDY_FIFO n 000000r 2 wait_to_read_FIFO n 000000r 2 LDY TUBE_BASE+n*2-1 000000r 2 .endmacro 000000r 2 000000r 2 000000r 1 .else 000000r 1 ;============================= 000000r 1 ; 000000r 1 ; These macros hide the polarity of the status flags 000000r 1 ; 000000r 1 ; 000000r 1 .macro wait_to_write_FIFO n 000000r 1 .local wait 000000r 1 wait: 000000r 1 BIT TUBE_BASE+n*2-2 ; S = (n-1)*2 == n*2-2 000000r 1 BVC wait ; writing tests using BVC 000000r 1 .endmacro 000000r 1 000000r 1 .macro wait_to_read_FIFO n 000000r 1 .local wait 000000r 1 wait: 000000r 1 BIT TUBE_BASE+n*2-2 000000r 1 BPL wait ; reading tests using BPL 000000r 1 .endmacro 000000r 1 000000r 1 000000r 1 ;========================= 000000r 1 .macro STA_FIFO n 000000r 1 wait_to_write_FIFO n 000000r 1 STA TUBE_BASE+n*2-1 ; S = (n-1)*2 == n*2-2 000000r 1 .endmacro 000000r 1 000000r 1 .macro STX_FIFO n 000000r 1 wait_to_write_FIFO n 000000r 1 STX TUBE_BASE+n*2-1 000000r 1 .endmacro 000000r 1 000000r 1 .macro STY_FIFO n 000000r 1 wait_to_write_FIFO n 000000r 1 STY TUBE_BASE+n*2-1 000000r 1 .endmacro 000000r 1 000000r 1 000000r 1 000000r 1 .macro LDA_FIFO n 000000r 1 wait_to_read_FIFO n 000000r 1 LDA TUBE_BASE+n*2-1 000000r 1 .endmacro 000000r 1 000000r 1 .macro LDX_FIFO n 000000r 1 wait_to_read_FIFO n 000000r 1 LDX TUBE_BASE+n*2-1 000000r 1 .endmacro 000000r 1 000000r 1 .macro LDY_FIFO n 000000r 1 wait_to_read_FIFO n 000000r 1 LDY TUBE_BASE+n*2-1 000000r 1 .endmacro 000000r 1 000000r 1 .endif 000000r 1 000000r 1 ; .enum command_codes 000000r 1 command_OSRDCH = $00 000000r 1 command_OSCLI = $02 000000r 1 command_OSBYTELO = $04 000000r 1 command_OSBYTEHI = $06 000000r 1 000000r 1 command_RDLINE = $0A 000000r 1 command_OSARGS = $0C 000000r 1 command_OSBGET = $0E 000000r 1 command_OSBPUT = $10 000000r 1 command_OSFIND = $12 000000r 1 command_OSFILE = $14 000000r 1 command_OSGBPB = $16 000000r 1 ; .endenum 000000r 1 000000r 1 000000r 1 .macro send_command_code code 000000r 1 LDA code 000000r 1 JSR SendCommand 000000r 1 .endmacro 000000r 1 000000r 1 000000r 1 000000r 1 ; 000000r 1 ; load% =$F800 000000r 1 .org $F800 ; actually the job of the linker 00F800 1 ; DIM mcode% $900 00F800 1 00F800 1 ; FOR P=0TO1 00F800 1 ; P%=load% 00F800 1 ; O%=mcode% 00F800 1 ; [OPT P*3+4 00F800 1 00F800 1 last_256_bytes = $FF00 00F800 1 last_4K_space = $F000 00F800 1 00F800 1 ROM_START: 00F800 1 00F800 1 RESET: 00F800 1 A2 00 LDX #0 ; Move 256 bytes 00F802 1 loop_F802: 00F802 1 BD 00 FF LDA last_256_bytes,X ; Read from ROM 00F805 1 9D 00 FF STA last_256_bytes,X ; Write to RAM 00F808 1 CA DEX 00F809 1 D0 F7 BNE loop_F802 00F80B 1 00F80B 1 ; 00F80B 1 A2 36 LDX #vector_table_size ; 00F80D 1 load_vector_table: 00F80D 1 BD 80 FF LDA vector_table_defaults,X 00F810 1 9D 00 02 STA vector_table,X ; Set up default vectors 00F813 1 CA DEX 00F814 1 10 F7 BPL load_vector_table 00F816 1 9A TXS ; Clear stack 00F817 1 ; 00F817 1 A2 F0 LDX #$F0 ; $FDFF+$F0 = $FEEF 00F819 1 loop_F819: 00F819 1 BD FF FD LDA $FDFF,X 00F81C 1 9D FF FD STA $FDFF,X ; Copy $FE00-$FEEF to RAM, avoiding 00F81F 1 CA DEX 00F820 1 D0 F7 BNE loop_F819 ; the Tube registers at $FEFx 00F822 1 ; 00F822 1 A0 00 LDY #RESET 00F828 1 85 F9 STA string_pointer+1 00F82A 1 ; 00F82A 1 ; loop_F82A: 00F82A 1 Copy_rest_of_ROM_to_RAM: ; Copy a page 00F82A 1 B1 F8 LDA (string_pointer),Y ; from ROM 00F82C 1 91 F8 STA (string_pointer),Y ; to RAM 00F82E 1 C8 INY 00F82F 1 D0 F9 BNE Copy_rest_of_ROM_to_RAM ; Loop for 256 bytes 00F831 1 ; 00F831 1 E6 F9 INC string_pointer+1 ; the high byte 00F833 1 A5 F9 LDA string_pointer+1 ; Inc. address high byte 00F835 1 C9 FE CMP #$FE 00F837 1 D0 F1 BNE Copy_rest_of_ROM_to_RAM ; Loop from $F800 to $FDFF 00F839 1 ; 00F839 1 A2 10 LDX #$10 00F83B 1 ; 00F83B 1 ; loop_F83B: 00F83B 1 Copy_jump_code_to_hex_0100: 00F83B 1 BD 59 F8 LDA code_for_post_ROM_copy,X 00F83E 1 9D 00 01 STA $0100,X ; Copy jump code to $100 00F841 1 CA DEX 00F842 1 10 F7 BPL Copy_jump_code_to_hex_0100 00F844 1 ; 00F844 1 A5 EE 85 F6 copy_word_from_src_to_dst_via_A pointer_to_current_program, pointer_to_transfer 00F848 1 A5 EF 85 F7 00F84C 1 00F84C 1 A9 00 LDA #$00 00F84E 1 85 FF STA escape_flag ; Clear Escape flag 00F850 1 85 F2 STA pointer_to_top_of_memory 00F852 1 A9 F8 LDA #$F8 00F854 1 85 F3 STA pointer_to_top_of_memory+1 ; Set memtop to start of ROM at $F800 00F856 1 4C 00 01 JMP $0100 ; Jump via low memory to page ROM out 00F859 1 00F859 1 ; Executed in low memory to page ROM out 00F859 1 ; -------------------------------------- 00F859 1 ; LF859: 00F859 1 code_for_post_ROM_copy: 00F859 1 AD F8 FE LDA TubeS1 ; Acessing the Tube disables the ROM 00F85C 1 58 CLI ; 00F85D 1 LF85D: 00F85D 1 4C 60 F8 JMP startup ; Jump to initialise I/O with banner 00F860 1 ; 00F860 1 vector_F85E = LF85D+1 00F860 1 ; 00F860 1 ; Warning: self-modifying code above! 00F860 1 ; 00F860 1 ; 00F860 1 00F860 1 ; LF860: 00F860 1 startup: 00F860 1 20 98 FE JSR PrText ; Display startup banner 00F863 1 0A .byte LF 00F864 1 41 63 6F 72 .byte "Acorn TUBE 6502 64K" 00F868 1 6E 20 54 55 00F86C 1 42 45 20 36 00F877 1 0A 0A 0D .byte LF, LF, CR 00F87A 1 00 .byte 0 00F87B 1 EA NOP 00F87C 1 00F87C 1 A9 8D 8D 5E load_vector_with_address_via_A vector_F85E, CmdOSLoop 00F880 1 F8 A9 F8 8D 00F884 1 5F F8 00F886 1 00F886 1 20 75 F9 JSR WaitByte ; Wait for Acknowledge 00F889 1 C9 80 CMP #$80 00F88B 1 F0 28 BEQ EnterCode ; If $80, jump to enter code 00F88D 1 ; Otherwise, enter command prompt loop 00F88D 1 00F88D 1 ; Minimal Command prompt 00F88D 1 ; Err 510 00F88D 1 CmdOSLoop: 00F88D 1 A9 2A LDA #'*' 00F88F 1 20 EE FF JSR OSWRCH ; Print '*' prompt 00F892 1 00F892 1 A2 5D A0 F9 load_xy #Control_block_for_command_prompt_input 00F896 1 00F896 1 A9 00 LDA #$00 00F898 1 20 F1 FF JSR OSWORD ; Read line to INPBUF 00F89B 1 B0 0A BCS CmdOSEscape 00F89D 1 00F89D 1 A2 36 A0 02 load_xy #INPBUF 00F8A1 1 00F8A1 1 20 F7 FF JSR OS_CLI 00F8A4 1 4C 8D F8 JMP CmdOSLoop ; and loop back for another 00F8A7 1 CmdOSEscape: 00F8A7 1 A9 7E LDA #$7E 00F8A9 1 20 F4 FF JSR OSBYTE ; Acknowledge Escape state 00F8AC 1 00 BRK 00F8AD 1 11 .byte 17 00F8AE 1 45 73 63 61 .byte "Escape" 00F8B2 1 70 65 00F8B4 1 00 BRK 00F8B5 1 00F8B5 1 00F8B5 1 ; Enter Code pointer to by $F6/7 00F8B5 1 ; Err 510 00F8B5 1 ; Checks to see if code has a ROM header, and verifies 00F8B5 1 ; it if it has 00F8B5 1 EnterCode: 00F8B5 1 A5 F6 LDA pointer_to_transfer 00F8B7 1 85 EE STA pointer_to_current_program 00F8B9 1 85 F2 STA pointer_to_top_of_memory ; Set current program and memtop 00F8BB 1 A5 F7 LDA pointer_to_transfer+1 00F8BD 1 85 EF STA pointer_to_current_program+1 00F8BF 1 85 F3 STA pointer_to_top_of_memory+1 ; to address being entered 00F8C1 1 A0 07 LDY #$07 00F8C3 1 B1 EE LDA (pointer_to_current_program),Y ; Get copyright offset 00F8C5 1 D8 CLD 00F8C6 1 18 CLC 00F8C7 1 65 EE ADC pointer_to_current_program 00F8C9 1 85 FD STA error_510_last_error 00F8CB 1 A9 00 LDA #$00 00F8CD 1 65 EF ADC pointer_to_current_program+1 00F8CF 1 85 FE STA error_510_last_error+1 ; $FD/E=>copyright message 00F8D1 1 ; 00F8D1 1 ; Now check for $00,"(C)" 00F8D1 1 A0 00 LDY #0 00F8D3 1 ; 00F8D3 1 B1 FD LDA (error_510_last_error),Y 00F8D5 1 D0 23 BNE no_copyright ; Jump if no initial $00 00F8D7 1 ; 00F8D7 1 C8 INY 00F8D8 1 B1 FD LDA (error_510_last_error),Y 00F8DA 1 C9 28 CMP #'(' 00F8DC 1 D0 1C BNE no_copyright ; Jump if no '(' 00F8DE 1 ; 00F8DE 1 C8 INY 00F8DF 1 B1 FD LDA (error_510_last_error),Y 00F8E1 1 C9 43 CMP #'C' 00F8E3 1 D0 15 BNE no_copyright ; Jump if no 'C' 00F8E5 1 ; 00F8E5 1 C8 INY 00F8E6 1 B1 FD LDA (error_510_last_error),Y 00F8E8 1 C9 29 CMP #')' 00F8EA 1 D0 0E BNE no_copyright ; Jump if no ')' 00F8EC 1 ; 00F8EC 1 ; $00,"(C)" exists 00F8EC 1 A0 06 LDY #$06 00F8EE 1 B1 EE LDA (pointer_to_current_program),Y ; Get ROM type 00F8F0 1 29 4F AND #$4F ; $4F == 01001111 00F8F2 1 C9 40 CMP #$40 00F8F4 1 90 09 BCC NotLanguage ; b6=0, not a language 00F8F6 1 ; 00F8F6 1 29 0D AND #$0D ; $0D == 00001101 00F8F8 1 D0 28 BNE Not6502Code ; type<>0 and <>2, not 6502 code 00F8FA 1 no_copyright: 00F8FA 1 A9 01 LDA #$01 00F8FC 1 6C F2 00 JMP (pointer_to_top_of_memory) ; Enter code with A=1 00F8FF 1 ; 00F8FF 1 ; Any existing error handler will probably have been overwritten 00F8FF 1 ; Set up new error handler before generating an error 00F8FF 1 NotLanguage: 00F8FF 1 00F8FF 1 A9 45 8D 02 load_vector_with_address_via_A BRKV, ErrorHandler ; Claim error handler 00F903 1 02 A9 F9 8D 00F907 1 03 02 00F909 1 00F909 1 00 BRK 00F90A 1 00 .byte 0 00F90B 1 54 68 69 73 .byte "This is not a language" 00F90F 1 20 69 73 20 00F913 1 6E 6F 74 20 00F921 1 00 .byte 0 00F922 1 00F922 1 Not6502Code: 00F922 1 A9 45 8D 02 load_vector_with_address_via_A BRKV, ErrorHandler ; Claim error handler 00F926 1 02 A9 F9 8D 00F92A 1 03 02 00F92C 1 00F92C 1 00 BRK 00F92D 1 00 .byte 0 00F92E 1 49 20 63 61 .byte "I cannot run this code" 00F932 1 6E 6E 6F 74 00F936 1 20 72 75 6E 00F944 1 00 .byte 0 00F945 1 00F945 1 ErrorHandler: 00F945 1 A2 FF LDX #$FF 00F947 1 9A TXS ; Clear stack 00F948 1 20 E7 FF JSR OSNEWL 00F94B 1 A0 01 LDY #$01 00F94D 1 loop_F94D: 00F94D 1 B1 FD LDA (error_510_last_error),Y 00F94F 1 F0 06 BEQ LF957 ; Print error string 00F951 1 20 EE FF JSR OSWRCH 00F954 1 C8 INY 00F955 1 D0 F6 BNE loop_F94D 00F957 1 LF957: 00F957 1 20 E7 FF JSR OSNEWL 00F95A 1 4C 8D F8 JMP CmdOSLoop ; Jump to command prompt 00F95D 1 00F95D 1 ; Control block for command prompt input 00F95D 1 ; -------------------------------------- 00F95D 1 LF95D: 00F95D 1 Control_block_for_command_prompt_input: 00F95D 1 36 02 .word INPBUF ; Input text to INPBUF at $236 00F95F 1 CA .byte $CA ; Up to $CA characters 00F960 1 20 .byte $20 ; Min =$20, 00F961 1 FF .byte $FF ; Max =$FF 00F962 1 00F962 1 00F962 1 ; MOS INTERFACE 00F962 1 ; Err 510 00F962 1 ; 00F962 1 ; 00F962 1 ; OSWRCH 0 Send character to output stream 00F962 1 ; Err 510 00F962 1 ; On entry, A 0 00F962 1 ; On exit, A #NAME? 00F962 1 ; 00F962 1 ; Tube data character -- 00F962 1 ; 00F962 1 osWRCH: 00F962 1 2C F8 FE BIT TubeS1 ; Read Tube R1 status 00F965 1 EA NOP ; is this delay needed? 00F966 1 50 FA BVC osWRCH ; Loop until b6 set 00F968 1 8D F9 FE STA TubeR1 00F96B 1 60 RTS ; Send character to Tube R1 00F96C 1 00F96C 1 00F96C 1 ; OSRDCH 0 Wait for character from input stream 00F96C 1 ; Err 510 00F96C 1 ; On exit, A Err 509 Cy=Escape flag 00F96C 1 ; 00F96C 1 ; Tube data $00 -- Carry Char 00F96C 1 ; 00F96C 1 osRDCH: 00F96C 1 A9 00 20 4A send_command_code #command_OSRDCH 00F970 1 FC 00F971 1 WaitCarryChar: 00F971 1 ; Wait for Carry and A 00F971 1 20 75 F9 JSR WaitByte 00F974 1 0A ASL A ; Wait for carry 00F975 1 00F975 1 WaitByte: 00F975 1 2C FA FE 10 LDA_FIFO 2 ; Fetch character 00F979 1 FB AD FB FE 00F97D 1 NullReturn: 00F97D 1 60 RTS 00F97E 1 00F97E 1 00F97E 1 ; Skip Spaces 00F97E 1 ; Err 510 00F97E 1 SkipSpaces1: 00F97E 1 C8 INY 00F97F 1 SkipSpaces: 00F97F 1 B1 F8 LDA (string_pointer),Y 00F981 1 C9 20 CMP #$20 00F983 1 F0 F9 BEQ SkipSpaces1 00F985 1 60 RTS 00F986 1 ; 00F986 1 ; Scan hex 00F986 1 ; Err 510 00F986 1 ScanHex: 00F986 1 A2 00 LDX #0 00F988 1 86 F0 STX hex_accumulator 00F98A 1 86 F1 STX hex_accumulator+1 ; Clear hex accumulator 00F98C 1 LF98C: 00F98C 1 B1 F8 LDA (string_pointer),Y ; Get current character 00F98E 1 C9 30 CMP #'0' 00F990 1 90 1F BCC LF9B1 ; <'0', exit 00F992 1 C5 3A CMP '9'+1 00F994 1 90 0A BCC LF9A0 ; '0'..'9', add to accumulator 00F996 1 29 DF AND #$DF 00F998 1 E9 07 SBC #7 00F99A 1 90 15 BCC LF9B1 ; Convert letter, if <'A', exit 00F99C 1 C9 40 CMP #$40 00F99E 1 B0 11 BCS LF9B1 ; >'F', exit 00F9A0 1 LF9A0: 00F9A0 1 0A ASL A 00F9A1 1 0A ASL A 00F9A2 1 0A ASL A 00F9A3 1 0A ASL A ; *16 00F9A4 1 A2 03 LDX #3 ; Prepare to move 3+1 bits 00F9A6 1 LF9A6: 00F9A6 1 0A ASL A 00F9A7 1 26 F0 ROL hex_accumulator 00F9A9 1 26 F1 ROL hex_accumulator+1 ; Move bits into accumulator 00F9AB 1 CA DEX 00F9AC 1 10 F8 BPL LF9A6 ; Loop for four bits, no overflow check 00F9AE 1 C8 INY 00F9AF 1 D0 DB BNE LF98C ; Move to next character 00F9B1 1 LF9B1: 00F9B1 1 60 RTS 00F9B2 1 00F9B2 1 00F9B2 1 ; Send string to Tube R2 00F9B2 1 ; Err 510 00F9B2 1 SendString: 00F9B2 1 86 F8 STX string_pointer 00F9B4 1 84 F9 STY string_pointer+1 ; Set $F8/9=>string 00F9B6 1 SendStringF8: 00F9B6 1 A0 00 LDY #0 00F9B8 1 00F9B8 1 00F9B8 1 00F9B8 1 00F9B8 1 loop_F9B8: 00F9B8 1 .if 1 00F9B8 1 2C FA FE 50 wait_to_write_FIFO 2 ; Wait for Tube R2 free 00F9BC 1 FB 00F9BD 1 B1 F8 LDA (string_pointer),Y 00F9BF 1 8D FB FE STA TubeR2 ; Send character to Tube R2 00F9C2 1 .else 00F9C2 1 00F9C2 1 LDA (string_pointer),Y ; alternatively, pre-fetch it? 00F9C2 1 STA_FIFO 2 00F9C2 1 .endif 00F9C2 1 C8 INY 00F9C3 1 C9 0D CMP #CR 00F9C5 1 D0 F1 BNE loop_F9B8 ; Loop until sent 00F9C7 1 A4 F9 LDY string_pointer+1 00F9C9 1 60 RTS ; Restore Y from string_pointer+1 and return 00F9CA 1 00F9CA 1 00F9CA 1 ; OSCLI 0 Execute command 00F9CA 1 ; Err 510 00F9CA 1 ; On entry, XY=>command string 00F9CA 1 ; On exit, XY= preserved 00F9CA 1 ; 00F9CA 1 osCLI: 00F9CA 1 48 PHA 00F9CB 1 86 F8 STX string_pointer 00F9CD 1 84 F9 STY string_pointer+1 ; Save A, $F8/9=>command string 00F9CF 1 A0 00 LDY #0 00F9D1 1 loop_F9D1: 00F9D1 1 20 7F F9 JSR SkipSpaces 00F9D4 1 C8 INY 00F9D5 1 C9 2A CMP #'*' 00F9D7 1 F0 F8 BEQ loop_F9D1 ; Skip spaces and stars 00F9D9 1 29 DF AND #$DF 00F9DB 1 AA TAX ; Ignore case, and save in X 00F9DC 1 B1 F8 LDA (string_pointer),Y ; Get next character 00F9DE 1 E0 47 CPX #'G' 00F9E0 1 F0 5C BEQ CmdGO ; Jump to check '*GO' 00F9E2 1 E0 48 CPX #'H' 00F9E4 1 D0 47 BNE osCLI_IO ; Not H---, jump to pass to Tube 00F9E6 1 C9 2E CMP #'.' 00F9E8 1 F0 2D BEQ CmdHELP ; H., jump to do *HELP 00F9EA 1 29 DF AND #$DF ; Ignore case 00F9EC 1 C9 45 CMP #'E' 00F9EE 1 D0 3D BNE osCLI_IO ; Not HE---, jump to pass to Tube 00F9F0 1 C8 INY 00F9F1 1 B1 F8 LDA (string_pointer),Y ; Get next character 00F9F3 1 C9 2E CMP #'.' 00F9F5 1 F0 20 BEQ CmdHELP ; HE., jump to do *HELP 00F9F7 1 29 DF AND #$DF ; Ignore case 00F9F9 1 C9 4C CMP #'L' 00F9FB 1 D0 30 BNE osCLI_IO ; Not HEL---, jump to pass to Tube 00F9FD 1 C8 INY 00F9FE 1 B1 F8 LDA (string_pointer),Y ; Get next character 00FA00 1 C9 2E CMP #'.' 00FA02 1 F0 13 BEQ CmdHELP ; HEL., jump to do *HELP 00FA04 1 29 DF AND #$DF ; Ignore case 00FA06 1 C9 50 CMP #'P' 00FA08 1 D0 23 BNE osCLI_IO ; Not HELP---, jump to pass to Tube 00FA0A 1 C8 INY 00FA0B 1 B1 F8 LDA (string_pointer),Y ; Get next character 00FA0D 1 29 DF AND #$DF ; Ignore case 00FA0F 1 C9 41 CMP #'A' 00FA11 1 90 04 BCC CmdHELP ; HELP terminated by non-letter, do *HELP 00FA13 1 C9 5B CMP #'[' 00FA15 1 90 16 BCC osCLI_IO ; HELP followed by letter, pass to Tube 00FA17 1 00FA17 1 ; *Help 0 Display help information 00FA17 1 ; -------------------------------- 00FA17 1 CmdHELP: 00FA17 1 20 98 FE JSR PrText ; Print help message 00FA1A 1 0A 0D .byte LF, CR 00FA1C 1 36 35 30 32 .byte "6502 TUBE 1.10" 00FA20 1 20 54 55 42 00FA24 1 45 20 31 2E 00FA2A 1 0A 0D .byte LF, CR 00FA2C 1 EA NOP ; Continue to pass '*HELP' command to Tube 00FA2D 1 00FA2D 1 00FA2D 1 ; OSCLI 0 Send command line to host 00FA2D 1 ; Err 510 00FA2D 1 ; On entry, $F8/9=>command string 00FA2D 1 ; 00FA2D 1 ; Tube data $02 string $0D -- $7F or $80 00FA2D 1 ; 00FA2D 1 osCLI_IO: 00FA2D 1 A9 02 20 4A send_command_code #command_OSCLI 00FA31 1 FC 00FA32 1 20 B6 F9 JSR SendStringF8 ; Send command string at $F8/9 00FA35 1 osCLI_Ack: 00FA35 1 20 75 F9 JSR WaitByte ; Wait for acknowledgement 00FA38 1 C9 80 CMP #$80 00FA3A 1 F0 20 BEQ LFA5C ; Jump if code to be entered 00FA3C 1 68 PLA 00FA3D 1 60 RTS ; Restore A and return 00FA3E 1 00FA3E 1 00FA3E 1 ; *GO 0 call machine code 00FA3E 1 ; ----------------------- 00FA3E 1 CmdGO: 00FA3E 1 29 DF AND #$DF ; Ignore case 00FA40 1 C9 4F CMP #'O' 00FA42 1 D0 E9 BNE osCLI_IO ; Not '*GO', jump to pass to Tube 00FA44 1 20 7E F9 JSR SkipSpaces1 ; Move past any spaces 00FA47 1 20 86 F9 JSR ScanHex 00FA4A 1 20 7F F9 JSR SkipSpaces ; Read hex value and move past spaces 00FA4D 1 C9 0D CMP #CR 00FA4F 1 D0 DC BNE osCLI_IO ; More parameters, pass to Tube to deal with 00FA51 1 8A TXA 00FA52 1 F0 08 BEQ LFA5C ; If no address given, jump to current program 00FA54 1 ; 00FA54 1 A5 F0 85 F6 copy_word_from_src_to_dst_via_A hex_accumulator, pointer_to_transfer 00FA58 1 A5 F1 85 F7 00FA5C 1 ; 00FA5C 1 00FA5C 1 LFA5C: 00FA5C 1 A5 EF LDA pointer_to_current_program+1 00FA5E 1 48 PHA 00FA5F 1 A5 EE LDA pointer_to_current_program 00FA61 1 48 PHA ; Save current program 00FA62 1 20 B5 F8 JSR EnterCode 00FA65 1 ; 00FA65 1 68 PLA 00FA66 1 85 EE STA pointer_to_current_program 00FA68 1 85 F2 STA pointer_to_top_of_memory ; Restore current program and 00FA6A 1 ; 00FA6A 1 68 PLA 00FA6B 1 85 EF STA pointer_to_current_program+1 00FA6D 1 85 F3 STA pointer_to_top_of_memory+1 ; set address top of memory to it 00FA6F 1 ; 00FA6F 1 68 PLA 00FA70 1 ; 00FA70 1 60 RTS 00FA71 1 00FA71 1 CheckAck: 00FA71 1 F0 C2 BEQ osCLI_Ack 00FA73 1 00FA73 1 00FA73 1 ; OSBYTE 0 Byte MOS functions 00FA73 1 ; Err 510 00FA73 1 ; On entry, A, X, Y=OSBYTE parameters 00FA73 1 ; On exit, A preserved 00FA73 1 ; If A<$80, X=returned value 00FA73 1 ; If A>$7F, X, Y, Carry=returned values 00FA73 1 ; 00FA73 1 osBYTE: 00FA73 1 C9 80 CMP #$80 00FA75 1 B0 25 BCS ByteHigh ; Jump for long OSBYTEs 00FA77 1 ; 00FA77 1 ; Tube data $04 X A -- X 00FA77 1 ; 00FA77 1 48 PHA 00FA78 1 .if 1 00FA78 1 A9 04 LDA #command_OSBYTELO ; Send command $04 0 OSBYTELO 00FA7A 1 2C FA FE 50 STA_FIFO 2 ;; inline code 00FA7E 1 FB 8D FB FE 00FA82 1 .else 00FA82 1 ; cannot use this, it calls SendCommand 00FA82 1 send_command_code #command_OSBYTELO 00FA82 1 .endif 00FA82 1 2C FA FE 50 STX_FIFO 2 00FA86 1 FB 8E FB FE 00FA8A 1 68 PLA ; Send single parameter 00FA8B 1 2C FA FE 50 STA_FIFO 2 ; Send function 00FA8F 1 FB 8D FB FE 00FA93 1 2C FA FE 10 LDX_FIFO 2 00FA97 1 FB AE FB FE 00FA9B 1 60 RTS ; Get return value 00FA9C 1 00FA9C 1 ByteHigh: 00FA9C 1 C9 82 CMP #$82 00FA9E 1 F0 5A BEQ Byte82 ; Read memory high word 00FAA0 1 C9 83 CMP #$83 00FAA2 1 F0 51 BEQ Byte83 ; Read bottom of memory 00FAA4 1 C9 84 CMP #$84 00FAA6 1 F0 48 BEQ Byte84 ; Read top of memory 00FAA8 1 ; 00FAA8 1 ; Tube data $06 X Y A -- Cy Y X 00FAA8 1 ; 00FAA8 1 48 PHA 00FAA9 1 A9 06 LDA #command_OSBYTEHI 00FAAB 1 2C FA FE 50 STA_FIFO 2 ; Send command $06 0 OSBYTEHI 00FAAF 1 FB 8D FB FE 00FAB3 1 2C FA FE 50 STX_FIFO 2 ; Send parameter 1 00FAB7 1 FB 8E FB FE 00FABB 1 2C FA FE 50 STY_FIFO 2 ; Send parameter 2 00FABF 1 FB 8C FB FE 00FAC3 1 68 PLA 00FAC4 1 2C FA FE 50 STA_FIFO 2 ; Send function 00FAC8 1 FB 8D FB FE 00FACC 1 C9 8E CMP #$8E 00FACE 1 F0 A1 BEQ CheckAck ; If select language, check to enter code 00FAD0 1 C9 9D CMP #$9D 00FAD2 1 F0 1B BEQ LFAEF ; Fast return with Fast BPUT 00FAD4 1 48 PHA ; Save function 00FAD5 1 2C FA FE 10 LDA_FIFO 2 00FAD9 1 FB AD FB FE 00FADD 1 0A ASL A 00FADE 1 68 PLA ; Get Carry 00FADF 1 .if 0 00FADF 1 wait_to_read_FIFO 2 00FADF 1 LDY TubeR2 ; Get return high byte 00FADF 1 wait_to_read_FIFO 2 00FADF 1 LDX TubeR2 ; Get return low byte 00FADF 1 .else 00FADF 1 2C FA FE 10 LDY_FIFO 2 ; Get return high byte 00FAE3 1 FB AC FB FE 00FAE7 1 2C FA FE 10 LDX_FIFO 2 ; Get return low byte 00FAEB 1 FB AE FB FE 00FAEF 1 .endif 00FAEF 1 LFAEF: 00FAEF 1 60 RTS 00FAF0 1 00FAF0 1 Byte84: 00FAF0 1 A6 F2 LDX pointer_to_top_of_memory 00FAF2 1 A4 F3 LDY pointer_to_top_of_memory+1 00FAF4 1 60 RTS ; Read top of memory from pointer_to_top_of_memory/3 00FAF5 1 Byte83: 00FAF5 1 A2 00 LDX #$00 00FAF7 1 A0 08 LDY #$08 00FAF9 1 60 RTS ; Read bottom of memory 00FAFA 1 Byte82: 00FAFA 1 A2 00 LDX #$00 00FAFC 1 A0 00 LDY #$00 00FAFE 1 60 RTS ; Return $0000 as memory high word 00FAFF 1 00FAFF 1 00FAFF 1 ; OSWORD 0 Various functions 00FAFF 1 ; Err 510 00FAFF 1 ; On entry, A 0 00FAFF 1 ; XY=>control block 00FAFF 1 ; 00FAFF 1 osWORD: 00FAFF 1 86 F8 STX string_pointer 00FB01 1 84 F9 STY string_pointer+1 ; $F8/9=>control block 00FB03 1 A8 TAY 00FB04 1 F0 71 BEQ RDLINE ; OSWORD 0, jump to read line 00FB06 1 48 PHA 00FB07 1 A0 08 LDY #$08 00FB09 1 2C FA FE 50 STY_FIFO 2 ; Send command $08 0 OSWORD 00FB0D 1 FB 8C FB FE 00FB11 1 2C FA FE 50 STA_FIFO 2 ; Send function 00FB15 1 FB 8D FB FE 00FB19 1 AA TAX 00FB1A 1 10 08 BPL WordSendLow ; Jump with functions<$80 00FB1C 1 A0 00 LDY #0 00FB1E 1 B1 F8 LDA (string_pointer),Y ; Get send block length from control block 00FB20 1 A8 TAY 00FB21 1 4C 2D FB JMP WordSend ; Jump to send control block 00FB24 1 00FB24 1 WordSendLow: 00FB24 1 BC BC FC LDY WordLengthsTx-1,X ; Get send block length from table 00FB27 1 E0 15 CPX #$15 00FB29 1 90 02 BCC WordSend ; Use this length for OSWORD 1 to $14 00FB2B 1 A0 10 LDY #$10 ; Send 16 bytes for OSWORD $15 to $7F 00FB2D 1 WordSend: 00FB2D 1 2C FA FE 50 STY_FIFO 2 ; Send send block length 00FB31 1 FB 8C FB FE 00FB35 1 88 DEY 00FB36 1 30 0D BMI nothing_to_send ; Zero or $81..$FF length, nothing to send 00FB38 1 00FB38 1 00FB38 1 loop_FB38: 00FB38 1 .if 1 00FB38 1 2C FA FE 50 wait_to_write_FIFO 2 00FB3C 1 FB 00FB3D 1 B1 F8 LDA (string_pointer),Y 00FB3F 1 8D FB FE STA TubeR2 ; Send byte from control block 00FB42 1 .else 00FB42 1 LDA (string_pointer),Y 00FB42 1 STA_FIFO 2 00FB42 1 .endif 00FB42 1 88 DEY 00FB43 1 10 F3 BPL loop_FB38 ; Loop for number to be sent 00FB45 1 LFB45: 00FB45 1 nothing_to_send: 00FB45 1 8A TXA 00FB46 1 10 08 BPL WordRecvLow ; Jump with functions < $80 00FB48 1 A0 01 LDY #$01 00FB4A 1 B1 F8 LDA (string_pointer),Y ; Get receive block length from control block 00FB4C 1 A8 TAY 00FB4D 1 4C 59 FB JMP WordRecv ; Jump to receive control block 00FB50 1 00FB50 1 WordRecvLow: 00FB50 1 BC D0 FC LDY WordLengthsRx-1,X ; Get receive length from table 00FB53 1 E0 15 CPX #$15 00FB55 1 90 02 BCC WordRecv ; Use this length for OSWORD 1 to $14 00FB57 1 A0 10 LDY #16 ; Receive 16 bytes for OSWORD $15 to $7F 00FB59 1 WordRecv: 00FB59 1 2C FA FE 50 STY_FIFO 2 ; Send receive block length 00FB5D 1 FB 8C FB FE 00FB61 1 88 DEY 00FB62 1 30 0D BMI LFB71 ; Zero of $81..$FF length, nothing to receive 00FB64 1 loop_FB64: 00FB64 1 2C FA FE 10 LDA_FIFO 2 00FB68 1 FB AD FB FE 00FB6C 1 91 F8 STA (string_pointer),Y ; Get byte to control block 00FB6E 1 88 DEY 00FB6F 1 10 F3 BPL loop_FB64 ; Loop for number to receive 00FB71 1 LFB71: 00FB71 1 A4 F9 LDY string_pointer+1 00FB73 1 A6 F8 LDX string_pointer 00FB75 1 68 PLA ; Restore registers 00FB76 1 60 RTS 00FB77 1 00FB77 1 00FB77 1 ; RDLINE 0 Read a line of text 00FB77 1 ; Err 510 00FB77 1 ; On entry, A 0 00FB77 1 ; XY=>control block 00FB77 1 ; On exit, A #NAME? 00FB77 1 ; Y for of returned string 00FB77 1 ; Cy=0 ok, Cy=1 Escape 00FB77 1 ; 00FB77 1 ; Tube data $0A block -- $FF or $7F string CR 00FB77 1 ; 00FB77 1 RDLINE: 00FB77 1 A9 0A 20 4A send_command_code #command_RDLINE 00FB7B 1 FC 00FB7C 1 A0 04 LDY #4 00FB7E 1 loop_FB7E: 00FB7E 1 .if 1 00FB7E 1 2C FA FE 50 wait_to_write_FIFO 2 00FB82 1 FB 00FB83 1 B1 F8 LDA (string_pointer),Y 00FB85 1 8D FB FE STA TubeR2 ; Send control block 00FB88 1 .else 00FB88 1 LDA (string_pointer),Y ; alternatively prefetch? 00FB88 1 STA_FIFO 2 00FB88 1 .endif 00FB88 1 88 DEY 00FB89 1 C0 01 CPY #$01 00FB8B 1 D0 F1 BNE loop_FB7E ; Loop for 4, 3, 2 00FB8D 1 A9 07 LDA #$07 00FB8F 1 20 4A FC JSR SendByte ; Send $07 as address high byte 00FB92 1 B1 F8 LDA (string_pointer),Y 00FB94 1 48 PHA ; Get text buffer address high byte 00FB95 1 88 DEY 00FB96 1 ; 00FB96 1 2C FA FE 50 STY_FIFO 2 ; Send $00 as address low byte 00FB9A 1 FB 8C FB FE 00FB9E 1 B1 F8 LDA (string_pointer),Y 00FBA0 1 48 PHA ; Get text buffer address low byte 00FBA1 1 A2 FF LDX #$FF 00FBA3 1 20 75 F9 JSR WaitByte ; Wait for response 00FBA6 1 C9 80 CMP #$80 00FBA8 1 B0 1D BCS RdLineEscape ; Jump if Escape returned 00FBAA 1 .if 0 00FBAA 1 PLA 00FBAA 1 STA string_pointer 00FBAA 1 PLA 00FBAA 1 STA string_pointer+1 ; Set $F8/9=>text buffer 00FBAA 1 .else 00FBAA 1 68 85 F8 68 pull_var16_via_A string_pointer 00FBAE 1 85 F9 00FBB0 1 .endif 00FBB0 1 A0 00 LDY #0 00FBB2 1 loop_RdLine: 00FBB2 1 2C FA FE 10 LDA_FIFO 2 00FBB6 1 FB AD FB FE 00FBBA 1 91 F8 STA (string_pointer),Y ; Store returned character 00FBBC 1 C8 INY 00FBBD 1 C9 0D CMP #CR 00FBBF 1 D0 F1 BNE loop_RdLine ; Loop until 00FBC1 1 A9 00 LDA #$00 00FBC3 1 88 DEY 00FBC4 1 18 CLC 00FBC5 1 E8 INX ; Return A=0, Y=len, X=00, Cy=0 00FBC6 1 60 RTS 00FBC7 1 00FBC7 1 RdLineEscape: 00FBC7 1 68 PLA 00FBC8 1 68 PLA 00FBC9 1 A9 00 LDA #$00 ; Return A=0, Y=len, X=FF, Cy=1 00FBCB 1 60 RTS 00FBCC 1 00FBCC 1 00FBCC 1 ; OSARGS 0 Read info on open file 00FBCC 1 ; Err 510 00FBCC 1 ; On entry, A 0 00FBCC 1 ; X Err 510 word in zero page 00FBCC 1 ; Y #NAME? 00FBCC 1 ; On exit, A #REF! value 00FBCC 1 ; X preserved 00FBCC 1 ; Y preserved 00FBCC 1 ; 00FBCC 1 ; Tube data $0C handle block function -- result block 00FBCC 1 ; 00FBCC 1 osARGS: 00FBCC 1 48 PHA 00FBCD 1 A9 0C 20 4A send_command_code #command_OSARGS 00FBD1 1 FC 00FBD2 1 ; 00FBD2 1 2C FA FE 50 STY_FIFO 2 ; Send handle 00FBD6 1 FB 8C FB FE 00FBDA 1 B5 03 LDA $03,X 00FBDC 1 00FBDC 1 20 4A FC JSR SendByte ; Send data word 00FBDF 1 B5 02 LDA $02,X 00FBE1 1 20 4A FC JSR SendByte 00FBE4 1 B5 01 LDA $01,X 00FBE6 1 20 4A FC JSR SendByte 00FBE9 1 B5 00 LDA $00,X 00FBEB 1 20 4A FC JSR SendByte 00FBEE 1 68 PLA 00FBEF 1 20 4A FC JSR SendByte ; Send function 00FBF2 1 20 75 F9 JSR WaitByte 00FBF5 1 48 PHA ; Get and save result 00FBF6 1 20 75 F9 JSR WaitByte 00FBF9 1 95 03 STA $03,X ; Receive data word 00FBFB 1 20 75 F9 JSR WaitByte 00FBFE 1 95 02 STA $02,X 00FC00 1 20 75 F9 JSR WaitByte 00FC03 1 95 01 STA $01,X 00FC05 1 20 75 F9 JSR WaitByte 00FC08 1 95 00 STA $00,X 00FC0A 1 68 PLA 00FC0B 1 60 RTS ; Get result back and return 00FC0C 1 00FC0C 1 00FC0C 1 ; OSFIND 0 Open of Close a file 00FC0C 1 ; Err 510 00FC0C 1 ; On entry, A #REF! 00FC0C 1 ; Y 0 or XY=>filename 00FC0C 1 ; On exit, A 0 or handle 00FC0C 1 ; 00FC0C 1 ; Tube data $12 function string $0D -- handle 00FC0C 1 ; $12 $00 handle -- $7F 00FC0C 1 ; 00FC0C 1 osFIND: 00FC0C 1 48 PHA 00FC0D 1 A9 12 20 4A send_command_code #command_OSFIND 00FC11 1 FC 00FC12 1 68 PLA 00FC13 1 20 4A FC JSR SendByte ; Send function 00FC16 1 C9 00 CMP #$00 00FC18 1 D0 0A BNE OPEN ; If <>0, jump to do OPEN 00FC1A 1 48 PHA 00FC1B 1 98 TYA 00FC1C 1 20 4A FC JSR SendByte ; Send handle 00FC1F 1 20 75 F9 JSR WaitByte 00FC22 1 68 PLA 00FC23 1 60 RTS ; Wait for acknowledge, restore regs and return 00FC24 1 OPEN: 00FC24 1 20 B2 F9 JSR SendString ; Send pathname 00FC27 1 4C 75 F9 JMP WaitByte ; Wait for and return handle 00FC2A 1 00FC2A 1 00FC2A 1 ; OSBGet 0 Get a byte from open file 00FC2A 1 ; Err 510 00FC2A 1 ; On entry, H #REF! 00FC2A 1 ; On exit, A #REF! Read 00FC2A 1 ; H 0 00FC2A 1 ; Cy set if EOF 00FC2A 1 ; 00FC2A 1 ; Tube data $0E handle -- Carry byte 00FC2A 1 ; 00FC2A 1 osBGET: 00FC2A 1 A9 0E 20 4A send_command_code #command_OSBGET 00FC2E 1 FC 00FC2F 1 98 TYA 00FC30 1 20 4A FC JSR SendByte ; Send handle 00FC33 1 4C 71 F9 JMP WaitCarryChar ; Jump to wait for Carry and byte 00FC36 1 00FC36 1 00FC36 1 ; OSBPut 0 Put a byte to an open file 00FC36 1 ; Err 510 00FC36 1 ; On entry, A A to write 00FC36 1 ; Y 0 00FC36 1 ; On exit, A #REF! 00FC36 1 ; Y 0 00FC36 1 ; 00FC36 1 ; Tube data $10 handle byte -- $7F 00FC36 1 ; 00FC36 1 osBPUT: 00FC36 1 48 PHA 00FC37 1 A9 10 20 4A send_command_code #command_OSBPUT 00FC3B 1 FC 00FC3C 1 98 TYA 00FC3D 1 20 4A FC JSR SendByte ; Send handle 00FC40 1 68 PLA 00FC41 1 20 4A FC JSR SendByte ; Send byte 00FC44 1 48 PHA 00FC45 1 20 75 F9 JSR WaitByte 00FC48 1 68 PLA 00FC49 1 60 RTS ; Wait for acknowledge and return 00FC4A 1 00FC4A 1 00FC4A 1 ; Send a byte to Tube R2 00FC4A 1 ; Err 510 00FC4A 1 SendCommand: 00FC4A 1 SendByte: 00FC4A 1 2C FA FE 50 STA_FIFO 2 00FC4E 1 FB 8D FB FE 00FC52 1 60 RTS 00FC53 1 00FC53 1 00FC53 1 ; OSFILE 0 Operate on whole files 00FC53 1 ; Err 510 00FC53 1 ; On entry, A #REF! 00FC53 1 ; XY=>control block 00FC53 1 ; On exit, A 0 00FC53 1 ; control block updated 00FC53 1 ; 00FC53 1 ; Tube data $14 block string function -- result block 00FC53 1 ; 00FC53 1 osFILE: 00FC53 1 84 FB STY pointer_at_FA+1 00FC55 1 86 FA STX pointer_at_FA ; $FA/B=>control block 00FC57 1 48 PHA 00FC58 1 A9 14 20 4A send_command_code #command_OSFILE 00FC5C 1 FC 00FC5D 1 A0 11 LDY #$11 00FC5F 1 loop_FC5F: 00FC5F 1 B1 FA LDA (pointer_at_FA),Y 00FC61 1 20 4A FC JSR SendByte ; Send control block 00FC64 1 88 DEY 00FC65 1 C0 01 CPY #$01 00FC67 1 D0 F6 BNE loop_FC5F ; Loop for $11..$02 00FC69 1 88 DEY 00FC6A 1 B1 FA LDA (pointer_at_FA),Y 00FC6C 1 AA TAX 00FC6D 1 C8 INY 00FC6E 1 B1 FA LDA (pointer_at_FA),Y 00FC70 1 A8 TAY ; Get pathname address to XY 00FC71 1 20 B2 F9 JSR SendString ; Send pathname 00FC74 1 68 PLA 00FC75 1 20 4A FC JSR SendByte ; Send function 00FC78 1 20 75 F9 JSR WaitByte 00FC7B 1 48 PHA ; Wait for result 00FC7C 1 A0 11 LDY #$11 00FC7E 1 loop_FC7E: 00FC7E 1 20 75 F9 JSR WaitByte 00FC81 1 91 FA STA (pointer_at_FA),Y ; Get control block back 00FC83 1 88 DEY 00FC84 1 C0 01 CPY #$01 00FC86 1 D0 F6 BNE loop_FC7E ; Loop for $11..$02 00FC88 1 A4 FB LDY pointer_at_FA+1 00FC8A 1 A6 FA LDX pointer_at_FA ; Restore registers 00FC8C 1 68 PLA 00FC8D 1 60 RTS ; Get result and return 00FC8E 1 00FC8E 1 00FC8E 1 ; OSGBPB 0 Multiple byte Read and write 00FC8E 1 ; Err 510 00FC8E 1 ; On entry, A #REF! 00FC8E 1 ; XY=>control block 00FC8E 1 ; On exit, A #REF! value 00FC8E 1 ; control block updated 00FC8E 1 ; 00FC8E 1 ; Tube data $16 block function -- block Carry result 00FC8E 1 ; 00FC8E 1 osGBPB: 00FC8E 1 84 FB STY pointer_at_FA+1 00FC90 1 86 FA STX pointer_at_FA ; $FA/B=>control block 00FC92 1 48 PHA 00FC93 1 A9 16 20 4A send_command_code #command_OSGBPB 00FC97 1 FC 00FC98 1 A0 0C LDY #$0C 00FC9A 1 loop_FC9A: 00FC9A 1 B1 FA LDA (pointer_at_FA),Y 00FC9C 1 20 4A FC JSR SendByte ; Send control block 00FC9F 1 88 DEY 00FCA0 1 10 F8 BPL loop_FC9A ; Loop for $0C..$00 00FCA2 1 68 PLA 00FCA3 1 20 4A FC JSR SendByte ; Send function 00FCA6 1 A0 0C LDY #$0C 00FCA8 1 loop_FCA8: 00FCA8 1 20 75 F9 JSR WaitByte 00FCAB 1 91 FA STA (pointer_at_FA),Y ; Get control block back 00FCAD 1 88 DEY 00FCAE 1 10 F8 BPL loop_FCA8 ; Loop for $0C..$00 00FCB0 1 A4 FB LDY pointer_at_FA+1 00FCB2 1 A6 FA LDX pointer_at_FA ; Restore registers 00FCB4 1 4C 71 F9 JMP WaitCarryChar ; Jump to get Carry and result 00FCB7 1 00FCB7 1 00FCB7 1 Unsupported: 00FCB7 1 00 BRK 00FCB8 1 FF .byte 255 00FCB9 1 42 61 64 .byte "Bad" 00FCBC 1 00 .byte 0 00FCBD 1 00FCBD 1 00FCBD 1 ; OSWORD control block lengths 00FCBD 1 ; Err 510 00FCBD 1 WordLengthsTx: 00FCBD 1 00 .byte $00 00FCBE 1 05 .byte $05 00FCBF 1 00 .byte $00 00FCC0 1 05 .byte $05 00FCC1 1 02 .byte $02 00FCC2 1 05 .byte $05 00FCC3 1 08 .byte $08 00FCC4 1 0E .byte $0E 00FCC5 1 04 .byte $04 00FCC6 1 01 .byte $01 00FCC7 1 01 .byte $01 00FCC8 1 05 .byte $05 00FCC9 1 00 .byte $00 00FCCA 1 01 .byte $01 00FCCB 1 20 .byte $20 00FCCC 1 10 .byte $10 00FCCD 1 0D .byte $0D 00FCCE 1 00 .byte $00 00FCCF 1 04 .byte $04 00FCD0 1 80 .byte $80 00FCD1 1 WordLengthsRx: 00FCD1 1 05 .byte $05 00FCD2 1 00 .byte $00 00FCD3 1 05 .byte $05 00FCD4 1 00 .byte $00 00FCD5 1 05 .byte $05 00FCD6 1 00 .byte $00 00FCD7 1 00 .byte $00 00FCD8 1 00 .byte $00 00FCD9 1 05 .byte $05 00FCDA 1 09 .byte $09 00FCDB 1 05 .byte $05 00FCDC 1 00 .byte $00 00FCDD 1 08 .byte $08 00FCDE 1 18 .byte $18 00FCDF 1 00 .byte $00 00FCE0 1 01 .byte $01 00FCE1 1 0D .byte $0D 00FCE2 1 80 .byte $80 00FCE3 1 04 .byte $04 00FCE4 1 80 .byte $80 00FCE5 1 00FCE5 1 ; Interrupt Handler 00FCE5 1 ; Err 510 00FCE5 1 InterruptHandler: 00FCE5 1 85 FC STA $FC 00FCE7 1 68 PLA 00FCE8 1 48 PHA ; Save A, get flags from stack 00FCE9 1 29 10 AND #$10 00FCEB 1 D0 10 BNE BRKHandler ; If BRK, jump to BRK handler 00FCED 1 6C 04 02 JMP (IRQ1V) ; Continue via IRQ1V handler 00FCF0 1 00FCF0 1 IRQ1Handler: 00FCF0 1 2C FE FE BIT TubeS4 00FCF3 1 30 4A BMI LFD3F ; If data in Tube R4, jump to process errors and transferes 00FCF5 1 2C F8 FE BIT TubeS1 00FCF8 1 30 1E BMI LFD18 ; If data in Tube R1, jump to process Escape and Events 00FCFA 1 6C 06 02 JMP (IRQ2V) ; Pass on to IRQ2V 00FCFD 1 00FCFD 1 BRKHandler: 00FCFD 1 8A TXA 00FCFE 1 48 PHA ; Save X 00FCFF 1 BA TSX 00FD00 1 BD 03 01 LDA $0103,X ; Get address from stack 00FD03 1 D8 CLD 00FD04 1 38 SEC 00FD05 1 E9 01 SBC #$01 00FD07 1 85 FD STA error_510_last_error 00FD09 1 BD 04 01 LDA $0104,X 00FD0C 1 E9 00 SBC #$00 00FD0E 1 85 FE STA error_510_last_error+1 ; $FD/E=>after BRK opcode 00FD10 1 68 PLA 00FD11 1 AA TAX 00FD12 1 A5 FC LDA $FC ; Restore X, get saved A 00FD14 1 58 CLI 00FD15 1 6C 02 02 JMP (BRKV) ; Restore IRQs, jump to Error Handler 00FD18 1 00FD18 1 00FD18 1 ; Interrupt generated by data in Tube R1 00FD18 1 ; -------------------------------------- 00FD18 1 LFD18: 00FD18 1 AD F9 FE LDA TubeR1 00FD1B 1 30 1C BMI LFD39 ; b7=1, jump to set Escape state 00FD1D 1 98 TYA 00FD1E 1 48 PHA 00FD1F 1 8A TXA 00FD20 1 48 PHA ; Save registers 00FD21 1 00FD21 1 20 80 FE JSR get_A_from_FIFO_1 00FD24 1 A8 TAY ; Get Y parameter from Tube R1 00FD25 1 20 80 FE JSR get_A_from_FIFO_1 00FD28 1 AA TAX ; Get X parameter from Tube R1 00FD29 1 20 80 FE JSR get_A_from_FIFO_1 ; Get event number from Tube R1 00FD2C 1 00FD2C 1 20 36 FD JSR LFD36 00FD2F 1 68 PLA 00FD30 1 AA TAX 00FD31 1 68 PLA 00FD32 1 A8 TAY ; Dispatch event, restore registers 00FD33 1 A5 FC LDA $FC 00FD35 1 40 RTI ; Restore A, return from interrupt 00FD36 1 LFD36: 00FD36 1 6C 20 02 JMP (EVNTV) 00FD39 1 LFD39: 00FD39 1 0A ASL A 00FD3A 1 85 FF STA $FF ; Set Escape flag from b6 00FD3C 1 A5 FC LDA $FC 00FD3E 1 40 RTI ; Restore A, return from interrupt 00FD3F 1 00FD3F 1 00FD3F 1 ; Interrupt generated by data in Tube R4 00FD3F 1 ; -------------------------------------- 00FD3F 1 LFD3F: 00FD3F 1 AD FF FE LDA TubeR4 00FD42 1 10 21 BPL LFD65 ; b7=0, jump for data transfer 00FD44 1 58 CLI 00FD45 1 ;; loop_FD45: 00FD45 1 2C FA FE 10 LDA_FIFO 2 ;; is this getting a dummy byte? 00FD49 1 FB AD FB FE 00FD4D 1 ; 00FD4D 1 A9 00 LDA #0 ;; A is cleared and stored immediately 00FD4F 1 8D 36 02 STA ERRBUF 00FD52 1 A8 TAY ; Store BRK opcode in error buffer 00FD53 1 20 75 F9 JSR WaitByte 00FD56 1 8D 37 02 STA ERRBUF+1 ; Get error number 00FD59 1 ; 00FD59 1 loop_FD59: 00FD59 1 C8 INY 00FD5A 1 20 75 F9 JSR WaitByte ; Store bytes fetched from Tube R2 00FD5D 1 99 37 02 STA ERRBUF+1,Y 00FD60 1 D0 F7 BNE loop_FD59 ; Loop until final zero 00FD62 1 4C 36 02 JMP ERRBUF ; Jump to error block to generate error 00FD65 1 00FD65 1 ; Data transfer initiated by IRQ via Tube R4 00FD65 1 ; ------------------------------------------ 00FD65 1 LFD65: 00FD65 1 8D FA FF STA NMIV+0 00FD68 1 98 TYA 00FD69 1 48 PHA ; Save transfer type, save Y 00FD6A 1 AC FA FF LDY NMIV+0 ; Get transfer type back 00FD6D 1 00FD6D 1 B9 70 FE LDA LFE70,Y 00FD70 1 8D FA FF STA NMIV+0 ; get NMI routine address from table 00FD73 1 B9 78 FE LDA LFE78,Y 00FD76 1 8D FB FF STA NMIV+1 ; and point NMIV to it 00FD79 1 00FD79 1 B9 60 FE LDA LFE60,Y 00FD7C 1 85 F4 STA address_of_byte_transfer_address ; Point $F4/5 to transfer address field 00FD7E 1 B9 68 FE LDA LFE68,Y 00FD81 1 85 F5 STA address_of_byte_transfer_address+1 00FD83 1 ; 00FD83 1 2C FE FE 10 LDA_FIFO 4 ; Get called ID from Tube R4 00FD87 1 FB AD FF FE 00FD8B 1 ; 00FD8B 1 C0 05 CPY #$05 00FD8D 1 F0 58 BEQ exit_FDE7 ; If 'TubeRelease', jump to exit 00FD8F 1 98 TYA 00FD90 1 48 PHA 00FD91 1 A0 01 LDY #$01 ; Save transfer type 00FD93 1 ; 00FD93 1 2C FE FE 10 LDA_FIFO 4 ; Fetch and disgard address byte 4 00FD97 1 FB AD FF FE 00FD9B 1 2C FE FE 10 LDA_FIFO 4 ; Fetch and disgard address byte 3 00FD9F 1 FB AD FF FE 00FDA3 1 ; 00FDA3 1 2C FE FE 10 LDA_FIFO 4 ; Fetch address byte 2, 00FDA7 1 FB AD FF FE 00FDAB 1 91 F4 STA (address_of_byte_transfer_address),Y ; and store in address 00FDAD 1 88 DEY 00FDAE 1 00FDAE 1 2C FE FE 10 LDA_FIFO 4 00FDB2 1 FB AD FF FE 00FDB6 1 91 F4 STA (address_of_byte_transfer_address),Y ; Fetch address byte 1, store in address 00FDB8 1 00FDB8 1 2C FD FE BIT TubeR3 ;; This tests the bits of the data register 00FDBB 1 2C FD FE BIT TubeR3 ;; Reads from Tube R3 twice, but A is not changed. 00FDBE 1 ;; Why? Is this a bug? 00FDBE 1 00FDBE 1 2C FE FE 10 LDA_FIFO 4 00FDC2 1 FB AD FF FE 00FDC6 1 68 PLA ; Get sync byte from Tube R4 00FDC7 1 C9 06 CMP #6 00FDC9 1 90 1C BCC exit_FDE7 ; Exit if not 256-byte transfers 00FDCB 1 D0 1F BNE Read_256_bytes_from_Tube_R3 ; Jump with 256-byte read 00FDCD 1 00FDCD 1 ; Send 256 bytes to Tube via R3 00FDCD 1 ; ----------------------------- 00FDCD 1 A0 00 LDY #0 00FDCF 1 00FDCF 1 loop_FDCF: 00FDCF 1 00FDCF 1 .if 1 00FDCF 1 ; original code does this: 00FDCF 1 ; 00FDCF 1 AD FC FE LDA TubeS3 00FDD2 1 29 80 AND #$80 ; isolate bit 7 = sign 00FDD4 1 ; 00FDD4 1 10 F9 BPL loop_FDCF ; Wait for Tube R3 free 00FDD6 1 .else 00FDD6 1 ; I think the BIT instruction would have been more efficient 00FDD6 1 wait_to_read_FIFO 3 00FDD6 1 AND #$80 ; do this outside the loop 00FDD6 1 .endif 00FDD6 1 00FDD6 1 00FDD6 1 00FDD6 1 NMI6Addr: 00FDD6 1 B9 FF FF LDA $FFFF,Y 00FDD9 1 8D FD FE STA TubeR3 ; Fetch byte and send to Tube R3 00FDDC 1 C8 INY 00FDDD 1 D0 F0 BNE loop_FDCF ; Loop for 256 bytes 00FDDF 1 00FDDF 1 2C FC FE 10 wait_to_read_FIFO 3 ; wait to read but then write ??? 00FDE3 1 FB 00FDE4 1 8D FD FE STA TubeR3 ; Send final sync byte 00FDE7 1 00FDE7 1 exit_FDE7: 00FDE7 1 68 PLA 00FDE8 1 A8 TAY 00FDE9 1 A5 FC LDA $FC 00FDEB 1 40 RTI ; Restore registers and return 00FDEC 1 00FDEC 1 ; Read 256 bytes from Tube via R3 00FDEC 1 ; ------------------------------- 00FDEC 1 00FDEC 1 LFDEC: 00FDEC 1 Read_256_bytes_from_Tube_R3: 00FDEC 1 A0 00 LDY #0 00FDEE 1 loop_FDEE: 00FDEE 1 .if 1 00FDEE 1 00FDEE 1 AD FC FE LDA TubeS3 00FDF1 1 29 80 AND #$80 00FDF3 1 10 F9 BPL loop_FDEE ; Wait for Tube R3 data present 00FDF5 1 AD FD FE LDA TubeR3 ; Fetch byte from Tube R3 00FDF8 1 ; 00FDEE 1 loop_FDEE: 00FDF8 1 ; 00FDEE 1 AD FC FE LDA TubeS3 00FDF8 1 ; 00FDF1 1 29 80 AND #$80 00FDF8 1 ; 00FDF3 1 10 F9 BPL loop_FDEE ; Wait for Tube R3 data present 00FDF8 1 ; 00FDF5 1 AD FD FE LDA TubeR3 ; Fetch byte from Tube R3 00FDF8 1 .else 00FDF8 1 LDA_FIFO 3 ;; would this do just as well? 00FDF8 1 NOP ;; nops to pad out to same size 00FDF8 1 NOP 00FDF8 1 .endif 00FDF8 1 00FDF8 1 NMI7Addr: 00FDF8 1 99 FF FF STA $FFFF,Y 00FDFB 1 C8 INY 00FDFC 1 D0 F0 BNE loop_FDEE ; Store byte and loop for 256 bytes 00FDFE 1 F0 E7 BEQ exit_FDE7 ; Jump to restore registers and return 00FE00 1 00FE00 1 ; Transfer 0 0 Transfer single byte to Tube 00FE00 1 ; ----------------------------------------- 00FE00 1 NMI0: 00FE00 1 48 PHA ; Save A 00FE01 1 NMI0Addr: 00FE01 1 AD FF FF LDA $FFFF 00FE04 1 8D FD FE STA TubeR3 ; Get byte and send to Tube R3 00FE07 1 00FE07 1 EE 02 FE D0 inc16 NMI0Addr+1 00FE0B 1 03 EE 03 FE 00FE0F 1 00FE0F 1 68 PLA 00FE10 1 40 RTI ; Restore A and return 00FE11 1 00FE11 1 ; Transfer 1 0 Transfer single byte from Tube 00FE11 1 ; ------------------------------------------- 00FE11 1 NMI1: 00FE11 1 48 PHA 00FE12 1 AD FD FE LDA TubeR3 ; Save A, get byte from Tube R3 00FE15 1 NMI1Addr: 00FE15 1 8D FF FF STA $FFFF ; Store byte 00FE18 1 ; 00FE18 1 ; Warning: The instruction above is self-modifying code! 00FE18 1 ; 00FE18 1 ; 00FE18 1 ; 00FE18 1 EE 16 FE D0 inc16 NMI1Addr+1 ; Increment transfer address 00FE1C 1 03 EE 17 FE 00FE20 1 00FE20 1 68 PLA 00FE21 1 40 RTI ; Restore A and return 00FE22 1 00FE22 1 ; Transfer 2 0 Transfer two bytes to Tube 00FE22 1 ; --------------------------------------- 00FE22 1 NMI2: 00FE22 1 48 PHA 00FE23 1 98 TYA 00FE24 1 48 PHA 00FE25 1 A0 00 LDY #0 ; Save registers 00FE27 1 B1 F6 LDA (pointer_to_transfer),Y 00FE29 1 8D FD FE STA TubeR3 ; Get byte and send to Tube R3 00FE2C 1 00FE2C 1 E6 F6 D0 02 inc16 pointer_to_transfer 00FE30 1 E6 F7 00FE32 1 00FE32 1 B1 F6 LDA (pointer_to_transfer),Y 00FE34 1 8D FD FE STA TubeR3 ; Get byte and send to Tube R3 00FE37 1 00FE37 1 E6 F6 D0 02 inc16 pointer_to_transfer 00FE3B 1 E6 F7 00FE3D 1 00FE3D 1 68 PLA 00FE3E 1 A8 TAY 00FE3F 1 68 PLA 00FE40 1 40 RTI ; Restore registers and return 00FE41 1 00FE41 1 ; Transfer 3 0 Transfer two bytes from Tube 00FE41 1 ; ----------------------------------------- 00FE41 1 NMI3: 00FE41 1 48 PHA 00FE42 1 98 TYA 00FE43 1 48 PHA 00FE44 1 A0 00 LDY #0 ; Save registers 00FE46 1 AD FD FE LDA TubeR3 00FE49 1 91 F6 STA (pointer_to_transfer),Y ; Get byte from Tube R3 and store 00FE4B 1 00FE4B 1 E6 F6 D0 02 inc16 pointer_to_transfer 00FE4F 1 E6 F7 00FE51 1 00FE51 1 AD FD FE LDA TubeR3 00FE54 1 91 F6 STA (pointer_to_transfer),Y ; Get byte from Tube R3 and store 00FE56 1 00FE56 1 E6 F6 D0 02 inc16 pointer_to_transfer 00FE5A 1 E6 F7 00FE5C 1 00FE5C 1 68 PLA 00FE5D 1 A8 TAY 00FE5E 1 68 PLA 00FE5F 1 40 RTI ; Restore registers and return 00FE60 1 00FE60 1 ; Data transfer address pointers 00FE60 1 ; ------------------------------ 00FE60 1 LFE60: 00FE60 1 02 .byte <(NMI0Addr+1) 00FE61 1 16 .byte <(NMI1Addr+1) 00FE62 1 F6 .byte <$00F6 00FE63 1 F6 .byte <$00F6 00FE64 1 F6 .byte <$00F6 00FE65 1 F6 .byte <$00F6 00FE66 1 D7 .byte <(NMI6Addr+1) 00FE67 1 F9 .byte <(NMI7Addr+1) 00FE68 1 LFE68: 00FE68 1 FE .byte >(NMI0Addr+1) 00FE69 1 FE .byte >(NMI1Addr+1) 00FE6A 1 00 .byte >$00F6 00FE6B 1 00 .byte >$00F6 00FE6C 1 00 .byte >$00F6 00FE6D 1 00 .byte >$00F6 00FE6E 1 FD .byte >(NMI6Addr+1) 00FE6F 1 FD .byte >(NMI7Addr+1) 00FE70 1 00FE70 1 ; Data transfer routine addresses 00FE70 1 ; ------------------------------- 00FE70 1 LFE70: 00FE70 1 00 .byte NMI0 00FE79 1 FE .byte >NMI1 00FE7A 1 FE .byte >NMI2 00FE7B 1 FE .byte >NMI3 00FE7C 1 FE .byte >NMI_Ack 00FE7D 1 FE .byte >NMI_Ack 00FE7E 1 FE .byte >NMI_Ack 00FE7F 1 FE .byte >NMI_Ack 00FE80 1 00FE80 1 00FE80 1 ; Wait for byte in Tube R1 while allowing requests via Tube R4 00FE80 1 ; Err 510 00FE80 1 LFE80: 00FE80 1 get_A_from_FIFO_1: 00FE80 1 00FE80 1 2C F8 FE BIT TubeS1 ; If data in Tube R1, jump to fetch it 00FE83 1 30 0F BMI fetch_A_from_tube_1_and_return 00FE85 1 00FE85 1 ; loop_FE85: ; unused label 00FE85 1 2C FE FE BIT TubeS4 ; Check if data present in Tube R4 00FE88 1 10 F6 BPL get_A_from_FIFO_1 ; If nothing there, jump back to check Tube R1 00FE8A 1 00FE8A 1 ; get her if Tube R4 has data. 00FE8A 1 A5 FC LDA $FC ; Save IRQ's A store in A register 00FE8C 1 00FE8C 1 08 PHP 00FE8D 1 58 CLI 00FE8E 1 28 PLP ; Allow an IRQ through to process R4 request 00FE8F 1 85 FC STA $FC 00FE91 1 4C 80 FE JMP get_A_from_FIFO_1 ; Restore IRQ's A store and jump back to check R1 00FE94 1 00FE94 1 fetch_A_from_tube_1_and_return: 00FE94 1 AD F9 FE LDA TubeR1 00FE97 1 60 RTS 00FE98 1 00FE98 1 00FE98 1 ; Print embedded string 00FE98 1 ; Err 510 00FE98 1 PrText: 00FE98 1 68 PLA 00FE99 1 85 FA STA pointer_at_FA 00FE9B 1 68 PLA 00FE9C 1 85 FB STA pointer_at_FA+1 ; $FA/B=>embedded string 00FE9E 1 A0 00 LDY #0 00FEA0 1 LFEA0: 00FEA0 1 00FEA0 1 E6 FA D0 02 inc16 pointer_at_FA ; pre-increment 00FEA4 1 E6 FB 00FEA6 1 B1 FA LDA (pointer_at_FA),Y ; Get character, 00FEA8 1 30 06 BMI LFEB0 ; exit if >$7F 00FEAA 1 20 EE FF JSR OSWRCH ; Print character 00FEAD 1 4C A0 FE JMP LFEA0 ; and loop back for more 00FEB0 1 LFEB0: 00FEB0 1 6C FA 00 JMP (pointer_at_FA) ; Jump back to code after string 00FEB3 1 00FEB3 1 00FEB3 1 ; Null NMI code 00FEB3 1 ; ------------- 00FEB3 1 NMI_Ack: ; Store to TubeR3 to acknowlege NMI 00FEB3 1 8D FD FE STA TubeR3 00FEB6 1 40 RTI 00FEB7 1 00FEB7 1 00FEB7 1 ; Spare space 00FEB7 1 ; Err 510 00FEB7 1 .ifdef reference_code 00FEB7 1 ;; .byte ($FEF0-$,$FF) 00FEB7 1 .else 00FEB7 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FEBB 1 FF FF FF FF 00FEBF 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FEC3 1 FF FF FF FF 00FEC7 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FECB 1 FF FF FF FF 00FECF 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FED3 1 FF FF FF FF 00FED7 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FEDB 1 FF FF FF FF 00FEDF 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FEE3 1 FF FF FF FF 00FEE7 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FEEB 1 FF FF FF FF 00FEEF 1 FF .byte $FF 00FEF0 1 00FEF0 1 .endif 00FEF0 1 00FEF0 1 00FEF0 1 IO_SPACE: 00FEF0 1 .ifdef reference_code 00FEF0 1 ; I/O Space 00FEF0 1 ; Err 510 00FEF0 1 ;; .byte STRING$(8,CHR$0) 00FEF0 1 .else 00FEF0 1 00 00 00 00 .byte $00,$00,$00,$00,$00,$00,$00,$00 00FEF4 1 00 00 00 00 00FEF8 1 .endif 00FEF8 1 ; Tube I/O Registers 00FEF8 1 ; Err 510 00FEF8 1 ; TubeSn = TUBE_BASE+n*2-2 00FEF8 1 ; TubeRn = TUBE_BASE+n*2 00FEF8 1 ; 00FEF8 1 TUBE_BASE: 00FEF8 1 TubeS1: ; $FEF8 00FEF8 1 00 .byte 0 00FEF9 1 TubeR1: ; $FEF9 00FEF9 1 00 .byte 0 00FEFA 1 TubeS2: ; $FEFA 00FEFA 1 00 .byte 0 00FEFB 1 TubeR2: ; $FEFB 00FEFB 1 00 .byte 0 00FEFC 1 TubeS3: ; $FEFC 00FEFC 1 00 .byte 0 00FEFD 1 TubeR3: ; $FEFD 00FEFD 1 00 .byte 0 00FEFE 1 TubeS4: ; $FEFE 00FEFE 1 00 .byte 0 00FEFF 1 TubeR4: ; $FEFF 00FEFF 1 00 .byte 0 00FF00 1 00FF00 1 00FF00 1 ; Spare space 00FF00 1 ; Err 510 00FF00 1 LFF00: 00FF00 1 .ifdef reference_code 00FF00 1 ;; .byte STRING$($FF80-P%,CHR$255) 00FF00 1 .else 00FF00 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF04 1 FF FF FF FF 00FF08 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF0C 1 FF FF FF FF 00FF10 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF14 1 FF FF FF FF 00FF18 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF1C 1 FF FF FF FF 00FF20 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF24 1 FF FF FF FF 00FF28 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF2C 1 FF FF FF FF 00FF30 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF34 1 FF FF FF FF 00FF38 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF3C 1 FF FF FF FF 00FF40 1 00FF40 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF44 1 FF FF FF FF 00FF48 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF4C 1 FF FF FF FF 00FF50 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF54 1 FF FF FF FF 00FF58 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF5C 1 FF FF FF FF 00FF60 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF64 1 FF FF FF FF 00FF68 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF6C 1 FF FF FF FF 00FF70 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF74 1 FF FF FF FF 00FF78 1 FF FF FF FF .word $FFFF,$FFFF,$FFFF,$FFFF 00FF7C 1 FF FF FF FF 00FF80 1 .endif 00FF80 1 00FF80 1 ; DEFAULT VECTOR TABLE 00FF80 1 ; Err 510 00FF80 1 LFF80: 00FF80 1 vector_table_defaults: 00FF80 1 B7 FC .word Unsupported ; $200 0 USERV 00FF82 1 45 F9 .word ErrorHandler ; $202 0 BRKV 00FF84 1 F0 FC .word IRQ1Handler ; $204 0 IRQ1V 00FF86 1 B7 FC .word Unsupported ; $206 0 IRQ2V 00FF88 1 CA F9 .word osCLI ; $208 0 CLIV 00FF8A 1 73 FA .word osBYTE ; $20A 0 BYTEV 00FF8C 1 FF FA .word osWORD ; $20C 0 WORDV 00FF8E 1 62 F9 .word osWRCH ; $20E 0 WRCHV 00FF90 1 6C F9 .word osRDCH ; $210 0 RDCHV 00FF92 1 53 FC .word osFILE ; $212 0 FILEV 00FF94 1 CC FB .word osARGS ; $214 0 ARGSV 00FF96 1 2A FC .word osBGET ; $216 0 BGetV 00FF98 1 36 FC .word osBPUT ; $218 0 BPutV 00FF9A 1 8E FC .word osGBPB ; $21A 0 GBPBV 00FF9C 1 0C FC .word osFIND ; $21C 0 FINDV 00FF9E 1 B7 FC .word Unsupported ; $21E 0 FSCV 00FFA0 1 7D F9 .word NullReturn ; $220 0 EVNTV 00FFA2 1 B7 FC .word Unsupported ; $222 0 UPTV 00FFA4 1 B7 FC .word Unsupported ; $224 0 NETV 00FFA6 1 B7 FC .word Unsupported ; $226 0 VduV 00FFA8 1 B7 FC .word Unsupported ; $228 0 KEYV 00FFAA 1 B7 FC .word Unsupported ; $22A 0 INSV 00FFAC 1 B7 FC .word Unsupported ; $22C 0 RemV 00FFAE 1 B7 FC .word Unsupported ; $22E 0 CNPV 00FFB0 1 7D F9 .word NullReturn ; $230 0 IND1V 00FFB2 1 7D F9 .word NullReturn ; $232 0 IND2V 00FFB4 1 7D F9 .word NullReturn ; $234 0 IND3V 00FFB6 1 00FFB6 1 00FFB6 1 VECDEF: ; at $FFB6 00FFB6 1 36 .byte vector_table_size ; $36 00FFB7 1 80 FF .word vector_table_defaults 00FFB9 1 OS_FFB9: ; $ 00FFB9 1 4C B7 FC JMP Unsupported 00FFBC 1 OS_FFBC: ; $FFBC 00FFBC 1 4C B7 FC JMP Unsupported 00FFBF 1 OS_FFBF: ; $FFBF 00FFBF 1 4C B7 FC JMP Unsupported 00FFC2 1 OS_FFC2: ; $FFC2 00FFC2 1 4C B7 FC JMP Unsupported 00FFC5 1 OS_FFC5: ; $FFC5 00FFC5 1 4C B7 FC JMP Unsupported 00FFC8 1 00FFC8 1 NVRDCH: ; $FFC8 00FFC8 1 4C 6C F9 JMP osRDCH 00FFCB 1 NVWRCH: ; $FFCB 00FFCB 1 4C 62 F9 JMP osWRCH 00FFCE 1 00FFCE 1 OSFIND: ; $FFCE 00FFCE 1 6C 1C 02 JMP (FINDV) 00FFD1 1 OSGBPB: ; $FFD1 00FFD1 1 6C 1A 02 JMP (GBPBV) 00FFD4 1 OSBPUT: ; $FFD4 00FFD4 1 6C 18 02 JMP (BPutV) 00FFD7 1 OSBGET: ; $FFD7 00FFD7 1 6C 16 02 JMP (BGetV) 00FFDA 1 OSARGS: ; $FFDA 00FFDA 1 6C 14 02 JMP (ARGSV) 00FFDD 1 OSFILE: ; $FFDD 00FFDD 1 6C 12 02 JMP (FILEV) 00FFE0 1 00FFE0 1 OSRDCH: 00FFE0 1 ; $FFE0 00FFE0 1 6C 10 02 JMP (RDCHV) 00FFE3 1 OSASCI: ; $FFE3 00FFE3 1 C9 0D CMP #CR 00FFE5 1 D0 07 BNE OSWRCH 00FFE7 1 OSNEWL: 00FFE7 1 ; $FFE7 00FFE7 1 A9 0A LDA #LF 00FFE9 1 20 EE FF JSR OSWRCH 00FFEC 1 OSWRCR: ; $FFEC 00FFEC 1 A9 0D LDA #CR 00FFEE 1 OSWRCH: ; $FFEE 00FFEE 1 6C 0E 02 JMP (WRCHV) 00FFF1 1 OSWORD: ; $FFF1 00FFF1 1 6C 0C 02 JMP (WORDV) 00FFF4 1 OSBYTE: ; $FFF4 00FFF4 1 6C 0A 02 JMP (BYTEV) 00FFF7 1 OS_CLI: ; $FFF7 00FFF7 1 6C 08 02 JMP (CLIV) 00FFFA 1 00FFFA 1 NMIV: ; $FFFA 00FFFA 1 00 FE .word NMI0 ; NMI Vector 00FFFC 1 RESETV: ; $FFFC 00FFFC 1 00 F8 .word RESET ; RESET Vector 00FFFE 1 IRQV: ; $FFFE 00FFFE 1 E5 FC .word InterruptHandler ; IRQ Vector 010000 1 ; ] 010000 1 ; NEXT 010000 1 ; OSCLI"Save Client +STR$~mcode%+ +STR$~O%+ +STR$~load%+ "+STR$~load% 010000 1 ; 9390 ON ERROR ON ERROR OFF 010000 1 ; END" 010000 1 ; *Quit 010000 1 010000 1