ca65 V2.15 - Git fa0709a Main file : source/vic20//vic20.a65 Current file: source/vic20//vic20.a65 000000r 1 000000r 1 .setcpu "6502" 000000r 1 000000r 1 .include "../asm6502.inc" 000000r 2 ASM_JMP = $4C 000000r 2 ASM_BIT2 = $24 000000r 2 ASM_BIT3 = $2C 000000r 2 000000r 2 ; Flags of the 6502 000000r 2 A6502_FLAGS_N = $80 ; Negative 000000r 2 A6502_FLAGS_V = $40 ; oVerflow 000000r 2 A6502_FLAGS_R = $20 ; Reserved 000000r 2 A6502_FLAGS_B = $10 ; Break (only valid on stack after BRK/IRQ, otherwise 0) 000000r 2 A6502_FLAGS_D = $08 ; Decimal 000000r 2 A6502_FLAGS_I = $04 ; Interrupt 000000r 2 A6502_FLAGS_Z = $02 ; Zero 000000r 2 A6502_FLAGS_C = $01 ; Carry 000000r 2 000000r 1 .include "../petscii.inc" 000000r 2 ASC_LF = $0A 000000r 2 ASC_CR = $0D 000000r 2 ASC_RVS = $12 000000r 2 ASC_HOME = $13 000000r 2 ASC_INSDEL = $14 000000r 2 000000r 2 ASC_LOWERCASE = $0E 000000r 2 ASC_UPPERCASE = $8E 000000r 2 ASC_DISALLOW_LOWERCASE = $08 000000r 2 ASC_ALLOW_LOWERCASE = $09 000000r 2 000000r 2 ASC_CURSORLEFTRIGHT = $1D 000000r 2 ASC_CURSORUPDOWN = $11 000000r 2 000000r 2 .if .defined(C64JAPAN) 000000r 2 ASC_PI = $B0 000000r 2 .else 000000r 2 ASC_PI = $DE 000000r 2 .endif 000000r 2 000000r 2 KEY_NONE = $40 000000r 2 KEY_STOP = $03 000000r 2 000000r 2 PETSCII_CRSR_RIGHT = $1D 000000r 2 000000r 1 000000r 1 .include "../macros.inc" 000000r 2 ; htasc - set the hi bit on the last byte of a string for termination 000000r 2 ; (by Tom Greene) 000000r 2 .macro htasc str 000000r 2 .repeat .strlen(str)-1,I 000000r 2 .byte .strat(str,I) 000000r 2 .endrep 000000r 2 .byte .strat(str,.strlen(str)-1) | $80 000000r 2 .endmacro 000000r 2 000000r 2 .macro htasc_floppy_error str 000000r 2 .byte .strat(str,0) | $80 000000r 2 .repeat .strlen(str)-2,I 000000r 2 .byte .strat(str,I + 1) 000000r 2 .endrep 000000r 2 .byte .strat(str,.strlen(str)-1) | $80 000000r 2 .endmacro 000000r 2 000000r 2 ; For every token, a byte gets put into segment "DUMMY". 000000r 2 ; This way, we count up with every token. The DUMMY segment 000000r 2 ; doesn't get linked into the binary. 000000r 2 .macro init_token_tables 000000r 2 .segment "VECTORS" 000000r 2 TOKEN_ADDRESS_TABLE: 000000r 2 .segment "KEYWORDS" 000000r 2 TOKEN_NAME_TABLE: 000000r 2 .segment "DUMMY" 000000r 2 DUMMY_START: 000000r 2 .endmacro 000000r 2 000000r 2 ; optionally define token symbol 000000r 2 ; count up token number 000000r 2 .macro define_token token 000000r 2 .segment "DUMMY" 000000r 2 .ifnblank token 000000r 2 token := <(*-DUMMY_START)+$80 000000r 2 .endif 000000r 2 .res 1; count up in any case 000000r 2 .endmacro 000000r 2 000000r 2 ; lay down a keyword, optionally define a token symbol 000000r 2 .macro keyword key, token 000000r 2 .segment "KEYWORDS" 000000r 2 htasc key 000000r 2 define_token token 000000r 2 .endmacro 000000r 2 000000r 2 ; lay down a keyword and an address (RTS style), 000000r 2 ; optionally define a token symbol 000000r 2 .macro keyword_rts key, vec, token 000000r 2 .segment "VECTORS" 000000r 2 .word vec-1 000000r 2 keyword key, token 000000r 2 .endmacro 000000r 2 000000r 2 ; lay down a keyword and an address, 000000r 2 ; optionally define a token symbol 000000r 2 .macro keyword_addr key, vec, token 000000r 2 .segment "VECTORS" 000000r 2 .addr vec 000000r 2 keyword key, token 000000r 2 .endmacro 000000r 2 000000r 2 .macro count_tokens 000000r 2 .segment "DUMMY" 000000r 2 NUM_TOKENS := <(*-DUMMY_START) 000000r 2 .endmacro 000000r 2 000000r 2 .macro init_error_table 000000r 2 .segment "DUMMY" 000000r 2 DUMMY_START_ERROR: 000000r 2 000000r 2 .segment "ERROR" 000000r 2 ERROR_MESSAGES: 000000r 2 .endmacro 000000r 2 000000r 2 .ifdef CBM2_EXT_FILE_ERRORS 000000r 2 .macro define_error_token token 000000r 2 .segment "DUMMY" 000000r 2 .ifnblank token 000000r 2 token := <(*-DUMMY_START_ERROR + 1) 000000r 2 .endif 000000r 2 .res 1; count up in any case 000000r 2 .endmacro 000000r 2 000000r 2 .macro define_error error, msg, addr 000000r 2 .segment "ERROR" 000000r 2 addr := * 000000r 2 htasc msg 000000r 2 define_error_token error 000000r 2 .endmacro 000000r 2 000000r 2 .else 000000r 2 .macro define_error error, msg, addr 000000r 2 .segment "ERROR" 000000r 2 error := <(*-ERROR_MESSAGES) 000000r 2 htasc msg 000000r 2 .endmacro 000000r 2 000000r 2 .endif 000000r 2 000000r 2 ;--------------------------------------------- 000000r 2 ; set the MSB of every byte of a string 000000r 2 .macro asc80 str 000000r 2 .repeat .strlen(str),I 000000r 2 .byte .strat(str,I)+$80 000000r 2 .endrep 000000r 2 .endmacro 000000r 2 000000r 2 000000r 1 000000r 1 .include "defines.inc" 000000r 2 .include "../c64/defines-c64vic20.inc" 000000r 3 000000r 3 COMPUTER_UNKNOWN=0 000000r 3 000000r 3 VIC20_GENERAL=COMPUTER_UNKNOWN + $10 000000r 3 VIC20_02=VIC20_GENERAL + 2 000000r 3 VIC20_06=VIC20_GENERAL + 6 000000r 3 VIC20_07=VIC20_GENERAL + 7 000000r 3 000000r 3 C64_GENERAL=VIC20_GENERAL + $20 000000r 3 C64_01=C64_GENERAL + 1 000000r 3 C64_02=C64_GENERAL + 2 000000r 3 C64_03=C64_GENERAL + 3 000000r 3 C64_SX64=C64_GENERAL + 4 000000r 3 C64_4064=C64_GENERAL + 5 000000r 3 C64_GS=C64_GENERAL + 6 000000r 3 000000r 3 .ifdef vic20 000000r 3 CompileComputer=VIC20_GENERAL + vic20 000000r 3 .elseif .defined(c64) 000000r 3 .if c64 = 4064 000000r 3 CompileComputer=C64_4064 000000r 3 .else 000000r 3 CompileComputer=C64_GENERAL + c64 000000r 3 .endif 000000r 3 .endif 000000r 3 000000r 3 .ifdef sx64 000000r 3 CompileComputer=C64_SX64 000000r 3 c64 = sx64 000000r 3 .endif 000000r 3 000000r 3 .ifdef c64gs 000000r 3 CompileComputer=C64_GS 000000r 3 c64 = c64gs 000000r 3 .endif 000000r 3 000000r 3 .ifndef CompileComputer 000000r 3 CompileComputer=COMPUTER_UNKNOWN 000000r 3 .endif 000000r 3 000000r 3 .macro FillCount count,filler 000000r 3 .repeat count 000000r 3 .ifblank filler 000000r 3 .byte DRIVEFILLER 000000r 3 .else 000000r 3 .byte filler 000000r 3 .endif 000000r 3 .endrep 000000r 3 .endmacro 000000r 3 000000r 3 .macro FillUntil address,filler 000000r 3 FillCount address-*,filler 000000r 3 .endmacro 000000r 3 000000r 3 .macro FillNOP count 000000r 3 FillCount count,$EA 000000r 3 .endmacro 000000r 3 000000r 3 IEEE_LISTEN = $20 ; on ATN, with primary address 000000r 3 IEEE_TALK = $40 ; on ATN, with primary address 000000r 3 IEEE_OPEN = $60 ; on ATN, with secondary address 000000r 3 IEEE_CLOSE = $E0 ; on ATN, with primary address 000000r 3 IEEE_SECONDARY = $F0 ; on ATN, with secondary address 000000r 3 000000r 3 IEEE_LOAD = IEEE_OPEN + 0 000000r 3 IEEE_SAVE = IEEE_OPEN + 1 000000r 3 000000r 3 IEEE_UNLISTEN = IEEE_LISTEN + $1F 000000r 3 IEEE_UNTALK = IEEE_TALK + $1F 000000r 3 000000r 3 STATUS_IEC_DEVICE_NOT_PRESENT = $80 000000r 3 STATUS_IEC_EOI = $40 000000r 3 STATUS_IEC_TIMEOUT_READ = $02 000000r 3 STATUS_IEC_TIMEOUT_WRITE = $01 000000r 3 000000r 3 STATUS_VERIFY = $10 000000r 3 000000r 3 STATUS_TAPE_EOT = $80 000000r 3 STATUS_TAPE_EOF = $40 ; not on LOAD and VERIFY 000000r 3 STATUS_TAPE_CHKSUM_ERR = $20 000000r 3 STATUS_TAPE_UNRECOVERABLE_READ_ERROR = $10 000000r 3 STATUS_TAPE_LONG_BLOCK = $08 000000r 3 STATUS_TAPE_SHORT_BLOCK = $04 000000r 3 000000r 3 000000r 2 000000r 2 TEXT_SHIFTRUNSTOP := TEXT_LOADRUN 000000r 2 END_TEXT_SHIFTRUNSTOP := END_TEXT_LOADRUN 000000r 2 000000r 2 DEFAULT_COLOR := COL_BLUE 000000r 2 000000r 2 .if CompileComputer=VIC20_02 000000r 2 DRIVEFILLER=$AA 000000r 2 CHECKSUM_E475=$D6 000000r 2 FILL_FFXX=$AA 000000r 2 BASIC_END := $E387 000000r 2 DEFAULT_VIA2_T1=$4289 000000r 2 .elseif CompileComputer=VIC20_06 000000r 2 DRIVEFILLER=$AA 000000r 2 CHECKSUM_E475=$41 000000r 2 FILL_FFXX=$FF 000000r 2 BASIC_END := $E387 000000r 2 DEFAULT_VIA2_T1=$4289 000000r 2 .elseif CompileComputer=VIC20_07 000000r 2 DRIVEFILLER=$AA 000000r 2 FILL_FFXX=$FF 000000r 2 CHECKSUM_E475=$E8 000000r 2 BASIC_END := $E387 000000r 2 DEFAULT_VIA2_T1=$4826 000000r 2 .endif 000000r 2 000000r 2 CHKSUM_BF52 = $BF 000000r 2 000000r 2 EDITOR_TAB = 11 000000r 2 EDITOR_COLS = 22 000000r 2 EDITOR_ROWS = 23 000000r 2 000000r 2 EDITOR_MAX_COMBINED_ROWS = 4 000000r 2 000000r 1 .include "memory.inc" 000000r 2 .include "../basic/basic-memory.inc" 000000r 3 .segment "MEM_BASIC_ZP": zeropage 000000r 3 000000r 3 xx xx zADRAY1: .res 2 ; $0003 000002r 3 xx xx zADRAY2: .res 2 ; $0005 000004r 3 xx zCHARAC: .res 1 ; $0007 000005r 3 xx zENDCHR: .res 1 ; $0008 000006r 3 xx zTRMPOS: .res 1 ; $0009 000007r 3 xx zVERCK: .res 1 ; $000A 000008r 3 xx zCOUNT: .res 1 ; $000B 000009r 3 xx zDIMFLG: .res 1 ; $000C 00000Ar 3 xx zVALTYP: .res 1 ; $000D 00000Br 3 xx zINTFLG: .res 1 ; $000E 00000Cr 3 xx zGARBFL: .res 1 ; $000F 00000Dr 3 xx zINTALLOWED: .res 1 ; $0010 ; TODO 00000Er 3 xx zSUBFLG: .res 1 ; $0011 00000Fr 3 xx zTANSGN: .res 1 ; $0012 000010r 3 xx z13: .res 1 ; $0013 ; TODO 000011r 3 xx xx zLINNUM: .res 2 ; $0014 000013r 3 xx zTEMPPT: .res 1 ; $0016 000014r 3 xx xx zLASTPT: .res 2 ; $0017 000016r 3 xx xx xx xx zTEMPST: .res 5 ; $0019 00001Ar 3 xx 00001Br 3 xx xx xx xx zCHANNL: .res 4 ; $001E 00001Fr 3 xx xx zINDEX: .res 2 ; $0022 000021r 3 xx xx zINDEX2: .res 2 ; $0024 000023r 3 xx xx xx xx zRESHO: .res 5 ; $0026 000027r 3 xx 000028r 3 zTEMP_28 := zRESHO + 2 ; TODO 000028r 3 xx xx zTXTTAB: .res 2 ; $002B 00002Ar 3 xx xx zVARTAB: .res 2 ; $002D 00002Cr 3 xx xx zARYTAB: .res 2 ; $002F 00002Er 3 xx xx zSTREND: .res 2 ; $0031 000030r 3 xx xx zFRETOP: .res 2 ; $0033 000032r 3 xx xx zFRESPC: .res 2 ; $0035 000034r 3 xx xx zMEMSIZ: .res 2 ; $0037 000036r 3 xx xx zCURLIN: .res 2 ; $0039 000038r 3 xx xx zOLDLIN: .res 2 ; $003B 00003Ar 3 xx xx zOLDTXT: .res 2 ; $003D 00003Cr 3 xx xx zDATLIN: .res 2 ; $003F 00003Er 3 xx xx zDATPTR: .res 2 ; $0041 000040r 3 xx xx zINPPTR: .res 2 ; $0043 000042r 3 xx xx zVARNAM: .res 2 ; $0045 000044r 3 xx xx zVARPNT: .res 2 ; $0047 000046r 3 xx xx zFORPNT: .res 2 ; $0049 000048r 3 xx xx zVARTXT: .res 2 ; $004B 00004Ar 3 xx zOPMASK: .res 1 ; $004D 00004Br 3 xx xx xx xx zTEMPF3: .res 5 ; $004E 00004Fr 3 xx 000050r 3 zTEMP_50 := zTEMPF3 + 2 ; TODO 000050r 3 xx zFOUR6: .res 1 ; $0053 000051r 3 xx xx xx zJMPER: .res 3 ; $0054 000054r 3 xx xx xx xx zTEMPF1: .res 5 ; $0057 000058r 3 xx 000059r 3 zTEMP_58 := zTEMPF1 + 1 ; TODO 000059r 3 zTEMP_5A := zTEMPF1 + 3 ; TODO 000059r 3 xx xx xx xx zTEMPF2: .res 5 ; $005C 00005Dr 3 xx 00005Er 3 zTEMP_5D := zTEMPF2 + 1 ; TODO 00005Er 3 zTEMP_5E := zTEMPF2 + 2 ; TODO 00005Er 3 zTEMP_5F := zTEMPF2 + 3 ; TODO 00005Er 3 zTEMP_60 := zTEMPF2 + 4 ; TODO 00005Er 3 xx xx xx xx zFAC: .res 7 ; $0061 000062r 3 xx xx xx 000065r 3 zFACEXP := zFAC ; $0061 000065r 3 zFACHO := zFAC + 1 ; $0062 000065r 3 zFACSGN := zFAC + 5 ; $0066 000065r 3 zSGNFLG := zFAC + 6 ; $0067 000065r 3 xx zBITS: .res 1 ; $0068 000066r 3 xx xx xx xx zARG: .res 7 ; $0069 00006Ar 3 xx xx xx 00006Dr 3 zARGEXP := zARG ; $0069 00006Dr 3 zARGHO := zARG + 1 ; $006A 00006Dr 3 zARGSGN := zARG + 5 ; $006E 00006Dr 3 zARISGN := zARG + 6 ; $006F 00006Dr 3 xx zFACOV: .res 1 ; $0070 00006Er 3 xx xx zFBUFPT: .res 2 ; $0071 000070r 3 xx xx xx xx zCHRGET: .res 6 ; $0073 000074r 3 xx xx 000076r 3 xx xx xx xx zCHRGOT: .res 7 ; $0079 00007Ar 3 xx xx xx 00007Dr 3 xx xx xx xx zCHRGOT_SPACE: .res 11 ; $0080 000081r 3 xx xx xx xx 000085r 3 xx xx xx 000088r 3 zTXTPTR := zCHRGOT + 1 ; $007A 000088r 3 xx xx xx xx zRNDX: .res 5 ; $008B 00008Cr 3 xx 00008Dr 3 00008Dr 3 .segment "MEM_BASIC_ZP2": zeropage 000000r 3 000000r 3 xx zASCWRK: .res 1 ; $00FF 000001r 3 000001r 3 .segment "STACK" 000000r 3 000000r 3 xx xx xx xx lSTACK: .res 256 000004r 3 xx xx xx xx 000008r 3 xx xx xx xx 000100r 3 000100r 3 .segment "MEM_BASIC_DATA_0200" 000000r 3 000000r 3 xx xx xx xx lBUF: .res 89 000004r 3 xx xx xx xx 000008r 3 xx xx xx xx 000059r 3 END_lBUF: 000059r 3 000059r 3 .segment "MEM_BASIC_DATA_0300" 000000r 3 000000r 3 xx xx lIERROR: .res 2 000002r 3 xx xx lIMAIN: .res 2 000004r 3 xx xx lICRNCH: .res 2 000006r 3 xx xx lIQPLOP: .res 2 000008r 3 xx xx lIGONE: .res 2 00000Ar 3 xx xx lIEVAL: .res 2 00000Cr 3 xx lSAREG: .res 1 00000Dr 3 xx lSXREG: .res 1 00000Er 3 xx lSYREG: .res 1 00000Fr 3 xx lSPREG: .res 1 000010r 3 000010r 3 .if CompileComputer >= C64_GENERAL 000010r 3 .segment "MEM_BASIC_USR" 000010r 3 .else 000010r 3 .segment "MEM_BASIC_USR": zeropage 000000r 3 .endif 000000r 3 000000r 3 xx lUSRPOK: .res 1 000001r 3 xx xx lUSRADD: .res 2 000003r 3 000003r 2 000003r 2 ;lVICSCN := $0400 000003r 2 ;lSPNTRN := $07F8 000003r 2 000003r 2 CARTRIDGE := $A000 000003r 2 CART_RESET := CARTRIDGE + 0 000003r 2 CART_NMI := CARTRIDGE + 2 000003r 2 CART_MAGIC := CARTRIDGE + 4 000003r 2 000003r 2 000003r 2 .include "../vic-i.inc" 000003r 3 VICI_O_OriginX := 0 ; bit 6-0: screen origin X, 4 pixels granularity 000003r 3 VICI_B_OriginX_Interlace := $80 ; 1 = interlace mode on, 0 = non-interlace (not on all VIC-I) 000003r 3 VICI_B_OriginX_OriginX_Mask := $7F 000003r 3 000003r 3 VICI_O_OriginY := 1 ; screen origin Y, 2 lines granularity 000003r 3 000003r 3 VICI_O_VideoColumns := 2 ; number of video columns 000003r 3 VICI_B_VideoColumns_Mask := $7F ; videocolumns are given by this value 000003r 3 VICI_B_VideoColumns_ScreenMemoryB9 := $80 ; b9 of screen memory location; b13-b10 are at VICI_O_MemoryLocations 000003r 3 000003r 3 VICI_O_03 := 3 000003r 3 VICI_O_04 := 4 000003r 3 000003r 3 VICI_O_MemoryLocations := 5 000003r 3 VICI_B_MemoryLocations_ScreenMemB10B13 := $F0 ; b13-b10 of screen memory locaiton; b9 is at VICI_O_VideoColumns (b13 is inverted in the VIC20!) 000003r 3 VICI_B_MemoryLocations_CharMemB10B13 := $0F ; b13-b10 of character memory location (b13 is inverted in the VIC20!) 000003r 3 000003r 3 VICI_O_06 := 6 000003r 3 VICI_O_07 := 7 000003r 3 VICI_O_08 := 8 000003r 3 VICI_O_09 := 9 000003r 3 VICI_O_0A := 10 000003r 3 VICI_O_0B := 11 000003r 3 VICI_O_0C := 12 000003r 3 VICI_O_0D := 13 000003r 3 VICI_O_0E := 14 000003r 3 VICI_O_0F := 15 000003r 3 000003r 3 COL_BLACK = 0 000003r 3 COL_WHITE = 1 000003r 3 COL_RED = 2 000003r 3 COL_3 = 3 000003r 3 COL_CYAN = 4 000003r 3 COL_GREEN = 5 000003r 3 COL_BLUE = 6 000003r 3 COL_YELLOW = 7 000003r 3 COL_ORANGE = 8 000003r 3 COL_LIGHTORANGE= 9 000003r 3 COL_PINK = 10 000003r 3 COL_LIGHTCYAN = 11 000003r 3 COL_LIGHTPURPLE= 12 000003r 3 COL_LIGHTGREEN = 13 000003r 3 COL_LIGHTBLUE = 14 000003r 3 COL_LIGHTYELLOW= 15 000003r 3 000003r 2 000003r 2 VIC := $9000 000003r 2 .if 0 000003r 2 VIC_00 := VIC + 0 000003r 2 VIC_01 := VIC + 1 000003r 2 VIC_02 := VIC + 2 000003r 2 VIC_03 := VIC + 3 000003r 2 VIC_04 := VIC + 4 000003r 2 VIC_05 := VIC + 5 000003r 2 VIC_06 := VIC + 6 000003r 2 VIC_07 := VIC + 7 000003r 2 VIC_08 := VIC + 8 000003r 2 VIC_09 := VIC + 9 000003r 2 VIC_0A := VIC + 10 000003r 2 VIC_0B := VIC + 11 000003r 2 VIC_0C := VIC + 12 000003r 2 VIC_0D := VIC + 13 000003r 2 VIC_0E := VIC + 14 000003r 2 VIC_0F := VIC + 15 000003r 2 .endif 000003r 2 000003r 2 .include "../via.inc" 000003r 3 VIA_O_PB := 0 000003r 3 VIA_O_PA := 1 000003r 3 VIA_O_DDRB := 2 000003r 3 VIA_O_DDRA := 3 000003r 3 VIA_O_T1CL := 4 000003r 3 VIA_O_T1CH := 5 000003r 3 VIA_O_T1CLL := 6 000003r 3 VIA_O_T1CHL := 7 000003r 3 VIA_O_T2CL := 8 000003r 3 VIA_O_T2CH := 9 000003r 3 VIA_O_SR := 10 000003r 3 VIA_O_ACR := 11 000003r 3 VIA_O_PCR := 12 000003r 3 VIA_O_IFR := 13 000003r 3 VIA_O_IEC := 14 000003r 3 VIA_O_PA_NO_HS := 15 000003r 3 000003r 3 VIA_IFR_B_CA2 := $01 ; cleared by read or write to PA 000003r 3 VIA_IFR_B_CA1 := $02 ; cleared by read or write to PA 000003r 3 VIA_IFR_B_SR := $04 ; cleared by read or write to SR 000003r 3 VIA_IFR_B_CB2 := $08 ; cleared by read or write to PB 000003r 3 VIA_IFR_B_CB1 := $10 ; cleared by read or write to PB 000003r 3 VIA_IFR_B_T2 := $20 ; cleared by read T2L or write T2H 000003r 3 VIA_IFR_B_T1 := $40 ; cleared by read T1L or write T1H 000003r 3 VIA_IFR_B_ANY := $80 ; cleared if all interrupts are cleared 000003r 3 000003r 3 VIA_IER_B_CA2 := VIA_IFR_B_CA2 000003r 3 VIA_IER_B_CA1 := VIA_IFR_B_CA1 000003r 3 VIA_IER_B_SR := VIA_IFR_B_SR 000003r 3 VIA_IER_B_CB2 := VIA_IFR_B_CB2 000003r 3 VIA_IER_B_CB1 := VIA_IFR_B_CB1 000003r 3 VIA_IER_B_T2 := VIA_IFR_B_T2 000003r 3 VIA_IER_B_T1 := VIA_IFR_B_T1 000003r 3 VIA_IER_BW_SET := $80 000003r 3 VIA_IER_BW_UNSET := $00 000003r 3 000003r 3 VIA_PCR_B_CA1_INPUT_POS_EDGE := $01 ; 1 = input on positive edge, 0 = input on negative edge 000003r 3 VIA_PCR_B_CA2_MASK := $0E 000003r 3 VIA_PCR_B_CA2_INPUT_NEG_CLEAR_ON_READ := $00 000003r 3 VIA_PCR_B_CA2_INPUT_NEG := $02 000003r 3 VIA_PCR_B_CA2_INPUT_POS_CLEAR_ON_READ := $04 000003r 3 VIA_PCR_B_CA2_INPUT_POS := $06 000003r 3 VIA_PCR_B_CA2_OUTPUT_HANDSHAKE := $08 000003r 3 VIA_PCR_B_CA2_OUTPUT_PULSE := $0A 000003r 3 VIA_PCR_B_CA2_OUTPUT_LOW := $0C 000003r 3 VIA_PCR_B_CA2_OUTPUT_HIGH := $0E 000003r 3 VIA_PCR_B_CB1_INPUT_POS_EDGE := $10 ; 1 = input on positive edge, 0 = input on negative edge 000003r 3 VIA_PCR_B_CB2_MASK := $E0 000003r 3 VIA_PCR_B_CB2_INPUT_NEG_CLEAR_ON_READ := $00 000003r 3 VIA_PCR_B_CB2_INPUT_NEG := $20 000003r 3 VIA_PCR_B_CB2_INPUT_POS_CLEAR_ON_READ := $40 000003r 3 VIA_PCR_B_CB2_INPUT_POS := $60 000003r 3 VIA_PCR_B_CB2_OUTPUT_HANDSHAKE := $80 000003r 3 VIA_PCR_B_CB2_OUTPUT_PULSE := $A0 000003r 3 VIA_PCR_B_CB2_OUTPUT_LOW := $C0 000003r 3 VIA_PCR_B_CB2_OUTPUT_HIGH := $E0 000003r 3 000003r 3 VIA_ACR_B_PA_LATCH_ENABLE := $01 000003r 3 VIA_ACR_B_PB_LATCH_ENABLE := $02 000003r 3 VIA_ACR_B_SHIFT_MASK := $1C 000003r 3 VIA_ACR_B_SHIFT_DISABLED := $00 000003r 3 VIA_ACR_B_SHIFT_IN_T2 := $04 000003r 3 VIA_ACR_B_SHIFT_IN_PHI2 := $08 000003r 3 VIA_ACR_B_SHIFT_IN_EXTCLOCK_CB1 := $0C 000003r 3 VIA_ACR_B_SHIFT_FREERUNNING_T2 := $10 000003r 3 VIA_ACR_B_SHIFT_OUT_T2 := $14 000003r 3 VIA_ACR_B_SHIFT_OUT_PHI2 := $18 000003r 3 VIA_ACR_B_SHIFT_OUT_EXTCLOCK_CB1 := $1C 000003r 3 VIA_ACR_B_T2_CONTROL_PB6 := $20 000003r 3 VIA_ACR_B_T1_CONTROL_MASK := $C0 000003r 3 VIA_ACR_B_T1_CONTROL_ONESHOT := $00 000003r 3 VIA_ACR_B_T1_CONTROL_FREERUN := $40 000003r 3 VIA_ACR_B_T1_CONTROL_ONESHOT_PB7 := $80 000003r 3 VIA_ACR_B_T1_CONTROL_FREERUN_PB7 := $C0 000003r 3 000003r 3 ; Alternative: 000003r 3 VIA_ACR_B_T1_CONTROL_ONETIME := $40 000003r 3 VIA_ACR_B_T1_CONTROL_PB7_OUTPUT := $80 000003r 3 000003r 2 000003r 2 VIA1 := $9110 000003r 2 VIA1_PB := VIA1 + 0 000003r 2 VIA1_PA := VIA1 + 1 000003r 2 VIA1_DDRB := VIA1 + 2 000003r 2 VIA1_DDRA := VIA1 + 3 000003r 2 VIA1_T1CL := VIA1 + 4 000003r 2 VIA1_T1CH := VIA1 + 5 000003r 2 VIA1_T1CLL := VIA1 + 6 000003r 2 VIA1_T1CHL := VIA1 + 7 000003r 2 VIA1_T2CL := VIA1 + 8 000003r 2 VIA1_T2CH := VIA1 + 9 000003r 2 VIA1_SR := VIA1 + 10 000003r 2 VIA1_ACR := VIA1 + 11 000003r 2 VIA1_PCR := VIA1 + 12 000003r 2 VIA1_IFR := VIA1 + 13 000003r 2 VIA1_IEC := VIA1 + 14 000003r 2 VIA1_PA_NO_HS := VIA1 + 15 000003r 2 000003r 2 VIA2 := $9120 000003r 2 VIA2_PB := VIA2 + 0 000003r 2 VIA2_PA := VIA2 + 1 000003r 2 VIA2_DDRB := VIA2 + 2 000003r 2 VIA2_DDRA := VIA2 + 3 000003r 2 VIA2_T1CL := VIA2 + 4 000003r 2 VIA2_T1CH := VIA2 + 5 000003r 2 VIA2_T1CLL := VIA2 + 6 000003r 2 VIA2_T1CHL := VIA2 + 7 000003r 2 VIA2_T2CL := VIA2 + 8 000003r 2 VIA2_T2CH := VIA2 + 9 000003r 2 VIA2_SR := VIA2 + 10 000003r 2 VIA2_ACR := VIA2 + 11 000003r 2 VIA2_PCR := VIA2 + 12 000003r 2 VIA2_IFR := VIA2 + 13 000003r 2 VIA2_IEC := VIA2 + 14 000003r 2 VIA2_PA_NO_HS := VIA2 + 15 000003r 2 000003r 2 VIA2_PB_B_CASS_WRITE := $04 000003r 2 ; CASS READ on CA1 000003r 2 VIA2_PB_B_JOY3 := $80 000003r 2 000003r 2 VIA1_PA_B_IEC_CLK_IN := $01 000003r 2 VIA1_PA_B_IEC_DATA_IN := $02 000003r 2 VIA1_PA_B_JOY0 := $04 000003r 2 VIA1_PA_B_JOY1 := $08 000003r 2 VIA1_PA_B_JOY2 := $10 000003r 2 VIA1_PA_B_LIGHTPEN := $20 000003r 2 VIA1_PA_B_CASS_SWITCH := $40 000003r 2 VIA1_PA_B_IEC_ATN_OUT := $80 000003r 2 000003r 2 VIA1_PB_B_0 := $01 000003r 2 VIA1_PB_B_1 := $02 000003r 2 VIA1_PB_B_2 := $04 000003r 2 VIA1_PB_B_3 := $08 000003r 2 VIA1_PB_B_4 := $10 000003r 2 VIA1_PB_B_5 := $20 000003r 2 VIA1_PB_B_6 := $40 000003r 2 VIA1_PB_B_7 := $80 000003r 2 000003r 2 COLORRAM := $9400 000003r 2 000003r 2 IOBASE := VIA1 000003r 2 000003r 2 FILE_KEYBOARD := 0 000003r 2 FILE_TAPE := 1 000003r 2 FILE_RS232 := 2 000003r 2 FILE_SCREEN := 3 000003r 2 FILE_IEC := 4 000003r 2 000003r 2 KEY_SHIFTRUN := $83 000003r 2 000003r 2 IEC_REG := VIA1_PA_NO_HS 000003r 2 ;IEC_DDR := VIA1_DDRA 000003r 2 000003r 2 IEC_B_ATN_OUT := VIA1_PA_B_IEC_ATN_OUT 000003r 2 IEC_B_CLK_OUT := $02 000003r 2 IEC_B_DATA_OUT := $20 000003r 2 IEC_B_CLK_IN := VIA1_PA_B_IEC_CLK_IN 000003r 2 IEC_B_DATA_IN := VIA1_PA_B_IEC_DATA_IN 000003r 2 000003r 2 IEC_REG_ATN_OUT := VIA1_PA_NO_HS 000003r 2 IEC_REG_DATA_CLK_OUT := VIA2_PCR 000003r 2 IEC_REG_DATA_CLK_IN := VIA1_PA_NO_HS 000003r 2 000003r 2 IEC_TIMER_LO := VIA2_T2CL 000003r 2 IEC_TIMER_HI := VIA2_T2CH 000003r 2 000003r 2 IEC_TIMER_FLAG_REG := VIA2_IFR 000003r 2 IEC_TIMER_FLAG_B := $20 000003r 2 000003r 2 TAPE_REG := VIA1_PA_NO_HS 000003r 2 TAPE_DDR := VIA1_DDRA 000003r 2 TAPE_B_WRITE := $08 000003r 2 TAPE_B_SENSE := $40 000003r 2 TAPE_B_MOTOR_ON := $02 000003r 2 TAPE_B_MOTOR_ON_ALL := $0E 000003r 2 TAPE_B_MOTOR_OFF_AND := $FD 000003r 2 TAPE_B_MOTOR_OFF_OR := $0C 000003r 2 000003r 2 TAPE_REG_WRITE := VIA2_PB 000003r 2 TAPE_REG_SENSE := VIA1_PA_NO_HS 000003r 2 TAPE_REG_MOTOR := VIA1_PCR 000003r 2 TAPE_REG_ICR := VIA2_IEC 000003r 2 TAPE_REG_ICR_B_CLEARALL := VIA_IER_BW_UNSET | $7F 000003r 2 TAPE_REG_ICR_B_CASSREAD := VIA_IER_BW_SET | VIA_IER_B_CA1 000003r 2 TAPE_REG_ICR_B_WR_TIMER := VIA_IER_BW_SET | VIA_IER_B_T2 000003r 2 TAPE_REG_ICR_B_SET_3 := VIA_IER_BW_SET | VIA_IER_B_T1 000003r 2 TAPE_REG_ICR_B_UNSET_3 := VIA_IER_BW_UNSET | VIA_IER_B_T1 000003r 2 000003r 2 TAPE_TIMER1_LO := VIA2_T2CL 000003r 2 TAPE_TIMER1_HI := VIA2_T2CH 000003r 2 TAPE_TIMER2_LO := VIA2_T1CL 000003r 2 TAPE_TIMER2_HI := VIA2_T1CH 000003r 2 TAPE_TIMER1_CONST := $15 000003r 2 000003r 2 KEYB_ROW := VIA2_PB 000003r 2 KEYB_COL := VIA2_PA 000003r 2 KEYB_COL_FOR_STOP := VIA2_PA_NO_HS 000003r 2 000003r 2 KEYB_ROW_CTRL := $FB 000003r 2 KEYB_COL_CTRL := $FE 000003r 2 KEYB_ROW_STOP := $F7 000003r 2 KEYB_ROW_STANDARD := $F7 000003r 2 KEYB_CHECK_STOP := $FE 000003r 2 000003r 2 RS232_REG_1 := VIA1_PB 000003r 2 RS232_REG_2 := VIA2_PB 000003r 2 RS232_TIMER_LO := VIA1_T1CL 000003r 2 RS232_TIMER_HI := VIA1_T1CH 000003r 2 000003r 1 000003r 1 .include "../basic/basic2.inc" 000003r 2 000003r 2 .segment "HEADER" 000000r 2 000000r 2 BASIC_START: 000000r 2 000000r 2 bRESTART: 000000r 2 rr rr .addr LE394 000002r 2 rr rr .addr LE37B 000004r 2 43 42 4D 42 .byte "CBMBASIC" 000008r 2 41 53 49 43 00000Cr 2 00000Cr 2 ; This is the table of the entry addresses of the various 00000Cr 2 ; BASIC commands. Every address is " - 1" as this table is 00000Cr 2 ; used in pushing the address onto the stack and perfoming 00000Cr 2 ; an RTS afterwards. 00000Cr 2 00000Cr 2 .segment "VECTORS" 000000r 2 000000r 2 .segment "KEYWORDS" 000000r 2 000000r 2 CONFIG_FILE=1 000000r 2 CONFIG_CBM_ALL=1 000000r 2 CONFIG_2=1 000000r 2 000000r 2 .include "token.s" 000000r 3 init_token_tables 000000r 3 000000r 3 rr rr 45 4E keyword_rts "END", bEND, TokEnd 000004r 3 C4 xx 000001r 3 rr rr 46 4F keyword_rts "FOR", bFOR, TokFor 000005r 3 D2 xx 000002r 3 rr rr 4E 45 keyword_rts "NEXT", bNEXT 000006r 3 58 D4 xx 000003r 3 rr rr 44 41 keyword_rts "DATA", bDATA 000007r 3 54 C1 xx 000004r 3 .ifdef CONFIG_FILE 000004r 3 rr rr 49 4E keyword_rts "INPUT#", bINPUTN 000008r 3 50 55 54 A3 00000Cr 3 xx 000005r 3 .endif 000005r 3 rr rr 49 4E keyword_rts "INPUT", bINPUT 000009r 3 50 55 D4 xx 000006r 3 rr rr 44 49 keyword_rts "DIM", bDIM2 00000Ar 3 CD xx 000007r 3 rr rr 52 45 keyword_rts "READ", bREAD 00000Br 3 41 C4 xx 000008r 3 .ifdef APPLE 000008r 3 keyword_rts "PLT", bPLT 000008r 3 .else 000008r 3 rr rr 4C 45 keyword_rts "LET", bLET 00000Cr 3 D4 xx 000009r 3 .endif 000009r 3 rr rr 47 4F keyword_rts "GOTO", bGOTO, TokGoto 00000Dr 3 54 CF xx 00000Ar 3 rr rr 52 55 keyword_rts "RUN", bRUN 00000Er 3 CE xx 00000Br 3 rr rr 49 C6 keyword_rts "IF", bIF 00000Fr 3 xx 00000Cr 3 rr rr 52 45 keyword_rts "RESTORE", bRESTOR 000010r 3 53 54 4F 52 000014r 3 C5 xx 00000Dr 3 rr rr 47 4F keyword_rts "GOSUB", bGOSUB, TokGosub 000011r 3 53 55 C2 xx 00000Er 3 rr rr 52 45 keyword_rts "RETURN", bRETURN 000012r 3 54 55 52 CE 000016r 3 xx 00000Fr 3 .ifdef APPLE 00000Fr 3 keyword_rts "TEX", bTEX, TokRem 00000Fr 3 .else 00000Fr 3 rr rr 52 45 keyword_rts "REM", bREM, TokRem 000013r 3 CD xx 000010r 3 .endif 000010r 3 rr rr 53 54 keyword_rts "STOP", bSTOP2 000014r 3 4F D0 xx 000011r 3 rr rr 4F CE keyword_rts "ON", bONGOTO 000015r 3 xx 000012r 3 .ifdef CONFIG_NULL 000012r 3 keyword_rts "NULL", bNULL 000012r 3 .endif 000012r 3 .ifdef KBD 000012r 3 keyword_rts "PLOD", bPLOD 000012r 3 keyword_rts "PSAV", bPSAV 000012r 3 keyword_rts "VLOD", bVLOD 000012r 3 keyword_rts "VSAV", bVSAV 000012r 3 .endif 000012r 3 .ifndef CONFIG_NO_POKE 000012r 3 rr rr 57 41 keyword_rts "WAIT", bWAIT 000016r 3 49 D4 xx 000013r 3 .endif 000013r 3 .ifndef KBD 000013r 3 rr rr 4C 4F keyword_rts "LOAD", bLOADT 000017r 3 41 C4 xx 000014r 3 rr rr 53 41 keyword_rts "SAVE", bSAVET 000018r 3 56 C5 xx 000015r 3 .endif 000015r 3 .ifdef CONFIG_CBM_ALL 000015r 3 rr rr 56 45 keyword_rts "VERIFY", bVERFYT 000019r 3 52 49 46 D9 00001Dr 3 xx 000016r 3 .endif 000016r 3 rr rr 44 45 keyword_rts "DEF", bDEF 00001Ar 3 C6 xx 000017r 3 .ifdef KBD 000017r 3 keyword_rts "SLOD", bSLOD 000017r 3 .endif 000017r 3 .ifndef CONFIG_NO_POKE 000017r 3 rr rr 50 4F keyword_rts "POKE", bPOKE 00001Br 3 4B C5 xx 000018r 3 .endif 000018r 3 .ifdef CONFIG_FILE 000018r 3 rr rr 50 52 keyword_rts "PRINT#", bPRINTN 00001Cr 3 49 4E 54 A3 000020r 3 xx 000019r 3 .endif 000019r 3 rr rr 50 52 keyword_rts "PRINT", bPRINT, TokPrint 00001Dr 3 49 4E D4 xx 00001Ar 3 rr rr 43 4F keyword_rts "CONT", bCONT 00001Er 3 4E D4 xx 00001Br 3 rr rr 4C 49 keyword_rts "LIST", bLIST 00001Fr 3 53 D4 xx 00001Cr 3 .ifdef CONFIG_CBM_ALL 00001Cr 3 rr rr 43 4C keyword_rts "CLR", bCLEAR 000020r 3 D2 xx 00001Dr 3 .else 00001Dr 3 keyword_rts "CLEAR", bCLEAR 00001Dr 3 .endif 00001Dr 3 .ifdef CONFIG_FILE 00001Dr 3 rr rr 43 4D keyword_rts "CMD", bCMD 000021r 3 C4 xx 00001Er 3 rr rr 53 59 keyword_rts "SYS", bSYS 000022r 3 D3 xx 00001Fr 3 rr rr 4F 50 keyword_rts "OPEN", bOPENT 000023r 3 45 CE xx 000020r 3 rr rr 43 4C keyword_rts "CLOSE", bCLOSET 000024r 3 4F 53 C5 xx 000021r 3 .endif 000021r 3 .ifndef CONFIG_SMALL 000021r 3 rr rr 47 45 keyword_rts "GET", bGET 000025r 3 D4 xx 000022r 3 .endif 000022r 3 .ifdef KBD 000022r 3 keyword_rts "PRT", bPRT 000022r 3 .endif 000022r 3 rr rr 4E 45 keyword_rts "NEW", bSCRTCH 000026r 3 D7 xx 000023r 3 000023r 3 count_tokens 000023r 3 000023r 3 54 41 42 A8 keyword "TAB(", TokTab 000027r 3 xx 000024r 3 54 CF xx keyword "TO", TokTo 000025r 3 46 CE xx keyword "FN", TokFn 000026r 3 53 50 43 A8 keyword "SPC(", TokSpc 00002Ar 3 xx 000027r 3 54 48 45 CE keyword "THEN", TokThen 00002Br 3 xx 000028r 3 4E 4F D4 xx keyword "NOT", TokNot 000029r 3 53 54 45 D0 keyword "STEP", TokStep 00002Dr 3 xx 00002Ar 3 AB xx keyword "+", TokPlus 00002Br 3 AD xx keyword "-", TokMinus 00002Cr 3 AA xx keyword "*" 00002Dr 3 AF xx keyword "/" 00002Er 3 .ifdef KBD 00002Er 3 keyword "#" 00002Er 3 .else 00002Er 3 DE xx keyword "^" 00002Fr 3 .endif 00002Fr 3 41 4E C4 xx keyword "AND" 000030r 3 4F D2 xx keyword "OR" 000031r 3 BE xx keyword ">", TokGreater 000032r 3 BD xx keyword "=", TokEqual 000033r 3 BC xx keyword "<" 000034r 3 000034r 3 .segment "VECTORS" 000046r 3 UNFNC: 000046r 3 000046r 3 rr rr 53 47 keyword_addr "SGN", bSGN, TokSgn 00004Ar 3 CE xx 000035r 3 rr rr 49 4E keyword_addr "INT", bINT 000039r 3 D4 xx 000036r 3 rr rr 41 42 keyword_addr "ABS", bABS 00003Ar 3 D3 xx 000037r 3 .ifdef KBD 000037r 3 keyword_addr "VER", bVER 000037r 3 .endif 000037r 3 .ifndef CONFIG_NO_POKE 000037r 3 .ifdef CONFIG_RAM 000037r 3 keyword_addr "USR", bIQERR 000037r 3 .else 000037r 3 rr rr 55 53 keyword_addr "USR", lUSRPOK 00003Br 3 D2 xx 000038r 3 .endif 000038r 3 .endif 000038r 3 rr rr 46 52 keyword_addr "FRE", bFRE 00003Cr 3 C5 xx 000039r 3 rr rr 50 4F keyword_addr "POS", bPOS 00003Dr 3 D3 xx 00003Ar 3 rr rr 53 51 keyword_addr "SQR", bSQR 00003Er 3 D2 xx 00003Br 3 rr rr 52 4E keyword_addr "RND", bRND 00003Fr 3 C4 xx 00003Cr 3 rr rr 4C 4F keyword_addr "LOG", bLOG 000040r 3 C7 xx 00003Dr 3 rr rr 45 58 keyword_addr "EXP", bEXP 000041r 3 D0 xx 00003Er 3 .segment "VECTORS" 00005Ar 3 UNFNC_COS: 00005Ar 3 rr rr 43 4F keyword_addr "COS", bCOS 00005Er 3 D3 xx 00003Fr 3 .segment "VECTORS" 00005Cr 3 UNFNC_SIN: 00005Cr 3 rr rr 53 49 keyword_addr "SIN", bSIN 000060r 3 CE xx 000040r 3 .segment "VECTORS" 00005Er 3 UNFNC_TAN: 00005Er 3 rr rr 54 41 keyword_addr "TAN", bTAN 000062r 3 CE xx 000041r 3 .segment "VECTORS" 000060r 3 UNFNC_ATN: 000060r 3 rr rr 41 54 keyword_addr "ATN", bATN 000064r 3 CE xx 000042r 3 .ifdef KBD 000042r 3 keyword_addr "GETC", bGETC 000042r 3 .endif 000042r 3 .ifndef CONFIG_NO_POKE 000042r 3 rr rr 50 45 keyword_addr "PEEK", bPEEK 000046r 3 45 CB xx 000043r 3 .endif 000043r 3 rr rr 4C 45 keyword_addr "LEN", bLEN 000047r 3 CE xx 000044r 3 rr rr 53 54 keyword_addr "STR$", bSTRD 000048r 3 52 A4 xx 000045r 3 rr rr 56 41 keyword_addr "VAL", bVAL 000049r 3 CC xx 000046r 3 rr rr 41 53 keyword_addr "ASC", bASC 00004Ar 3 C3 xx 000047r 3 rr rr 43 48 keyword_addr "CHR$", bCHRD 00004Br 3 52 A4 xx 000048r 3 rr rr 4C 45 keyword_addr "LEFT$", bLEFTD, TokLeftS 00004Cr 3 46 54 A4 xx 000049r 3 rr rr 52 49 keyword_addr "RIGHT$", bRIGHTD 00004Dr 3 47 48 54 A4 000051r 3 xx 00004Ar 3 rr rr 4D 49 keyword_addr "MID$", bMIDD 00004Er 3 44 A4 xx 00004Br 3 .ifdef CONFIG_2 00004Br 3 47 CF xx keyword "GO", TokGo 00004Cr 3 .endif 00004Cr 3 .segment "KEYWORDS" 0000FFr 3 00 .byte 0 000100r 3 000100r 3 .segment "VECTORS" 000074r 3 MATHTBL: 000074r 3 79 .byte $79 000075r 3 rr rr .word FADDT-1 000077r 3 79 .byte $79 000078r 3 rr rr .word FSUBT-1 00007Ar 3 7B .byte $7B 00007Br 3 rr rr .word FMULTT-1 00007Dr 3 7B .byte $7B 00007Er 3 rr rr .word FDIVT-1 000080r 3 7F .byte $7F 000081r 3 rr rr .word bFPWRT-1 000083r 3 50 .byte $50 000084r 3 rr rr .word TAND-1 000086r 3 46 .byte $46 000087r 3 rr rr .word bOROP-1 000089r 3 7D .byte $7D 00008Ar 3 rr rr .word bNEGOP-1 00008Cr 3 5A .byte $5A 00008Dr 3 rr rr .word bEQUOP-1 00008Fr 3 64 .byte $64 000090r 3 rr rr .word bDOREL-1 000092r 3 000092r 2 000092r 2 .segment "VECTORS" 000092r 2 000092r 2 bSTMDSP = TOKEN_ADDRESS_TABLE 000092r 2 bFUNDSP = UNFNC 000092r 2 000092r 2 000092r 2 ; This is the table of the BASIC functions. 000092r 2 000092r 2 ; This is the table of the operands. Every entry consists 000092r 2 ; of 3 consecutive bytes: A first byte (@?) and the address 000092r 2 ; of the processing function ( - 1). 000092r 2 000092r 2 bOPTAB = MATHTBL 000092r 2 000092r 2 ;.segment "KEYWORDS" 000092r 2 000092r 2 bRESLST = TOKEN_NAME_TABLE 000092r 2 000092r 2 ; This is the list of the reserved words. Every word ends 000092r 2 ; with the last byte having bit 7 set. 000092r 2 ; The list ends with the last byte being 0. 000092r 2 ; The complete list is not allowed to exceed 256 byte! 000092r 2 000092r 2 TokPi = $FF 000092r 2 000092r 2 000092r 2 .segment "ERROR" 000000r 2 000000r 2 ; This is the table of error strings. Every entry ends with 000000r 2 ; bit 7 set. 000000r 2 000000r 2 ErrTooManyFiles = 1 000000r 2 ErrFileOpen = 2 000000r 2 ErrFileNotOpen = 3 000000r 2 ErrFileNotFound = 4 000000r 2 ErrDeviceNotPresent = 5 000000r 2 ErrNotInputFile = 6 000000r 2 ErrNotOutputFile = 7 000000r 2 ErrMissingFileName = 8 000000r 2 ErrIllegalDeviceNumber = 9 000000r 2 ErrNextWithoutFor = 10 000000r 2 ErrSyntax = 11 000000r 2 ErrReturnWithoutGosub = 12 000000r 2 ErrOutOfData = 13 000000r 2 ErrIllegalQuantity = 14 000000r 2 ErrOverflow = 15 000000r 2 ErrOutOfMemory = 16 000000r 2 ErrUndefinedStatement = 17 000000r 2 ErrBadSubscript = 18 000000r 2 ErrRedimdArray = 19 000000r 2 ErrDivisionByZero = 20 000000r 2 ErrIllegalDirect = 21 000000r 2 ErrTypeMismatch = 22 000000r 2 ErrStringTooLong = 23 000000r 2 ErrFileData = 24 000000r 2 ErrFormulaTooComplex = 25 000000r 2 ErrCantContinue = 26 000000r 2 ErrUndefdFunction = 27 000000r 2 ErrVerify = 28 000000r 2 ErrLoad = 29 000000r 2 ErrBreak = 30 000000r 2 000000r 2 000000r 2 bERRTAB: 000000r 2 StrTooManyFiles: 000000r 2 54 4F 4F 20 htasc "TOO MANY FILES" 000004r 2 4D 41 4E 59 000008r 2 20 46 49 4C 00000Er 2 StrFileOpen: 00000Er 2 46 49 4C 45 htasc "FILE OPEN" 000012r 2 20 4F 50 45 000016r 2 CE 000017r 2 StrFileNotOpen: 000017r 2 46 49 4C 45 htasc "FILE NOT OPEN" 00001Br 2 20 4E 4F 54 00001Fr 2 20 4F 50 45 000024r 2 StrFileNotFound: 000024r 2 46 49 4C 45 htasc "FILE NOT FOUND" 000028r 2 20 4E 4F 54 00002Cr 2 20 46 4F 55 000032r 2 StrDeviceNotPresent: 000032r 2 44 45 56 49 htasc "DEVICE NOT PRESENT" 000036r 2 43 45 20 4E 00003Ar 2 4F 54 20 50 000044r 2 StrNotInputFile: 000044r 2 4E 4F 54 20 htasc "NOT INPUT FILE" 000048r 2 49 4E 50 55 00004Cr 2 54 20 46 49 000052r 2 StrNotOutputFile: 000052r 2 4E 4F 54 20 htasc "NOT OUTPUT FILE" 000056r 2 4F 55 54 50 00005Ar 2 55 54 20 46 000061r 2 StrMissingFileName: 000061r 2 4D 49 53 53 htasc "MISSING FILE NAME" 000065r 2 49 4E 47 20 000069r 2 46 49 4C 45 000072r 2 StrIllegalDeviceNumber: 000072r 2 49 4C 4C 45 htasc "ILLEGAL DEVICE NUMBER" 000076r 2 47 41 4C 20 00007Ar 2 44 45 56 49 000087r 2 StrNextWithoutFor: 000087r 2 4E 45 58 54 htasc "NEXT WITHOUT FOR" 00008Br 2 20 57 49 54 00008Fr 2 48 4F 55 54 000097r 2 StrSyntax: 000097r 2 53 59 4E 54 htasc "SYNTAX" 00009Br 2 41 D8 00009Dr 2 StrReturnWithoutGosub: 00009Dr 2 52 45 54 55 htasc "RETURN WITHOUT GOSUB" 0000A1r 2 52 4E 20 57 0000A5r 2 49 54 48 4F 0000B1r 2 StrOutOfData: 0000B1r 2 4F 55 54 20 htasc "OUT OF DATA" 0000B5r 2 4F 46 20 44 0000B9r 2 41 54 C1 0000BCr 2 StrIllegalQuantity: 0000BCr 2 49 4C 4C 45 htasc "ILLEGAL QUANTITY" 0000C0r 2 47 41 4C 20 0000C4r 2 51 55 41 4E 0000CCr 2 StrOverflow: 0000CCr 2 4F 56 45 52 htasc "OVERFLOW" 0000D0r 2 46 4C 4F D7 0000D4r 2 StrOutOfMemory: 0000D4r 2 4F 55 54 20 htasc "OUT OF MEMORY" 0000D8r 2 4F 46 20 4D 0000DCr 2 45 4D 4F 52 0000E1r 2 StrUndefinedStatement: 0000E1r 2 55 4E 44 45 htasc "UNDEF'D STATEMENT" 0000E5r 2 46 27 44 20 0000E9r 2 53 54 41 54 0000F2r 2 StrBadSubscript: 0000F2r 2 42 41 44 20 htasc "BAD SUBSCRIPT" 0000F6r 2 53 55 42 53 0000FAr 2 43 52 49 50 0000FFr 2 StrRedimdArray: 0000FFr 2 52 45 44 49 htasc "REDIM'D ARRAY" 000103r 2 4D 27 44 20 000107r 2 41 52 52 41 00010Cr 2 StrDivisionByZero: 00010Cr 2 44 49 56 49 htasc "DIVISION BY ZERO" 000110r 2 53 49 4F 4E 000114r 2 20 42 59 20 00011Cr 2 StrIllegalDirect: 00011Cr 2 49 4C 4C 45 htasc "ILLEGAL DIRECT" 000120r 2 47 41 4C 20 000124r 2 44 49 52 45 00012Ar 2 StrTypeMismatch: 00012Ar 2 54 59 50 45 htasc "TYPE MISMATCH" 00012Er 2 20 4D 49 53 000132r 2 4D 41 54 43 000137r 2 StrStringTooLong: 000137r 2 53 54 52 49 htasc "STRING TOO LONG" 00013Br 2 4E 47 20 54 00013Fr 2 4F 4F 20 4C 000146r 2 StrFileData: 000146r 2 46 49 4C 45 htasc "FILE DATA" 00014Ar 2 20 44 41 54 00014Er 2 C1 00014Fr 2 StrFormulaTooComplex: 00014Fr 2 46 4F 52 4D htasc "FORMULA TOO COMPLEX" 000153r 2 55 4C 41 20 000157r 2 54 4F 4F 20 000162r 2 StrCantContinue: 000162r 2 43 41 4E 27 htasc "CAN'T CONTINUE" 000166r 2 54 20 43 4F 00016Ar 2 4E 54 49 4E 000170r 2 StrUndefdFunction: 000170r 2 55 4E 44 45 htasc "UNDEF'D FUNCTION" 000174r 2 46 27 44 20 000178r 2 46 55 4E 43 000180r 2 StrVerify: 000180r 2 56 45 52 49 htasc "VERIFY" 000184r 2 46 D9 000186r 2 StrLoad: 000186r 2 4C 4F 41 C4 htasc "LOAD" 00018Ar 2 00018Ar 2 ; This is the list of pointers into the error strings. 00018Ar 2 00018Ar 2 bERRPTR: 00018Ar 2 rr rr .addr StrTooManyFiles 00018Cr 2 rr rr .addr StrFileOpen 00018Er 2 rr rr .addr StrFileNotOpen 000190r 2 rr rr .addr StrFileNotFound 000192r 2 rr rr .addr StrDeviceNotPresent 000194r 2 rr rr .addr StrNotInputFile 000196r 2 rr rr .addr StrNotOutputFile 000198r 2 rr rr .addr StrMissingFileName 00019Ar 2 rr rr .addr StrIllegalDeviceNumber 00019Cr 2 rr rr .addr StrNextWithoutFor 00019Er 2 rr rr .addr StrSyntax 0001A0r 2 rr rr .addr StrReturnWithoutGosub 0001A2r 2 rr rr .addr StrOutOfData 0001A4r 2 rr rr .addr StrIllegalQuantity 0001A6r 2 rr rr .addr StrOverflow 0001A8r 2 rr rr .addr StrOutOfMemory 0001AAr 2 rr rr .addr StrUndefinedStatement 0001ACr 2 rr rr .addr StrBadSubscript 0001AEr 2 rr rr .addr StrRedimdArray 0001B0r 2 rr rr .addr StrDivisionByZero 0001B2r 2 rr rr .addr StrIllegalDirect 0001B4r 2 rr rr .addr StrTypeMismatch 0001B6r 2 rr rr .addr StrStringTooLong 0001B8r 2 rr rr .addr StrFileData 0001BAr 2 rr rr .addr StrFormulaTooComplex 0001BCr 2 rr rr .addr StrCantContinue 0001BEr 2 rr rr .addr StrUndefdFunction 0001C0r 2 rr rr .addr StrVerify 0001C2r 2 rr rr .addr StrLoad 0001C4r 2 rr rr .addr StrBreak 0001C6r 2 0001C6r 2 0D 4F 4B 0D bOKK: .byte $0D,"OK",$0D,$00 0001CAr 2 00 0001CBr 2 0001CBr 2 .segment "CODE" 000000r 2 000000r 2 StrError: 000000r 2 .if CompileComputer >= C64_GENERAL 000000r 2 .byte ' ' 000000r 2 .else 000000r 2 0D .byte $0D 000001r 2 .endif 000001r 2 20 45 52 52 .byte " ERROR" 000005r 2 4F 52 000007r 2 00 .byte $00 000008r 2 000008r 2 StrIn: 000008r 2 20 49 4E 20 .byte " IN " 00000Cr 2 00 .byte $00 00000Dr 2 00000Dr 2 StrReady: 00000Dr 2 0D 0A .byte $0D,$0A 00000Fr 2 52 45 41 44 .byte "READY." 000013r 2 59 2E 000015r 2 0D 0A 00 .byte $0D,$0A,$00 000018r 2 000018r 2 StrCrBreak: 000018r 2 0D 0A .byte $0D,$0A 00001Ar 2 StrBreak: 00001Ar 2 42 52 45 41 .byte "BREAK" 00001Er 2 4B 00001Fr 2 00 .byte $00 000020r 2 000020r 2 A0 .byte $A0 ; @? 000021r 2 000021r 2 ; This routine tries to find a stack entry for a 000021r 2 ; previous "FOR" statement. 000021r 2 ; 000021r 2 ; Input: 000021r 2 ; zFORPNT/zFORPNT + 1: 000021r 2 ; Contans the variable name of the variable given 000021r 2 ; by the "NEXT" command. 000021r 2 ; If ANY for has to be closed, zFORPNT + 1 is 0. 000021r 2 ; 000021r 2 ; Output: 000021r 2 ; X: 000021r 2 ; contains a pointer into the stack page 000021r 2 ; where the "FOR entry" is located. 000021r 2 ; 000021r 2 ; Z: 000021r 2 ; Is set iff an entry has been found. 000021r 2 ; OR the stack has been exhausted. 000021r 2 ; 000021r 2 ; zFORPNT/zFORPNT + 1: 000021r 2 ; contains the variable name of the variable 000021r 2 ; being "NEXT"ed, even if no variable name 000021r 2 ; was given on input. 000021r 2 ; 000021r 2 ; Remarks: 000021r 2 ; This function is tricks as it also handles the 000021r 2 ; FOR, GOSUB and RETURN statements. @ 000021r 2 000021r 2 bFNDFOR: 000021r 2 BA tsx 000022r 2 E8 inx 000023r 2 E8 inx 000024r 2 E8 inx 000025r 2 E8 inx 000026r 2 @Loop: 000026r 2 ; first check if there is a "FOR entry" 000026r 2 BD rr rr lda lSTACK + 1,x 000029r 2 C9 81 cmp #TokFor 00002Br 2 D0 21 bne @Ret ; no FOR entry, return with error 00002Dr 2 00002Dr 2 ; check if the user asked for a specific variable 00002Dr 2 A5 rr lda zFORPNT + 1 00002Fr 2 D0 0A bne @TestVar ; yes, this, test this variable 000031r 2 000031r 2 ; no variable name was given, just take the current 000031r 2 ; one out of the stack entry 000031r 2 BD rr rr lda lSTACK + 2,x 000034r 2 85 rr sta zFORPNT 000036r 2 BD rr rr lda lSTACK + 3,x 000039r 2 85 rr sta zFORPNT + 1 00003Br 2 00003Br 2 ; now, test if the variable in the stack entry 00003Br 2 ; is the right one. 00003Br 2 ; If no variable is given, it will be the right one 00003Br 2 ; as we just took that one out of the stack entry. 00003Br 2 @TestVar: 00003Br 2 DD rr rr cmp lSTACK + 3,x 00003Er 2 D0 07 bne @UnWind ; not the same, unwind the stack 000040r 2 A5 rr lda zFORPNT 000042r 2 DD rr rr cmp lSTACK + 2,x 000045r 2 F0 07 beq @Ret ; ok, we found the variable, quit. 000047r 2 000047r 2 ; we have not found the variable. Unwind the stack, 000047r 2 ; that is, remove the current "FOR entry" and test 000047r 2 ; if there is another one before that. 000047r 2 @UnWind: 000047r 2 ; add 18 to the stack pointer to skip to the next entry 000047r 2 8A txa 000048r 2 18 clc 000049r 2 69 12 adc #18 00004Br 2 AA tax 00004Cr 2 00004Cr 2 ; if we did not reach the end of the stack, test the next entry 00004Cr 2 ; This one is a bit tricky. It only works as expected because 00004Cr 2 ; X has been incremented four times at the beginning of this 00004Cr 2 ; function. 00004Cr 2 D0 D8 bne @Loop 00004Er 2 00004Er 2 60 @Ret: rts 00004Fr 2 00004Fr 2 00004Fr 2 20 rr rr bBLTU: jsr bREASON 000052r 2 85 rr sta zSTREND 000054r 2 84 rr sty zSTREND + 1 000056r 2 000056r 2 ; Move memory around 000056r 2 ; 000056r 2 ; Input: 000056r 2 ; zTEMP_5F: Old begin 000056r 2 ; zTEMP_5A: Old end ( + 1) 000056r 2 ; zTEMP_58: New end ( + 1) 000056r 2 ; 000056r 2 ; Remark: 000056r 2 ; If both areas overlap, the new area has to be "above" the old one. 000056r 2 ; 000056r 2 MoveMem: 000056r 2 000056r 2 @OldBegin = zTEMP_5F 000056r 2 @OldEndP1 = zTEMP_5A 000056r 2 @NewEndP1 = zTEMP_58 000056r 2 000056r 2 ; calculate length of block to transfer 000056r 2 ; via subtracting Old begin from old end ( + 1). 000056r 2 ; 000056r 2 38 sec 000057r 2 A5 rr lda @OldEndP1 000059r 2 E5 rr sbc @OldBegin 00005Br 2 85 rr sta zINDEX ; low byte of length into zIndex 00005Dr 2 A8 tay ; and remember it in Y, too. 00005Er 2 A5 rr lda @OldEndP1 + 1 000060r 2 E5 rr sbc @OldBegin + 1 000062r 2 AA tax ; now, the high byte of length is in X 000063r 2 000063r 2 E8 inx 000064r 2 98 tya ; check low byte of length 000065r 2 F0 23 beq @SkipPartialPage ; is 0, thus, we do net have a partial page to process 000067r 2 000067r 2 ; now, subtract "page hangover" (low byte of length to move) 000067r 2 ; from OldEndP1 and NewEndP1. 000067r 2 ; This way, we process this "hangover" at first. Afterwards, only complete 000067r 2 ; pages have to be processed. 000067r 2 000067r 2 A5 rr lda @OldEndP1 000069r 2 38 sec 00006Ar 2 E5 rr sbc zINDEX 00006Cr 2 85 rr sta @OldEndP1 00006Er 2 B0 03 bcs @CalcNewEnd 000070r 2 C6 rr dec @OldEndP1 + 1 000072r 2 38 sec 000073r 2 000073r 2 @CalcNewEnd: 000073r 2 A5 rr lda @NewEndP1 000075r 2 E5 rr sbc zINDEX 000077r 2 85 rr sta @NewEndP1 000079r 2 B0 08 bcs @ProcessNextPage 00007Br 2 C6 rr dec @NewEndP1 + 1 00007Dr 2 90 04 bcc @ProcessNextPage ; unconditional jump 00007Fr 2 ; -------------------------- 00007Fr 2 00007Fr 2 @Loop: 00007Fr 2 B1 rr lda (@OldEndP1),y ; copy from old... 000081r 2 91 rr sta (@NewEndP1),y ; ... to new location 000083r 2 @ProcessNextPage: 000083r 2 88 dey ; number of bytes to process in this page 000084r 2 D0 F9 bne @Loop ; not zero? Then, copy memory. 000086r 2 000086r 2 ; copy the "last" byte of each page separately 000086r 2 B1 rr lda (@OldEndP1),y 000088r 2 91 rr sta (@NewEndP1),y 00008Ar 2 00008Ar 2 @SkipPartialPage: 00008Ar 2 ; decrement the page numbers of source and destination 00008Ar 2 ; and check if we have more pages to process (x). 00008Ar 2 00008Ar 2 C6 rr dec @OldEndP1 + 1 00008Cr 2 C6 rr dec @NewEndP1 + 1 00008Er 2 CA dex 00008Fr 2 D0 F2 bne @ProcessNextPage 000091r 2 60 rts 000092r 2 000092r 2 000092r 2 ; check if there is enough memory on the stack 000092r 2 ; 000092r 2 ; Input: 000092r 2 ; A: 000092r 2 ; Half of the number of bytes to check for 000092r 2 ; (that is, the number of double bytes) 000092r 2 ; 000092r 2 ; Output: 000092r 2 ; If this function returns, there is enough memory 000092r 2 ; on the stack. 000092r 2 ; 000092r 2 ; Remark: 000092r 2 ; If there is not enough memory on the stack, this 000092r 2 ; function does not return, but outputs an "?OUT OF MEMORY ERROR" 000092r 2 ; 000092r 2 bGETSTK: 000092r 2 ; first of all, calculate how much byte we would not 000092r 2 0A asl a ; as we are checking for double-words, multiply with 2 000093r 2 69 3E adc #$3E ; add a "security area" (@? Why $3E = 62) 000095r 2 B0 35 bcs bOMERR ; we overflowed, that is, it would not even fit into the 256 byte stack 000097r 2 85 rr sta zINDEX ; remember the value 000099r 2 000099r 2 ; now, check if the stack pointer is higher than what we just calculated 000099r 2 BA tsx 00009Ar 2 E4 rr cpx zINDEX 00009Cr 2 90 2E bcc bOMERR 00009Er 2 60 rts 00009Fr 2 00009Fr 2 bREASON: 00009Fr 2 C4 rr cpy zFRETOP + 1 0000A1r 2 90 28 bcc @Ret 0000A3r 2 D0 04 bne @LA412 0000A5r 2 C5 rr cmp zFRETOP 0000A7r 2 90 22 bcc @Ret 0000A9r 2 0000A9r 2 ; save zTMPF1 and zTMPF2 area onto the stack 0000A9r 2 0000A9r 2 @SAVE_AREA_SIZE = zFACEXP - zTEMPF1 0000A9r 2 0000A9r 2 48 @LA412: pha 0000AAr 2 A2 09 ldx #@SAVE_AREA_SIZE - 1 0000ACr 2 98 tya 0000ADr 2 48 @LA416: pha 0000AEr 2 B5 rr lda zTEMPF1,x 0000B0r 2 CA dex 0000B1r 2 10 FA bpl @LA416 0000B3r 2 0000B3r 2 20 rr rr jsr bGARBAG 0000B6r 2 0000B6r 2 ; restore the zTMPF1 and zTMPF2 area from the stack 0000B6r 2 A2 F7 ldx #-(@SAVE_AREA_SIZE - 1) 0000B8r 2 68 @LA421: pla 0000B9r 2 95 rr sta zTEMPF1 + @SAVE_AREA_SIZE,x 0000BBr 2 E8 inx 0000BCr 2 30 FA bmi @LA421 0000BEr 2 68 pla 0000BFr 2 A8 tay 0000C0r 2 68 pla 0000C1r 2 C4 rr cpy zFRETOP + 1 0000C3r 2 90 06 bcc @Ret 0000C5r 2 D0 05 bne bOMERR 0000C7r 2 C5 rr cmp zFRETOP 0000C9r 2 B0 01 bcs bOMERR 0000CBr 2 60 @Ret: rts 0000CCr 2 0000CCr 2 A2 10 bOMERR: ldx #ErrOutOfMemory 0000CEr 2 6C rr rr bERROR: jmp (lIERROR) ; for the VIC - 20, this is a no-op 0000D1r 2 ; for the C64, only proceed if bit 7 0000D1r 2 ; of the error code is not set 0000D1r 2 0000D1r 2 ; output a specific error message 0000D1r 2 ; 0000D1r 2 ; Input: 0000D1r 2 ; X: 0000D1r 2 ; The number of the error message 0000D1r 2 ; 0000D1r 2 ; Remark: 0000D1r 2 ; After outputting the message, this function returns into 0000D1r 2 ; the main BASIC loop. It never returns to its caller. 0000D1r 2 ; 0000D1r 2 ErrorOut: 0000D1r 2 8A txa ; multiply the error number with 2 0000D2r 2 0A asl a ; (this gives a pointer into the error text table) 0000D3r 2 AA tax 0000D4r 2 BD rr rr lda bERRPTR - 2,x ; Get the low byte 0000D7r 2 85 rr sta zINDEX 0000D9r 2 BD rr rr lda bERRPTR - 1,x ; and the high byte into zIndex/zIndex + 1 0000DCr 2 85 rr sta zINDEX + 1 0000DEr 2 0000DEr 2 20 rr rr jsr kCLRCHN ; clear channel, that is, output to the screen 0000E1r 2 0000E1r 2 A9 00 lda #0 ; make sure: we do not want to output LF after CR anymore 0000E3r 2 85 rr sta z13 0000E5r 2 20 rr rr jsr bCRDO ; output a CR 0000E8r 2 0000E8r 2 20 rr rr jsr LAB45 ; output a question mark '?' 0000EBr 2 0000EBr 2 ; now, output the text from the table 0000EBr 2 0000EBr 2 A0 00 ldy #0 ; start at the first character of the text 0000EDr 2 B1 rr @Loop: lda (zINDEX),y ; get the next character 0000EFr 2 48 pha ; remember it 0000F0r 2 29 7F and #$7F ; clear bit 7 (thus, make it printable) 0000F2r 2 20 rr rr jsr LAB47 ; output the character 0000F5r 2 C8 iny ; proceed to the next character 0000F6r 2 68 pla ; get back the remembered character 0000F7r 2 10 F4 bpl @Loop ; if bit 7 was not set, proceed to the next character 0000F9r 2 0000F9r 2 20 rr rr jsr LA67A ; initialize stack pointers (hardware stack and string stack) 0000FCr 2 0000FCr 2 ; output the text "error" 0000FCr 2 0000FCr 2 A9 rr lda #StrError 000100r 2 000100r 2 20 rr rr bERRFIN:jsr bSTROUT ; output the text given in A/Y.a 000103r 2 000103r 2 A4 rr ldy zCURLIN + 1 ; get high byte of current line (is $FF if in direct mode) 000105r 2 C8 iny 000106r 2 F0 03 beq bREADY ; it was $FF, thus, skip th next instruction 000108r 2 20 rr rr jsr bINPRT ; output "in line XXX" 00010Br 2 00010Br 2 A9 rr bREADY: lda #StrReady 00010Fr 2 20 rr rr jsr bSTROUT 000112r 2 A9 80 lda #$80 ; set the direct modus flag 000114r 2 20 rr rr jsr kSETMSG 000117r 2 000117r 2 6C rr rr bMAIN: jmp (lIMAIN) ; points to IMAIN normally 00011Ar 2 20 rr rr IMAIN: jsr bINLIN 00011Dr 2 86 rr stx zTXTPTR 00011Fr 2 84 rr sty zTXTPTR + 1 000121r 2 20 rr rr jsr zCHRGET 000124r 2 AA tax 000125r 2 F0 F0 beq bMAIN 000127r 2 A2 FF ldx #$FF ; set the line number to >= $FF00 = 65280 - as line numbers > 64999 are not allowed, this is a marker that no program is running currently 000129r 2 86 rr stx zCURLIN + 1 00012Br 2 90 06 bcc bMAIN1 00012Dr 2 20 rr rr jsr bCRUNCH 000130r 2 4C rr rr jmp bGONE 000133r 2 20 rr rr bMAIN1: jsr bLINGET 000136r 2 20 rr rr jsr bCRUNCH 000139r 2 84 rr bINSLIN:sty zCOUNT 00013Br 2 00013Br 2 @58 = zTEMPF1 + 1 00013Br 2 @5A = zTEMPF1 + 3 00013Br 2 00013Br 2 @5F = zTEMPF2 + 3 00013Br 2 00013Br 2 20 rr rr jsr bFNDLIN 00013Er 2 90 44 bcc @LA4ED 000140r 2 A0 01 ldy #1 000142r 2 B1 rr lda (@5F),y 000144r 2 85 rr sta zINDEX + 1 000146r 2 A5 rr lda zVARTAB 000148r 2 85 rr sta zINDEX 00014Ar 2 A5 rr lda @5F + 1 00014Cr 2 85 rr sta zINDEX2 + 1 00014Er 2 A5 rr lda @5F 000150r 2 88 dey 000151r 2 F1 rr sbc (@5F),y 000153r 2 18 clc 000154r 2 65 rr adc zVARTAB 000156r 2 85 rr sta zVARTAB 000158r 2 85 rr sta zINDEX2 00015Ar 2 A5 rr lda zVARTAB + 1 00015Cr 2 69 FF adc #-1 00015Er 2 85 rr sta zVARTAB + 1 000160r 2 E5 rr sbc @5F + 1 000162r 2 AA tax 000163r 2 38 sec 000164r 2 A5 rr lda @5F 000166r 2 E5 rr sbc zVARTAB 000168r 2 A8 tay 000169r 2 B0 03 bcs @LA4D7 00016Br 2 E8 inx 00016Cr 2 C6 rr dec zINDEX2 + 1 00016Er 2 @LA4D7: 00016Er 2 18 clc 00016Fr 2 65 rr adc zINDEX 000171r 2 90 03 bcc @LA4DF 000173r 2 C6 rr dec zINDEX + 1 000175r 2 18 clc 000176r 2 @LA4DF: 000176r 2 B1 rr lda (zINDEX),y 000178r 2 91 rr sta (zINDEX2),y 00017Ar 2 C8 iny 00017Br 2 D0 F9 bne @LA4DF 00017Dr 2 E6 rr inc zINDEX + 1 00017Fr 2 E6 rr inc zINDEX2 + 1 000181r 2 CA dex 000182r 2 D0 F2 bne @LA4DF 000184r 2 @LA4ED: 000184r 2 20 rr rr jsr LA659 000187r 2 20 rr rr jsr bLINKPRG 00018Ar 2 AD rr rr lda lBUF 00018Dr 2 F0 88 beq bMAIN 00018Fr 2 18 clc 000190r 2 A5 rr lda zVARTAB 000192r 2 85 rr sta @5A 000194r 2 65 rr adc zCOUNT 000196r 2 85 rr sta @58 000198r 2 A4 rr ldy zVARTAB + 1 00019Ar 2 84 rr sty @5A + 1 00019Cr 2 90 01 bcc @LA508 00019Er 2 C8 iny 00019Fr 2 @LA508: 00019Fr 2 84 rr sty @58 + 1 0001A1r 2 20 rr rr jsr bBLTU 0001A4r 2 A5 rr lda zLINNUM 0001A6r 2 A4 rr ldy zLINNUM + 1 0001A8r 2 8D rr rr sta lBUF - 2 0001ABr 2 8C rr rr sty lBUF - 1 0001AEr 2 A5 rr lda zSTREND 0001B0r 2 A4 rr ldy zSTREND + 1 0001B2r 2 85 rr sta zVARTAB 0001B4r 2 84 rr sty zVARTAB + 1 0001B6r 2 A4 rr ldy zCOUNT 0001B8r 2 88 dey 0001B9r 2 @LA522: 0001B9r 2 B9 rr rr lda lBUF - 4,y 0001BCr 2 91 rr sta (@5F),y 0001BEr 2 88 dey 0001BFr 2 10 F8 bpl @LA522 0001C1r 2 20 rr rr LA52A: jsr LA659 0001C4r 2 20 rr rr jsr bLINKPRG 0001C7r 2 4C rr rr jmp bMAIN 0001CAr 2 bLINKPRG: 0001CAr 2 A5 rr lda zTXTTAB 0001CCr 2 A4 rr ldy zTXTTAB + 1 0001CEr 2 85 rr sta zINDEX 0001D0r 2 84 rr sty zINDEX + 1 0001D2r 2 18 clc 0001D3r 2 @LA53C: 0001D3r 2 A0 01 ldy #1 0001D5r 2 B1 rr lda (zINDEX),y 0001D7r 2 F0 1D beq @Ret 0001D9r 2 A0 04 ldy #4 0001DBr 2 @LA544: 0001DBr 2 C8 iny 0001DCr 2 B1 rr lda (zINDEX),y 0001DEr 2 D0 FB bne @LA544 0001E0r 2 C8 iny 0001E1r 2 98 tya 0001E2r 2 65 rr adc zINDEX 0001E4r 2 AA tax 0001E5r 2 A0 00 ldy #0 0001E7r 2 91 rr sta (zINDEX),y 0001E9r 2 A5 rr lda zINDEX + 1 0001EBr 2 69 00 adc #0 0001EDr 2 C8 iny 0001EEr 2 91 rr sta (zINDEX),y 0001F0r 2 86 rr stx zINDEX 0001F2r 2 85 rr sta zINDEX + 1 0001F4r 2 90 DD bcc @LA53C 0001F6r 2 60 @Ret: rts 0001F7r 2 0001F7r 2 A2 00 bINLIN: ldx #0 0001F9r 2 20 rr rr @LA562: jsr bCHIN 0001FCr 2 C9 0D cmp #ASC_CR 0001FEr 2 F0 0D beq @LA576 000200r 2 9D rr rr sta lBUF,x 000203r 2 E8 inx 000204r 2 E0 59 cpx #END_lBUF - lBUF 000206r 2 90 F1 bcc @LA562 000208r 2 A2 17 ldx #ErrStringTooLong 00020Ar 2 4C rr rr jmp bERROR 00020Dr 2 00020Dr 2 4C rr rr @LA576: jmp bSTREND 000210r 2 000210r 2 6C rr rr bCRUNCH:jmp (lICRNCH) 000213r 2 A6 rr LA57C: ldx zTXTPTR 000215r 2 A0 04 ldy #$04 000217r 2 84 rr sty zGARBFL 000219r 2 BD rr rr LA582: lda lBUF,x 00021Cr 2 10 07 bpl @LA58E 00021Er 2 C9 FF cmp #TokPi 000220r 2 F0 3E beq LA5C9 000222r 2 E8 inx 000223r 2 D0 F4 bne LA582 000225r 2 @LA58E: 000225r 2 C9 20 cmp #' ' 000227r 2 F0 37 beq LA5C9 000229r 2 85 rr sta zENDCHR 00022Br 2 C9 22 cmp #'"' 00022Dr 2 F0 56 beq LA5EE 00022Fr 2 24 rr bit zGARBFL 000231r 2 70 2D bvs LA5C9 000233r 2 C9 3F cmp #'?' 000235r 2 D0 04 bne @LA5A4 000237r 2 A9 99 lda #TokPrint 000239r 2 D0 25 bne LA5C9 00023Br 2 @LA5A4: 00023Br 2 C9 30 cmp #'0' 00023Dr 2 90 04 bcc @LA5AC 00023Fr 2 C9 3C cmp #'<' 000241r 2 90 1D bcc LA5C9 000243r 2 @LA5AC: 000243r 2 84 rr sty zFBUFPT 000245r 2 A0 00 ldy #0 000247r 2 84 rr sty zCOUNT 000249r 2 88 dey 00024Ar 2 86 rr stx zTXTPTR 00024Cr 2 CA dex 00024Dr 2 C8 LA5B6: iny 00024Er 2 E8 inx 00024Fr 2 BD rr rr LA5B8: lda lBUF,x 000252r 2 38 sec 000253r 2 F9 rr rr sbc bRESLST,y 000256r 2 F0 F5 beq LA5B6 000258r 2 C9 80 cmp #$80 00025Ar 2 D0 30 bne LA5F5 00025Cr 2 05 rr ora zCOUNT 00025Er 2 A4 rr LA5C7: ldy zFBUFPT 000260r 2 E8 LA5C9: inx 000261r 2 C8 iny 000262r 2 99 rr rr sta lBUF - 5,y 000265r 2 B9 rr rr lda lBUF - 5,y 000268r 2 F0 36 beq LA609 00026Ar 2 38 sec 00026Br 2 E9 3A sbc #$3A ; ':' @? 00026Dr 2 F0 04 beq @LA5DC 00026Fr 2 C9 49 cmp #$49 ; DATA @? 000271r 2 D0 02 bne @LA5DE 000273r 2 @LA5DC: 000273r 2 85 rr sta zGARBFL 000275r 2 @LA5DE: 000275r 2 38 sec 000276r 2 E9 55 sbc #$55 ; REM @? 000278r 2 D0 9F bne LA582 00027Ar 2 JDLA5E3: 00027Ar 2 85 rr sta zENDCHR 00027Cr 2 BD rr rr LA5E5: lda lBUF,x 00027Fr 2 F0 DF beq LA5C9 000281r 2 C5 rr cmp zENDCHR 000283r 2 F0 DB beq LA5C9 000285r 2 C8 LA5EE: iny 000286r 2 99 rr rr sta lBUF - 5,y 000289r 2 E8 inx 00028Ar 2 D0 F0 bne LA5E5 00028Cr 2 A6 rr LA5F5: ldx zTXTPTR 00028Er 2 E6 rr inc zCOUNT 000290r 2 C8 @LA5F9: iny 000291r 2 B9 rr rr lda bRESLST - 1,y 000294r 2 10 FA bpl @LA5F9 000296r 2 B9 rr rr lda bRESLST,y 000299r 2 D0 B4 bne LA5B8 00029Br 2 BD rr rr lda lBUF,x 00029Er 2 10 BE bpl LA5C7 0002A0r 2 99 rr rr LA609: sta lBUF - 3,y 0002A3r 2 C6 rr dec zTXTPTR + 1 ; = 1, this is (>(lBUF - 1)) 0002A5r 2 A9 rr lda #2 0002EEr 2 85 rr sta zVARTAB + 1 0002F0r 2 0002F0r 2 20 rr rr LA659: jsr bSTXPT 0002F3r 2 A9 00 lda #0 0002F5r 2 0002F5r 2 D0 2D bCLEAR: bne RetA68D 0002F7r 2 20 rr rr LA660: jsr kCLALL 0002FAr 2 A5 rr LA663: lda zMEMSIZ 0002FCr 2 A4 rr ldy zMEMSIZ + 1 0002FEr 2 85 rr sta zFRETOP 000300r 2 84 rr sty zFRETOP + 1 000302r 2 A5 rr lda zVARTAB 000304r 2 A4 rr ldy zVARTAB + 1 000306r 2 85 rr sta zARYTAB 000308r 2 84 rr sty zARYTAB + 1 00030Ar 2 85 rr sta zSTREND 00030Cr 2 84 rr sty zSTREND + 1 00030Er 2 20 rr rr LA677: jsr bRESTOR 000311r 2 000311r 2 A2 rr LA67A: ldx #zTEMPST 000313r 2 86 rr stx zTEMPPT 000315r 2 68 pla 000316r 2 A8 tay 000317r 2 68 pla 000318r 2 A2 FA ldx #-6 00031Ar 2 9A txs ; Stackpointer to $01FA 00031Br 2 48 pha 00031Cr 2 98 tya 00031Dr 2 48 pha 00031Er 2 A9 00 lda #0 000320r 2 85 rr sta zOLDTXT + 1 000322r 2 85 rr sta zINTALLOWED 000324r 2 RetA68D: 000324r 2 60 rts 000325r 2 000325r 2 18 bSTXPT: clc 000326r 2 A5 rr lda zTXTTAB 000328r 2 69 FF adc #<-1 00032Ar 2 85 rr sta zTXTPTR 00032Cr 2 A5 rr lda zTXTTAB + 1 00032Er 2 69 FF adc #>-1 000330r 2 85 rr sta zTXTPTR + 1 000332r 2 60 rts 000333r 2 000333r 2 90 06 bLIST: bcc LA6A4 000335r 2 F0 04 beq LA6A4 000337r 2 C9 AB cmp #TokMinus 000339r 2 D0 E9 bne RetA68D 00033Br 2 LA6A4: 00033Br 2 20 rr rr jsr bLINGET 00033Er 2 20 rr rr jsr bFNDLIN 000341r 2 20 rr rr jsr zCHRGOT 000344r 2 F0 0C beq @LA6BB 000346r 2 C9 AB cmp #TokMinus 000348r 2 D0 8E bne RetA641 00034Ar 2 20 rr rr jsr zCHRGET 00034Dr 2 20 rr rr jsr bLINGET 000350r 2 D0 86 bne RetA641 000352r 2 @LA6BB: 000352r 2 68 pla 000353r 2 68 pla 000354r 2 A5 rr lda zLINNUM 000356r 2 05 rr ora zLINNUM + 1 000358r 2 D0 06 bne LA6C9 00035Ar 2 JDLA6C3: 00035Ar 2 A9 FF lda #-1 00035Cr 2 85 rr sta zLINNUM 00035Er 2 85 rr sta zLINNUM + 1 000360r 2 A0 01 LA6C9: ldy #1 000362r 2 84 rr sty zGARBFL 000364r 2 B1 rr lda (zTEMP_5F),y 000366r 2 F0 43 beq LA714 000368r 2 20 rr rr jsr bSTOP 00036Br 2 JDLA6D4: 00036Br 2 20 rr rr jsr bCRDO 00036Er 2 C8 iny 00036Fr 2 B1 rr lda (zTEMP_5F),y 000371r 2 AA tax 000372r 2 C8 iny 000373r 2 B1 rr lda (zTEMP_5F),y 000375r 2 C5 rr cmp zLINNUM + 1 000377r 2 D0 04 bne @LA6E6 000379r 2 E4 rr cpx zLINNUM 00037Br 2 F0 02 beq @LA6E8 00037Dr 2 B0 2C @LA6E6: bcs LA714 00037Fr 2 84 rr @LA6E8: sty zFORPNT 000381r 2 20 rr rr jsr LBDCD 000384r 2 A9 20 lda #' ' 000386r 2 A4 rr LA6EF: ldy zFORPNT 000388r 2 29 7F and #$7F 00038Ar 2 20 rr rr LA6F3: jsr LAB47 00038Dr 2 C9 22 cmp #'"' 00038Fr 2 D0 06 bne LA700 000391r 2 A5 rr lda zGARBFL 000393r 2 49 FF eor #$FF 000395r 2 85 rr sta zGARBFL 000397r 2 C8 LA700: iny 000398r 2 F0 11 beq LA714 00039Ar 2 B1 rr lda (zTEMP_5F),y 00039Cr 2 D0 10 bne bQPLOP 00039Er 2 A8 tay 00039Fr 2 B1 rr lda (zTEMP_5F),y 0003A1r 2 AA tax 0003A2r 2 C8 iny 0003A3r 2 B1 rr lda (zTEMP_5F),y 0003A5r 2 86 rr stx zTEMP_5F 0003A7r 2 85 rr sta zTEMP_5F + 1 0003A9r 2 D0 B5 bne LA6C9 0003ABr 2 LA714: 0003ABr 2 .if CompileComputer >= C64_GENERAL 0003ABr 2 jmp ReadyVector 0003ABr 2 .else 0003ABr 2 4C rr rr jmp bREADY 0003AEr 2 .endif 0003AEr 2 0003AEr 2 6C rr rr bQPLOP: jmp (lIQPLOP) 0003B1r 2 10 D7 LA71A: bpl LA6F3 0003B3r 2 C9 FF cmp #TokPi 0003B5r 2 F0 D3 beq LA6F3 0003B7r 2 24 rr bit zGARBFL 0003B9r 2 30 CF bmi LA6F3 0003BBr 2 38 sec 0003BCr 2 E9 7F sbc #$7F 0003BEr 2 AA tax 0003BFr 2 84 rr sty zFORPNT 0003C1r 2 A0 FF ldy #$FF 0003C3r 2 @LA72C: 0003C3r 2 CA dex 0003C4r 2 F0 08 beq @LA737 0003C6r 2 @LA72F: 0003C6r 2 C8 iny 0003C7r 2 B9 rr rr lda bRESLST,y 0003CAr 2 10 FA bpl @LA72F 0003CCr 2 30 F5 bmi @LA72C 0003CEr 2 @LA737: 0003CEr 2 C8 iny 0003CFr 2 B9 rr rr lda bRESLST,y 0003D2r 2 30 B2 bmi LA6EF 0003D4r 2 20 rr rr jsr LAB47 0003D7r 2 D0 F5 bne @LA737 0003D9r 2 0003D9r 2 A9 80 bFOR: lda #$80 0003DBr 2 85 rr sta zINTALLOWED 0003DDr 2 20 rr rr jsr bLET 0003E0r 2 20 rr rr jsr bFNDFOR 0003E3r 2 D0 05 bne @LA753 0003E5r 2 8A txa 0003E6r 2 69 0F adc #$0F 0003E8r 2 AA tax 0003E9r 2 9A txs 0003EAr 2 @LA753: 0003EAr 2 68 pla 0003EBr 2 68 pla 0003ECr 2 A9 09 lda #$09 0003EEr 2 20 rr rr jsr bGETSTK 0003F1r 2 20 rr rr jsr bDATAN 0003F4r 2 18 clc 0003F5r 2 98 tya 0003F6r 2 65 rr adc zTXTPTR 0003F8r 2 48 pha 0003F9r 2 A5 rr lda zTXTPTR + 1 0003FBr 2 69 00 adc #0 0003FDr 2 48 pha 0003FEr 2 A5 rr lda zCURLIN + 1 000400r 2 48 pha 000401r 2 A5 rr lda zCURLIN 000403r 2 48 pha 000404r 2 A9 A4 lda #TokTo 000406r 2 20 rr rr jsr LAEFF 000409r 2 20 rr rr jsr LAD8D 00040Cr 2 20 rr rr jsr bFRMNUM 00040Fr 2 A5 rr lda zFACSGN 000411r 2 09 7F ora #$7F 000413r 2 25 rr and zFACHO 000415r 2 85 rr sta zFACHO 000417r 2 A9 rr lda #<@LA78B 000419r 2 A0 rr ldy #>@LA78B 00041Br 2 85 rr sta zINDEX 00041Dr 2 84 rr sty zINDEX + 1 00041Fr 2 4C rr rr jmp LAE43 000422r 2 000422r 2 @LA78B: 000422r 2 A9 rr lda #bFPTABL 000426r 2 20 rr rr jsr bMOVFM 000429r 2 20 rr rr jsr zCHRGOT 00042Cr 2 C9 A9 cmp #TokStep 00042Er 2 D0 06 bne @LA79F 000430r 2 20 rr rr jsr zCHRGET 000433r 2 20 rr rr jsr bFRMNUM 000436r 2 @LA79F: 000436r 2 20 rr rr jsr bSIGN 000439r 2 20 rr rr jsr LAE38 00043Cr 2 A5 rr lda zFORPNT + 1 00043Er 2 48 pha 00043Fr 2 A5 rr lda zFORPNT 000441r 2 48 pha 000442r 2 A9 81 lda #TokFor 000444r 2 48 pha 000445r 2 20 rr rr bNEWSTT:jsr bSTOP 000448r 2 A5 rr lda zTXTPTR 00044Ar 2 A4 rr ldy zTXTPTR + 1 00044Cr 2 C0 rr cpy #>lBUF 00044Er 2 EA nop 00044Fr 2 F0 04 beq @LA7BE 000451r 2 85 rr sta zOLDTXT 000453r 2 84 rr sty zOLDTXT + 1 000455r 2 @LA7BE: 000455r 2 A0 00 ldy #0 000457r 2 B1 rr lda (zTXTPTR),y 000459r 2 D0 43 bne LA807 00045Br 2 00045Br 2 A0 02 bCKEOL: ldy #2 00045Dr 2 B1 rr lda (zTXTPTR),y 00045Fr 2 18 clc 000460r 2 D0 03 bne @LA7CE 000462r 2 4C rr rr jmp LA84B 000465r 2 @LA7CE: 000465r 2 C8 iny 000466r 2 B1 rr lda (zTXTPTR),y 000468r 2 85 rr sta zCURLIN 00046Ar 2 C8 iny 00046Br 2 B1 rr lda (zTXTPTR),y 00046Dr 2 85 rr sta zCURLIN + 1 00046Fr 2 98 tya 000470r 2 65 rr adc zTXTPTR 000472r 2 85 rr sta zTXTPTR 000474r 2 90 02 bcc bGONE 000476r 2 E6 rr inc zTXTPTR + 1 000478r 2 000478r 2 6C rr rr bGONE: jmp (lIGONE) 00047Br 2 20 rr rr LA7E4: jsr zCHRGET 00047Er 2 20 rr rr jsr bGONE3 000481r 2 4C rr rr jmp bNEWSTT 000484r 2 F0 3C bGONE3: beq RetA82B 000486r 2 E9 80 LA7EF: sbc #TokEnd 000488r 2 90 11 bcc @LA804 00048Ar 2 C9 23 cmp #TokTab - TokEnd 00048Cr 2 B0 17 bcs LA80E 00048Er 2 0A asl a 00048Fr 2 A8 tay 000490r 2 B9 rr rr lda bSTMDSP + 1,y 000493r 2 48 pha 000494r 2 B9 rr rr lda bSTMDSP,y 000497r 2 48 pha 000498r 2 4C rr rr jmp zCHRGET 00049Br 2 @LA804: 00049Br 2 4C rr rr jmp bLET 00049Er 2 00049Er 2 C9 3A LA807: cmp #':' 0004A0r 2 F0 D6 beq bGONE 0004A2r 2 4C rr rr LA80B: jmp bSYNERR 0004A5r 2 0004A5r 2 C9 4B LA80E: cmp #TokGo - $80 0004A7r 2 D0 F9 bne LA80B 0004A9r 2 20 rr rr jsr zCHRGET 0004ACr 2 A9 A4 lda #TokTo 0004AEr 2 20 rr rr jsr LAEFF 0004B1r 2 4C rr rr jmp bGOTO 0004B4r 2 38 bRESTOR:sec 0004B5r 2 A5 rr lda zTXTTAB 0004B7r 2 E9 01 sbc #1 0004B9r 2 A4 rr ldy zTXTTAB + 1 0004BBr 2 B0 01 bcs LA827 0004BDr 2 88 dey 0004BEr 2 85 rr LA827: sta zDATPTR 0004C0r 2 84 rr sty zDATPTR + 1 0004C2r 2 RetA82B: 0004C2r 2 60 rts 0004C3r 2 0004C3r 2 20 rr rr bSTOP: jsr kSTOP 0004C6r 2 B0 01 bSTOP2: bcs LA832 0004C8r 2 18 bEND: clc 0004C9r 2 D0 3C LA832: bne RetA870 0004CBr 2 A5 rr lda zTXTPTR 0004CDr 2 A4 rr ldy zTXTPTR + 1 0004CFr 2 A6 rr ldx zCURLIN + 1 0004D1r 2 E8 inx 0004D2r 2 F0 0C beq @LA849 0004D4r 2 85 rr sta zOLDTXT 0004D6r 2 84 rr sty zOLDTXT + 1 0004D8r 2 A5 rr lda zCURLIN 0004DAr 2 A4 rr ldy zCURLIN + 1 0004DCr 2 85 rr sta zOLDLIN 0004DEr 2 84 rr sty zOLDLIN + 1 0004E0r 2 @LA849: 0004E0r 2 68 pla 0004E1r 2 68 pla 0004E2r 2 0004E2r 2 A9 rr LA84B: lda #StrCrBreak 0004E6r 2 90 03 bcc LA854 0004E8r 2 4C rr rr jmp bERRFIN 0004EBr 2 0004EBr 2 LA854: 0004EBr 2 .if CompileComputer >= C64_GENERAL 0004EBr 2 jmp ReadyVector 0004EBr 2 .else 0004EBr 2 4C rr rr jmp bREADY 0004EEr 2 .endif 0004EEr 2 0004EEr 2 D0 17 bCONT: bne RetA870 0004F0r 2 A2 1A ldx #ErrCantContinue 0004F2r 2 A4 rr ldy zOLDTXT + 1 0004F4r 2 D0 03 bne @LA862 0004F6r 2 4C rr rr jmp bERROR 0004F9r 2 0004F9r 2 @LA862: 0004F9r 2 A5 rr lda zOLDTXT 0004FBr 2 85 rr sta zTXTPTR 0004FDr 2 84 rr sty zTXTPTR + 1 0004FFr 2 A5 rr lda zOLDLIN 000501r 2 A4 rr ldy zOLDLIN + 1 000503r 2 85 rr sta zCURLIN 000505r 2 84 rr sty zCURLIN + 1 000507r 2 RetA870: 000507r 2 60 rts 000508r 2 000508r 2 08 bRUN: php 000509r 2 A9 00 lda #0 00050Br 2 20 rr rr jsr kSETMSG 00050Er 2 28 plp 00050Fr 2 D0 03 bne @LA87D 000511r 2 4C rr rr jmp LA659 000514r 2 000514r 2 @LA87D: 000514r 2 20 rr rr jsr LA660 000517r 2 4C rr rr jmp LA897 00051Ar 2 00051Ar 2 A9 03 bGOSUB: lda #3 ; we want to push 3 16 bit values on the stack 00051Cr 2 20 rr rr jsr bGETSTK ; check for enough memory on stack 00051Fr 2 A5 rr lda zTXTPTR + 1 000521r 2 48 pha 000522r 2 A5 rr lda zTXTPTR 000524r 2 48 pha 000525r 2 A5 rr lda zCURLIN + 1 000527r 2 48 pha 000528r 2 A5 rr lda zCURLIN 00052Ar 2 48 pha 00052Br 2 A9 8D lda #TokGosub 00052Dr 2 48 pha 00052Er 2 00052Er 2 20 rr rr LA897: jsr zCHRGOT 000531r 2 20 rr rr jsr bGOTO 000534r 2 4C rr rr jmp bNEWSTT 000537r 2 000537r 2 20 rr rr bGOTO: jsr bLINGET 00053Ar 2 20 rr rr jsr LA909 00053Dr 2 38 sec 00053Er 2 A5 rr lda zCURLIN 000540r 2 E5 rr sbc zLINNUM 000542r 2 A5 rr lda zCURLIN + 1 000544r 2 E5 rr sbc zLINNUM + 1 000546r 2 B0 0B bcs @LA8BC 000548r 2 98 tya 000549r 2 38 sec 00054Ar 2 65 rr adc zTXTPTR 00054Cr 2 A6 rr ldx zTXTPTR + 1 00054Er 2 90 07 bcc @LA8C0 000550r 2 E8 inx 000551r 2 B0 04 bcs @LA8C0 000553r 2 @LA8BC: 000553r 2 A5 rr lda zTXTTAB 000555r 2 A6 rr ldx zTXTTAB + 1 000557r 2 @LA8C0: 000557r 2 20 rr rr jsr LA617 00055Ar 2 90 1E bcc LA8E3 00055Cr 2 A5 rr lda zTEMP_5F 00055Er 2 E9 01 sbc #<1 000560r 2 85 rr sta zTXTPTR 000562r 2 A5 rr lda zTEMP_5F + 1 000564r 2 E9 00 sbc #>0 000566r 2 85 rr sta zTXTPTR + 1 000568r 2 RetA8D1: 000568r 2 60 rts 000569r 2 000569r 2 D0 FD bRETURN:bne RetA8D1 00056Br 2 A9 FF lda #-1 00056Dr 2 85 rr sta zFORPNT + 1 00056Fr 2 20 rr rr jsr bFNDFOR 000572r 2 9A txs 000573r 2 C9 8D cmp #TokGosub 000575r 2 F0 0B beq LA8EB 000577r 2 A2 0C ldx #ErrReturnWithoutGosub 000579r 2 2C .byte ASM_BIT3 00057Ar 2 A2 11 LA8E3: ldx #ErrUndefinedStatement 00057Cr 2 4C rr rr jmp bERROR 00057Fr 2 4C rr rr LA8E8: jmp bSYNERR 000582r 2 68 LA8EB: pla 000583r 2 68 pla 000584r 2 85 rr sta zCURLIN 000586r 2 68 pla 000587r 2 85 rr sta zCURLIN + 1 000589r 2 68 pla 00058Ar 2 85 rr sta zTXTPTR 00058Cr 2 68 pla 00058Dr 2 85 rr sta zTXTPTR + 1 00058Fr 2 00058Fr 2 20 rr rr bDATA: jsr bDATAN 000592r 2 98 LA8FB: tya 000593r 2 000593r 2 JDLA8FC: 000593r 2 18 clc 000594r 2 65 rr adc zTXTPTR 000596r 2 85 rr sta zTXTPTR 000598r 2 90 02 bcc RetA905 00059Ar 2 E6 rr inc zTXTPTR + 1 00059Cr 2 RetA905: 00059Cr 2 60 rts 00059Dr 2 00059Dr 2 A2 3A bDATAN: ldx #':' 00059Fr 2 2C .byte ASM_BIT3 0005A0r 2 A2 00 LA909: ldx #0 ; end of line 0005A2r 2 86 rr stx zCHARAC 0005A4r 2 A0 00 ldy #0 0005A6r 2 84 rr sty zENDCHR 0005A8r 2 LA911: 0005A8r 2 A5 rr lda zENDCHR 0005AAr 2 A6 rr ldx zCHARAC 0005ACr 2 85 rr sta zCHARAC 0005AEr 2 JDLA917: 0005AEr 2 86 rr stx zENDCHR 0005B0r 2 @LA919: 0005B0r 2 B1 rr lda (zTXTPTR),y 0005B2r 2 F0 E8 beq RetA905 0005B4r 2 C5 rr cmp zENDCHR 0005B6r 2 F0 E4 beq RetA905 0005B8r 2 C8 iny 0005B9r 2 C9 22 cmp #'"' 0005BBr 2 D0 F3 bne @LA919 0005BDr 2 F0 E9 beq LA911 0005BFr 2 ; ---------------- 0005BFr 2 0005BFr 2 20 rr rr bIF: jsr bFRMEVL 0005C2r 2 20 rr rr jsr zCHRGOT 0005C5r 2 C9 89 cmp #TokGoto 0005C7r 2 F0 05 beq @LA937 0005C9r 2 A9 A7 lda #TokThen 0005CBr 2 20 rr rr jsr LAEFF 0005CEr 2 @LA937: 0005CEr 2 A5 rr lda zFACEXP 0005D0r 2 D0 05 bne LA940 0005D2r 2 0005D2r 2 20 rr rr bREM: jsr LA909 0005D5r 2 F0 BB beq LA8FB 0005D7r 2 20 rr rr LA940: jsr zCHRGOT 0005DAr 2 B0 03 bcs @LA948 0005DCr 2 4C rr rr jmp bGOTO 0005DFr 2 0005DFr 2 @LA948: 0005DFr 2 4C rr rr jmp bGONE3 0005E2r 2 0005E2r 2 20 rr rr bONGOTO:jsr LB79E 0005E5r 2 48 pha 0005E6r 2 C9 8D cmp #TokGosub 0005E8r 2 F0 04 beq LA957 0005EAr 2 C9 89 LA953: cmp #TokGoto 0005ECr 2 D0 91 bne LA8E8 0005EEr 2 C6 rr LA957: dec zFACHO + 3 0005F0r 2 D0 04 bne @LA95F 0005F2r 2 68 pla 0005F3r 2 4C rr rr jmp LA7EF 0005F6r 2 @LA95F: 0005F6r 2 20 rr rr jsr zCHRGET 0005F9r 2 20 rr rr jsr bLINGET 0005FCr 2 C9 2C cmp #',' 0005FEr 2 F0 EE beq LA957 000600r 2 68 pla 000601r 2 RetA96A: 000601r 2 60 rts 000602r 2 000602r 2 A2 00 bLINGET:ldx #0 000604r 2 86 rr stx zLINNUM 000606r 2 86 rr stx zLINNUM + 1 000608r 2 @LA971: 000608r 2 B0 F7 bcs RetA96A 00060Ar 2 E9 2F sbc #'0' - 1 00060Cr 2 85 rr sta zCHARAC 00060Er 2 A5 rr lda zLINNUM + 1 000610r 2 85 rr sta zINDEX 000612r 2 C9 19 cmp #>6400 ; interestingly, <6400 is 0. 000614r 2 B0 D4 bcs LA953 000616r 2 A5 rr lda zLINNUM 000618r 2 0A asl a 000619r 2 26 rr rol zINDEX 00061Br 2 0A asl a 00061Cr 2 26 rr rol zINDEX 00061Er 2 65 rr adc zLINNUM 000620r 2 85 rr sta zLINNUM 000622r 2 A5 rr lda zINDEX 000624r 2 65 rr adc zLINNUM + 1 000626r 2 85 rr sta zLINNUM + 1 000628r 2 06 rr asl zLINNUM 00062Ar 2 26 rr rol zLINNUM + 1 00062Cr 2 A5 rr lda zLINNUM 00062Er 2 65 rr adc zCHARAC 000630r 2 85 rr sta zLINNUM 000632r 2 90 02 bcc @LA99F 000634r 2 E6 rr inc zLINNUM + 1 000636r 2 @LA99F: 000636r 2 20 rr rr jsr zCHRGET 000639r 2 4C rr rr jmp @LA971 00063Cr 2 00063Cr 2 20 rr rr bLET: jsr bPTRGET 00063Fr 2 85 rr sta zFORPNT 000641r 2 84 rr sty zFORPNT + 1 000643r 2 A9 B2 lda #TokEqual 000645r 2 20 rr rr jsr LAEFF 000648r 2 A5 rr lda zINTFLG 00064Ar 2 48 pha 00064Br 2 A5 rr lda zVALTYP 00064Dr 2 48 pha 00064Er 2 20 rr rr jsr bFRMEVL 000651r 2 68 pla 000652r 2 2A rol a 000653r 2 20 rr rr jsr LAD90 000656r 2 D0 18 bne bPUTSTR 000658r 2 68 pla 000659r 2 10 12 LA9C2: bpl bPTFLPT 00065Br 2 00065Br 2 20 rr rr bPUTINT:jsr bROUND 00065Er 2 20 rr rr jsr bAYINT 000661r 2 A0 00 ldy #0 000663r 2 A5 rr lda zFACHO + 2 000665r 2 91 rr sta (zFORPNT),y 000667r 2 C8 iny 000668r 2 A5 rr lda zFACHO + 3 00066Ar 2 91 rr sta (zFORPNT),y 00066Cr 2 60 rts 00066Dr 2 4C rr rr bPTFLPT:jmp LBBD0 000670r 2 000670r 2 68 bPUTSTR:pla 000671r 2 A4 rr LA9DA: ldy zFORPNT + 1 000673r 2 C0 rr cpy #>bTI ; is the variable TI$? 000675r 2 D0 4C bne bGETSPT 000677r 2 20 rr rr jsr LB6A6 00067Ar 2 C9 06 bPUTTIM:cmp #6 00067Cr 2 D0 3D bne @LAA24 00067Er 2 A0 00 ldy #0 000680r 2 84 rr sty zFACEXP 000682r 2 84 rr sty zFACSGN 000684r 2 @LA9ED: 000684r 2 84 rr sty zFBUFPT 000686r 2 20 rr rr jsr @LAA1D 000689r 2 20 rr rr jsr bMUL10 00068Cr 2 E6 rr inc zFBUFPT 00068Er 2 A4 rr ldy zFBUFPT 000690r 2 20 rr rr jsr @LAA1D 000693r 2 20 rr rr jsr bMOVAF 000696r 2 AA tax 000697r 2 F0 05 beq @LAA07 000699r 2 E8 inx 00069Ar 2 8A txa 00069Br 2 20 rr rr jsr LBAED 00069Er 2 @LAA07: 00069Er 2 A4 rr ldy zFBUFPT 0006A0r 2 C8 iny 0006A1r 2 C0 06 cpy #6 0006A3r 2 D0 DF bne @LA9ED 0006A5r 2 20 rr rr jsr bMUL10 0006A8r 2 20 rr rr jsr bQINT 0006ABr 2 A6 rr ldx zFACHO + 2 0006ADr 2 A4 rr ldy zFACHO + 1 0006AFr 2 A5 rr lda zFACHO + 3 0006B1r 2 4C rr rr jmp kSETTIM 0006B4r 2 0006B4r 2 @LAA1D: 0006B4r 2 B1 rr lda (zINDEX),y 0006B6r 2 20 rr rr jsr zCHRGOT_SPACE 0006B9r 2 90 03 bcc @LAA27 0006BBr 2 @LAA24: 0006BBr 2 4C rr rr jmp bIQERR 0006BEr 2 0006BEr 2 @LAA27: 0006BEr 2 E9 2F sbc #'0' - 1 ; carry is already set! 0006C0r 2 4C rr rr jmp LBD7E 0006C3r 2 0006C3r 2 A0 02 bGETSPT:ldy #2 0006C5r 2 B1 rr lda (zFACHO + 2),y 0006C7r 2 C5 rr cmp zFRETOP + 1 0006C9r 2 90 17 bcc @LAA4B 0006CBr 2 D0 07 bne @LAA3D 0006CDr 2 88 dey 0006CEr 2 B1 rr lda (zFACHO + 2),y 0006D0r 2 C5 rr cmp zFRETOP 0006D2r 2 90 0E bcc @LAA4B 0006D4r 2 @LAA3D: 0006D4r 2 A4 rr ldy zFACHO + 3 0006D6r 2 C4 rr cpy zVARTAB + 1 0006D8r 2 90 08 bcc @LAA4B 0006DAr 2 D0 0D bne @LAA52 0006DCr 2 A5 rr lda zFACHO + 2 0006DEr 2 C5 rr cmp zVARTAB 0006E0r 2 B0 07 bcs @LAA52 0006E2r 2 @LAA4B: 0006E2r 2 A5 rr lda zFACHO + 2 0006E4r 2 A4 rr ldy zFACHO + 3 0006E6r 2 4C rr rr jmp @LAA68 0006E9r 2 0006E9r 2 @LAA52: 0006E9r 2 A0 00 ldy #0 0006EBr 2 B1 rr lda (zFACHO + 2),y 0006EDr 2 20 rr rr jsr LB475 0006F0r 2 A5 rr lda zTEMP_50 0006F2r 2 A4 rr ldy zTEMP_50 + 1 0006F4r 2 85 rr sta zARISGN 0006F6r 2 84 rr sty zFACOV 0006F8r 2 20 rr rr jsr bMOVINS 0006FBr 2 A9 rr lda #zFAC 0006FFr 2 @LAA68: 0006FFr 2 85 rr sta zTEMP_50 000701r 2 84 rr sty zTEMP_50 + 1 000703r 2 20 rr rr jsr bFREFAC 000706r 2 A0 00 ldy #0 000708r 2 B1 rr lda (zTEMP_50),y 00070Ar 2 91 rr sta (zFORPNT),y 00070Cr 2 C8 iny 00070Dr 2 B1 rr lda (zTEMP_50),y 00070Fr 2 91 rr sta (zFORPNT),y 000711r 2 C8 iny 000712r 2 B1 rr lda (zTEMP_50),y 000714r 2 91 rr sta (zFORPNT),y 000716r 2 60 rts 000717r 2 000717r 2 20 rr rr bPRINTN:jsr bCMD 00071Ar 2 4C rr rr jmp LABB5 00071Dr 2 00071Dr 2 20 rr rr bCMD: jsr LB79E 000720r 2 F0 05 beq @LAA90 000722r 2 A9 2C lda #',' 000724r 2 20 rr rr jsr LAEFF 000727r 2 @LAA90: 000727r 2 08 php 000728r 2 86 rr stx z13 00072Ar 2 20 rr rr jsr bCKOUT 00072Dr 2 28 plp 00072Er 2 4C rr rr jmp bPRINT 000731r 2 000731r 2 20 rr rr bSTRDON:jsr LAB21 000734r 2 000734r 2 20 rr rr LAA9D: jsr zCHRGOT 000737r 2 000737r 2 F0 35 bPRINT: beq bCRDO 000739r 2 F0 43 LAAA2: beq RetAAE7 00073Br 2 C9 A3 cmp #TokTab 00073Dr 2 F0 50 beq LAAF8 00073Fr 2 C9 A6 cmp #TokSpc 000741r 2 18 clc 000742r 2 F0 4B beq LAAF8 000744r 2 C9 2C cmp #',' 000746r 2 F0 37 beq bCOMPRT 000748r 2 C9 3B cmp #';' 00074Ar 2 F0 5E beq LAB13 00074Cr 2 20 rr rr jsr bFRMEVL 00074Fr 2 24 rr bVAROP: bit zVALTYP 000751r 2 30 DE bmi bSTRDON 000753r 2 20 rr rr jsr bFOUT 000756r 2 20 rr rr jsr bSTRLIT 000759r 2 20 rr rr jsr LAB21 00075Cr 2 20 rr rr jsr bOUTSPC 00075Fr 2 D0 D3 bne LAA9D 000761r 2 A9 00 bSTREND:lda #0 000763r 2 9D rr rr sta lBUF,x 000766r 2 A2 rr ldx #<(lBUF - 1) 000768r 2 A0 rr ldy #>(lBUF - 1) 00076Ar 2 A5 rr lda z13 00076Cr 2 D0 10 bne RetAAE7 00076Er 2 00076Er 2 ; output a CR and possibly a LF 00076Er 2 ; 00076Er 2 ; Input: 00076Er 2 ; none 00076Er 2 ; 00076Er 2 ; Remark: 00076Er 2 ; At first, this function outputs a CR ($0D). If z13 is negative, 00076Er 2 ; it outputs a LF afterwards. 00076Er 2 ; 00076Er 2 A9 0D bCRDO: lda #ASC_CR ; output the CR 000770r 2 20 rr rr jsr LAB47 000773r 2 24 rr bit z13 ; check: Shall we output a LF? 000775r 2 10 05 bpl LAAE5 000777r 2 A9 0A lda #ASC_LF ; yes, output the LF 000779r 2 20 rr rr jsr LAB47 00077Cr 2 49 FF LAAE5: eor #$FF 00077Er 2 RetAAE7: 00077Er 2 60 rts 00077Fr 2 00077Fr 2 38 bCOMPRT:sec 000780r 2 20 rr rr jsr kPLOT 000783r 2 98 tya 000784r 2 38 sec 000785r 2 @LAAEE: 000785r 2 E9 0B sbc #EDITOR_TAB 000787r 2 B0 FC bcs @LAAEE 000789r 2 49 FF eor #$FF 00078Br 2 69 01 adc #$01 00078Dr 2 D0 16 bne LAB0E 00078Fr 2 08 LAAF8: php 000790r 2 38 sec 000791r 2 20 rr rr jsr kPLOT 000794r 2 84 rr sty zTRMPOS 000796r 2 20 rr rr jsr bGTBYTC 000799r 2 C9 29 cmp #')' 00079Br 2 D0 59 bne LAB5F 00079Dr 2 28 plp 00079Er 2 90 06 bcc LAB0F 0007A0r 2 8A txa 0007A1r 2 E5 rr sbc zTRMPOS 0007A3r 2 90 05 bcc LAB13 0007A5r 2 AA LAB0E: tax 0007A6r 2 E8 LAB0F: inx 0007A7r 2 CA LAB10: dex 0007A8r 2 D0 06 bne LAB19 0007AAr 2 20 rr rr LAB13: jsr zCHRGET 0007ADr 2 4C rr rr jmp LAAA2 0007B0r 2 0007B0r 2 20 rr rr LAB19: jsr bOUTSPC 0007B3r 2 D0 F2 bne LAB10 0007B5r 2 0007B5r 2 20 rr rr bSTROUT:jsr bSTRLIT 0007B8r 2 0007B8r 2 20 rr rr LAB21: jsr LB6A6 0007BBr 2 AA tax 0007BCr 2 A0 00 ldy #0 0007BEr 2 E8 inx 0007BFr 2 @LAB28: 0007BFr 2 CA dex 0007C0r 2 F0 BC beq RetAAE7 0007C2r 2 B1 rr lda (zINDEX),y 0007C4r 2 20 rr rr jsr LAB47 0007C7r 2 C8 iny 0007C8r 2 C9 0D cmp #ASC_CR 0007CAr 2 D0 F3 bne @LAB28 0007CCr 2 20 rr rr jsr LAAE5 0007CFr 2 4C rr rr jmp @LAB28 0007D2r 2 0007D2r 2 A5 rr bOUTSPC:lda z13 0007D4r 2 F0 03 beq @LAB42 0007D6r 2 A9 20 lda #' ' 0007D8r 2 2C .byte ASM_BIT3 0007D9r 2 @LAB42: 0007D9r 2 A9 1D lda #ASC_CURSORLEFTRIGHT 0007DBr 2 2C .byte ASM_BIT3 0007DCr 2 0007DCr 2 0007DCr 2 A9 3F LAB45: lda #'?' 0007DEr 2 0007DEr 2 20 rr rr LAB47: jsr bCHOUT 0007E1r 2 29 FF and #$FF 0007E3r 2 60 rts 0007E4r 2 0007E4r 2 A5 rr bDOAGIN:lda zSUBFLG 0007E6r 2 F0 11 beq LAB62 0007E8r 2 30 04 bmi @LAB57 0007EAr 2 A0 FF ldy #$FF 0007ECr 2 D0 04 bne @LAB5B 0007EEr 2 ; --------------- 0007EEr 2 @LAB57: 0007EEr 2 A5 rr lda zDATLIN 0007F0r 2 A4 rr ldy zDATLIN + 1 0007F2r 2 @LAB5B: 0007F2r 2 85 rr sta zCURLIN 0007F4r 2 84 rr sty zCURLIN + 1 0007F6r 2 4C rr rr LAB5F: jmp bSYNERR 0007F9r 2 A5 rr LAB62: lda z13 0007FBr 2 F0 05 beq @LAB6B 0007FDr 2 A2 18 ldx #ErrFileData 0007FFr 2 4C rr rr jmp bERROR 000802r 2 000802r 2 @LAB6B: 000802r 2 A9 rr lda #StrRedoFromStart 000806r 2 20 rr rr jsr bSTROUT 000809r 2 A5 rr lda zOLDTXT 00080Br 2 A4 rr ldy zOLDTXT + 1 00080Dr 2 85 rr sta zTXTPTR 00080Fr 2 84 rr sty zTXTPTR + 1 000811r 2 60 rts 000812r 2 000812r 2 20 rr rr bGET: jsr bERRDIR 000815r 2 C9 23 cmp #'#' 000817r 2 D0 10 bne @LAB92 000819r 2 20 rr rr jsr zCHRGET 00081Cr 2 20 rr rr jsr LB79E 00081Fr 2 A9 2C lda #',' 000821r 2 20 rr rr jsr LAEFF 000824r 2 86 rr stx z13 000826r 2 20 rr rr jsr bCKIN 000829r 2 @LAB92: 000829r 2 A2 rr ldx #<(lBUF + 1) 00082Br 2 A0 rr ldy #>(lBUF + 1) 00082Dr 2 A9 00 lda #0 00082Fr 2 8D rr rr sta lBUF + 1 000832r 2 A9 40 lda #$40 000834r 2 20 rr rr jsr LAC0F 000837r 2 A6 rr ldx z13 000839r 2 D0 13 bne LABB7 00083Br 2 60 rts 00083Cr 2 00083Cr 2 20 rr rr bINPUTN:jsr LB79E 00083Fr 2 A9 2C lda #',' 000841r 2 20 rr rr jsr LAEFF 000844r 2 86 rr stx z13 000846r 2 20 rr rr jsr bCKIN 000849r 2 20 rr rr jsr LABCE 00084Cr 2 A5 rr LABB5: lda z13 00084Er 2 20 rr rr LABB7: jsr kCLRCHN 000851r 2 A2 00 ldx #0 000853r 2 86 rr stx z13 000855r 2 60 rts 000856r 2 C9 22 bINPUT: cmp #'"' 000858r 2 D0 0B bne LABCE 00085Ar 2 20 rr rr jsr LAEBD 00085Dr 2 A9 3B lda #';' 00085Fr 2 20 rr rr jsr LAEFF 000862r 2 20 rr rr jsr LAB21 000865r 2 20 rr rr LABCE: jsr bERRDIR 000868r 2 A9 2C lda #',' 00086Ar 2 8D rr rr sta lBUF - 1 00086Dr 2 20 rr rr LABD6: jsr bQINLIN 000870r 2 A5 rr lda z13 000872r 2 F0 0D beq bBUFFUL 000874r 2 20 rr rr jsr kREADST 000877r 2 29 02 and #$02 000879r 2 F0 06 beq bBUFFUL 00087Br 2 20 rr rr jsr LABB5 00087Er 2 4C rr rr jmp bDATA 000881r 2 000881r 2 AD rr rr bBUFFUL:lda lBUF 000884r 2 D0 1E bne LAC0D 000886r 2 A5 rr lda z13 000888r 2 D0 E3 bne LABD6 00088Ar 2 20 rr rr jsr bDATAN 00088Dr 2 4C rr rr jmp LA8FB 000890r 2 000890r 2 A5 rr bQINLIN:lda z13 000892r 2 D0 06 bne @LAC03 000894r 2 20 rr rr jsr LAB45 000897r 2 20 rr rr jsr bOUTSPC 00089Ar 2 @LAC03: 00089Ar 2 4C rr rr jmp bINLIN 00089Dr 2 00089Dr 2 A6 rr bREAD: ldx zDATPTR 00089Fr 2 A4 rr ldy zDATPTR + 1 0008A1r 2 A9 98 lda #$98 0008A3r 2 2C .byte ASM_BIT3 0008A4r 2 A9 00 LAC0D: lda #0 0008A6r 2 85 rr LAC0F: sta zSUBFLG 0008A8r 2 86 rr stx zINPPTR 0008AAr 2 84 rr sty zINPPTR + 1 0008ACr 2 20 rr rr LAC15: jsr bPTRGET 0008AFr 2 85 rr sta zFORPNT 0008B1r 2 84 rr sty zFORPNT + 1 0008B3r 2 A5 rr lda zTXTPTR 0008B5r 2 A4 rr ldy zTXTPTR + 1 0008B7r 2 85 rr sta zVARTXT 0008B9r 2 84 rr sty zVARTXT + 1 0008BBr 2 A6 rr ldx zINPPTR 0008BDr 2 A4 rr ldy zINPPTR + 1 0008BFr 2 86 rr stx zTXTPTR 0008C1r 2 84 rr sty zTXTPTR + 1 0008C3r 2 20 rr rr jsr zCHRGOT 0008C6r 2 D0 20 bne LAC51 0008C8r 2 24 rr bit zSUBFLG 0008CAr 2 50 0C bvc LAC41 0008CCr 2 0008CCr 2 20 rr rr bRGDET: jsr bGETIN 0008CFr 2 8D rr rr sta lBUF 0008D2r 2 A2 rr ldx #<(lBUF - 1) 0008D4r 2 A0 rr ldy #>(lBUF - 1) 0008D6r 2 D0 0C bne LAC4D 0008D8r 2 30 75 LAC41: bmi LACB8 0008DAr 2 A5 rr lda z13 0008DCr 2 D0 03 bne @LAC4A 0008DEr 2 20 rr rr jsr LAB45 0008E1r 2 @LAC4A: 0008E1r 2 20 rr rr jsr bQINLIN 0008E4r 2 0008E4r 2 86 rr LAC4D: stx zTXTPTR 0008E6r 2 84 rr sty zTXTPTR + 1 0008E8r 2 20 rr rr LAC51: jsr zCHRGET 0008EBr 2 24 rr bit zVALTYP 0008EDr 2 10 31 bpl @LAC89 0008EFr 2 24 rr bit zSUBFLG 0008F1r 2 50 09 bvc @LAC65 0008F3r 2 E8 inx 0008F4r 2 86 rr stx zTXTPTR 0008F6r 2 A9 00 lda #0 0008F8r 2 85 rr sta zCHARAC 0008FAr 2 F0 0C beq @LAC71 0008FCr 2 @LAC65: 0008FCr 2 85 rr sta zCHARAC 0008FEr 2 C9 22 cmp #'"' 000900r 2 F0 07 beq @LAC72 000902r 2 A9 3A lda #':' 000904r 2 85 rr sta zCHARAC 000906r 2 A9 2C lda #',' 000908r 2 @LAC71: 000908r 2 18 clc 000909r 2 @LAC72: 000909r 2 85 rr sta zENDCHR 00090Br 2 A5 rr lda zTXTPTR 00090Dr 2 A4 rr ldy zTXTPTR + 1 00090Fr 2 69 00 adc #0 000911r 2 90 01 bcc @LAC7D 000913r 2 C8 iny 000914r 2 @LAC7D: 000914r 2 20 rr rr jsr LB48D 000917r 2 20 rr rr jsr LB7E2 00091Ar 2 20 rr rr jsr LA9DA 00091Dr 2 4C rr rr jmp @LAC91 000920r 2 @LAC89: 000920r 2 20 rr rr jsr bFIN 000923r 2 A5 rr lda zINTFLG 000925r 2 20 rr rr jsr LA9C2 000928r 2 @LAC91: 000928r 2 20 rr rr jsr zCHRGOT 00092Br 2 F0 07 beq @LAC9D 00092Dr 2 C9 2C cmp #',' 00092Fr 2 F0 03 beq @LAC9D 000931r 2 4C rr rr jmp bDOAGIN 000934r 2 000934r 2 @LAC9D: 000934r 2 A5 rr lda zTXTPTR 000936r 2 A4 rr ldy zTXTPTR + 1 000938r 2 85 rr sta zINPPTR 00093Ar 2 84 rr sty zINPPTR + 1 00093Cr 2 A5 rr lda zVARTXT 00093Er 2 A4 rr ldy zVARTXT + 1 000940r 2 85 rr sta zTXTPTR 000942r 2 84 rr sty zTXTPTR + 1 000944r 2 20 rr rr jsr zCHRGOT 000947r 2 F0 2D beq LACDF 000949r 2 20 rr rr jsr bCHKCMA 00094Cr 2 4C rr rr jmp LAC15 00094Fr 2 20 rr rr LACB8: jsr bDATAN 000952r 2 C8 iny 000953r 2 AA tax 000954r 2 D0 12 bne @LACD1 000956r 2 A2 0D ldx #$0D 000958r 2 C8 iny 000959r 2 B1 rr lda (zTXTPTR),y 00095Br 2 F0 6C beq LAD32 00095Dr 2 C8 iny 00095Er 2 B1 rr lda (zTXTPTR),y 000960r 2 85 rr sta zDATLIN 000962r 2 C8 iny 000963r 2 B1 rr lda (zTXTPTR),y 000965r 2 C8 iny 000966r 2 85 rr sta zDATLIN + 1 000968r 2 @LACD1: 000968r 2 20 rr rr jsr LA8FB 00096Br 2 20 rr rr jsr zCHRGOT 00096Er 2 AA tax 00096Fr 2 E0 83 cpx #$83 000971r 2 D0 DC bne LACB8 000973r 2 4C rr rr jmp LAC51 000976r 2 A5 rr LACDF: lda zINPPTR 000978r 2 A4 rr ldy zINPPTR + 1 00097Ar 2 A6 rr ldx zSUBFLG 00097Cr 2 10 03 bpl @LACEA 00097Er 2 4C rr rr jmp LA827 000981r 2 @LACEA: 000981r 2 A0 00 ldy #0 000983r 2 B1 rr lda (zINPPTR),y 000985r 2 F0 0B beq @Ret 000987r 2 A5 rr lda z13 000989r 2 D0 07 bne @Ret 00098Br 2 A9 rr lda #bEXINT 00098Fr 2 4C rr rr jmp bSTROUT 000992r 2 60 @Ret: rts 000993r 2 000993r 2 3F 45 58 54 bEXINT: .byte "?EXTRA IGNORED",$0D,$00 000997r 2 52 41 20 49 00099Br 2 47 4E 4F 52 0009A3r 2 0009A3r 2 StrRedoFromStart: 0009A3r 2 3F 52 45 44 .byte "?REDO FROM START",$0D,$00 0009A7r 2 4F 20 46 52 0009ABr 2 4F 4D 20 53 0009B5r 2 0009B5r 2 D0 04 bNEXT: bne LAD24 0009B7r 2 A0 00 ldy #0 0009B9r 2 F0 03 beq LAD27 0009BBr 2 20 rr rr LAD24: jsr bPTRGET 0009BEr 2 85 rr LAD27: sta zFORPNT 0009C0r 2 84 rr sty zFORPNT + 1 0009C2r 2 20 rr rr jsr bFNDFOR 0009C5r 2 F0 05 beq LAD35 0009C7r 2 A2 0A ldx #ErrNextWithoutFor 0009C9r 2 4C rr rr LAD32: jmp bERROR 0009CCr 2 9A LAD35: txs 0009CDr 2 8A txa 0009CEr 2 18 clc 0009CFr 2 69 04 adc #$04 0009D1r 2 48 pha 0009D2r 2 69 06 adc #$06 0009D4r 2 85 rr sta zINDEX2 0009D6r 2 68 pla 0009D7r 2 A0 01 ldy #$01 0009D9r 2 20 rr rr jsr bMOVFM 0009DCr 2 BA tsx 0009DDr 2 BD rr rr lda lSTACK + 9,x 0009E0r 2 85 rr sta zFACSGN 0009E2r 2 A5 rr lda zFORPNT 0009E4r 2 A4 rr ldy zFORPNT + 1 0009E6r 2 20 rr rr jsr bFADD 0009E9r 2 20 rr rr jsr LBBD0 0009ECr 2 A0 01 ldy #$01 0009EEr 2 20 rr rr jsr LBC5D 0009F1r 2 BA tsx 0009F2r 2 38 sec 0009F3r 2 FD rr rr sbc lSTACK + 9,x 0009F6r 2 F0 17 beq LAD78 0009F8r 2 BD rr rr bDONEXT:lda lSTACK + 15,x 0009FBr 2 85 rr sta zCURLIN 0009FDr 2 BD rr rr lda lSTACK + 16,x 000A00r 2 85 rr sta zCURLIN + 1 000A02r 2 BD rr rr lda lSTACK + 18,x 000A05r 2 85 rr sta zTXTPTR 000A07r 2 BD rr rr lda lSTACK + 17,x 000A0Ar 2 85 rr sta zTXTPTR + 1 000A0Cr 2 4C rr rr LAD75: jmp bNEWSTT 000A0Fr 2 8A LAD78: txa 000A10r 2 69 11 adc #17 000A12r 2 AA tax 000A13r 2 9A txs 000A14r 2 20 rr rr jsr zCHRGOT 000A17r 2 C9 2C cmp #',' 000A19r 2 D0 F1 bne LAD75 000A1Br 2 20 rr rr jsr zCHRGET 000A1Er 2 20 rr rr jsr LAD24 000A21r 2 20 rr rr bFRMNUM:jsr bFRMEVL 000A24r 2 18 LAD8D: clc 000A25r 2 24 .byte ASM_BIT2 000A26r 2 38 LAD8F: sec 000A27r 2 24 rr LAD90: bit zVALTYP 000A29r 2 30 03 bmi LAD97 000A2Br 2 B0 03 bcs LAD99 000A2Dr 2 60 LAD96: rts 000A2Er 2 B0 FD LAD97: bcs LAD96 000A30r 2 A2 16 LAD99: ldx #ErrTypeMismatch 000A32r 2 4C rr rr jmp bERROR 000A35r 2 A6 rr bFRMEVL:ldx zTXTPTR 000A37r 2 D0 02 bne LADA4 000A39r 2 C6 rr dec zTXTPTR + 1 000A3Br 2 C6 rr LADA4: dec zTXTPTR 000A3Dr 2 A2 00 ldx #0 000A3Fr 2 24 .byte ASM_BIT2 000A40r 2 48 LADA9: pha 000A41r 2 8A txa 000A42r 2 48 pha 000A43r 2 A9 01 lda #1 000A45r 2 20 rr rr jsr bGETSTK 000A48r 2 20 rr rr jsr bEVAL 000A4Br 2 A9 00 lda #$00 000A4Dr 2 85 rr sta zOPMASK 000A4Fr 2 20 rr rr LADB8: jsr zCHRGOT 000A52r 2 38 LADBB: sec 000A53r 2 E9 B1 sbc #TokGreater 000A55r 2 90 17 bcc LADD7 000A57r 2 C9 03 cmp #TokSgn - TokGreater 000A59r 2 B0 13 bcs LADD7 000A5Br 2 C9 01 cmp #TokEqual - TokGreater 000A5Dr 2 2A rol a 000A5Er 2 49 01 eor #$01 000A60r 2 45 rr eor zOPMASK 000A62r 2 C5 rr cmp zOPMASK 000A64r 2 90 61 bcc LAE30 000A66r 2 85 rr sta zOPMASK 000A68r 2 20 rr rr jsr zCHRGET 000A6Br 2 4C rr rr jmp LADBB 000A6Er 2 A6 rr LADD7: ldx zOPMASK 000A70r 2 D0 2C bne LAE07 000A72r 2 B0 7B bcs LAE58 000A74r 2 69 07 adc #$07 000A76r 2 90 77 bcc LAE58 000A78r 2 65 rr adc zVALTYP 000A7Ar 2 D0 03 bne LADE8 000A7Cr 2 4C rr rr jmp bCAT 000A7Fr 2 69 FF LADE8: adc #-1 000A81r 2 85 rr sta zINDEX 000A83r 2 0A asl a 000A84r 2 65 rr adc zINDEX 000A86r 2 A8 tay 000A87r 2 68 LADF0: pla 000A88r 2 D9 rr rr cmp bOPTAB,y 000A8Br 2 B0 67 bcs LAE5D 000A8Dr 2 20 rr rr jsr LAD8D 000A90r 2 48 LADF9: pha 000A91r 2 20 rr rr LADFA: jsr LAE20 000A94r 2 68 pla 000A95r 2 A4 rr ldy zVARTXT 000A97r 2 10 17 bpl LAE19 000A99r 2 AA tax 000A9Ar 2 F0 56 beq LAE5B 000A9Cr 2 D0 5F bne LAE66 000A9Er 2 46 rr LAE07: lsr zVALTYP 000AA0r 2 8A txa 000AA1r 2 2A rol a 000AA2r 2 A6 rr ldx zTXTPTR 000AA4r 2 D0 02 bne LAE11 000AA6r 2 C6 rr dec zTXTPTR + 1 000AA8r 2 C6 rr LAE11: dec zTXTPTR 000AAAr 2 A0 1B ldy #$1B 000AACr 2 85 rr sta zOPMASK 000AAEr 2 D0 D7 bne LADF0 000AB0r 2 D9 rr rr LAE19: cmp bOPTAB,y 000AB3r 2 B0 48 bcs LAE66 000AB5r 2 90 D9 bcc LADF9 000AB7r 2 B9 rr rr LAE20: lda bOPTAB + 2,y 000ABAr 2 48 pha 000ABBr 2 B9 rr rr lda bOPTAB + 1,y 000ABEr 2 48 pha 000ABFr 2 20 rr rr jsr LAE33 000AC2r 2 A5 rr lda zOPMASK 000AC4r 2 4C rr rr jmp LADA9 000AC7r 2 4C rr rr LAE30: jmp bSYNERR 000ACAr 2 A5 rr LAE33: lda zFACSGN 000ACCr 2 BE rr rr ldx bOPTAB,y 000ACFr 2 A8 LAE38: tay 000AD0r 2 68 pla 000AD1r 2 85 rr sta zINDEX 000AD3r 2 E6 rr inc zINDEX 000AD5r 2 68 pla 000AD6r 2 85 rr sta zINDEX + 1 000AD8r 2 98 tya 000AD9r 2 48 pha 000ADAr 2 20 rr rr LAE43: jsr bROUND 000ADDr 2 A5 rr lda zFACHO + 3 000ADFr 2 48 pha 000AE0r 2 A5 rr lda zFACHO + 2 000AE2r 2 48 pha 000AE3r 2 A5 rr lda zFACHO + 1 000AE5r 2 48 pha 000AE6r 2 A5 rr lda zFACHO 000AE8r 2 48 pha 000AE9r 2 A5 rr lda zFACEXP 000AEBr 2 48 pha 000AECr 2 6C rr rr jmp (zINDEX) 000AEFr 2 A0 FF LAE58: ldy #$FF 000AF1r 2 68 pla 000AF2r 2 F0 23 LAE5B: beq LAE80 000AF4r 2 C9 64 LAE5D: cmp #$64 000AF6r 2 F0 03 beq LAE64 000AF8r 2 20 rr rr jsr LAD8D 000AFBr 2 84 rr LAE64: sty zVARTXT 000AFDr 2 68 LAE66: pla 000AFEr 2 4A lsr a 000AFFr 2 85 rr sta zTANSGN 000B01r 2 68 pla 000B02r 2 85 rr sta zARGEXP 000B04r 2 68 pla 000B05r 2 85 rr sta zARGHO 000B07r 2 68 pla 000B08r 2 85 rr sta zARGHO + 1 000B0Ar 2 68 pla 000B0Br 2 85 rr sta zARGHO + 2 000B0Dr 2 68 pla 000B0Er 2 85 rr sta zARGHO + 3 000B10r 2 68 pla 000B11r 2 85 rr sta zARGSGN 000B13r 2 45 rr eor zFACSGN 000B15r 2 85 rr sta zARISGN 000B17r 2 A5 rr LAE80: lda zFACEXP 000B19r 2 60 rts 000B1Ar 2 6C rr rr bEVAL: jmp (lIEVAL) 000B1Dr 2 A9 00 LAE86: lda #$00 000B1Fr 2 85 rr sta zVALTYP 000B21r 2 20 rr rr LAE8A: jsr zCHRGET 000B24r 2 B0 03 bcs LAE92 000B26r 2 4C rr rr LAE8F: jmp bFIN 000B29r 2 20 rr rr LAE92: jsr bISLETC 000B2Cr 2 90 03 bcc LAE9A 000B2Er 2 4C rr rr jmp bISVAR 000B31r 2 C9 FF LAE9A: cmp #$FF 000B33r 2 D0 0F bne bQDOT 000B35r 2 A9 rr lda #bPIVAL 000B39r 2 20 rr rr jsr bMOVFM 000B3Cr 2 4C rr rr jmp zCHRGET 000B3Fr 2 000B3Fr 2 82 49 0F DA bPIVAL: .byte $82,$49,$0F,$DA,$A1 000B43r 2 A1 000B44r 2 000B44r 2 C9 2E bQDOT: cmp #'.' 000B46r 2 F0 DE beq LAE8F 000B48r 2 C9 AB cmp #TokMinus 000B4Ar 2 F0 58 beq bDOMIN 000B4Cr 2 C9 AA cmp #TokPlus 000B4Er 2 F0 D1 beq LAE8A 000B50r 2 C9 22 cmp #'"' 000B52r 2 D0 0F bne LAECC 000B54r 2 A5 rr LAEBD: lda zTXTPTR 000B56r 2 A4 rr ldy zTXTPTR + 1 000B58r 2 69 00 adc #0 000B5Ar 2 90 01 bcc LAEC6 000B5Cr 2 C8 iny 000B5Dr 2 20 rr rr LAEC6: jsr bSTRLIT 000B60r 2 4C rr rr jmp LB7E2 000B63r 2 C9 A8 LAECC: cmp #TokNot 000B65r 2 D0 13 bne LAEE3 000B67r 2 A0 18 ldy #$18 000B69r 2 D0 3B bne LAF0F 000B6Br 2 20 rr rr bEQUOP: jsr bAYINT 000B6Er 2 A5 rr lda zFACHO + 3 000B70r 2 49 FF eor #$FF 000B72r 2 A8 tay 000B73r 2 A5 rr lda zFACHO + 2 000B75r 2 49 FF eor #$FF 000B77r 2 4C rr rr jmp bGIVAYF 000B7Ar 2 C9 A5 LAEE3: cmp #TokFn 000B7Cr 2 D0 03 bne LAEEA 000B7Er 2 4C rr rr jmp bFNDOER 000B81r 2 C9 B4 LAEEA: cmp #TokSgn 000B83r 2 90 03 bcc bOARCHK 000B85r 2 4C rr rr jmp bISFUN 000B88r 2 20 rr rr bOARCHK:jsr bCHKopen 000B8Br 2 20 rr rr jsr bFRMEVL 000B8Er 2 bCHKclose: 000B8Er 2 A9 29 lda #')' 000B90r 2 2C .byte ASM_BIT3 000B91r 2 bCHKopen: 000B91r 2 A9 28 lda #'(' 000B93r 2 2C .byte ASM_BIT3 000B94r 2 A9 2C bCHKCMA:lda #',' 000B96r 2 A0 00 LAEFF: ldy #0 000B98r 2 D1 rr cmp (zTXTPTR),y 000B9Ar 2 D0 03 bne bSYNERR 000B9Cr 2 4C rr rr jmp zCHRGET 000B9Fr 2 A2 0B bSYNERR:ldx #ErrSyntax 000BA1r 2 4C rr rr jmp bERROR 000BA4r 2 A0 15 bDOMIN: ldy #$15 000BA6r 2 68 LAF0F: pla 000BA7r 2 68 pla 000BA8r 2 4C rr rr jmp LADFA 000BABr 2 38 bRSVVAR:sec 000BACr 2 A5 rr lda zFACHO + 2 000BAEr 2 E9 rr sbc #BASIC_START 000BB4r 2 90 08 bcc LAF27 000BB6r 2 A9 87 lda #BASIC_END 000BBCr 2 E5 rr sbc zFACHO + 3 000BBEr 2 60 LAF27: rts 000BBFr 2 20 rr rr bISVAR: jsr bPTRGET 000BC2r 2 85 rr sta zFACHO + 2 000BC4r 2 84 rr sty zFACHO + 3 000BC6r 2 A6 rr ldx zVARNAM 000BC8r 2 A4 rr ldy zVARNAM + 1 000BCAr 2 A5 rr lda zVALTYP 000BCCr 2 F0 26 beq LAF5D 000BCEr 2 A9 00 lda #0 000BD0r 2 85 rr sta zFACOV 000BD2r 2 20 rr rr jsr bRSVVAR 000BD5r 2 90 1C bcc LAF5C 000BD7r 2 E0 54 cpx #'T' ; "T" 000BD9r 2 D0 18 bne LAF5C 000BDBr 2 C0 C9 cpy #'I' + $80 ; "I$" 000BDDr 2 D0 14 bne LAF5C 000BDFr 2 20 rr rr bTISASC:jsr LAF84 000BE2r 2 84 rr sty zTEMP_5E 000BE4r 2 88 dey 000BE5r 2 84 rr sty zFBUFPT 000BE7r 2 A0 06 ldy #6 000BE9r 2 84 rr sty zTEMP_5D 000BEBr 2 A0 24 ldy #$24 000BEDr 2 20 rr rr jsr bFOUTIM 000BF0r 2 4C rr rr jmp LB46F 000BF3r 2 60 LAF5C: rts 000BF4r 2 24 rr LAF5D: bit zINTFLG 000BF6r 2 10 0D bpl LAF6E 000BF8r 2 A0 00 ldy #0 000BFAr 2 B1 rr lda (zFACHO + 2),y 000BFCr 2 AA tax 000BFDr 2 C8 iny 000BFEr 2 B1 rr lda (zFACHO + 2),y 000C00r 2 A8 tay 000C01r 2 8A txa 000C02r 2 4C rr rr jmp bGIVAYF 000C05r 2 20 rr rr LAF6E: jsr bRSVVAR 000C08r 2 90 2D bcc LAFA0 000C0Ar 2 E0 54 cpx #'T' 000C0Cr 2 D0 1B bne LAF92 000C0Er 2 C0 49 cpy #'I' 000C10r 2 D0 25 bne LAFA0 000C12r 2 20 rr rr jsr LAF84 000C15r 2 98 tya 000C16r 2 A2 A0 ldx #$A0 000C18r 2 4C rr rr jmp LBC4F 000C1Br 2 20 rr rr LAF84: jsr kRDTIM 000C1Er 2 86 rr stx zFACHO + 2 000C20r 2 84 rr sty zFACHO + 1 000C22r 2 85 rr sta zFACHO + 3 000C24r 2 A0 00 ldy #0 000C26r 2 84 rr sty zFACHO 000C28r 2 60 rts 000C29r 2 E0 53 LAF92: cpx #'S' 000C2Br 2 D0 0A bne LAFA0 000C2Dr 2 C0 54 cpy #'T' 000C2Fr 2 D0 06 bne LAFA0 000C31r 2 20 rr rr jsr kREADST 000C34r 2 4C rr rr jmp LBC3C 000C37r 2 A5 rr LAFA0: lda zFACHO + 2 000C39r 2 A4 rr ldy zFACHO + 3 000C3Br 2 4C rr rr jmp bMOVFM 000C3Er 2 0A bISFUN: asl a 000C3Fr 2 48 pha 000C40r 2 AA tax 000C41r 2 20 rr rr jsr zCHRGET 000C44r 2 E0 8F cpx #TokRem 000C46r 2 90 20 bcc bNUMFUN 000C48r 2 20 rr rr bSTRFUN:jsr bCHKopen 000C4Br 2 20 rr rr jsr bFRMEVL 000C4Er 2 20 rr rr jsr bCHKCMA 000C51r 2 20 rr rr jsr LAD8F 000C54r 2 68 pla 000C55r 2 AA tax 000C56r 2 A5 rr lda zFACHO + 3 000C58r 2 48 pha 000C59r 2 A5 rr lda zFACHO + 2 000C5Br 2 48 pha 000C5Cr 2 8A txa 000C5Dr 2 48 pha 000C5Er 2 20 rr rr jsr LB79E 000C61r 2 68 pla 000C62r 2 A8 tay 000C63r 2 8A txa 000C64r 2 48 pha 000C65r 2 4C rr rr jmp LAFD6 000C68r 2 20 rr rr bNUMFUN:jsr bOARCHK 000C6Br 2 68 pla 000C6Cr 2 A8 tay 000C6Dr 2 B9 rr rr LAFD6: lda bFUNDSP - 2*(TokSgn - $80),y 000C70r 2 85 rr sta zJMPER + 1 000C72r 2 B9 rr rr lda bFUNDSP - 2*(TokSgn - $80) + 1,y 000C75r 2 85 rr sta zJMPER + 2 000C77r 2 20 rr rr jsr zJMPER 000C7Ar 2 4C rr rr jmp LAD8D 000C7Dr 2 A0 FF bOROP: ldy #$FF 000C7Fr 2 2C .byte ASM_BIT3 000C80r 2 A0 00 TAND: ldy #0 000C82r 2 84 rr sty zCOUNT 000C84r 2 20 rr rr jsr bAYINT 000C87r 2 A5 rr lda zFACHO + 2 000C89r 2 45 rr eor zCOUNT 000C8Br 2 85 rr sta zCHARAC 000C8Dr 2 A5 rr lda zFACHO + 3 000C8Fr 2 45 rr eor zCOUNT 000C91r 2 85 rr sta zENDCHR 000C93r 2 20 rr rr jsr bMOVFA 000C96r 2 20 rr rr jsr bAYINT 000C99r 2 A5 rr lda zFACHO + 3 000C9Br 2 45 rr eor zCOUNT 000C9Dr 2 25 rr and zENDCHR 000C9Fr 2 45 rr eor zCOUNT 000CA1r 2 A8 tay 000CA2r 2 A5 rr lda zFACHO + 2 000CA4r 2 45 rr eor zCOUNT 000CA6r 2 25 rr and zCHARAC 000CA8r 2 45 rr eor zCOUNT 000CAAr 2 4C rr rr jmp bGIVAYF 000CADr 2 20 rr rr bDOREL: jsr LAD90 000CB0r 2 B0 13 bcs bSTRREL 000CB2r 2 A5 rr bNUMREL:lda zARGSGN 000CB4r 2 09 7F ora #$7F 000CB6r 2 25 rr and zARGHO 000CB8r 2 85 rr sta zARGHO 000CBAr 2 A9 rr lda #zARG 000CBEr 2 20 rr rr jsr bFCOMP 000CC1r 2 AA tax 000CC2r 2 4C rr rr jmp LB061 000CC5r 2 A9 00 bSTRREL:lda #0 000CC7r 2 85 rr sta zVALTYP 000CC9r 2 C6 rr dec zOPMASK 000CCBr 2 20 rr rr jsr LB6A6 000CCEr 2 85 rr sta zFACEXP 000CD0r 2 86 rr stx zFACHO 000CD2r 2 84 rr sty zFACHO + 1 000CD4r 2 A5 rr lda zARGHO + 2 000CD6r 2 A4 rr ldy zARGHO + 3 000CD8r 2 20 rr rr jsr LB6AA 000CDBr 2 86 rr stx zARGHO + 2 000CDDr 2 84 rr sty zARGHO + 3 000CDFr 2 AA tax 000CE0r 2 38 sec 000CE1r 2 E5 rr sbc zFACEXP 000CE3r 2 F0 08 beq LB056 000CE5r 2 A9 01 lda #1 000CE7r 2 90 04 bcc LB056 000CE9r 2 A6 rr ldx zFACEXP 000CEBr 2 A9 FF lda #$FF 000CEDr 2 85 rr LB056: sta zFACSGN 000CEFr 2 A0 FF ldy #$FF 000CF1r 2 E8 inx 000CF2r 2 C8 LB05B: iny 000CF3r 2 CA dex 000CF4r 2 D0 07 bne LB066 000CF6r 2 A6 rr ldx zFACSGN 000CF8r 2 30 0F LB061: bmi LB072 000CFAr 2 18 clc 000CFBr 2 90 0C bcc LB072 000CFDr 2 B1 rr LB066: lda (zARGHO + 2),y 000CFFr 2 D1 rr cmp (zFACHO),y 000D01r 2 F0 EF beq LB05B 000D03r 2 A2 FF ldx #$FF 000D05r 2 B0 02 bcs LB072 000D07r 2 A2 01 ldx #$01 000D09r 2 E8 LB072: inx 000D0Ar 2 8A txa 000D0Br 2 2A rol a 000D0Cr 2 25 rr and zTANSGN 000D0Er 2 F0 02 beq LB07B 000D10r 2 A9 FF lda #$FF 000D12r 2 4C rr rr LB07B: jmp LBC3C 000D15r 2 20 rr rr bDIM: jsr bCHKCMA 000D18r 2 AA bDIM2: tax 000D19r 2 20 rr rr jsr LB090 000D1Cr 2 20 rr rr jsr zCHRGOT 000D1Fr 2 D0 F4 bne bDIM 000D21r 2 60 rts 000D22r 2 A2 00 bPTRGET:ldx #$00 000D24r 2 20 rr rr jsr zCHRGOT 000D27r 2 86 rr LB090: stx zDIMFLG 000D29r 2 85 rr LB092: sta zVARNAM 000D2Br 2 20 rr rr jsr zCHRGOT 000D2Er 2 20 rr rr jsr bISLETC 000D31r 2 B0 03 bcs LB09F 000D33r 2 4C rr rr LB09C: jmp bSYNERR 000D36r 2 A2 00 LB09F: ldx #$00 000D38r 2 86 rr stx zVALTYP 000D3Ar 2 86 rr stx zINTFLG 000D3Cr 2 20 rr rr jsr zCHRGET 000D3Fr 2 90 05 bcc LB0AF 000D41r 2 20 rr rr jsr bISLETC 000D44r 2 90 0B bcc LB0BA 000D46r 2 AA LB0AF: tax 000D47r 2 20 rr rr LB0B0: jsr zCHRGET 000D4Ar 2 90 FB bcc LB0B0 000D4Cr 2 20 rr rr jsr bISLETC 000D4Fr 2 B0 F6 bcs LB0B0 000D51r 2 C9 24 LB0BA: cmp #'$' 000D53r 2 D0 06 bne LB0C4 000D55r 2 A9 FF lda #$FF 000D57r 2 85 rr sta zVALTYP 000D59r 2 D0 10 bne LB0D4 000D5Br 2 C9 25 LB0C4: cmp #'%' 000D5Dr 2 D0 13 bne LB0DB 000D5Fr 2 A5 rr lda zINTALLOWED 000D61r 2 D0 D0 bne LB09C 000D63r 2 A9 80 lda #$80 000D65r 2 85 rr sta zINTFLG 000D67r 2 05 rr ora zVARNAM 000D69r 2 85 rr sta zVARNAM 000D6Br 2 8A LB0D4: txa 000D6Cr 2 09 80 ora #$80 000D6Er 2 AA tax 000D6Fr 2 20 rr rr jsr zCHRGET 000D72r 2 86 rr LB0DB: stx zVARNAM + 1 000D74r 2 38 sec 000D75r 2 05 rr ora zINTALLOWED 000D77r 2 E9 28 sbc #'(' 000D79r 2 D0 03 bne bORDVAR 000D7Br 2 4C rr rr jmp bISARY 000D7Er 2 A0 00 bORDVAR:ldy #$00 000D80r 2 84 rr sty zINTALLOWED 000D82r 2 A5 rr lda zVARTAB 000D84r 2 A6 rr ldx zVARTAB + 1 000D86r 2 86 rr LB0EF: stx zTEMP_5F + 1 000D88r 2 85 rr LB0F1: sta zTEMP_5F 000D8Ar 2 E4 rr cpx zARYTAB + 1 000D8Cr 2 D0 04 bne LB0FB 000D8Er 2 C5 rr cmp zARYTAB 000D90r 2 F0 22 beq bNOTFNS 000D92r 2 A5 rr LB0FB: lda zVARNAM 000D94r 2 D1 rr cmp (zTEMP_5F),y 000D96r 2 D0 08 bne LB109 000D98r 2 A5 rr lda zVARNAM + 1 000D9Ar 2 C8 iny 000D9Br 2 D1 rr cmp (zTEMP_5F),y 000D9Dr 2 F0 7D beq LB185 000D9Fr 2 88 dey 000DA0r 2 18 LB109: clc 000DA1r 2 A5 rr lda zTEMP_5F 000DA3r 2 69 07 adc #7 000DA5r 2 90 E1 bcc LB0F1 000DA7r 2 E8 inx 000DA8r 2 D0 DC bne LB0EF 000DAAr 2 C9 41 bISLETC:cmp #'A' 000DACr 2 90 05 bcc LB11C 000DAEr 2 E9 5B sbc #'Z' + 1 000DB0r 2 38 sec 000DB1r 2 E9 A5 sbc #-('Z' + 1) 000DB3r 2 60 LB11C: rts 000DB4r 2 68 bNOTFNS:pla 000DB5r 2 48 pha 000DB6r 2 C9 2A cmp #$2A ; ? 000DB8r 2 D0 05 bne bNOTEVL 000DBAr 2 A9 rr LB123: lda #bTI ; so it can be recognized 000DBEr 2 60 rts 000DBFr 2 A5 rr bNOTEVL:lda zVARNAM 000DC1r 2 A4 rr ldy zVARNAM + 1 000DC3r 2 C9 54 cmp #'T' ; "T" 000DC5r 2 D0 0B bne LB13B 000DC7r 2 C0 C9 cpy #'I' + $80 ; "I$" 000DC9r 2 F0 EF beq LB123 000DCBr 2 C0 49 cpy #'I' 000DCDr 2 D0 03 bne LB13B 000DCFr 2 4C rr rr LB138: jmp bSYNERR 000DD2r 2 C9 53 LB13B: cmp #'S' 000DD4r 2 D0 04 bne LB143 000DD6r 2 C0 54 cpy #'T' 000DD8r 2 F0 F5 beq LB138 000DDAr 2 A5 rr LB143: lda zARYTAB 000DDCr 2 A4 rr ldy zARYTAB + 1 000DDEr 2 85 rr sta zTEMP_5F 000DE0r 2 84 rr sty zTEMP_5F + 1 000DE2r 2 A5 rr lda zSTREND 000DE4r 2 A4 rr ldy zSTREND + 1 000DE6r 2 85 rr sta zTEMP_5A 000DE8r 2 84 rr sty zTEMP_5A + 1 000DEAr 2 18 clc 000DEBr 2 69 07 adc #7 000DEDr 2 90 01 bcc LB159 000DEFr 2 C8 iny 000DF0r 2 85 rr LB159: sta zTEMP_58 000DF2r 2 84 rr sty zTEMP_58 + 1 000DF4r 2 20 rr rr jsr bBLTU 000DF7r 2 A5 rr lda zTEMP_58 000DF9r 2 A4 rr ldy zTEMP_58 + 1 000DFBr 2 C8 iny 000DFCr 2 85 rr sta zARYTAB 000DFEr 2 84 rr sty zARYTAB + 1 000E00r 2 A0 00 ldy #0 000E02r 2 A5 rr lda zVARNAM 000E04r 2 91 rr sta (zTEMP_5F),y 000E06r 2 C8 iny 000E07r 2 A5 rr lda zVARNAM + 1 000E09r 2 91 rr sta (zTEMP_5F),y 000E0Br 2 A9 00 lda #0 000E0Dr 2 C8 iny 000E0Er 2 91 rr sta (zTEMP_5F),y 000E10r 2 C8 iny 000E11r 2 91 rr sta (zTEMP_5F),y 000E13r 2 C8 iny 000E14r 2 91 rr sta (zTEMP_5F),y 000E16r 2 C8 iny 000E17r 2 91 rr sta (zTEMP_5F),y 000E19r 2 C8 iny 000E1Ar 2 91 rr sta (zTEMP_5F),y 000E1Cr 2 A5 rr LB185: lda zTEMP_5F 000E1Er 2 18 clc 000E1Fr 2 69 02 adc #2 000E21r 2 A4 rr ldy zTEMP_5F + 1 000E23r 2 90 01 bcc LB18F 000E25r 2 C8 iny 000E26r 2 85 rr LB18F: sta zVARPNT 000E28r 2 84 rr sty zVARPNT + 1 000E2Ar 2 60 rts 000E2Br 2 A5 rr bARYGET:lda zCOUNT 000E2Dr 2 0A asl a 000E2Er 2 69 05 adc #5 000E30r 2 65 rr adc zTEMP_5F 000E32r 2 A4 rr ldy zTEMP_5F + 1 000E34r 2 90 01 bcc LB1A0 000E36r 2 C8 iny 000E37r 2 85 rr LB1A0: sta zTEMP_58 000E39r 2 84 rr sty zTEMP_58 + 1 000E3Br 2 60 rts 000E3Cr 2 000E3Cr 2 90 80 00 00 bN32768:.byte $90,$80,$00,$00,$00 000E40r 2 00 000E41r 2 000E41r 2 20 rr rr bFACINX:jsr bAYINT 000E44r 2 A5 rr lda zFACHO + 2 000E46r 2 A4 rr ldy zFACHO + 3 000E48r 2 60 rts 000E49r 2 20 rr rr bINTIDX:jsr zCHRGET 000E4Cr 2 20 rr rr jsr bFRMEVL 000E4Fr 2 20 rr rr LB1B8: jsr LAD8D 000E52r 2 A5 rr lda zFACSGN 000E54r 2 30 0D bmi LB1CC 000E56r 2 A5 rr bAYINT: lda zFACEXP 000E58r 2 C9 90 cmp #$90 000E5Ar 2 90 09 bcc LB1CE 000E5Cr 2 A9 rr lda #bN32768 000E60r 2 20 rr rr jsr bFCOMP 000E63r 2 D0 7A LB1CC: bne bIQERR 000E65r 2 4C rr rr LB1CE: jmp bQINT 000E68r 2 A5 rr bISARY: lda zDIMFLG 000E6Ar 2 05 rr ora zINTFLG 000E6Cr 2 48 pha 000E6Dr 2 A5 rr lda zVALTYP 000E6Fr 2 48 pha 000E70r 2 A0 00 ldy #0 000E72r 2 98 LB1DB: tya 000E73r 2 48 pha 000E74r 2 A5 rr lda zVARNAM + 1 000E76r 2 48 pha 000E77r 2 A5 rr lda zVARNAM 000E79r 2 48 pha 000E7Ar 2 20 rr rr jsr bINTIDX 000E7Dr 2 68 pla 000E7Er 2 85 rr sta zVARNAM 000E80r 2 68 pla 000E81r 2 85 rr sta zVARNAM + 1 000E83r 2 68 pla 000E84r 2 A8 tay 000E85r 2 BA tsx 000E86r 2 BD rr rr lda lSTACK + 2,x 000E89r 2 48 pha 000E8Ar 2 BD rr rr lda lSTACK + 1,x 000E8Dr 2 48 pha 000E8Er 2 A5 rr lda zFACHO + 2 000E90r 2 9D rr rr sta lSTACK + 2,x 000E93r 2 A5 rr lda zFACHO + 3 000E95r 2 9D rr rr sta lSTACK + 1,x 000E98r 2 C8 iny 000E99r 2 20 rr rr jsr zCHRGOT 000E9Cr 2 C9 2C cmp #',' 000E9Er 2 F0 D2 beq LB1DB 000EA0r 2 84 rr sty zCOUNT 000EA2r 2 20 rr rr jsr bCHKclose 000EA5r 2 68 pla 000EA6r 2 85 rr sta zVALTYP 000EA8r 2 68 pla 000EA9r 2 85 rr sta zINTFLG 000EABr 2 29 7F and #$7F 000EADr 2 85 rr sta zDIMFLG 000EAFr 2 A6 rr bFNDARY:ldx zARYTAB 000EB1r 2 A5 rr lda zARYTAB + 1 000EB3r 2 86 rr LB21C: stx zTEMP_5F 000EB5r 2 85 rr sta zTEMP_5F + 1 000EB7r 2 C5 rr cmp zSTREND + 1 000EB9r 2 D0 04 bne LB228 000EBBr 2 E4 rr cpx zSTREND 000EBDr 2 F0 39 beq bNOTFDD 000EBFr 2 A0 00 LB228: ldy #0 000EC1r 2 B1 rr lda (zTEMP_5F),y 000EC3r 2 C8 iny 000EC4r 2 C5 rr cmp zVARNAM 000EC6r 2 D0 06 bne LB237 000EC8r 2 A5 rr lda zVARNAM + 1 000ECAr 2 D1 rr cmp (zTEMP_5F),y 000ECCr 2 F0 16 beq bRAERR 000ECEr 2 C8 LB237: iny 000ECFr 2 B1 rr lda (zTEMP_5F),y 000ED1r 2 18 clc 000ED2r 2 65 rr adc zTEMP_5F 000ED4r 2 AA tax 000ED5r 2 C8 iny 000ED6r 2 B1 rr lda (zTEMP_5F),y 000ED8r 2 65 rr adc zTEMP_5F + 1 000EDAr 2 90 D7 bcc LB21C 000EDCr 2 A2 12 bBSERR: ldx #ErrBadSubscript 000EDEr 2 2C .byte ASM_BIT3 000EDFr 2 A2 0E bIQERR: ldx #ErrIllegalQuantity 000EE1r 2 4C rr rr LB24A: jmp bERROR 000EE4r 2 A2 13 bRAERR: ldx #ErrRedimdArray 000EE6r 2 A5 rr lda zDIMFLG 000EE8r 2 D0 F7 bne LB24A 000EEAr 2 20 rr rr jsr bARYGET 000EEDr 2 A5 rr lda zCOUNT 000EEFr 2 A0 04 ldy #4 000EF1r 2 D1 rr cmp (zTEMP_5F),y 000EF3r 2 D0 E7 bne bBSERR 000EF5r 2 4C rr rr jmp LB2EA 000EF8r 2 20 rr rr bNOTFDD:jsr bARYGET 000EFBr 2 20 rr rr jsr bREASON 000EFEr 2 A0 00 ldy #0 000F00r 2 84 rr sty zFBUFPT + 1 000F02r 2 A2 05 ldx #5 000F04r 2 A5 rr lda zVARNAM 000F06r 2 91 rr sta (zTEMP_5F),y 000F08r 2 10 01 bpl LB274 000F0Ar 2 CA dex 000F0Br 2 C8 LB274: iny 000F0Cr 2 A5 rr lda zVARNAM + 1 000F0Er 2 91 rr sta (zTEMP_5F),y 000F10r 2 10 02 bpl LB27D 000F12r 2 CA dex 000F13r 2 CA dex 000F14r 2 86 rr LB27D: stx zFBUFPT 000F16r 2 A5 rr lda zCOUNT 000F18r 2 C8 iny 000F19r 2 C8 iny 000F1Ar 2 C8 iny 000F1Br 2 91 rr sta (zTEMP_5F),y 000F1Dr 2 A2 0B LB286: ldx #11 000F1Fr 2 A9 00 lda #0 000F21r 2 24 rr bit zDIMFLG 000F23r 2 50 08 bvc LB296 000F25r 2 68 pla 000F26r 2 18 clc 000F27r 2 69 01 adc #1 000F29r 2 AA tax 000F2Ar 2 68 pla 000F2Br 2 69 00 adc #0 000F2Dr 2 C8 LB296: iny 000F2Er 2 91 rr sta (zTEMP_5F),y 000F30r 2 C8 iny 000F31r 2 8A txa 000F32r 2 91 rr sta (zTEMP_5F),y 000F34r 2 20 rr rr jsr bUMULT 000F37r 2 86 rr stx zFBUFPT 000F39r 2 85 rr sta zFBUFPT + 1 000F3Br 2 A4 rr ldy zINDEX 000F3Dr 2 C6 rr dec zCOUNT 000F3Fr 2 D0 DC bne LB286 000F41r 2 65 rr adc zTEMP_58 + 1 000F43r 2 B0 5D bcs LB30B 000F45r 2 85 rr sta zTEMP_58 + 1 000F47r 2 A8 tay 000F48r 2 8A txa 000F49r 2 65 rr adc zTEMP_58 000F4Br 2 90 03 bcc LB2B9 000F4Dr 2 C8 iny 000F4Er 2 F0 52 beq LB30B 000F50r 2 20 rr rr LB2B9: jsr bREASON 000F53r 2 85 rr sta zSTREND 000F55r 2 84 rr sty zSTREND + 1 000F57r 2 A9 00 lda #0 000F59r 2 E6 rr inc zFBUFPT + 1 000F5Br 2 A4 rr ldy zFBUFPT 000F5Dr 2 F0 05 beq LB2CD 000F5Fr 2 88 LB2C8: dey 000F60r 2 91 rr sta (zTEMP_58),y 000F62r 2 D0 FB bne LB2C8 000F64r 2 C6 rr LB2CD: dec zTEMP_58 + 1 000F66r 2 C6 rr dec zFBUFPT + 1 000F68r 2 D0 F5 bne LB2C8 000F6Ar 2 E6 rr inc zTEMP_58 + 1 000F6Cr 2 38 sec 000F6Dr 2 A5 rr lda zSTREND 000F6Fr 2 E5 rr sbc zTEMP_5F 000F71r 2 A0 02 ldy #2 000F73r 2 91 rr sta (zTEMP_5F),y 000F75r 2 A5 rr lda zSTREND + 1 000F77r 2 C8 iny 000F78r 2 E5 rr sbc zTEMP_5F + 1 000F7Ar 2 91 rr sta (zTEMP_5F),y 000F7Cr 2 A5 rr lda zDIMFLG 000F7Er 2 D0 62 bne LB34B 000F80r 2 C8 iny 000F81r 2 B1 rr LB2EA: lda (zTEMP_5F),y 000F83r 2 85 rr sta zCOUNT 000F85r 2 A9 00 lda #0 000F87r 2 85 rr sta zFBUFPT 000F89r 2 85 rr LB2F2: sta zFBUFPT + 1 000F8Br 2 C8 iny 000F8Cr 2 68 pla 000F8Dr 2 AA tax 000F8Er 2 85 rr sta zFACHO + 2 000F90r 2 68 pla 000F91r 2 85 rr sta zFACHO + 3 000F93r 2 D1 rr cmp (zTEMP_5F),y 000F95r 2 90 0E bcc bINLPN2 000F97r 2 D0 06 bne LB308 000F99r 2 C8 iny 000F9Ar 2 8A txa 000F9Br 2 D1 rr cmp (zTEMP_5F),y 000F9Dr 2 90 07 bcc LB30F 000F9Fr 2 4C rr rr LB308: jmp bBSERR 000FA2r 2 4C rr rr LB30B: jmp bOMERR 000FA5r 2 000FA5r 2 C8 bINLPN2:iny 000FA6r 2 A5 rr LB30F: lda zFBUFPT + 1 000FA8r 2 05 rr ora zFBUFPT 000FAAr 2 18 clc 000FABr 2 F0 0A beq LB320 000FADr 2 20 rr rr jsr bUMULT 000FB0r 2 8A txa 000FB1r 2 65 rr adc zFACHO + 2 000FB3r 2 AA tax 000FB4r 2 98 tya 000FB5r 2 A4 rr ldy zINDEX 000FB7r 2 65 rr LB320: adc zFACHO + 3 000FB9r 2 86 rr stx zFBUFPT 000FBBr 2 C6 rr dec zCOUNT 000FBDr 2 D0 CA bne LB2F2 000FBFr 2 85 rr sta zFBUFPT + 1 000FC1r 2 A2 05 ldx #5 000FC3r 2 A5 rr lda zVARNAM 000FC5r 2 10 01 bpl LB331 000FC7r 2 CA dex 000FC8r 2 A5 rr LB331: lda zVARNAM + 1 000FCAr 2 10 02 bpl LB337 000FCCr 2 CA dex 000FCDr 2 CA dex 000FCEr 2 86 rr LB337: stx zTEMP_28 000FD0r 2 A9 00 lda #0 000FD2r 2 20 rr rr jsr LB355 000FD5r 2 8A txa 000FD6r 2 65 rr adc zTEMP_58 000FD8r 2 85 rr sta zVARPNT 000FDAr 2 98 tya 000FDBr 2 65 rr adc zTEMP_58 + 1 000FDDr 2 85 rr sta zVARPNT + 1 000FDFr 2 A8 tay 000FE0r 2 A5 rr lda zVARPNT 000FE2r 2 60 LB34B: rts 000FE3r 2 84 rr bUMULT: sty zINDEX 000FE5r 2 B1 rr lda (zTEMP_5F),y 000FE7r 2 85 rr sta zTEMP_28 000FE9r 2 88 dey 000FEAr 2 B1 rr lda (zTEMP_5F),y 000FECr 2 85 rr LB355: sta zTEMP_28 + 1 000FEEr 2 A9 10 lda #$10 000FF0r 2 85 rr sta zTEMP_5D 000FF2r 2 A2 00 ldx #0 000FF4r 2 A0 00 ldy #0 000FF6r 2 8A LB35F: txa 000FF7r 2 0A asl a 000FF8r 2 AA tax 000FF9r 2 98 tya 000FFAr 2 2A rol a 000FFBr 2 A8 tay 000FFCr 2 B0 A4 bcs LB30B 000FFEr 2 06 rr asl zFBUFPT 001000r 2 26 rr rol zFBUFPT + 1 001002r 2 90 0B bcc LB378 001004r 2 18 clc 001005r 2 8A txa 001006r 2 65 rr adc zTEMP_28 001008r 2 AA tax 001009r 2 98 tya 00100Ar 2 65 rr adc zTEMP_28 + 1 00100Cr 2 A8 tay 00100Dr 2 B0 93 bcs LB30B 00100Fr 2 C6 rr LB378: dec zTEMP_5D 001011r 2 D0 E3 bne LB35F 001013r 2 60 rts 001014r 2 A5 rr bFRE: lda zVALTYP 001016r 2 F0 03 beq LB384 001018r 2 20 rr rr jsr LB6A6 00101Br 2 20 rr rr LB384: jsr bGARBAG 00101Er 2 38 sec 00101Fr 2 A5 rr lda zFRETOP 001021r 2 E5 rr sbc zSTREND 001023r 2 A8 tay 001024r 2 A5 rr lda zFRETOP + 1 001026r 2 E5 rr sbc zSTREND + 1 001028r 2 A2 00 bGIVAYF:ldx #0 00102Ar 2 86 rr stx zVALTYP 00102Cr 2 85 rr sta zFACHO 00102Er 2 84 rr sty zFACHO + 1 001030r 2 A2 90 ldx #$90 001032r 2 4C rr rr jmp LBC44 001035r 2 38 bPOS: sec 001036r 2 20 rr rr jsr kPLOT 001039r 2 A9 00 LB3A2: lda #0 00103Br 2 F0 EB beq bGIVAYF 00103Dr 2 A6 rr bERRDIR:ldx zCURLIN + 1 00103Fr 2 E8 inx 001040r 2 D0 A0 bne LB34B 001042r 2 A2 15 ldx #ErrIllegalDirect 001044r 2 2C .byte ASM_BIT3 001045r 2 A2 1B bUFERR: ldx #ErrUndefdFunction 001047r 2 4C rr rr jmp bERROR 00104Ar 2 00104Ar 2 20 rr rr bDEF: jsr bGETFNM 00104Dr 2 20 rr rr jsr bERRDIR 001050r 2 20 rr rr jsr bCHKopen 001053r 2 A9 80 lda #$80 001055r 2 85 rr sta zINTALLOWED 001057r 2 20 rr rr jsr bPTRGET 00105Ar 2 20 rr rr jsr LAD8D 00105Dr 2 20 rr rr jsr bCHKclose 001060r 2 A9 B2 lda #TokEqual 001062r 2 20 rr rr jsr LAEFF 001065r 2 48 pha 001066r 2 A5 rr lda zVARPNT + 1 001068r 2 48 pha 001069r 2 A5 rr lda zVARPNT 00106Br 2 48 pha 00106Cr 2 A5 rr lda zTXTPTR + 1 00106Er 2 48 pha 00106Fr 2 A5 rr lda zTXTPTR 001071r 2 48 pha 001072r 2 20 rr rr jsr bDATA 001075r 2 4C rr rr jmp LB44F 001078r 2 A9 A5 bGETFNM:lda #TokFn 00107Ar 2 20 rr rr jsr LAEFF 00107Dr 2 09 80 ora #$80 00107Fr 2 85 rr sta zINTALLOWED 001081r 2 20 rr rr jsr LB092 001084r 2 85 rr sta zTEMPF3 001086r 2 84 rr sty zTEMPF3 + 1 001088r 2 4C rr rr jmp LAD8D 00108Br 2 20 rr rr bFNDOER:jsr bGETFNM 00108Er 2 A5 rr lda zTEMPF3 + 1 001090r 2 48 pha 001091r 2 A5 rr lda zTEMPF3 001093r 2 48 pha 001094r 2 20 rr rr jsr bOARCHK 001097r 2 20 rr rr jsr LAD8D 00109Ar 2 68 pla 00109Br 2 85 rr sta zTEMPF3 00109Dr 2 68 pla 00109Er 2 85 rr sta zTEMPF3 + 1 0010A0r 2 A0 02 ldy #2 0010A2r 2 B1 rr lda (zTEMPF3),y 0010A4r 2 85 rr sta zVARPNT 0010A6r 2 AA tax 0010A7r 2 C8 iny 0010A8r 2 B1 rr lda (zTEMPF3),y 0010AAr 2 F0 99 beq bUFERR 0010ACr 2 85 rr sta zVARPNT + 1 0010AEr 2 C8 iny 0010AFr 2 B1 rr LB418: lda (zVARPNT),y 0010B1r 2 48 pha 0010B2r 2 88 dey 0010B3r 2 10 FA bpl LB418 0010B5r 2 A4 rr ldy zVARPNT + 1 0010B7r 2 20 rr rr jsr LBBD4 0010BAr 2 A5 rr lda zTXTPTR + 1 0010BCr 2 48 pha 0010BDr 2 A5 rr lda zTXTPTR 0010BFr 2 48 pha 0010C0r 2 B1 rr lda (zTEMPF3),y 0010C2r 2 85 rr sta zTXTPTR 0010C4r 2 C8 iny 0010C5r 2 B1 rr lda (zTEMPF3),y 0010C7r 2 85 rr sta zTXTPTR + 1 0010C9r 2 A5 rr lda zVARPNT + 1 0010CBr 2 48 pha 0010CCr 2 A5 rr lda zVARPNT 0010CEr 2 48 pha 0010CFr 2 20 rr rr jsr bFRMNUM 0010D2r 2 68 pla 0010D3r 2 85 rr sta zTEMPF3 0010D5r 2 68 pla 0010D6r 2 85 rr sta zTEMPF3 + 1 0010D8r 2 20 rr rr jsr zCHRGOT 0010DBr 2 F0 03 beq LB449 0010DDr 2 4C rr rr jmp bSYNERR 0010E0r 2 68 LB449: pla 0010E1r 2 85 rr sta zTXTPTR 0010E3r 2 68 pla 0010E4r 2 85 rr sta zTXTPTR + 1 0010E6r 2 A0 00 LB44F: ldy #0 0010E8r 2 68 pla 0010E9r 2 91 rr sta (zTEMPF3),y 0010EBr 2 68 pla 0010ECr 2 C8 iny 0010EDr 2 91 rr sta (zTEMPF3),y 0010EFr 2 68 pla 0010F0r 2 C8 iny 0010F1r 2 91 rr sta (zTEMPF3),y 0010F3r 2 68 pla 0010F4r 2 C8 iny 0010F5r 2 91 rr sta (zTEMPF3),y 0010F7r 2 68 pla 0010F8r 2 C8 iny 0010F9r 2 91 rr sta (zTEMPF3),y 0010FBr 2 60 rts 0010FCr 2 20 rr rr bSTRD: jsr LAD8D 0010FFr 2 A0 00 ldy #0 001101r 2 20 rr rr jsr LBDDF 001104r 2 68 pla 001105r 2 68 pla 001106r 2 A9 rr LB46F: lda #<(zASCWRK) 001108r 2 A0 rr ldy #>(zASCWRK) 00110Ar 2 F0 12 beq bSTRLIT 00110Cr 2 ; ------------- 00110Cr 2 00110Cr 2 A6 rr LB475: ldx zFACHO + 2 00110Er 2 A4 rr ldy zFACHO + 3 001110r 2 86 rr stx zTEMP_50 001112r 2 84 rr sty zTEMP_50 + 1 001114r 2 20 rr rr LB47D: jsr bGETSPA 001117r 2 86 rr stx zFACHO 001119r 2 84 rr sty zFACHO + 1 00111Br 2 85 rr sta zFACEXP 00111Dr 2 60 rts 00111Er 2 A2 22 bSTRLIT:ldx #'"' 001120r 2 86 rr stx zCHARAC 001122r 2 86 rr stx zENDCHR 001124r 2 85 rr LB48D: sta zARISGN 001126r 2 84 rr sty zFACOV 001128r 2 85 rr sta zFACHO 00112Ar 2 84 rr sty zFACHO + 1 00112Cr 2 A0 FF ldy #-1 00112Er 2 C8 LB497: iny 00112Fr 2 B1 rr lda (zARISGN),y 001131r 2 F0 0C beq LB4A8 001133r 2 C5 rr cmp zCHARAC 001135r 2 F0 04 beq LB4A4 001137r 2 C5 rr cmp zENDCHR 001139r 2 D0 F3 bne LB497 00113Br 2 C9 22 LB4A4: cmp #'"' 00113Dr 2 F0 01 beq LB4A9 00113Fr 2 18 LB4A8: clc 001140r 2 84 rr LB4A9: sty zFACEXP 001142r 2 98 tya 001143r 2 65 rr adc zARISGN 001145r 2 85 rr sta zFBUFPT 001147r 2 A6 rr ldx zFACOV 001149r 2 90 01 bcc LB4B5 00114Br 2 E8 inx 00114Cr 2 86 rr LB4B5: stx zFBUFPT + 1 00114Er 2 A5 rr lda zFACOV 001150r 2 F0 04 beq LB4BF 001152r 2 C9 02 cmp #2 001154r 2 D0 0B bne LB4CA 001156r 2 98 LB4BF: tya 001157r 2 20 rr rr jsr LB475 00115Ar 2 A6 rr ldx zARISGN 00115Cr 2 A4 rr ldy zFACOV 00115Er 2 JDLB4C7: 00115Er 2 20 rr rr jsr LB688 001161r 2 A6 rr LB4CA: ldx zTEMPPT 001163r 2 E0 rr cpx #zTEMPST + 9 001165r 2 D0 05 bne bPUTNW1 001167r 2 A2 19 ldx #ErrFormulaTooComplex 001169r 2 4C rr rr LB4D2: jmp bERROR 00116Cr 2 A5 rr bPUTNW1:lda zFACEXP 00116Er 2 95 00 sta 0,x 001170r 2 A5 rr lda zFACHO 001172r 2 95 01 sta 1,x 001174r 2 A5 rr lda zFACHO + 1 001176r 2 95 02 sta 2,x 001178r 2 A0 rr ldy #>zTEMPST 00117Ar 2 86 rr stx zFACHO + 2 00117Cr 2 84 rr sty zFACHO + 3 00117Er 2 84 rr sty zFACOV 001180r 2 88 dey 001181r 2 84 rr sty zVALTYP 001183r 2 86 rr stx zLASTPT 001185r 2 E8 inx 001186r 2 E8 inx 001187r 2 E8 inx 001188r 2 86 rr stx zTEMPPT 00118Ar 2 60 rts 00118Br 2 46 rr bGETSPA:lsr zGARBFL 00118Dr 2 48 LB4F6: pha 00118Er 2 49 FF eor #$FF 001190r 2 38 sec 001191r 2 65 rr adc zFRETOP 001193r 2 A4 rr ldy zFRETOP + 1 001195r 2 B0 01 bcs LB501 001197r 2 88 dey 001198r 2 C4 rr LB501: cpy zSTREND + 1 00119Ar 2 90 11 bcc LB516 00119Cr 2 D0 04 bne LB50B 00119Er 2 C5 rr cmp zSTREND 0011A0r 2 90 0B bcc LB516 0011A2r 2 85 rr LB50B: sta zFRETOP 0011A4r 2 84 rr sty zFRETOP + 1 0011A6r 2 85 rr sta zFRESPC 0011A8r 2 84 rr sty zFRESPC + 1 0011AAr 2 AA tax 0011ABr 2 68 pla 0011ACr 2 60 rts 0011ADr 2 A2 10 LB516: ldx #$10 0011AFr 2 A5 rr lda zGARBFL 0011B1r 2 30 B6 bmi LB4D2 0011B3r 2 20 rr rr jsr bGARBAG 0011B6r 2 A9 80 lda #$80 0011B8r 2 85 rr sta zGARBFL 0011BAr 2 68 pla 0011BBr 2 D0 D0 bne LB4F6 0011BDr 2 A6 rr bGARBAG:ldx zMEMSIZ 0011BFr 2 A5 rr lda zMEMSIZ + 1 0011C1r 2 86 rr LB52A: stx zFRETOP 0011C3r 2 85 rr sta zFRETOP + 1 0011C5r 2 A0 00 ldy #0 0011C7r 2 84 rr sty zTEMPF3 + 1 0011C9r 2 84 rr sty zTEMPF3 0011CBr 2 A5 rr lda zSTREND 0011CDr 2 A6 rr ldx zSTREND + 1 0011CFr 2 85 rr sta zTEMP_5F 0011D1r 2 86 rr stx zTEMP_5F + 1 0011D3r 2 A9 rr lda #zTEMPST 0011D7r 2 85 rr sta zINDEX 0011D9r 2 86 rr stx zINDEX + 1 0011DBr 2 C5 rr LB544: cmp zTEMPPT 0011DDr 2 F0 05 beq LB54D 0011DFr 2 20 rr rr jsr LB5C7 0011E2r 2 F0 F7 beq LB544 0011E4r 2 A9 07 LB54D: lda #$07 0011E6r 2 85 rr sta zFOUR6 0011E8r 2 A5 rr lda zVARTAB 0011EAr 2 A6 rr ldx zVARTAB + 1 0011ECr 2 85 rr sta zINDEX 0011EEr 2 86 rr stx zINDEX + 1 0011F0r 2 E4 rr LB559: cpx zARYTAB + 1 0011F2r 2 D0 04 bne LB561 0011F4r 2 C5 rr cmp zARYTAB 0011F6r 2 F0 05 beq LB566 0011F8r 2 20 rr rr LB561: jsr bDVARS 0011FBr 2 F0 F3 beq LB559 0011FDr 2 85 rr LB566: sta zTEMP_58 0011FFr 2 86 rr stx zTEMP_58 + 1 001201r 2 A9 03 lda #3 001203r 2 85 rr sta zFOUR6 001205r 2 A5 rr LB56E: lda zTEMP_58 001207r 2 A6 rr ldx zTEMP_58 + 1 001209r 2 E4 rr LB572: cpx zSTREND + 1 00120Br 2 D0 07 bne LB57D 00120Dr 2 C5 rr cmp zSTREND 00120Fr 2 D0 03 bne LB57D 001211r 2 4C rr rr jmp bGRBPAS 001214r 2 85 rr LB57D: sta zINDEX 001216r 2 86 rr stx zINDEX + 1 001218r 2 A0 00 ldy #0 00121Ar 2 B1 rr lda (zINDEX),y 00121Cr 2 AA tax 00121Dr 2 C8 iny 00121Er 2 B1 rr lda (zINDEX),y 001220r 2 08 php 001221r 2 C8 iny 001222r 2 B1 rr lda (zINDEX),y 001224r 2 65 rr adc zTEMP_58 001226r 2 85 rr sta zTEMP_58 001228r 2 C8 iny 001229r 2 B1 rr lda (zINDEX),y 00122Br 2 65 rr adc zTEMP_58 + 1 00122Dr 2 85 rr sta zTEMP_58 + 1 00122Fr 2 28 plp 001230r 2 10 D3 bpl LB56E 001232r 2 8A txa 001233r 2 30 D0 bmi LB56E 001235r 2 C8 iny 001236r 2 B1 rr lda (zINDEX),y 001238r 2 A0 00 ldy #0 00123Ar 2 0A asl a 00123Br 2 69 05 adc #5 00123Dr 2 65 rr adc zINDEX 00123Fr 2 85 rr sta zINDEX 001241r 2 90 02 bcc LB5AE 001243r 2 E6 rr inc zINDEX + 1 001245r 2 A6 rr LB5AE: ldx zINDEX + 1 001247r 2 E4 rr LB5B0: cpx zTEMP_58 + 1 001249r 2 D0 04 bne LB5B8 00124Br 2 C5 rr cmp zTEMP_58 00124Dr 2 F0 BA beq LB572 00124Fr 2 20 rr rr LB5B8: jsr LB5C7 001252r 2 F0 F3 beq LB5B0 001254r 2 B1 rr bDVARS: lda (zINDEX),y 001256r 2 30 35 bmi LB5F6 001258r 2 C8 iny 001259r 2 B1 rr lda (zINDEX),y 00125Br 2 10 30 bpl LB5F6 00125Dr 2 C8 iny 00125Er 2 B1 rr LB5C7: lda (zINDEX),y 001260r 2 F0 2B beq LB5F6 001262r 2 C8 iny 001263r 2 B1 rr lda (zINDEX),y 001265r 2 AA tax 001266r 2 C8 iny 001267r 2 B1 rr lda (zINDEX),y 001269r 2 C5 rr cmp zFRETOP + 1 00126Br 2 90 06 bcc LB5DC 00126Dr 2 D0 1E bne LB5F6 00126Fr 2 E4 rr cpx zFRETOP 001271r 2 B0 1A bcs LB5F6 001273r 2 C5 rr LB5DC: cmp zTEMP_5F + 1 001275r 2 90 16 bcc LB5F6 001277r 2 D0 04 bne LB5E6 001279r 2 E4 rr cpx zTEMP_5F 00127Br 2 90 10 bcc LB5F6 00127Dr 2 86 rr LB5E6: stx zTEMP_5F 00127Fr 2 85 rr sta zTEMP_5F + 1 001281r 2 A5 rr lda zINDEX 001283r 2 A6 rr ldx zINDEX + 1 001285r 2 85 rr sta zTEMPF3 001287r 2 86 rr stx zTEMPF3 + 1 001289r 2 A5 rr lda zFOUR6 00128Br 2 85 rr sta zJMPER + 1 00128Dr 2 A5 rr LB5F6: lda zFOUR6 00128Fr 2 18 clc 001290r 2 65 rr adc zINDEX 001292r 2 85 rr sta zINDEX 001294r 2 90 02 bcc LB601 001296r 2 E6 rr inc zINDEX + 1 001298r 2 A6 rr LB601: ldx zINDEX + 1 00129Ar 2 A0 00 ldy #0 00129Cr 2 60 rts 00129Dr 2 A5 rr bGRBPAS:lda zTEMPF3 + 1 00129Fr 2 05 rr ora zTEMPF3 0012A1r 2 F0 F5 beq LB601 0012A3r 2 A5 rr lda zJMPER + 1 0012A5r 2 29 04 and #$04 0012A7r 2 4A lsr a 0012A8r 2 A8 tay 0012A9r 2 85 rr sta zJMPER + 1 0012ABr 2 B1 rr lda (zTEMPF3),y 0012ADr 2 65 rr adc zTEMP_5F 0012AFr 2 85 rr sta zTEMP_5A 0012B1r 2 A5 rr lda zTEMP_5F + 1 0012B3r 2 69 00 adc #0 0012B5r 2 85 rr sta zTEMP_5A + 1 0012B7r 2 A5 rr lda zFRETOP 0012B9r 2 A6 rr ldx zFRETOP + 1 0012BBr 2 85 rr sta zTEMP_58 0012BDr 2 86 rr stx zTEMP_58 + 1 0012BFr 2 20 rr rr jsr MoveMem 0012C2r 2 A4 rr ldy zJMPER + 1 0012C4r 2 C8 iny 0012C5r 2 A5 rr lda zTEMP_58 0012C7r 2 91 rr sta (zTEMPF3),y 0012C9r 2 AA tax 0012CAr 2 E6 rr inc zTEMP_58 + 1 0012CCr 2 A5 rr lda zTEMP_58 + 1 0012CEr 2 C8 iny 0012CFr 2 91 rr sta (zTEMPF3),y 0012D1r 2 4C rr rr jmp LB52A 0012D4r 2 A5 rr bCAT: lda zFACHO + 3 0012D6r 2 48 pha 0012D7r 2 A5 rr lda zFACHO + 2 0012D9r 2 48 pha 0012DAr 2 20 rr rr jsr bEVAL 0012DDr 2 20 rr rr jsr LAD8F 0012E0r 2 68 pla 0012E1r 2 85 rr sta zARISGN 0012E3r 2 68 pla 0012E4r 2 85 rr sta zFACOV 0012E6r 2 A0 00 ldy #0 0012E8r 2 B1 rr lda (zARISGN),y 0012EAr 2 18 clc 0012EBr 2 71 rr adc (zFACHO + 2),y 0012EDr 2 90 05 bcc LB65D 0012EFr 2 A2 17 ldx #ErrStringTooLong 0012F1r 2 4C rr rr jmp bERROR 0012F4r 2 20 rr rr LB65D: jsr LB475 0012F7r 2 20 rr rr jsr bMOVINS 0012FAr 2 A5 rr lda zTEMP_50 0012FCr 2 A4 rr ldy zTEMP_50 + 1 0012FEr 2 20 rr rr jsr LB6AA 001301r 2 20 rr rr jsr LB68C 001304r 2 A5 rr lda zARISGN 001306r 2 A4 rr ldy zFACOV 001308r 2 20 rr rr jsr LB6AA 00130Br 2 20 rr rr jsr LB4CA 00130Er 2 4C rr rr jmp LADB8 001311r 2 A0 00 bMOVINS:ldy #0 001313r 2 B1 rr lda (zARISGN),y 001315r 2 48 pha 001316r 2 C8 iny 001317r 2 B1 rr lda (zARISGN),y 001319r 2 AA tax 00131Ar 2 C8 iny 00131Br 2 B1 rr lda (zARISGN),y 00131Dr 2 A8 tay 00131Er 2 68 pla 00131Fr 2 86 rr LB688: stx zINDEX 001321r 2 84 rr sty zINDEX + 1 001323r 2 A8 LB68C: tay 001324r 2 F0 0A beq LB699 001326r 2 48 pha 001327r 2 88 LB690: dey 001328r 2 B1 rr lda (zINDEX),y 00132Ar 2 91 rr sta (zFRESPC),y 00132Cr 2 98 tya 00132Dr 2 D0 F8 bne LB690 00132Fr 2 68 pla 001330r 2 18 LB699: clc 001331r 2 65 rr adc zFRESPC 001333r 2 85 rr sta zFRESPC 001335r 2 90 02 bcc LB6A2 001337r 2 E6 rr inc zFRESPC + 1 001339r 2 60 LB6A2: rts 00133Ar 2 20 rr rr bFRESTR:jsr LAD8F 00133Dr 2 A5 rr LB6A6: lda zFACHO + 2 00133Fr 2 A4 rr ldy zFACHO + 3 001341r 2 85 rr LB6AA: sta zINDEX 001343r 2 84 rr sty zINDEX + 1 001345r 2 20 rr rr jsr bFREFAC 001348r 2 08 php 001349r 2 A0 00 ldy #0 00134Br 2 B1 rr lda (zINDEX),y 00134Dr 2 48 pha 00134Er 2 C8 iny 00134Fr 2 B1 rr lda (zINDEX),y 001351r 2 AA tax 001352r 2 C8 iny 001353r 2 B1 rr lda (zINDEX),y 001355r 2 A8 tay 001356r 2 68 pla 001357r 2 28 plp 001358r 2 D0 13 bne LB6D6 00135Ar 2 C4 rr cpy zFRETOP + 1 00135Cr 2 D0 0F bne LB6D6 00135Er 2 E4 rr cpx zFRETOP 001360r 2 D0 0B bne LB6D6 001362r 2 48 pha 001363r 2 18 clc 001364r 2 65 rr adc zFRETOP 001366r 2 85 rr sta zFRETOP 001368r 2 90 02 bcc LB6D5 00136Ar 2 E6 rr inc zFRETOP + 1 00136Cr 2 68 LB6D5: pla 00136Dr 2 86 rr LB6D6: stx zINDEX 00136Fr 2 84 rr sty zINDEX + 1 001371r 2 60 rts 001372r 2 C4 rr bFREFAC:cpy zLASTPT + 1 001374r 2 D0 0C bne LB6EB 001376r 2 C5 rr cmp zLASTPT 001378r 2 D0 08 bne LB6EB 00137Ar 2 85 rr sta zTEMPPT 00137Cr 2 E9 03 sbc #3 00137Er 2 85 rr sta zLASTPT 001380r 2 A0 00 ldy #0 001382r 2 60 LB6EB: rts 001383r 2 20 rr rr bCHRD: jsr LB7A1 001386r 2 8A txa 001387r 2 48 pha 001388r 2 A9 01 lda #1 00138Ar 2 20 rr rr jsr LB47D 00138Dr 2 68 pla 00138Er 2 A0 00 ldy #0 001390r 2 91 rr sta (zFACHO),y 001392r 2 68 pla 001393r 2 68 pla 001394r 2 4C rr rr jmp LB4CA 001397r 2 20 rr rr bLEFTD: jsr bPREAM 00139Ar 2 D1 rr cmp (zTEMP_50),y 00139Cr 2 98 tya 00139Dr 2 90 04 LB706: bcc LB70C 00139Fr 2 B1 rr lda (zTEMP_50),y 0013A1r 2 AA tax 0013A2r 2 98 tya 0013A3r 2 48 LB70C: pha 0013A4r 2 8A LB70D: txa 0013A5r 2 48 LB70E: pha 0013A6r 2 20 rr rr jsr LB47D 0013A9r 2 A5 rr lda zTEMP_50 0013ABr 2 A4 rr ldy zTEMP_50 + 1 0013ADr 2 20 rr rr jsr LB6AA 0013B0r 2 68 pla 0013B1r 2 A8 tay 0013B2r 2 68 pla 0013B3r 2 18 clc 0013B4r 2 65 rr adc zINDEX 0013B6r 2 85 rr sta zINDEX 0013B8r 2 90 02 bcc LB725 0013BAr 2 E6 rr inc zINDEX + 1 0013BCr 2 98 LB725: tya 0013BDr 2 20 rr rr jsr LB68C 0013C0r 2 4C rr rr jmp LB4CA 0013C3r 2 20 rr rr bRIGHTD:jsr bPREAM 0013C6r 2 18 clc 0013C7r 2 F1 rr sbc (zTEMP_50),y 0013C9r 2 49 FF eor #$FF 0013CBr 2 4C rr rr jmp LB706 0013CEr 2 A9 FF bMIDD: lda #$FF 0013D0r 2 85 rr sta zFACHO + 3 0013D2r 2 20 rr rr jsr zCHRGOT 0013D5r 2 C9 29 cmp #')' 0013D7r 2 F0 06 beq LB748 0013D9r 2 20 rr rr jsr bCHKCMA 0013DCr 2 20 rr rr jsr LB79E 0013DFr 2 20 rr rr LB748: jsr bPREAM 0013E2r 2 F0 4B beq LB798 0013E4r 2 CA dex 0013E5r 2 8A txa 0013E6r 2 48 pha 0013E7r 2 18 clc 0013E8r 2 A2 00 ldx #0 0013EAr 2 F1 rr sbc (zTEMP_50),y 0013ECr 2 B0 B6 bcs LB70D 0013EEr 2 49 FF eor #$FF 0013F0r 2 C5 rr cmp zFACHO + 3 0013F2r 2 90 B1 bcc LB70E 0013F4r 2 A5 rr lda zFACHO + 3 0013F6r 2 B0 AD bcs LB70E 0013F8r 2 20 rr rr bPREAM: jsr bCHKclose 0013FBr 2 68 pla 0013FCr 2 A8 tay 0013FDr 2 68 pla 0013FEr 2 85 rr sta zJMPER + 1 001400r 2 68 pla 001401r 2 68 pla 001402r 2 68 pla 001403r 2 AA tax 001404r 2 68 pla 001405r 2 85 rr sta zTEMP_50 001407r 2 68 pla 001408r 2 85 rr sta zTEMP_50 + 1 00140Ar 2 A5 rr lda zJMPER + 1 00140Cr 2 48 pha 00140Dr 2 98 tya 00140Er 2 48 pha 00140Fr 2 A0 00 ldy #0 001411r 2 8A txa 001412r 2 60 rts 001413r 2 20 rr rr bLEN: jsr bLEN1 001416r 2 4C rr rr jmp LB3A2 001419r 2 20 rr rr bLEN1: jsr bFRESTR 00141Cr 2 A2 00 ldx #0 00141Er 2 86 rr stx zVALTYP 001420r 2 A8 tay 001421r 2 60 rts 001422r 2 20 rr rr bASC: jsr bLEN1 001425r 2 F0 08 beq LB798 001427r 2 A0 00 ldy #0 001429r 2 B1 rr lda (zINDEX),y 00142Br 2 A8 tay 00142Cr 2 4C rr rr jmp LB3A2 00142Fr 2 4C rr rr LB798: jmp bIQERR 001432r 2 20 rr rr bGTBYTC:jsr zCHRGET 001435r 2 20 rr rr LB79E: jsr bFRMNUM 001438r 2 20 rr rr LB7A1: jsr LB1B8 00143Br 2 A6 rr ldx zFACHO + 2 00143Dr 2 D0 F0 bne LB798 00143Fr 2 A6 rr ldx zFACHO + 3 001441r 2 4C rr rr jmp zCHRGOT 001444r 2 20 rr rr bVAL: jsr bLEN1 001447r 2 D0 03 bne bSTRVAL 001449r 2 4C rr rr jmp LB8F7 00144Cr 2 A6 rr bSTRVAL:ldx zTXTPTR 00144Er 2 A4 rr ldy zTXTPTR + 1 001450r 2 86 rr stx zFBUFPT 001452r 2 84 rr sty zFBUFPT + 1 001454r 2 A6 rr ldx zINDEX 001456r 2 86 rr stx zTXTPTR 001458r 2 18 clc 001459r 2 65 rr adc zINDEX 00145Br 2 85 rr sta zINDEX2 00145Dr 2 A6 rr ldx zINDEX + 1 00145Fr 2 86 rr stx zTXTPTR + 1 001461r 2 90 01 bcc LB7CD 001463r 2 E8 inx 001464r 2 86 rr LB7CD: stx zINDEX2 + 1 001466r 2 A0 00 ldy #0 001468r 2 B1 rr lda (zINDEX2),y 00146Ar 2 48 pha 00146Br 2 98 tya 00146Cr 2 91 rr sta (zINDEX2),y 00146Er 2 20 rr rr jsr zCHRGOT 001471r 2 20 rr rr jsr bFIN 001474r 2 68 pla 001475r 2 A0 00 ldy #0 001477r 2 91 rr sta (zINDEX2),y 001479r 2 A6 rr LB7E2: ldx zFBUFPT 00147Br 2 A4 rr ldy zFBUFPT + 1 00147Dr 2 86 rr stx zTXTPTR 00147Fr 2 84 rr sty zTXTPTR + 1 001481r 2 60 rts 001482r 2 20 rr rr bGETNUM:jsr bFRMNUM 001485r 2 20 rr rr jsr bGETADR 001488r 2 20 rr rr LB7F1: jsr bCHKCMA 00148Br 2 4C rr rr jmp LB79E 00148Er 2 A5 rr bGETADR:lda zFACSGN 001490r 2 30 9D bmi LB798 001492r 2 A5 rr lda zFACEXP 001494r 2 C9 91 cmp #$91 ; exponent for 65536 001496r 2 B0 97 bcs LB798 001498r 2 20 rr rr jsr bQINT 00149Br 2 A5 rr lda zFACHO + 2 00149Dr 2 A4 rr ldy zFACHO + 3 00149Fr 2 84 rr sty zLINNUM 0014A1r 2 85 rr sta zLINNUM + 1 0014A3r 2 60 rts 0014A4r 2 A5 rr bPEEK: lda zLINNUM + 1 0014A6r 2 48 pha 0014A7r 2 A5 rr lda zLINNUM 0014A9r 2 48 pha 0014AAr 2 20 rr rr jsr bGETADR 0014ADr 2 A0 00 ldy #0 0014AFr 2 B1 rr lda (zLINNUM),y 0014B1r 2 A8 tay 0014B2r 2 68 pla 0014B3r 2 85 rr sta zLINNUM 0014B5r 2 68 pla 0014B6r 2 85 rr sta zLINNUM + 1 0014B8r 2 4C rr rr jmp LB3A2 0014BBr 2 20 rr rr bPOKE: jsr bGETNUM 0014BEr 2 8A txa 0014BFr 2 A0 00 ldy #0 0014C1r 2 91 rr sta (zLINNUM),y 0014C3r 2 60 rts 0014C4r 2 20 rr rr bWAIT: jsr bGETNUM 0014C7r 2 86 rr stx zFORPNT 0014C9r 2 A2 00 ldx #0 0014CBr 2 20 rr rr jsr zCHRGOT 0014CEr 2 F0 03 beq LB83C 0014D0r 2 20 rr rr jsr LB7F1 0014D3r 2 86 rr LB83C: stx zFORPNT + 1 0014D5r 2 A0 00 ldy #0 0014D7r 2 B1 rr LB840: lda (zLINNUM),y 0014D9r 2 45 rr eor zFORPNT + 1 0014DBr 2 25 rr and zFORPNT 0014DDr 2 F0 F8 beq LB840 0014DFr 2 60 LB848: rts 0014E0r 2 A9 rr bFADDH: lda #bFHALF 0014E4r 2 4C rr rr jmp bFADD 0014E7r 2 20 rr rr bFSUB: jsr bCONUPK 0014EAr 2 A5 rr FSUBT: lda zFACSGN 0014ECr 2 49 FF eor #$FF 0014EEr 2 85 rr sta zFACSGN 0014F0r 2 45 rr eor zARGSGN 0014F2r 2 85 rr sta zARISGN 0014F4r 2 A5 rr lda zFACEXP 0014F6r 2 4C rr rr jmp FADDT 0014F9r 2 20 rr rr bFADD5: jsr LB999 0014FCr 2 90 3C bcc LB8A3 0014FEr 2 20 rr rr bFADD: jsr bCONUPK 001501r 2 D0 03 FADDT: bne LB86F 001503r 2 4C rr rr jmp bMOVFA 001506r 2 A6 rr LB86F: ldx zFACOV 001508r 2 86 rr stx zJMPER + 2 00150Ar 2 A2 rr ldx #zARGEXP 00150Cr 2 A5 rr lda zARGEXP 00150Er 2 A8 LB877: tay 00150Fr 2 F0 CE beq LB848 001511r 2 38 sec 001512r 2 E5 rr sbc zFACEXP 001514r 2 F0 24 beq LB8A3 001516r 2 90 12 bcc LB893 001518r 2 84 rr sty zFACEXP 00151Ar 2 A4 rr ldy zARGSGN 00151Cr 2 84 rr sty zFACSGN 00151Er 2 49 FF eor #$FF 001520r 2 69 00 adc #0 001522r 2 A0 00 ldy #0 001524r 2 84 rr sty zJMPER + 2 001526r 2 A2 rr ldx #zFACEXP 001528r 2 D0 04 bne LB897 00152Ar 2 A0 00 LB893: ldy #0 00152Cr 2 84 rr sty zFACOV 00152Er 2 C9 F9 LB897: cmp #$F9 001530r 2 30 C7 bmi bFADD5 001532r 2 A8 tay 001533r 2 A5 rr lda zFACOV 001535r 2 56 01 lsr 1,x 001537r 2 20 rr rr jsr LB9B0 00153Ar 2 24 rr LB8A3: bit zARISGN 00153Cr 2 10 57 bpl LB8FE 00153Er 2 A0 rr ldy #zFACEXP 001540r 2 E0 rr cpx #zARGEXP 001542r 2 F0 02 beq LB8AF 001544r 2 A0 rr ldy #zARGEXP 001546r 2 38 LB8AF: sec 001547r 2 49 FF eor #$FF 001549r 2 65 rr adc zJMPER + 2 00154Br 2 85 rr sta zFACOV 00154Dr 2 B9 04 00 lda 4,y 001550r 2 F5 04 sbc 4,x 001552r 2 85 rr sta zFACHO + 3 001554r 2 B9 rr rr lda zADRAY1,y 001557r 2 F5 rr sbc zADRAY1,x 001559r 2 85 rr sta zFACHO + 2 00155Br 2 B9 02 00 lda 2,y 00155Er 2 F5 02 sbc 2,x 001560r 2 85 rr sta zFACHO + 1 001562r 2 B9 01 00 lda 1,y 001565r 2 F5 01 sbc 1,x 001567r 2 85 rr sta zFACHO 001569r 2 B0 03 LB8D2: bcs LB8D7 00156Br 2 20 rr rr jsr bNEGFAC 00156Er 2 A0 00 LB8D7: ldy #0 001570r 2 98 tya 001571r 2 18 clc 001572r 2 A6 rr LB8DB: ldx zFACHO 001574r 2 D0 4A bne LB929 001576r 2 A6 rr ldx zFACHO + 1 001578r 2 86 rr stx zFACHO 00157Ar 2 A6 rr ldx zFACHO + 2 00157Cr 2 86 rr stx zFACHO + 1 00157Er 2 A6 rr ldx zFACHO + 3 001580r 2 86 rr stx zFACHO + 2 001582r 2 A6 rr ldx zFACOV 001584r 2 86 rr stx zFACHO + 3 001586r 2 84 rr sty zFACOV 001588r 2 69 08 adc #8 00158Ar 2 C9 20 cmp #$20 00158Cr 2 D0 E4 bne LB8DB 00158Er 2 A9 00 LB8F7: lda #0 001590r 2 85 rr LB8F9: sta zFACEXP 001592r 2 85 rr LB8FB: sta zFACSGN 001594r 2 60 rts 001595r 2 65 rr LB8FE: adc zJMPER + 2 001597r 2 85 rr sta zFACOV 001599r 2 A5 rr lda zFACHO + 3 00159Br 2 65 rr adc zARGHO + 3 00159Dr 2 85 rr sta zFACHO + 3 00159Fr 2 A5 rr lda zFACHO + 2 0015A1r 2 65 rr adc zARGHO + 2 0015A3r 2 85 rr sta zFACHO + 2 0015A5r 2 A5 rr lda zFACHO + 1 0015A7r 2 65 rr adc zARGHO + 1 0015A9r 2 85 rr sta zFACHO + 1 0015ABr 2 A5 rr lda zFACHO 0015ADr 2 65 rr adc zARGHO 0015AFr 2 85 rr sta zFACHO 0015B1r 2 4C rr rr jmp LB936 0015B4r 2 69 01 LB91D: adc #1 0015B6r 2 06 rr asl zFACOV 0015B8r 2 26 rr rol zFACHO + 3 0015BAr 2 26 rr rol zFACHO + 2 0015BCr 2 26 rr rol zFACHO + 1 0015BEr 2 26 rr rol zFACHO 0015C0r 2 10 F2 LB929: bpl LB91D 0015C2r 2 38 sec 0015C3r 2 E5 rr sbc zFACEXP 0015C5r 2 B0 C7 bcs LB8F7 0015C7r 2 49 FF eor #$FF 0015C9r 2 69 01 adc #1 0015CBr 2 85 rr sta zFACEXP 0015CDr 2 90 0E LB936: bcc LB946 0015CFr 2 E6 rr LB938: inc zFACEXP 0015D1r 2 F0 42 beq bOVERR 0015D3r 2 66 rr ror zFACHO 0015D5r 2 66 rr ror zFACHO + 1 0015D7r 2 66 rr ror zFACHO + 2 0015D9r 2 66 rr ror zFACHO + 3 0015DBr 2 66 rr ror zFACOV 0015DDr 2 60 LB946: rts 0015DEr 2 A5 rr bNEGFAC:lda zFACSGN 0015E0r 2 49 FF eor #$FF 0015E2r 2 85 rr sta zFACSGN 0015E4r 2 A5 rr LB94D: lda zFACHO 0015E6r 2 49 FF eor #$FF 0015E8r 2 85 rr sta zFACHO 0015EAr 2 A5 rr lda zFACHO + 1 0015ECr 2 49 FF eor #$FF 0015EEr 2 85 rr sta zFACHO + 1 0015F0r 2 A5 rr lda zFACHO + 2 0015F2r 2 49 FF eor #$FF 0015F4r 2 85 rr sta zFACHO + 2 0015F6r 2 A5 rr lda zFACHO + 3 0015F8r 2 49 FF eor #$FF 0015FAr 2 85 rr sta zFACHO + 3 0015FCr 2 A5 rr lda zFACOV 0015FEr 2 49 FF eor #$FF 001600r 2 85 rr sta zFACOV 001602r 2 E6 rr inc zFACOV 001604r 2 D0 0E bne LB97D 001606r 2 E6 rr LB96F: inc zFACHO + 3 001608r 2 D0 0A bne LB97D 00160Ar 2 E6 rr inc zFACHO + 2 00160Cr 2 D0 06 bne LB97D 00160Er 2 E6 rr inc zFACHO + 1 001610r 2 D0 02 bne LB97D 001612r 2 E6 rr inc zFACHO 001614r 2 60 LB97D: rts 001615r 2 A2 0F bOVERR: ldx #ErrOverflow 001617r 2 4C rr rr jmp bERROR 00161Ar 2 A2 rr bMULSHF:ldx #zRESHO - 1 00161Cr 2 B4 04 LB985: ldy 4,x 00161Er 2 84 rr sty zFACOV 001620r 2 B4 03 ldy 3,x 001622r 2 94 04 sty 4,x 001624r 2 B4 02 ldy 2,x 001626r 2 94 03 sty 3,x 001628r 2 B4 01 ldy 1,x 00162Ar 2 94 02 sty 2,x 00162Cr 2 A4 rr ldy zBITS 00162Er 2 94 01 sty 1,x 001630r 2 69 08 LB999: adc #8 001632r 2 30 E8 bmi LB985 001634r 2 F0 E6 beq LB985 001636r 2 E9 08 sbc #8 001638r 2 A8 tay 001639r 2 A5 rr lda zFACOV 00163Br 2 B0 14 bcs LB9BA 00163Dr 2 16 01 LB9A6: asl 1,x 00163Fr 2 90 02 bcc LB9AC 001641r 2 F6 01 inc 1,x 001643r 2 76 01 LB9AC: ror 1,x 001645r 2 76 01 ror 1,x 001647r 2 76 02 LB9B0: ror 2,x 001649r 2 76 03 ror 3,x 00164Br 2 76 04 ror 4,x 00164Dr 2 6A ror a 00164Er 2 C8 iny 00164Fr 2 D0 EC bne LB9A6 001651r 2 18 LB9BA: clc 001652r 2 60 rts 001653r 2 001653r 2 81 00 00 00 bFPTABL:.byte $81,$00,$00,$00,$00 ; FP 1 001657r 2 00 001658r 2 03 LB9C1: .byte $03 ; Grade of polynomial 001659r 2 7F 5E 56 CB .byte $7F,$5E,$56,$CB,$79 ; .434255942 00165Dr 2 79 00165Er 2 80 13 9B 0B .byte $80,$13,$9B,$0B,$64 ; .576584541 001662r 2 64 001663r 2 80 76 38 93 .byte $80,$76,$38,$93,$16 ; .961800759 001667r 2 16 001668r 2 82 38 AA 3B .byte $82,$38,$AA,$3B,$20 ; 2.88539007 00166Cr 2 20 00166Dr 2 80 35 04 F3 LB9D6: .byte $80,$35,$04,$F3,$34 ; 1 / SQR(2) 001671r 2 34 001672r 2 81 35 04 F3 LB9DB: .byte $81,$35,$04,$F3,$34 ; SQR(2) 001676r 2 34 001677r 2 80 80 00 00 LB9E0: .byte $80,$80,$00,$00,$00 ; - 0.5 00167Br 2 00 00167Cr 2 80 31 72 17 LB9E5: .byte $80,$31,$72,$17,$F8 ; LOG(2) 001680r 2 F8 001681r 2 001681r 2 20 rr rr bLOG: jsr bSIGN 001684r 2 F0 02 beq LB9F1 001686r 2 10 03 bpl LB9F4 001688r 2 4C rr rr LB9F1: jmp bIQERR 00168Br 2 A5 rr LB9F4: lda zFACEXP 00168Dr 2 E9 7F sbc #$7F 00168Fr 2 48 pha 001690r 2 A9 80 lda #$80 001692r 2 85 rr sta zFACEXP 001694r 2 A9 rr lda #LB9D6 001698r 2 20 rr rr jsr bFADD 00169Br 2 A9 rr lda #LB9DB 00169Fr 2 20 rr rr jsr bFDIVT 0016A2r 2 A9 rr lda #bFPTABL 0016A6r 2 20 rr rr jsr bFSUB 0016A9r 2 A9 rr lda #LB9C1 0016ADr 2 20 rr rr jsr bPOLYX 0016B0r 2 A9 rr lda #LB9E0 0016B4r 2 20 rr rr jsr bFADD 0016B7r 2 68 pla 0016B8r 2 20 rr rr jsr LBD7E 0016BBr 2 A9 rr lda #LB9E5 0016BFr 2 20 rr rr bFMULT: jsr bCONUPK 0016C2r 2 D0 03 FMULTT: bne LBA30 0016C4r 2 4C rr rr jmp LBA8B 0016C7r 2 20 rr rr LBA30: jsr bMULDIV 0016CAr 2 A9 00 lda #$00 0016CCr 2 85 rr sta zRESHO 0016CEr 2 85 rr sta zRESHO + 1 0016D0r 2 85 rr sta zRESHO + 2 0016D2r 2 85 rr sta zRESHO + 3 0016D4r 2 A5 rr lda zFACOV 0016D6r 2 20 rr rr jsr bMULPLY 0016D9r 2 A5 rr lda zFACHO + 3 0016DBr 2 20 rr rr jsr bMULPLY 0016DEr 2 A5 rr lda zFACHO + 2 0016E0r 2 20 rr rr jsr bMULPLY 0016E3r 2 A5 rr lda zFACHO + 1 0016E5r 2 20 rr rr jsr bMULPLY 0016E8r 2 A5 rr lda zFACHO 0016EAr 2 20 rr rr jsr LBA5E 0016EDr 2 4C rr rr jmp LBB8F 0016F0r 2 D0 03 bMULPLY:bne LBA5E 0016F2r 2 4C rr rr jmp bMULSHF 0016F5r 2 4A LBA5E: lsr a 0016F6r 2 09 80 ora #$80 0016F8r 2 A8 LBA61: tay 0016F9r 2 90 19 bcc LBA7D 0016FBr 2 18 clc 0016FCr 2 A5 rr lda zRESHO + 3 0016FEr 2 65 rr adc zARGHO + 3 001700r 2 85 rr sta zRESHO + 3 001702r 2 A5 rr lda zRESHO + 2 001704r 2 65 rr adc zARGHO + 2 001706r 2 85 rr sta zRESHO + 2 001708r 2 A5 rr lda zRESHO + 1 00170Ar 2 65 rr adc zARGHO + 1 00170Cr 2 85 rr sta zRESHO + 1 00170Er 2 A5 rr lda zRESHO 001710r 2 65 rr adc zARGHO 001712r 2 85 rr sta zRESHO 001714r 2 66 rr LBA7D: ror zRESHO 001716r 2 66 rr ror zRESHO + 1 001718r 2 66 rr ror zRESHO + 2 00171Ar 2 66 rr ror zRESHO + 3 00171Cr 2 66 rr ror zFACOV 00171Er 2 98 tya 00171Fr 2 4A lsr a 001720r 2 D0 D6 bne LBA61 001722r 2 60 LBA8B: rts 001723r 2 85 rr bCONUPK:sta zINDEX 001725r 2 84 rr sty zINDEX + 1 001727r 2 A0 04 ldy #4 001729r 2 B1 rr lda (zINDEX),y 00172Br 2 85 rr sta zARGHO + 3 00172Dr 2 88 dey 00172Er 2 B1 rr lda (zINDEX),y 001730r 2 85 rr sta zARGHO + 2 001732r 2 88 dey 001733r 2 B1 rr lda (zINDEX),y 001735r 2 85 rr sta zARGHO + 1 001737r 2 88 dey 001738r 2 B1 rr lda (zINDEX),y 00173Ar 2 85 rr sta zARGSGN 00173Cr 2 45 rr eor zFACSGN 00173Er 2 85 rr sta zARISGN 001740r 2 A5 rr lda zARGSGN 001742r 2 09 80 ora #$80 001744r 2 85 rr sta zARGHO 001746r 2 88 dey 001747r 2 B1 rr lda (zINDEX),y 001749r 2 85 rr sta zARGEXP 00174Br 2 A5 rr lda zFACEXP 00174Dr 2 60 rts 00174Er 2 A5 rr bMULDIV:lda zARGEXP 001750r 2 F0 1F LBAB9: beq LBADA 001752r 2 18 clc 001753r 2 65 rr adc zFACEXP 001755r 2 90 04 bcc LBAC4 001757r 2 30 1D bmi LBADF 001759r 2 18 clc 00175Ar 2 2C .byte ASM_BIT3 00175Br 2 10 14 LBAC4: bpl LBADA 00175Dr 2 69 80 adc #$80 00175Fr 2 85 rr sta zFACEXP 001761r 2 D0 03 bne LBACF 001763r 2 4C rr rr jmp LB8FB 001766r 2 A5 rr LBACF: lda zARISGN 001768r 2 85 rr sta zFACSGN 00176Ar 2 60 rts 00176Br 2 A5 rr bMLDVEX:lda zFACSGN 00176Dr 2 49 FF eor #$FF 00176Fr 2 30 05 bmi LBADF 001771r 2 68 LBADA: pla 001772r 2 68 pla 001773r 2 4C rr rr jmp LB8F7 001776r 2 4C rr rr LBADF: jmp bOVERR 001779r 2 20 rr rr bMUL10: jsr bMOVAF 00177Cr 2 AA tax 00177Dr 2 F0 10 beq LBAF8 00177Fr 2 18 clc 001780r 2 69 02 adc #2 ; exponent + 2, thus, X * 4 001782r 2 B0 F2 bcs LBADF 001784r 2 A2 00 LBAED: ldx #0 001786r 2 86 rr stx zARISGN 001788r 2 20 rr rr jsr LB877 00178Br 2 E6 rr inc zFACEXP ; exponent + 2, thus, ((X * 4) + X) * 2 = X * 10 00178Dr 2 F0 E7 beq LBADF 00178Fr 2 60 LBAF8: rts 001790r 2 001790r 2 84 20 00 00 bTENC: .byte $84,$20,$00,$00,$00 001794r 2 00 001795r 2 001795r 2 20 rr rr bDIV10: jsr bMOVAF 001798r 2 A9 rr lda #bTENC 00179Cr 2 A2 00 ldx #0 00179Er 2 86 rr bFDIV: stx zARISGN 0017A0r 2 20 rr rr jsr bMOVFM 0017A3r 2 4C rr rr jmp FDIVT 0017A6r 2 20 rr rr bFDIVT: jsr bCONUPK 0017A9r 2 F0 76 FDIVT: beq LBB8A 0017ABr 2 20 rr rr jsr bROUND 0017AEr 2 A9 00 lda #0 0017B0r 2 38 sec 0017B1r 2 E5 rr sbc zFACEXP 0017B3r 2 85 rr sta zFACEXP 0017B5r 2 20 rr rr jsr bMULDIV 0017B8r 2 E6 rr inc zFACEXP 0017BAr 2 F0 BA beq LBADF 0017BCr 2 A2 FC ldx #-4 0017BEr 2 A9 01 lda #1 0017C0r 2 A4 rr LBB29: ldy zARGHO 0017C2r 2 C4 rr cpy zFACHO 0017C4r 2 D0 10 bne LBB3F 0017C6r 2 A4 rr ldy zARGHO + 1 0017C8r 2 C4 rr cpy zFACHO + 1 0017CAr 2 D0 0A bne LBB3F 0017CCr 2 A4 rr ldy zARGHO + 2 0017CEr 2 C4 rr cpy zFACHO + 2 0017D0r 2 D0 04 bne LBB3F 0017D2r 2 A4 rr ldy zARGHO + 3 0017D4r 2 C4 rr cpy zFACHO + 3 0017D6r 2 08 LBB3F: php 0017D7r 2 2A rol a 0017D8r 2 90 09 bcc LBB4C 0017DAr 2 E8 inx 0017DBr 2 95 rr sta zRESHO + 3,x 0017DDr 2 F0 32 beq LBB7A 0017DFr 2 10 34 bpl LBB7E 0017E1r 2 A9 01 lda #1 0017E3r 2 28 LBB4C: plp 0017E4r 2 B0 0E bcs LBB5D 0017E6r 2 06 rr LBB4F: asl zARGHO + 3 0017E8r 2 26 rr rol zARGHO + 2 0017EAr 2 26 rr rol zARGHO + 1 0017ECr 2 26 rr rol zARGHO 0017EEr 2 B0 E6 bcs LBB3F 0017F0r 2 30 CE bmi LBB29 0017F2r 2 10 E2 bpl LBB3F 0017F4r 2 0017F4r 2 A8 LBB5D: tay 0017F5r 2 A5 rr lda zARGHO + 3 0017F7r 2 E5 rr sbc zFACHO + 3 0017F9r 2 85 rr sta zARGHO + 3 0017FBr 2 A5 rr lda zARGHO + 2 0017FDr 2 E5 rr sbc zFACHO + 2 0017FFr 2 85 rr sta zARGHO + 2 001801r 2 A5 rr lda zARGHO + 1 001803r 2 E5 rr sbc zFACHO + 1 001805r 2 85 rr sta zARGHO + 1 001807r 2 A5 rr lda zARGHO 001809r 2 E5 rr sbc zFACHO 00180Br 2 85 rr sta zARGHO 00180Dr 2 98 tya 00180Er 2 4C rr rr jmp LBB4F 001811r 2 A9 40 LBB7A: lda #$40 001813r 2 D0 CE bne LBB4C 001815r 2 ; ----------- 001815r 2 0A LBB7E: asl a 001816r 2 0A asl a 001817r 2 0A asl a 001818r 2 0A asl a 001819r 2 0A asl a 00181Ar 2 0A asl a 00181Br 2 85 rr sta zFACOV 00181Dr 2 28 plp 00181Er 2 4C rr rr jmp LBB8F 001821r 2 A2 14 LBB8A: ldx #ErrDivisionByZero 001823r 2 4C rr rr jmp bERROR 001826r 2 A5 rr LBB8F: lda zRESHO 001828r 2 85 rr sta zFACHO 00182Ar 2 A5 rr lda zRESHO + 1 00182Cr 2 85 rr sta zFACHO + 1 00182Er 2 A5 rr lda zRESHO + 2 001830r 2 85 rr sta zFACHO + 2 001832r 2 A5 rr lda zRESHO + 3 001834r 2 85 rr sta zFACHO + 3 001836r 2 4C rr rr jmp LB8D7 001839r 2 85 rr bMOVFM: sta zINDEX 00183Br 2 84 rr sty zINDEX + 1 00183Dr 2 A0 04 ldy #4 00183Fr 2 B1 rr lda (zINDEX),y 001841r 2 85 rr sta zFACHO + 3 001843r 2 88 dey 001844r 2 B1 rr lda (zINDEX),y 001846r 2 85 rr sta zFACHO + 2 001848r 2 88 dey 001849r 2 B1 rr lda (zINDEX),y 00184Br 2 85 rr sta zFACHO + 1 00184Dr 2 88 dey 00184Er 2 B1 rr lda (zINDEX),y 001850r 2 85 rr sta zFACSGN 001852r 2 09 80 ora #$80 001854r 2 85 rr sta zFACHO 001856r 2 88 dey 001857r 2 B1 rr lda (zINDEX),y 001859r 2 85 rr sta zFACEXP 00185Br 2 84 rr sty zFACOV 00185Dr 2 60 rts 00185Er 2 A2 rr bMOV2F: ldx #zTEMPF2 001860r 2 2C .byte ASM_BIT3 001861r 2 A2 rr LBBCA: ldx #zTEMPF1 001863r 2 A0 00 ldy #0 001865r 2 F0 04 beq LBBD4 001867r 2 A6 rr LBBD0: ldx zFORPNT 001869r 2 A4 rr ldy zFORPNT + 1 00186Br 2 20 rr rr LBBD4: jsr bROUND 00186Er 2 86 rr stx zINDEX 001870r 2 84 rr sty zINDEX + 1 001872r 2 A0 04 ldy #4 001874r 2 A5 rr lda zFACHO + 3 001876r 2 91 rr sta (zINDEX),y 001878r 2 88 dey 001879r 2 A5 rr lda zFACHO + 2 00187Br 2 91 rr sta (zINDEX),y 00187Dr 2 88 dey 00187Er 2 A5 rr lda zFACHO + 1 001880r 2 91 rr sta (zINDEX),y 001882r 2 88 dey 001883r 2 A5 rr lda zFACSGN 001885r 2 09 7F ora #$7F 001887r 2 25 rr and zFACHO 001889r 2 91 rr sta (zINDEX),y 00188Br 2 88 dey 00188Cr 2 A5 rr lda zFACEXP 00188Er 2 91 rr sta (zINDEX),y 001890r 2 84 rr sty zFACOV 001892r 2 60 rts 001893r 2 A5 rr bMOVFA: lda zARGSGN 001895r 2 85 rr LBBFE: sta zFACSGN 001897r 2 A2 05 ldx #5 ; why 5, but 6 in LBC0F? 001899r 2 B5 rr LBC02: lda zARG - 1,x 00189Br 2 95 rr sta zFAC - 1,x 00189Dr 2 CA dex 00189Er 2 D0 F9 bne LBC02 0018A0r 2 86 rr stx zFACOV 0018A2r 2 60 rts 0018A3r 2 20 rr rr bMOVAF: jsr bROUND 0018A6r 2 A2 06 LBC0F: ldx #6 ; why 6, but 5 in LBBFE + 2? 0018A8r 2 B5 rr LBC11: lda zFAC - 1,x 0018AAr 2 95 rr sta zARG - 1,x 0018ACr 2 CA dex 0018ADr 2 D0 F9 bne LBC11 0018AFr 2 86 rr stx zFACOV 0018B1r 2 60 LBC1A: rts 0018B2r 2 A5 rr bROUND: lda zFACEXP 0018B4r 2 F0 FB beq LBC1A 0018B6r 2 06 rr asl zFACOV 0018B8r 2 90 F7 bcc LBC1A 0018BAr 2 20 rr rr LBC23: jsr LB96F 0018BDr 2 D0 F2 bne LBC1A 0018BFr 2 4C rr rr jmp LB938 0018C2r 2 A5 rr bSIGN: lda zFACEXP 0018C4r 2 F0 09 beq LBC38 0018C6r 2 A5 rr LBC2F: lda zFACSGN 0018C8r 2 2A LBC31: rol a 0018C9r 2 A9 FF lda #$FF 0018CBr 2 B0 02 bcs LBC38 0018CDr 2 A9 01 lda #1 0018CFr 2 60 LBC38: rts 0018D0r 2 20 rr rr bSGN: jsr bSIGN 0018D3r 2 85 rr LBC3C: sta zFACHO 0018D5r 2 A9 00 lda #$00 0018D7r 2 85 rr sta zFACHO + 1 0018D9r 2 A2 88 ldx #$88 0018DBr 2 A5 rr LBC44: lda zFACHO 0018DDr 2 49 FF eor #$FF 0018DFr 2 2A rol a 0018E0r 2 A9 00 LBC49: lda #$00 0018E2r 2 85 rr sta zFACHO + 3 0018E4r 2 85 rr sta zFACHO + 2 0018E6r 2 86 rr LBC4F: stx zFACEXP 0018E8r 2 85 rr sta zFACOV 0018EAr 2 85 rr sta zFACSGN 0018ECr 2 4C rr rr jmp LB8D2 0018EFr 2 46 rr bABS: lsr zFACSGN 0018F1r 2 60 rts 0018F2r 2 85 rr bFCOMP: sta zINDEX2 0018F4r 2 84 rr LBC5D: sty zINDEX2 + 1 0018F6r 2 A0 00 ldy #0 0018F8r 2 B1 rr lda (zINDEX2),y 0018FAr 2 C8 iny 0018FBr 2 AA tax 0018FCr 2 F0 C4 beq bSIGN 0018FEr 2 B1 rr lda (zINDEX2),y 001900r 2 45 rr eor zFACSGN 001902r 2 30 C2 bmi LBC2F 001904r 2 E4 rr cpx zFACEXP 001906r 2 D0 21 bne LBC92 001908r 2 B1 rr lda (zINDEX2),y 00190Ar 2 09 80 ora #$80 00190Cr 2 C5 rr cmp zFACHO 00190Er 2 D0 19 bne LBC92 001910r 2 C8 iny 001911r 2 B1 rr lda (zINDEX2),y 001913r 2 C5 rr cmp zFACHO + 1 001915r 2 D0 12 bne LBC92 001917r 2 C8 iny 001918r 2 B1 rr lda (zINDEX2),y 00191Ar 2 C5 rr cmp zFACHO + 2 00191Cr 2 D0 0B bne LBC92 00191Er 2 C8 iny 00191Fr 2 A9 7F lda #$7F 001921r 2 C5 rr cmp zFACOV 001923r 2 B1 rr lda (zINDEX2),y 001925r 2 E5 rr sbc zFACHO + 3 001927r 2 F0 28 beq LBCBA 001929r 2 A5 rr LBC92: lda zFACSGN 00192Br 2 90 02 bcc LBC98 00192Dr 2 49 FF eor #$FF 00192Fr 2 4C rr rr LBC98: jmp LBC31 001932r 2 A5 rr bQINT: lda zFACEXP 001934r 2 F0 4A beq LBCE9 001936r 2 38 sec 001937r 2 E9 A0 sbc #$A0 001939r 2 24 rr bit zFACSGN 00193Br 2 10 09 bpl LBCAF 00193Dr 2 AA tax 00193Er 2 A9 FF lda #$FF 001940r 2 85 rr sta zBITS 001942r 2 20 rr rr jsr LB94D 001945r 2 8A txa 001946r 2 A2 61 LBCAF: ldx #$61 001948r 2 C9 F9 cmp #$F9 00194Ar 2 10 06 bpl LBCBB 00194Cr 2 20 rr rr jsr LB999 00194Fr 2 84 rr sty zBITS 001951r 2 60 LBCBA: rts 001952r 2 A8 LBCBB: tay 001953r 2 A5 rr lda zFACSGN 001955r 2 29 80 and #$80 001957r 2 46 rr lsr zFACHO 001959r 2 05 rr ora zFACHO 00195Br 2 85 rr sta zFACHO 00195Dr 2 20 rr rr jsr LB9B0 001960r 2 84 rr sty zBITS 001962r 2 60 rts 001963r 2 A5 rr bINT: lda zFACEXP 001965r 2 C9 A0 cmp #$A0 001967r 2 B0 20 bcs LBCF2 001969r 2 20 rr rr jsr bQINT 00196Cr 2 84 rr sty zFACOV 00196Er 2 A5 rr lda zFACSGN 001970r 2 84 rr sty zFACSGN 001972r 2 49 80 eor #$80 001974r 2 2A rol a 001975r 2 A9 A0 lda #$A0 001977r 2 85 rr sta zFACEXP 001979r 2 A5 rr lda zFACHO + 3 00197Br 2 85 rr sta zCHARAC 00197Dr 2 4C rr rr jmp LB8D2 001980r 2 85 rr LBCE9: sta zFACHO 001982r 2 85 rr sta zFACHO + 1 001984r 2 85 rr sta zFACHO + 2 001986r 2 85 rr sta zFACHO + 3 001988r 2 A8 tay 001989r 2 60 LBCF2: rts 00198Ar 2 A0 00 bFIN: ldy #0 00198Cr 2 A2 0A ldx #zFACSGN - zTEMPF2 00198Er 2 94 rr LBCF7: sty zTEMPF2 + 1,x 001990r 2 CA dex 001991r 2 10 FB bpl LBCF7 001993r 2 90 0F bcc LBD0D 001995r 2 C9 2D cmp #'-' 001997r 2 D0 04 bne LBD06 001999r 2 86 rr stx zSGNFLG 00199Br 2 F0 04 beq LBD0A 00199Dr 2 C9 2B LBD06: cmp #'+' 00199Fr 2 D0 05 bne LBD0F 0019A1r 2 20 rr rr LBD0A: jsr zCHRGET 0019A4r 2 90 5B LBD0D: bcc LBD6A 0019A6r 2 C9 2E LBD0F: cmp #'.' 0019A8r 2 F0 2E beq LBD41 0019AAr 2 C9 45 cmp #'E' 0019ACr 2 D0 30 bne LBD47 0019AEr 2 20 rr rr jsr zCHRGET 0019B1r 2 90 17 bcc LBD33 0019B3r 2 C9 AB cmp #TokMinus 0019B5r 2 F0 0E beq LBD2E 0019B7r 2 C9 2D cmp #'-' 0019B9r 2 F0 0A beq LBD2E 0019BBr 2 C9 AA cmp #TokPlus 0019BDr 2 F0 08 beq LBD30 0019BFr 2 C9 2B cmp #'+' 0019C1r 2 F0 04 beq LBD30 0019C3r 2 D0 07 bne LBD35 0019C5r 2 66 rr LBD2E: ror zTEMP_60 0019C7r 2 20 rr rr LBD30: jsr zCHRGET 0019CAr 2 90 5C LBD33: bcc LBD91 0019CCr 2 24 rr LBD35: bit zTEMP_60 0019CEr 2 10 0E bpl LBD47 0019D0r 2 A9 00 lda #0 0019D2r 2 38 sec 0019D3r 2 E5 rr sbc zTEMP_5E 0019D5r 2 4C rr rr jmp LBD49 0019D8r 2 66 rr LBD41: ror zTEMP_5F 0019DAr 2 24 rr bit zTEMP_5F 0019DCr 2 50 C3 bvc LBD0A 0019DEr 2 A5 rr LBD47: lda zTEMP_5E 0019E0r 2 38 LBD49: sec 0019E1r 2 E5 rr sbc zTEMP_5D 0019E3r 2 85 rr sta zTEMP_5E 0019E5r 2 F0 12 beq LBD62 0019E7r 2 10 09 bpl LBD5B 0019E9r 2 20 rr rr LBD52: jsr bDIV10 0019ECr 2 E6 rr inc zTEMP_5E 0019EEr 2 D0 F9 bne LBD52 0019F0r 2 F0 07 beq LBD62 0019F2r 2 20 rr rr LBD5B: jsr bMUL10 0019F5r 2 C6 rr dec zTEMP_5E 0019F7r 2 D0 F9 bne LBD5B 0019F9r 2 A5 rr LBD62: lda zSGNFLG 0019FBr 2 30 01 bmi LBD67 0019FDr 2 60 rts 0019FEr 2 4C rr rr LBD67: jmp bNEGOP 001A01r 2 48 LBD6A: pha 001A02r 2 24 rr bit zTEMP_5F 001A04r 2 10 02 bpl LBD71 001A06r 2 E6 rr inc zTEMP_5D 001A08r 2 20 rr rr LBD71: jsr bMUL10 001A0Br 2 68 pla 001A0Cr 2 38 sec 001A0Dr 2 E9 30 sbc #'0' 001A0Fr 2 20 rr rr jsr LBD7E 001A12r 2 4C rr rr jmp LBD0A 001A15r 2 48 LBD7E: pha 001A16r 2 20 rr rr jsr bMOVAF 001A19r 2 68 pla 001A1Ar 2 20 rr rr jsr LBC3C 001A1Dr 2 A5 rr lda zARGSGN 001A1Fr 2 45 rr eor zFACSGN 001A21r 2 85 rr sta zARISGN 001A23r 2 A6 rr ldx zFACEXP 001A25r 2 4C rr rr jmp FADDT 001A28r 2 A5 rr LBD91: lda zTEMP_5E 001A2Ar 2 C9 0A cmp #10 ; $0A 001A2Cr 2 90 09 bcc LBDA0 001A2Er 2 A9 64 lda #100 ; $64 001A30r 2 24 rr bit zTEMP_60 001A32r 2 30 11 bmi LBDAE 001A34r 2 4C rr rr jmp bOVERR 001A37r 2 0A LBDA0: asl a 001A38r 2 0A asl a 001A39r 2 18 clc 001A3Ar 2 65 rr adc zTEMP_5E 001A3Cr 2 0A asl a 001A3Dr 2 18 clc 001A3Er 2 A0 00 ldy #0 001A40r 2 71 rr adc (zTXTPTR),y 001A42r 2 38 sec 001A43r 2 E9 30 sbc #'0' 001A45r 2 85 rr LBDAE: sta zTEMP_5E 001A47r 2 4C rr rr jmp LBD30 001A4Ar 2 001A4Ar 2 9B 3E BC 1F bN0999: .byte $9B,$3E,$BC,$1F,$FD ; FP: 99999999.9 001A4Er 2 FD 001A4Fr 2 9E 6E 6B 27 LBDB8: .byte $9E,$6E,$6B,$27,$FD ; FP: 999999999 001A53r 2 FD 001A54r 2 9E 6E 6B 28 LBDBD: .byte $9E,$6E,$6B,$28,$00 ; FP: 1E9 001A58r 2 00 001A59r 2 001A59r 2 A9 rr bINPRT: lda #StrIn 001A5Dr 2 20 rr rr jsr LBDDA 001A60r 2 001A60r 2 A5 rr lda zCURLIN + 1 ; output the current line number 001A62r 2 A6 rr ldx zCURLIN 001A64r 2 85 rr LBDCD: sta zFACHO 001A66r 2 86 rr stx zFACHO + 1 001A68r 2 A2 90 ldx #$90 001A6Ar 2 38 sec 001A6Br 2 20 rr rr jsr LBC49 001A6Er 2 20 rr rr jsr LBDDF 001A71r 2 4C rr rr LBDDA: jmp bSTROUT 001A74r 2 001A74r 2 A0 01 bFOUT: ldy #1 001A76r 2 A9 20 LBDDF: lda #' ' 001A78r 2 24 rr bit zFACSGN 001A7Ar 2 10 02 bpl LBDE7 001A7Cr 2 A9 2D lda #'-' 001A7Er 2 99 rr rr LBDE7: sta zASCWRK,y 001A81r 2 85 rr sta zFACSGN 001A83r 2 84 rr sty zFBUFPT 001A85r 2 C8 iny 001A86r 2 A9 30 lda #'0' 001A88r 2 A6 rr ldx zFACEXP 001A8Ar 2 D0 03 bne LBDF8 001A8Cr 2 4C rr rr jmp LBF04 001A8Fr 2 A9 00 LBDF8: lda #$00 001A91r 2 E0 80 cpx #$80 001A93r 2 F0 02 beq LBE00 001A95r 2 B0 09 bcs LBE09 001A97r 2 A9 rr LBE00: lda #LBDBD 001A9Br 2 20 rr rr jsr bFMULT 001A9Er 2 A9 F7 lda #$F7 001AA0r 2 85 rr LBE09: sta zTEMP_5D 001AA2r 2 A9 rr LBE0B: lda #LBDB8 001AA6r 2 20 rr rr jsr bFCOMP 001AA9r 2 F0 1E beq LBE32 001AABr 2 10 12 bpl LBE28 001AADr 2 A9 rr LBE16: lda #bN0999 001AB1r 2 20 rr rr jsr bFCOMP 001AB4r 2 F0 02 beq LBE21 001AB6r 2 10 0E bpl LBE2F 001AB8r 2 20 rr rr LBE21: jsr bMUL10 001ABBr 2 C6 rr dec zTEMP_5D 001ABDr 2 D0 EE bne LBE16 001ABFr 2 20 rr rr LBE28: jsr bDIV10 001AC2r 2 E6 rr inc zTEMP_5D 001AC4r 2 D0 DC bne LBE0B 001AC6r 2 20 rr rr LBE2F: jsr bFADDH 001AC9r 2 20 rr rr LBE32: jsr bQINT 001ACCr 2 A2 01 ldx #$01 001ACEr 2 A5 rr lda zTEMP_5D 001AD0r 2 18 clc 001AD1r 2 69 0A adc #$0A 001AD3r 2 30 09 bmi LBE47 001AD5r 2 C9 0B cmp #$0B 001AD7r 2 B0 06 bcs LBE48 001AD9r 2 69 FF adc #$FF 001ADBr 2 AA tax 001ADCr 2 A9 02 lda #$02 001ADEr 2 38 LBE47: sec 001ADFr 2 E9 02 LBE48: sbc #$02 001AE1r 2 85 rr sta zTEMP_5E 001AE3r 2 86 rr stx zTEMP_5D 001AE5r 2 8A txa 001AE6r 2 F0 02 beq LBE53 001AE8r 2 10 13 bpl LBE66 001AEAr 2 A4 rr LBE53: ldy zFBUFPT 001AECr 2 A9 2E lda #'.' 001AEEr 2 C8 iny 001AEFr 2 99 rr rr sta zASCWRK,y 001AF2r 2 8A txa 001AF3r 2 F0 06 beq LBE64 001AF5r 2 A9 30 lda #'0' 001AF7r 2 C8 iny 001AF8r 2 99 rr rr sta zASCWRK,y 001AFBr 2 84 rr LBE64: sty zFBUFPT 001AFDr 2 A0 00 LBE66: ldy #$00 001AFFr 2 A2 80 bFOUTIM:ldx #$80 001B01r 2 A5 rr LBE6A: lda zFACHO + 3 001B03r 2 18 clc 001B04r 2 79 rr rr adc LBF16 + 3,y 001B07r 2 85 rr sta zFACHO + 3 001B09r 2 A5 rr lda zFACHO + 2 001B0Br 2 79 rr rr adc LBF16 + 2,y 001B0Er 2 85 rr sta zFACHO + 2 001B10r 2 A5 rr lda zFACHO + 1 001B12r 2 79 rr rr adc LBF16 + 1,y 001B15r 2 85 rr sta zFACHO + 1 001B17r 2 A5 rr lda zFACHO 001B19r 2 79 rr rr adc LBF16,y 001B1Cr 2 85 rr sta zFACHO 001B1Er 2 E8 inx 001B1Fr 2 B0 04 bcs LBE8E 001B21r 2 10 DE bpl LBE6A 001B23r 2 30 02 bmi LBE90 001B25r 2 30 DA LBE8E: bmi LBE6A 001B27r 2 8A LBE90: txa 001B28r 2 90 04 bcc LBE97 001B2Ar 2 49 FF eor #$FF 001B2Cr 2 69 0A adc #10 001B2Er 2 69 2F LBE97: adc #'0' - 1 001B30r 2 C8 iny 001B31r 2 C8 iny 001B32r 2 C8 iny 001B33r 2 C8 iny 001B34r 2 84 rr sty zVARPNT 001B36r 2 A4 rr ldy zFBUFPT 001B38r 2 C8 iny 001B39r 2 AA tax 001B3Ar 2 29 7F and #$7F 001B3Cr 2 99 rr rr sta zASCWRK,y 001B3Fr 2 C6 rr dec zTEMP_5D 001B41r 2 D0 06 bne LBEB2 001B43r 2 A9 2E lda #'.' 001B45r 2 C8 iny 001B46r 2 99 rr rr sta zASCWRK,y 001B49r 2 84 rr LBEB2: sty zFBUFPT 001B4Br 2 A4 rr ldy zVARPNT 001B4Dr 2 8A txa 001B4Er 2 49 FF eor #$FF 001B50r 2 29 80 and #$80 001B52r 2 AA tax 001B53r 2 C0 24 cpy #$24 ; @? 001B55r 2 F0 04 beq LBEC4 001B57r 2 C0 3C cpy #$3C ; @? 001B59r 2 D0 A6 bne LBE6A 001B5Br 2 A4 rr LBEC4: ldy zFBUFPT 001B5Dr 2 B9 rr rr LBEC6: lda zASCWRK,y 001B60r 2 88 dey 001B61r 2 C9 30 cmp #'0' 001B63r 2 F0 F8 beq LBEC6 001B65r 2 C9 2E cmp #'.' 001B67r 2 F0 01 beq LBED3 001B69r 2 C8 iny 001B6Ar 2 A9 2B LBED3: lda #'+' 001B6Cr 2 A6 rr ldx zTEMP_5E 001B6Er 2 F0 2E beq LBF07 001B70r 2 10 08 bpl LBEE3 001B72r 2 A9 00 lda #0 001B74r 2 38 sec 001B75r 2 E5 rr sbc zTEMP_5E 001B77r 2 AA tax 001B78r 2 A9 2D lda #'-' 001B7Ar 2 99 rr rr LBEE3: sta lSTACK + 1,y 001B7Dr 2 A9 45 lda #'E' 001B7Fr 2 99 rr rr sta lSTACK,y 001B82r 2 8A txa 001B83r 2 A2 2F ldx #'0' - 1 001B85r 2 38 sec 001B86r 2 E8 LBEEF: inx 001B87r 2 E9 0A sbc #10 001B89r 2 B0 FB bcs LBEEF 001B8Br 2 69 3A adc #'9' + 1 001B8Dr 2 99 rr rr sta lSTACK + 3,y 001B90r 2 8A txa 001B91r 2 99 rr rr sta lSTACK + 2,y 001B94r 2 A9 00 lda #0 001B96r 2 99 rr rr sta lSTACK + 4,y 001B99r 2 F0 08 beq LBF0C 001B9Br 2 99 rr rr LBF04: sta zASCWRK,y 001B9Er 2 A9 00 LBF07: lda #0 001BA0r 2 99 rr rr sta lSTACK,y 001BA3r 2 A9 rr LBF0C: lda #lSTACK 001BA7r 2 60 rts 001BA8r 2 80 00 00 00 bFHALF: .byte $80,$00,$00,$00,$00 001BACr 2 00 001BADr 2 001BADr 2 bFNULL = bFHALF + 2 001BADr 2 bTI = bFNULL 001BADr 2 001BADr 2 FA 0A 1F 00 LBF16: .byte $FA,$0A,$1F,$00 001BB1r 2 001BB1r 2 00 98 96 80 .byte $00,$98,$96,$80 001BB5r 2 FF F0 BD C0 .byte $FF,$F0,$BD,$C0 001BB9r 2 00 01 86 A0 .byte $00,$01,$86,$A0 001BBDr 2 FF FF D8 F0 .byte $FF,$FF,$D8,$F0 001BC1r 2 00 00 03 E8 .byte $00,$00,$03,$E8 001BC5r 2 FF FF FF 9C .byte $FF,$FF,$FF,$9C 001BC9r 2 00 00 00 0A .byte $00,$00,$00,$0A 001BCDr 2 FF FF FF FF .byte $FF,$FF,$FF,$FF 001BD1r 2 001BD1r 2 FF DF 0A 80 .byte $FF,$DF,$0A,$80 001BD5r 2 00 03 4B C0 .byte $00,$03,$4B,$C0 001BD9r 2 FF FF 73 60 .byte $FF,$FF,$73,$60 001BDDr 2 00 00 0E 10 .byte $00,$00,$0E,$10 001BE1r 2 FF FF FD A8 .byte $FF,$FF,$FD,$A8 001BE5r 2 00 00 00 3C .byte $00,$00,$00,$3C 001BE9r 2 001BE9r 2 ; This seems to be something like a checksum for the BASIC-ROM. 001BE9r 2 001BE9r 2 BF .byte CHKSUM_BF52 001BEAr 2 001BEAr 2 ; FillUntil BASIC_START + $1F71,BASIC_FILLER 001BEAr 2 001BEAr 2 .segment "BASICSQR" 000000r 2 000000r 2 20 rr rr bSQR: jsr bMOVAF 000003r 2 A9 rr lda #bFHALF 000007r 2 20 rr rr jsr bMOVFM 00000Ar 2 F0 70 bFPWRT: beq bEXP 00000Cr 2 A5 rr lda zARGEXP 00000Er 2 D0 03 bne LBF84 000010r 2 4C rr rr jmp LB8F9 000013r 2 A2 rr LBF84: ldx #zTEMPF3 000017r 2 20 rr rr jsr LBBD4 00001Ar 2 A5 rr lda zARGSGN 00001Cr 2 10 0F bpl LBF9E 00001Er 2 20 rr rr jsr bINT 000021r 2 A9 rr lda #zTEMPF3 000025r 2 20 rr rr jsr bFCOMP 000028r 2 D0 03 bne LBF9E 00002Ar 2 98 tya 00002Br 2 A4 rr ldy zCHARAC 00002Dr 2 20 rr rr LBF9E: jsr LBBFE 000030r 2 98 tya 000031r 2 48 pha 000032r 2 20 rr rr jsr bLOG 000035r 2 A9 rr lda #zTEMPF3 000039r 2 20 rr rr jsr bFMULT 00003Cr 2 20 rr rr jsr bEXP 00003Fr 2 68 pla 000040r 2 4A lsr a 000041r 2 90 0A bcc LBFBE 000043r 2 A5 rr bNEGOP: lda zFACEXP 000045r 2 F0 06 beq LBFBE 000047r 2 A5 rr lda zFACSGN 000049r 2 49 FF eor #$FF 00004Br 2 85 rr sta zFACSGN 00004Dr 2 60 LBFBE: rts 00004Er 2 00004Er 2 bLOGEB2: 00004Er 2 81 38 AA 3B .byte $81,$38,$AA,$3B,$29 000052r 2 29 000053r 2 LBFC4: 000053r 2 07 .byte $07 000054r 2 71 34 58 3E .byte $71,$34,$58,$3E,$56 000058r 2 56 000059r 2 74 16 7E B3 .byte $74,$16,$7E,$B3,$1B 00005Dr 2 1B 00005Er 2 77 2F EE E3 .byte $77,$2F,$EE,$E3,$85 000062r 2 85 000063r 2 7A 1D 84 1C .byte $7A,$1D,$84,$1C,$2A 000067r 2 2A 000068r 2 7C 63 59 58 .byte $7C,$63,$59,$58,$0A 00006Cr 2 0A 00006Dr 2 7E 75 FD E7 .byte $7E,$75,$FD,$E7,$C6 000071r 2 C6 000072r 2 80 31 72 18 .byte $80,$31,$72,$18,$10 000076r 2 10 000077r 2 81 00 00 00 .byte $81,$00,$00,$00,$00 00007Br 2 00 00007Cr 2 00007Cr 2 A9 rr bEXP: lda #bLOGEB2 000080r 2 20 rr rr jsr bFMULT 000083r 2 A5 rr lda zFACOV 000085r 2 69 50 adc #$50 000087r 2 90 03 bcc LBFFD 000089r 2 20 rr rr jsr LBC23 00008Cr 2 00008Cr 2 LBFFD: 00008Cr 2 00008Cr 2 .segment "BASICSQRJMP" 000000r 2 000000r 2 4C rr rr jmp LE000 000003r 2 000003r 2 .segment "BASICSQR2" 000000r 2 000000r 2 LE000: 000000r 2 85 rr sta zJMPER + 2 000002r 2 000002r 2 .segment "BASICSQR3" 000000r 2 20 rr rr jsr LBC0F 000003r 2 A5 rr lda zFACEXP 000005r 2 C9 88 cmp #$88 000007r 2 90 03 bcc LE00E 000009r 2 20 rr rr LE00B: jsr bMLDVEX 00000Cr 2 20 rr rr LE00E: jsr bINT 00000Fr 2 A5 rr lda zCHARAC 000011r 2 18 clc 000012r 2 69 81 adc #$81 000014r 2 F0 F3 beq LE00B 000016r 2 38 sec 000017r 2 E9 01 sbc #1 000019r 2 48 pha 00001Ar 2 A2 05 ldx #5 00001Cr 2 B5 rr LE01E: lda zARGEXP,x 00001Er 2 B4 rr ldy zFACEXP,x 000020r 2 95 rr sta zFACEXP,x 000022r 2 94 rr sty zARGEXP,x 000024r 2 CA dex 000025r 2 10 F5 bpl LE01E 000027r 2 A5 rr lda zJMPER + 2 000029r 2 85 rr sta zFACOV 00002Br 2 20 rr rr jsr FSUBT 00002Er 2 20 rr rr jsr bNEGOP 000031r 2 A9 rr lda #LBFC4 000035r 2 20 rr rr jsr LE059 000038r 2 A9 00 lda #0 00003Ar 2 85 rr sta zARISGN 00003Cr 2 68 pla 00003Dr 2 20 rr rr jsr LBAB9 000040r 2 60 rts 000041r 2 85 rr bPOLYX: sta zFBUFPT 000043r 2 84 rr sty zFBUFPT + 1 000045r 2 20 rr rr jsr LBBCA 000048r 2 A9 rr lda #zTEMPF1 00004Ar 2 20 rr rr jsr bFMULT 00004Dr 2 20 rr rr jsr LE05D 000050r 2 A9 rr lda #zTEMPF1 000054r 2 4C rr rr jmp bFMULT 000057r 2 85 rr LE059: sta zFBUFPT 000059r 2 84 rr sty zFBUFPT + 1 00005Br 2 20 rr rr LE05D: jsr bMOV2F 00005Er 2 B1 rr lda (zFBUFPT),y 000060r 2 85 rr sta zSGNFLG 000062r 2 A4 rr ldy zFBUFPT 000064r 2 C8 iny 000065r 2 98 tya 000066r 2 D0 02 bne LE06C 000068r 2 E6 rr inc zFBUFPT + 1 00006Ar 2 85 rr LE06C: sta zFBUFPT 00006Cr 2 A4 rr ldy zFBUFPT + 1 00006Er 2 20 rr rr LE070: jsr bFMULT 000071r 2 A5 rr lda zFBUFPT 000073r 2 A4 rr ldy zFBUFPT + 1 000075r 2 18 clc 000076r 2 69 05 adc #5 000078r 2 90 01 bcc LE07D 00007Ar 2 C8 iny 00007Br 2 85 rr LE07D: sta zFBUFPT 00007Dr 2 84 rr sty zFBUFPT + 1 00007Fr 2 20 rr rr jsr bFADD 000082r 2 A9 rr lda #zTEMPF2 000086r 2 C6 rr dec zSGNFLG 000088r 2 D0 E4 bne LE070 00008Ar 2 60 rts 00008Br 2 98 35 44 7A bRMULC: .byte $98,$35,$44,$7A,$00 00008Fr 2 00 000090r 2 68 28 B1 46 LE092: .byte $68,$28,$B1,$46,$00 000094r 2 00 000095r 2 000095r 2 20 rr rr bRND: jsr bSIGN 000098r 2 30 37 bmi LE0D3 00009Ar 2 D0 20 bne LE0BE 00009Cr 2 20 rr rr jsr kIOBASE 00009Fr 2 86 rr stx zINDEX 0000A1r 2 84 rr sty zINDEX + 1 0000A3r 2 A0 04 ldy #4 0000A5r 2 B1 rr lda (zINDEX),y 0000A7r 2 85 rr sta zFACHO 0000A9r 2 C8 iny 0000AAr 2 B1 rr lda (zINDEX),y 0000ACr 2 85 rr sta zFACHO + 2 0000AEr 2 A0 08 ldy #8 0000B0r 2 B1 rr lda (zINDEX),y 0000B2r 2 85 rr sta zFACHO + 1 0000B4r 2 C8 iny 0000B5r 2 B1 rr lda (zINDEX),y 0000B7r 2 85 rr sta zFACHO + 3 0000B9r 2 4C rr rr jmp LE0E3 0000BCr 2 A9 rr LE0BE: lda #zRNDX 0000C0r 2 20 rr rr jsr bMOVFM 0000C3r 2 A9 rr lda #bRMULC 0000C7r 2 20 rr rr jsr bFMULT 0000CAr 2 A9 rr lda #LE092 0000CEr 2 20 rr rr jsr bFADD 0000D1r 2 A6 rr LE0D3: ldx zFACHO + 3 0000D3r 2 A5 rr lda zFACHO 0000D5r 2 85 rr sta zFACHO + 3 0000D7r 2 86 rr stx zFACHO 0000D9r 2 A6 rr ldx zFACHO + 1 0000DBr 2 A5 rr lda zFACHO + 2 0000DDr 2 85 rr sta zFACHO + 1 0000DFr 2 86 rr stx zFACHO + 2 0000E1r 2 A9 00 LE0E3: lda #0 0000E3r 2 85 rr sta zFACSGN 0000E5r 2 A5 rr lda zFACEXP 0000E7r 2 85 rr sta zFACOV 0000E9r 2 A9 80 lda #$80 0000EBr 2 85 rr sta zFACEXP 0000EDr 2 20 rr rr jsr LB8D7 0000F0r 2 A2 rr ldx #zRNDX 0000F4r 2 4C rr rr LE0F6: jmp LBBD4 0000F7r 2 C9 F0 bBIOERR:cmp #$F0 0000F9r 2 D0 07 bne LE104 0000FBr 2 84 rr sty zMEMSIZ + 1 0000FDr 2 86 rr stx zMEMSIZ 0000FFr 2 4C rr rr jmp LA663 000102r 2 AA LE104: tax 000103r 2 D0 02 bne LE109 000105r 2 A2 1E ldx #ErrBreak 000107r 2 4C rr rr LE109: jmp bERROR 00010Ar 2 20 rr rr bCHOUT: jsr kCHROUT 00010Dr 2 B0 E8 bcs bBIOERR 00010Fr 2 60 rts 000110r 2 20 rr rr bCHIN: jsr kCHRIN 000113r 2 B0 E2 bcs bBIOERR 000115r 2 60 rts 000116r 2 bCKOUT: 000116r 2 .if CompileComputer >= C64_02 000116r 2 jsr LE4AD 000116r 2 .else 000116r 2 20 rr rr jsr kCHKOUT 000119r 2 .endif 000119r 2 B0 DC bcs bBIOERR 00011Br 2 60 rts 00011Cr 2 20 rr rr bCKIN: jsr kCHKIN 00011Fr 2 B0 D6 bcs bBIOERR 000121r 2 60 rts 000122r 2 20 rr rr bGETIN: jsr kGETIN 000125r 2 B0 D0 bcs bBIOERR 000127r 2 60 rts 000128r 2 20 rr rr bSYS: jsr bFRMNUM 00012Br 2 20 rr rr jsr bGETADR 00012Er 2 A9 rr lda #>(LE147 - 1) 000130r 2 48 pha 000131r 2 A9 rr lda #<(LE147 - 1) 000133r 2 48 pha 000134r 2 AD rr rr lda lSPREG 000137r 2 48 pha 000138r 2 AD rr rr lda lSAREG 00013Br 2 AE rr rr ldx lSXREG 00013Er 2 AC rr rr ldy lSYREG 000141r 2 28 plp 000142r 2 6C rr rr jmp (zLINNUM) 000145r 2 08 LE147: php 000146r 2 8D rr rr sta lSAREG 000149r 2 8E rr rr stx lSXREG 00014Cr 2 8C rr rr sty lSYREG 00014Fr 2 68 pla 000150r 2 8D rr rr sta lSPREG 000153r 2 60 rts 000154r 2 20 rr rr bSAVET: jsr bSLPARA 000157r 2 A6 rr ldx zVARTAB 000159r 2 A4 rr ldy zVARTAB + 1 00015Br 2 A9 rr lda #zTXTTAB 00015Dr 2 20 rr rr jsr kSAVE 000160r 2 B0 95 bcs bBIOERR 000162r 2 60 rts 000163r 2 A9 01 bVERFYT:lda #1 000165r 2 2C .byte ASM_BIT3 000166r 2 000166r 2 A9 00 bLOADT: lda #0 000168r 2 85 rr sta zVERCK 00016Ar 2 20 rr rr jsr bSLPARA 00016Dr 2 A5 rr lda zVERCK 00016Fr 2 A6 rr ldx zTXTTAB 000171r 2 A4 rr ldy zTXTTAB + 1 000173r 2 20 rr rr jsr kLOAD 000176r 2 B0 rr bcs LE1D1 000178r 2 A5 rr lda zVERCK 00017Ar 2 F0 1A beq ChkStatus 00017Cr 2 JDLE17E: 00017Cr 2 A2 1C ldx #ErrVerify 00017Er 2 20 rr rr jsr kREADST 000181r 2 29 10 and #$10 000183r 2 000183r 2 .if CompileComputer >= C64_GENERAL 000183r 2 bne LE19E 000183r 2 .else 000183r 2 000183r 2 F0 03 beq @E187 000185r 2 4C rr rr jmp bERROR 000188r 2 .endif 000188r 2 000188r 2 A5 rr @E187: lda zTXTPTR 00018Ar 2 00018Ar 2 C9 rr cmp #>lBUF 00018Cr 2 F0 07 beq LE194 00018Er 2 A9 rr lda #bOKK 000192r 2 000192r 2 4C rr rr jmp bSTROUT 000195r 2 60 LE194: rts 000196r 2 000196r 2 ChkStatus: 000196r 2 20 rr rr jsr kREADST 000199r 2 29 BF and #$BF 00019Br 2 F0 05 beq LE1A1 00019Dr 2 A2 1D ldx #ErrLoad 00019Fr 2 4C rr rr LE19E: jmp bERROR 0001A2r 2 A5 rr LE1A1: lda zTXTPTR + 1 0001A4r 2 C9 rr cmp #>lBUF 0001A6r 2 D0 0E bne LE1B5 0001A8r 2 JDLE1A7: 0001A8r 2 86 rr stx zVARTAB 0001AAr 2 84 rr sty zVARTAB + 1 0001ACr 2 A9 rr lda #StrReady 0001B0r 2 20 rr rr jsr bSTROUT 0001B3r 2 4C rr rr jmp LA52A 0001B6r 2 20 rr rr LE1B5: jsr bSTXPT 0001B9r 2 0001B9r 2 .if CompileComputer >= C64_GENERAL 0001B9r 2 jsr bLINKPRG 0001B9r 2 jmp LA677 0001B9r 2 .elseif CompileComputer >= VIC20_06 0001B9r 2 4C rr rr JMP LE476 0001BCr 2 .else 0001BCr 2 JMP LA677 0001BCr 2 .endif 0001BCr 2 0001BCr 2 ; FillUntil BASIC_START_2 + $01BE 0001BCr 2 .segment "BASICOPEN" 000000r 2 000000r 2 20 rr rr bOPENT: jsr bOCPARA 000003r 2 20 rr rr jsr kOPEN 000006r 2 B0 0B bcs LE1D1 000008r 2 60 rts 000009r 2 20 rr rr bCLOSET:jsr bOCPARA 00000Cr 2 A5 rr lda zFORPNT 00000Er 2 20 rr rr jsr kCLOSE 000011r 2 90 rr bcc LE194 000013r 2 4C rr rr LE1D1: jmp bBIOERR 000016r 2 A9 00 bSLPARA:lda #0 000018r 2 20 rr rr jsr kSETNAM 00001Br 2 A2 01 ldx #1 00001Dr 2 A0 00 ldy #0 00001Fr 2 .ifdef JIFFY 00001Fr 2 jsr JDLF73A 00001Fr 2 .else 00001Fr 2 20 rr rr jsr kSETLFS 000022r 2 .endif 000022r 2 20 rr rr jsr bDEFLT 000025r 2 20 rr rr jsr LE257 000028r 2 20 rr rr jsr bDEFLT 00002Br 2 20 rr rr jsr bCOMBYT 00002Er 2 A0 00 ldy #0 000030r 2 86 rr stx zFORPNT 000032r 2 20 rr rr jsr kSETLFS 000035r 2 20 rr rr jsr bDEFLT 000038r 2 20 rr rr jsr bCOMBYT 00003Br 2 8A txa 00003Cr 2 A8 tay 00003Dr 2 A6 rr ldx zFORPNT 00003Fr 2 4C rr rr jmp kSETLFS 000042r 2 20 rr rr bCOMBYT:jsr bCMMERR 000045r 2 4C rr rr jmp LB79E 000048r 2 20 rr rr bDEFLT: jsr zCHRGOT 00004Br 2 D0 02 bne LE20D 00004Dr 2 68 pla 00004Er 2 68 pla 00004Fr 2 60 LE20D: rts 000050r 2 20 rr rr bCMMERR:jsr bCHKCMA 000053r 2 20 rr rr LE211: jsr zCHRGOT 000056r 2 D0 F7 bne LE20D 000058r 2 4C rr rr jmp bSYNERR 00005Br 2 A9 00 bOCPARA:lda #0 00005Dr 2 20 rr rr jsr kSETNAM 000060r 2 20 rr rr jsr LE211 000063r 2 20 rr rr jsr LB79E 000066r 2 86 rr stx zFORPNT 000068r 2 8A txa 000069r 2 A2 01 ldx #1 00006Br 2 JDLE229: 00006Br 2 A0 00 ldy #0 00006Dr 2 20 rr rr jsr kSETLFS 000070r 2 20 rr rr jsr bDEFLT 000073r 2 20 rr rr jsr bCOMBYT 000076r 2 86 rr stx zFORPNT + 1 000078r 2 A0 00 ldy #0 00007Ar 2 A5 rr lda zFORPNT 00007Cr 2 E0 03 cpx #3 00007Er 2 90 01 bcc LE23F 000080r 2 88 dey 000081r 2 20 rr rr LE23F: jsr kSETLFS 000084r 2 20 rr rr jsr bDEFLT 000087r 2 20 rr rr jsr bCOMBYT 00008Ar 2 8A txa 00008Br 2 A8 tay 00008Cr 2 A6 rr ldx zFORPNT + 1 00008Er 2 A5 rr lda zFORPNT 000090r 2 20 rr rr jsr kSETLFS 000093r 2 20 rr rr jsr bDEFLT 000096r 2 20 rr rr jsr bCMMERR 000099r 2 20 rr rr LE257: jsr bFRMEVL 00009Cr 2 JDLE25A: 00009Cr 2 20 rr rr jsr bFRESTR 00009Fr 2 A6 rr ldx zINDEX 0000A1r 2 A4 rr ldy zINDEX + 1 0000A3r 2 4C rr rr jmp kSETNAM 0000A6r 2 A9 rr bCOS: lda #bPI2 0000AAr 2 20 rr rr jsr bFADD 0000ADr 2 20 rr rr bSIN: jsr bMOVAF 0000B0r 2 A9 rr lda #LE2E5 0000B4r 2 A6 rr ldx zARGSGN 0000B6r 2 20 rr rr jsr bFDIV 0000B9r 2 20 rr rr jsr bMOVAF 0000BCr 2 20 rr rr jsr bINT 0000BFr 2 A9 00 lda #0 0000C1r 2 85 rr sta zARISGN 0000C3r 2 20 rr rr jsr FSUBT 0000C6r 2 A9 rr lda #LE2EA 0000CAr 2 20 rr rr jsr bFSUB 0000CDr 2 A5 rr lda zFACSGN 0000CFr 2 48 pha 0000D0r 2 10 0D bpl LE29D 0000D2r 2 20 rr rr jsr bFADDH 0000D5r 2 A5 rr lda zFACSGN 0000D7r 2 30 09 bmi LE2A0 0000D9r 2 A5 rr lda zTANSGN 0000DBr 2 49 FF eor #$FF 0000DDr 2 85 rr sta zTANSGN 0000DFr 2 20 rr rr LE29D: jsr bNEGOP 0000E2r 2 A9 rr LE2A0: lda #LE2EA 0000E6r 2 20 rr rr jsr bFADD 0000E9r 2 68 pla 0000EAr 2 10 03 bpl LE2AD 0000ECr 2 20 rr rr jsr bNEGOP 0000EFr 2 A9 rr LE2AD: lda #LE2EF 0000F3r 2 4C rr rr jmp bPOLYX 0000F6r 2 20 rr rr bTAN: jsr LBBCA 0000F9r 2 A9 00 lda #$00 0000FBr 2 85 rr sta zTANSGN 0000FDr 2 20 rr rr jsr bSIN 000100r 2 A2 rr ldx #zTEMPF3 000104r 2 20 rr rr jsr LE0F6 000107r 2 A9 rr lda #zTEMPF1 00010Br 2 20 rr rr jsr bMOVFM 00010Er 2 A9 00 lda #$00 000110r 2 85 rr sta zFACSGN 000112r 2 A5 rr lda zTANSGN 000114r 2 20 rr rr jsr LE2DC 000117r 2 A9 rr lda #zTEMPF3 00011Br 2 4C rr rr jmp bFDIVT 00011Er 2 48 LE2DC: pha 00011Fr 2 4C rr rr jmp LE29D 000122r 2 000122r 2 81 49 0F DA bPI2: .byte $81,$49,$0F,$DA,$A2 000126r 2 A2 000127r 2 83 49 0F DA LE2E5: .byte $83,$49,$0F,$DA,$A2 00012Br 2 A2 00012Cr 2 7F 00 00 00 LE2EA: .byte $7F,$00,$00,$00,$00 000130r 2 00 000131r 2 05 LE2EF: .byte $05 000132r 2 84 E6 1A 2D .byte $84,$E6,$1A,$2D,$1B 000136r 2 1B 000137r 2 86 28 07 FB .byte $86,$28,$07,$FB,$F8 00013Br 2 F8 00013Cr 2 87 99 68 89 .byte $87,$99,$68,$89,$01 000140r 2 01 000141r 2 87 23 35 DF .byte $87,$23,$35,$DF,$E1 000145r 2 E1 000146r 2 86 A5 5D E7 .byte $86,$A5,$5D,$E7,$28 00014Ar 2 28 00014Br 2 83 49 0F DA .byte $83,$49,$0F,$DA,$A2 00014Fr 2 A2 000150r 2 000150r 2 A5 rr bATN: lda zFACSGN 000152r 2 48 pha 000153r 2 10 03 bpl LE316 000155r 2 20 rr rr jsr bNEGOP 000158r 2 A5 rr LE316: lda zFACEXP 00015Ar 2 48 pha 00015Br 2 C9 81 cmp #$81 00015Dr 2 90 07 bcc LE324 00015Fr 2 A9 rr lda #bFPTABL 000163r 2 20 rr rr jsr bFDIVT 000166r 2 A9 rr LE324: lda #bATNCON 00016Ar 2 20 rr rr jsr bPOLYX 00016Dr 2 68 pla 00016Er 2 C9 81 cmp #$81 000170r 2 90 07 bcc LE337 000172r 2 A9 rr lda #bPI2 000176r 2 20 rr rr jsr bFSUB 000179r 2 68 LE337: pla 00017Ar 2 10 03 bpl LE33D 00017Cr 2 4C rr rr jmp bNEGOP 00017Fr 2 60 LE33D: rts 000180r 2 000180r 2 0B bATNCON:.byte $0B 000181r 2 76 B3 83 BD .byte $76,$B3,$83,$BD,$D3 000185r 2 D3 000186r 2 79 1E F4 A6 .byte $79,$1E,$F4,$A6,$F5 00018Ar 2 F5 00018Br 2 7B 83 FC B0 .byte $7B,$83,$FC,$B0,$10 00018Fr 2 10 000190r 2 7C 0C 1F 67 .byte $7C,$0C,$1F,$67,$CA 000194r 2 CA 000195r 2 7C DE 53 CB .byte $7C,$DE,$53,$CB,$C1 000199r 2 C1 00019Ar 2 7D 14 64 70 .byte $7D,$14,$64,$70,$4C 00019Er 2 4C 00019Fr 2 7D B7 EA 51 .byte $7D,$B7,$EA,$51,$7A 0001A3r 2 7A 0001A4r 2 7D 63 30 88 .byte $7D,$63,$30,$88,$7E 0001A8r 2 7E 0001A9r 2 7E 92 44 99 .byte $7E,$92,$44,$99,$3A 0001ADr 2 3A 0001AEr 2 7E 4C CC 91 .byte $7E,$4C,$CC,$91,$C7 0001B2r 2 C7 0001B3r 2 7F AA AA AA .byte $7F,$AA,$AA,$AA,$13 0001B7r 2 13 0001B8r 2 81 00 00 00 .byte $81,$00,$00,$00,$00 0001BCr 2 00 0001BDr 2 0001BDr 2 .if CompileComputer >= C64_GENERAL 0001BDr 2 LE37B: jsr kCLRCHN 0001BDr 2 lda #0 0001BDr 2 sta z13 0001BDr 2 jsr LA67A 0001BDr 2 cli 0001BDr 2 0001BDr 2 ; Patch: Output READY, but respect the (lIERROR) vector 0001BDr 2 ReadyVector: 0001BDr 2 ldx #$80 ; errorcode = bit 7 set, that is, no error occurred 0001BDr 2 jmp (lIERROR) ; by default, this is a no-op 0001BDr 2 0001BDr 2 PatchErrorOut: 0001BDr 2 txa ; check the error code 0001BDr 2 bmi @LE391 ; bit 7 set? Then no error occurred, jump to "ready" 0001BDr 2 jmp ErrorOut ; output the error 0001BDr 2 @LE391: 0001BDr 2 jmp bREADY 0001BDr 2 .endif 0001BDr 2 0001BDr 2 LE394: 0001BDr 2 .ifdef JIFFY 0001BDr 2 jsr JDLE4B7 0001BDr 2 .else 0001BDr 2 20 rr rr jsr LE453 0001C0r 2 .endif 0001C0r 2 20 rr rr jsr LE3BF 0001C3r 2 20 rr rr jsr LE422 0001C6r 2 A2 FB ldx #-5 ; stack pointer to $01FB 0001C8r 2 9A txs 0001C9r 2 0001C9r 2 .if CompileComputer >= C64_GENERAL 0001C9r 2 bne ReadyVector 0001C9r 2 .else 0001C9r 2 4C rr rr jmp bREADY 0001CCr 2 .endif 0001CCr 2 0001CCr 2 .segment "CHRGET" 000000r 2 000000r 2 COPY_OF_CHRGET: 000000r 2 E6 rr inc zTXTPTR 000002r 2 D0 02 bne COPY_OF_CHRGOT 000004r 2 E6 rr inc zTXTPTR + 1 000006r 2 000006r 2 COPY_OF_CHRGOT: 000006r 2 AD 60 EA lda $EA60 ; this is just a dummy address 000009r 2 C9 3A cmp #'9' + 1 00000Br 2 B0 0A bcs COPY_OF_CHRGOT_RTS 00000Dr 2 00000Dr 2 COPY_OF_CHRGOT_SPACE: 00000Dr 2 C9 20 cmp #' ' 00000Fr 2 F0 EF beq COPY_OF_CHRGET 000011r 2 38 sec 000012r 2 E9 30 sbc #'0' 000014r 2 38 sec 000015r 2 E9 D0 sbc #-'0' 000017r 2 COPY_OF_CHRGOT_RTS: 000017r 2 60 rts 000018r 2 000018r 2 80 4F C7 52 .byte $80,$4F,$C7,$52,$58 00001Cr 2 58 00001Dr 2 00001Dr 2 END_COPY_OF_CHRGET: 00001Dr 2 00001Dr 2 .segment "INIT" 000000r 2 000000r 2 A9 4C LE3BF: lda #ASM_JMP 000002r 2 85 rr sta zJMPER 000004r 2 85 rr sta lUSRPOK 000006r 2 A9 rr lda #bIQERR 00000Ar 2 85 rr sta lUSRADD 00000Cr 2 84 rr sty lUSRADD + 1 00000Er 2 A9 rr lda #bGIVAYF 000012r 2 85 rr sta zADRAY2 000014r 2 84 rr sty zADRAY2 + 1 000016r 2 A9 rr lda #bFACINX 00001Ar 2 85 rr sta zADRAY1 00001Cr 2 84 rr sty zADRAY1 + 1 00001Er 2 A2 1C ldx #END_COPY_OF_CHRGET - COPY_OF_CHRGET - 1 000020r 2 BD rr rr LE3E2: lda COPY_OF_CHRGET,x 000023r 2 95 rr sta zCHRGET,x 000025r 2 CA dex 000026r 2 10 F8 bpl LE3E2 000028r 2 A9 03 lda #$03 00002Ar 2 85 rr sta zFOUR6 00002Cr 2 A9 00 lda #0 00002Er 2 85 rr sta zBITS 000030r 2 85 rr sta z13 000032r 2 85 rr sta zLASTPT + 1 000034r 2 A2 01 ldx #1 000036r 2 8E rr rr stx lBUF - 3 000039r 2 8E rr rr stx lBUF - 4 00003Cr 2 A2 rr ldx #zTEMPST 00003Er 2 86 rr stx zTEMPPT 000040r 2 38 sec 000041r 2 20 rr rr jsr kMEMBOT 000044r 2 86 rr stx zTXTTAB 000046r 2 84 rr sty zTXTTAB + 1 000048r 2 38 sec 000049r 2 20 rr rr jsr kMEMTOP 00004Cr 2 86 rr stx zMEMSIZ 00004Er 2 84 rr sty zMEMSIZ + 1 000050r 2 86 rr stx zFRETOP 000052r 2 84 rr sty zFRETOP + 1 000054r 2 A0 00 ldy #0 000056r 2 98 tya 000057r 2 91 rr sta (zTXTTAB),y 000059r 2 E6 rr inc zTXTTAB 00005Br 2 D0 02 bne LE421 00005Dr 2 E6 rr inc zTXTTAB + 1 00005Fr 2 60 LE421: rts 000060r 2 A5 rr LE422: lda zTXTTAB 000062r 2 A4 rr ldy zTXTTAB + 1 000064r 2 20 rr rr jsr bREASON 000067r 2 A9 rr lda #LE473 00006Br 2 .if CompileComputer = C64_4064 00006Br 2 jmp LE441 00006Br 2 .else 00006Br 2 20 rr rr jsr bSTROUT 00006Er 2 .endif 00006Er 2 A5 rr lda zMEMSIZ 000070r 2 38 sec 000071r 2 E5 rr sbc zTXTTAB 000073r 2 AA tax 000074r 2 A5 rr lda zMEMSIZ + 1 000076r 2 E5 rr sbc zTXTTAB + 1 000078r 2 20 rr rr jsr LBDCD 00007Br 2 A9 rr lda #LE460 00007Fr 2 20 rr rr LE441: jsr bSTROUT 000082r 2 4C rr rr jmp LA644 000085r 2 000085r 2 .if CompileComputer < C64_GENERAL 000085r 2 .include "../vic20/basic-texts.inc" 000085r 3 LE460: 000085r 3 20 42 59 54 .byte " BYTES FREE",$0D,$00 000089r 3 45 53 20 46 00008Dr 3 52 45 45 0D 000092r 3 000092r 3 93 LE473: .byte $93 000093r 3 2A 2A 2A 2A .byte "**** CBM BASIC V2 ****" 000097r 3 20 43 42 4D 00009Br 3 20 42 41 53 0000A9r 3 0D 00 .byte $0D,$00 0000ABr 3 0000ABr 2 .endif 0000ABr 2 0000ABr 2 LE447: 0000ABr 2 .if CompileComputer >= C64_GENERAL 0000ABr 2 .ifdef JIFFY 0000ABr 2 .addr JDLF763 0000ABr 2 .else 0000ABr 2 .addr PatchErrorOut ; for the C64, check if bit 7 of the error code is set. 0000ABr 2 .endif 0000ABr 2 .else 0000ABr 2 rr rr .addr ErrorOut ; for the VIC20, this is always an error. 0000ADr 2 .endif 0000ADr 2 0000ADr 2 .if CompileComputer = C64_GS 0000ADr 2 .addr C64GS_Init 0000ADr 2 .else 0000ADr 2 rr rr .addr IMAIN 0000AFr 2 .endif 0000AFr 2 0000AFr 2 .ifdef JIFFY 0000AFr 2 .addr LEA64 0000AFr 2 .else 0000AFr 2 rr rr .addr LA57C 0000B1r 2 .endif 0000B1r 2 rr rr .addr LA71A 0000B3r 2 rr rr .addr LA7E4 0000B5r 2 rr rr .addr LAE86 0000B7r 2 END_LE447: 0000B7r 2 0000B7r 2 A2 0B LE453: ldx #END_LE447 - LE447 - 1 0000B9r 2 BD rr rr LE455: lda LE447,x 0000BCr 2 9D rr rr sta lIERROR,x 0000BFr 2 CA dex 0000C0r 2 10 F7 bpl LE455 0000C2r 2 60 rts 0000C3r 2 0000C3r 2 .if CompileComputer >= C64_GENERAL 0000C3r 2 .byte $00 ; basic checksum? 0000C3r 2 0000C3r 2 .include "../c64/basic-texts.inc" 0000C3r 2 .endif 0000C3r 2 0000C3r 2 .if CompileComputer < C64_GENERAL 0000C3r 2 0000C3r 2 LE37B: 0000C3r 2 20 rr rr jsr kCLRCHN 0000C6r 2 A9 00 lda #0 0000C8r 2 85 rr sta z13 0000CAr 2 20 rr rr jsr LA67A 0000CDr 2 58 cli 0000CEr 2 4C rr rr jmp bREADY 0000D1r 2 0000D1r 2 41 .byte CHECKSUM_E475 0000D2r 2 0000D2r 2 .if CompileComputer >= VIC20_06 0000D2r 2 LE476: 0000D2r 2 20 rr rr jsr bLINKPRG 0000D5r 2 4C rr rr jmp LA677 0000D8r 2 .endif 0000D8r 2 .endif 0000D8r 2 0000D8r 1 0000D8r 1 .include "../kernal/kernal-memory.inc" 0000D8r 2 .segment "MEM_KERNAL_ZP": zeropage 000000r 2 000000r 2 xx zSTATUS: .res 1 ; $0090 ; status of TAPE/IEC routines 000001r 2 000001r 2 xx zSTKEY: .res 1 ; $0091 000002r 2 xx zSVXT: .res 1 ; $0092 000003r 2 xx zVERCKK: .res 1 ; $0093 ; verify flag: Remember in KLOAD if LOAD (=0) or VERIFY (=1) is requested. 000004r 2 xx zC3PO: .res 1 ; $0094 ; delayed byte for IEC output 000005r 2 ; As an EOI must be signaled BEFORE the last byte is transferred, 000005r 2 ; the KERNAL routines use a delayed write approach: 000005r 2 ; 000005r 2 ; It starts with zC3PO = 0. 000005r 2 ; When the first byte to be output is given to the IEC routines, 000005r 2 ; it is written to zBSOUR, and zC3PO.7 is set. 000005r 2 ; When the next byte is written, zC3PO is tested. As it is negative, 000005r 2 ; the byte in zBSOUR is being output to the IEC bus. Afterwards, 000005r 2 ; the new byte is written into zBSOUR. 000005r 2 ; When the last byte is transferred, the next command transmitted 000005r 2 ; (i.e. LISTEN, TALK, UNLISTEN, UNTALK) tests for zC3PO. As it is 000005r 2 ; negative, the last byte (in zBSOUR) is output to the IEC bus, and 000005r 2 ; an EOI is signalled. 000005r 2 ; 000005r 2 xx zBSOUR: .res 1 ; $0095 ; The byte to write on the IEC bus. (see also zC3PO) 000006r 2 xx zSYNO: .res 1 ; $0096 000007r 2 xx zTEMPX: .res 1 ; $0097 000008r 2 xx zLDTND: .res 1 ; $0098 ; number of active entries in the lLAT, lFAT and lSAT table 000009r 2 xx zDFLTN: .res 1 ; $0099 00000Ar 2 xx zDFLTO: .res 1 ; $009A 00000Br 2 xx zPRTY: .res 1 ; $009B 00000Cr 2 xx zDPSW: .res 1 ; $009C 00000Dr 2 xx zNSGFLG: .res 1 ; $009D ; message output policy: 00000Er 2 ; bit 7: Output "Loading", "Saving", "Verifying", "Found", ... messages 00000Er 2 ; bit 6: Output "I/O ERROR #n" if KERNAL routines encounter an error 00000Er 2 ; This value is only set by kSETMSG. 00000Er 2 00000Er 2 xx zPTR1: .res 1 ; $009E 00000Fr 2 xx zPTR2: .res 1 ; $009F 000010r 2 xx xx xx zTIME: .res 3 ; $00A0 000013r 2 xx zTSFCNT: .res 1 ; $00A3 ; mark: signal EOI (== $80) or not (== $00) on IEC bus. 000014r 2 xx zTBTCNT: .res 1 ; $00A4 000015r 2 xx zCNTDN: .res 1 ; $00A5 000016r 2 xx zBUFPNT: .res 1 ; $00A6 ; pointer into tape buffer (lTBUFFR), stored as an index 0..(TBUFFR_SIZE - 1): Contains the last value that was written or read. 000017r 2 xx zINBIT: .res 1 ; $00A7 000018r 2 xx zBITC1: .res 1 ; $00A8 000019r 2 xx zRINONE: .res 1 ; $00A9 00001Ar 2 xx zRIDATA: .res 1 ; $00AA 00001Br 2 xx zRIPRTY: .res 1 ; $00AB 00001Cr 2 xx xx zSAL: .res 2 ; $00AC 00001Er 2 xx xx zEAL: .res 2 ; $00AE 000020r 2 xx xx zCMPO: .res 2 ; $00B0 000022r 2 xx xx zTAPE1: .res 2 ; $00B2 000024r 2 xx zBITTS: .res 1 ; $00B4 000025r 2 xx zNXTBIT: .res 1 ; $00B5 000026r 2 xx zRODATA: .res 1 ; $00B6 000027r 2 xx zFNLEN: .res 1 ; $00B7 ; length of the name of the file to be opened. Address at zFNADR. Only used on OPEN and LOAD. 000028r 2 xx zLA: .res 1 ; $00B8 ; logical device number of current open file (or in preparation to a call to OPEN) 000029r 2 xx zSA: .res 1 ; $00B9 ; device (primary) address of current open file (or in preparation to a call to OPEN) 00002Ar 2 xx zFA: .res 1 ; $00BA ; secondary address of current open file (or in preparation to a call to OPEN) 00002Br 2 xx xx zFNADR: .res 2 ; $00BB ; address of the name of the file to be opened. Length at zFNLEN. Only used on OPEN and LOAD. 00002Dr 2 xx zROPRTY: .res 1 ; $00BD 00002Er 2 xx zFSBLK: .res 1 ; $00BE 00002Fr 2 xx zMYCH: .res 1 ; $00BF 000030r 2 xx zCAS1: .res 1 ; $00C0 ; 0 if no tape operation in progress, != 0 otherwise. Use in the IRQ routine to switch off tape motor, if needed. 000031r 2 xx xx zSTAL: .res 2 ; $00C1 000033r 2 xx xx zMEMUSS: .res 2 ; $00C3 000035r 2 xx zLSTX: .res 1 ; $00C5 ; last pressed key. That is, after keyboard scanning completes, this becomes a copy of zSFDX. This is used for determining if key repetition is to be performed. 000036r 2 xx zNDX: .res 1 ; $00C6 ; current numbers of characters in the keyboard buffer (lKEYD). The maximum is stored in lXMAX. 000037r 2 xx zRVS: .res 1 ; $00C7 000038r 2 xx zINDX: .res 1 ; $00C8 000039r 2 xx zLXSP: .res 1 ; $00C9 00003Ar 2 xx zTEMP_zPNTR: .res 1 ; $00CA ; temporary buffer for cursorpos (zPNTR) inside of BASIN 00003Br 2 xx zSFDX: .res 1 ; $00CB ; key code if the code that is currently found pressed 00003Cr 2 xx zBLNSW: .res 1 ; $00CC ; blink switch: <> 0 -> disable cursor, == 0 -> enable cursor 00003Dr 2 xx zBLNCT: .res 1 ; $00CD 00003Er 2 xx zGDBLN: .res 1 ; $00CE 00003Fr 2 xx zBLNON: .res 1 ; $00CF ; current blink state: 0 = cursor currently invisible, 1 = cursor is just now visible on the screen 000040r 2 xx zCRSW: .res 1 ; $00D0 ; used in editor routines for sreen input: > 0 if CR has been pressed, 0 if there has not been any input yet (or no CR has been pressed yet) 000041r 2 xx xx zPNT: .res 2 ; $00D1 ; pointer to start of current cursor row in video RAM (cf. zUSER) 000043r 2 xx zPNTR: .res 1 ; $00D3 ; column of current cursor position (0 ... X-1) 000044r 2 xx zQTSW: .res 1 ; $00D4 ; quotation mark switch: 1 = we are in quotation mode, 0 = we are not. 000045r 2 xx zLNMX: .res 1 ; $00D5 ; maximum column number in the current (logical) line 000046r 2 xx zTBLX: .res 1 ; $00D6 ; row of current cursor positon (0 ... Y-1) 000047r 2 xx zSCHAR: .res 1 ; $00D7 ; temporary storage for a character in editor routines for input and output, and temporary storage in tape routines 000048r 2 xx zINSRT: .res 1 ; $00D8 ; number of characters to output in INSERT mode. 0 = we are not in insert mode 000049r 2 xx xx xx xx zLDTB1: .res 26 ; $00D9 ; high byte of start address of (logical) screen rows 00004Dr 2 xx xx xx xx 000051r 2 xx xx xx xx 000063r 2 ; Bit 7 ($80) is 1 if this line is "stand-alone"; 000063r 2 ; it is 0 if this line is combined with the previous one 000063r 2 ; the lower bits (and #>lVIDEORAM_SIZE) define the high byte bits of the start address of this row. 000063r 2 ; 000063r 2 ; For the last row, this table entry contains $FF as an end marker. 000063r 2 000063r 2 xx xx zUSER: .res 2 ; $00F3 ; pointer to start of current cursor row in color RAM (cf. zPNT) 000065r 2 xx xx zKEYTAB: .res 2 ; $00F5 000067r 2 xx xx zRIBUF: .res 2 ; $00F7 ; pointer to the RS232 input buffer (ring buffer) (see also lRIDBE, lRIDBS) 000069r 2 xx xx zROBUF: .res 2 ; $00F9 ; pointer to the RS232 output buffer (ring buffer) (see also lRODBE, lRODBS) 00006Br 2 xx xx xx xx zFREKXP: .res 4 ; $00FB 00006Fr 2 00006Fr 2 .segment "MEM_KERNAL_DATA_0200" 000000r 2 000000r 2 ; the following table contains the data (logical file number, primary address, secondary address) for open files. 000000r 2 ; The entries correspond to each other: That is, lLAT + x, lFAT + x and lSAT + x contain the data for the file 000000r 2 ; with the index (*not* logical file number!) x. 000000r 2 000000r 2 lLAT_Size := 10 000000r 2 xx xx xx xx lLAT: .res lLAT_Size ; $0259 ; table of logical file numbers for open files. Number of active entries in zLDTND. Cannot be 0 for active files. 000004r 2 xx xx xx xx 000008r 2 xx xx 00000Ar 2 xx xx xx xx lFAT: .res lLAT_Size ; $0263 ; table of device (primary) addresses for open files. Number of active entries in zLDTND. 00000Er 2 xx xx xx xx 000012r 2 xx xx 000014r 2 xx xx xx xx lSAT: .res lLAT_Size ; $026D ; table of secondary addresses for open files. Number of active entries in zLDTND. 000018r 2 xx xx xx xx 00001Cr 2 xx xx 00001Er 2 00001Er 2 xx xx xx xx lKEYD: .res 10 ; $0277 000022r 2 xx xx xx xx 000026r 2 xx xx 000028r 2 xx xx lMEMSTR: .res 2 ; $0281 00002Ar 2 xx xx lMEMSIZ: .res 2 ; $0283 00002Cr 2 xx lTIMOUT: .res 1 ; $0285 00002Dr 2 xx lCOLOR: .res 1 ; $0286 ; default color (bit 7 must be 0, or CHROUT_SCREEN will behave erroneouskly!) 00002Er 2 xx lGDCOL: .res 1 ; $0287 00002Fr 2 xx lHIBASE: .res 1 ; $0288 ; high byte of video RAM address 000030r 2 xx lXMAX: .res 1 ; $0289 ; maximum number of characters in the keyboard buffer (lKEYD). zNDX is checked against this value 000031r 2 xx lRPTFLG: .res 1 ; $028A ; repeat flag for keys 000032r 2 ; bit 7 ($80) == 1 -> repeat all keys 000032r 2 ; bit 6 ($40) == 1 -> do not repeat any key 000032r 2 ; else: Repeat special keys (space, CRSRS, INS/DEL), but not the others 000032r 2 000032r 2 ; the test is done starting with bit 7, then bit 6. 000032r 2 ; thus, if both are set, all keys are repeated 000032r 2 000032r 2 xx lKOUNT: .res 1 ; $028B ; delay counter for key repetitions. This is decremented on every IRQ, starting from 4. 000033r 2 000033r 2 xx lDELAY: .res 1 ; $028C ; delay counter for key repetitions. It is used for the initial delay before the key repetition starts. 000034r 2 000034r 2 xx lSHFLAG: .res 1 ; $028D ; contains the state of the shift keys while scanning the keyboard. 000035r 2 ; The state is an OR between the following values, if the correspondig key is pressed: 000035r 2 ; bit 0 ($01) = shift 000035r 2 ; bit 1 ($02) = C= 000035r 2 ; bit 2 ($04) = CTRL 000035r 2 lSHFLAG_SHIFT := $01 000035r 2 lSHFLAG_CBM := $02 000035r 2 lSHFLAG_CTRL := $04 000035r 2 000035r 2 xx lLSTSHF: .res 1 ; $028E ; contains the *last* shift state. That is, after the keyboard is scanned, this becomes a copy of lSHFLAG. This way, the KERNAL prevents a repeated toggling when pressend SHIFT + C= 000036r 2 xx xx lKEYLOG: .res 2 ; $028F 000038r 2 xx lMODE: .res 1 ; $0291 ; determines editor mode. 000039r 2 ; bit 7 ($80) == 1 -> Switching between uppercase-mode and lowercase-mode via SHIFT + C= is not allowed 000039r 2 ; bit 4 ($10) == 1 -> TODO ??? (used in VIC20-02) 000039r 2 ; bit 3 ($08) == 1 -> we are in lowercase mode, == 0 -> we are in uppercase mode (only VIC20-02) 000039r 2 ; on VIC20-02, lMODE also contains the offset into the @KEYTABS_VEC table ($00-$16) 000039r 2 000039r 2 ; on the VIC20-02, lMODE is used in CHROUT_SCREEN to determine if some chars are to 000039r 2 ; be translated (according to CHROUT_REPLACEMENT_TABLE). If lMODE is not 0, the 000039r 2 ; translation is done. If it is 0, the translation is skipped. 000039r 2 000039r 2 xx lAUTODN: .res 1 ; $0292 ; TODO "Auto down" flag: (Flag: "combine line with next line, if needed") 00003Ar 2 00003Ar 2 ; If the output is done because of some key press, lAUTODN is not 0. In this case, 00003Ar 2 ; when the output reaches the end of a row, this row is combined with the next 00003Ar 2 ; row. Furthermore, the screen contents below the current line are scrolled down. 00003Ar 2 00003Ar 2 ; If the output is done without some key press, lAUTODN is 0. In this case, 00003Ar 2 ; when the output reaches the end of a row, this row is combined with the next 00003Ar 2 ; one, but the screen contents are NOT scrolled down. 00003Ar 2 00003Ar 2 xx lM51CTR: .res 1 ; $0293 00003Br 2 xx lM51CDR: .res 1 ; $0294 00003Cr 2 xx xx lM51AJB: .res 2 ; $0295 00003Er 2 xx lRSSTAT: .res 1 ; $0297 00003Fr 2 xx lBITNUM: .res 1 ; $0298 000040r 2 xx xx lBAUDOF: .res 2 ; $0299 000042r 2 xx lRIDBE: .res 1 ; $029B ; RS232 input buffer at zRIBUF: read pointer 000043r 2 xx lRIDBS: .res 1 ; $029C ; RS232 input buffer at zRIBUF: write pointer 000044r 2 xx lRODBS: .res 1 ; $029D ; RS232 output buffer at zROBUF: read pointer 000045r 2 xx lRODBE: .res 1 ; $029E ; RS232 output buffer at zROBUF: write pointer 000046r 2 xx xx lIRQTMP: .res 2 ; $029F 000048r 2 000048r 2 .if CompileComputer >= C64_GENERAL 000048r 2 000048r 2 lENABL: .res 1 ; $02A1 ; CIA2 ICR temporary register 000048r 2 lTODSNS: .res 1 ; $02A2 000048r 2 lTRDTMP: .res 1 ; $02A3 000048r 2 lTD1IRQ: .res 1 ; $02A4 000048r 2 lTLNIDX: .res 1 ; $02A5 000048r 2 lTVSFLG: .res 1 ; $02A6 000048r 2 000048r 2 .else 000048r 2 000048r 2 lTLNIDX := $00F2 000048r 2 000048r 2 .endif 000048r 2 000048r 2 .segment "MEM_KERNAL_DATA_0300" 000000r 2 000000r 2 xx xx lCINV: .res 2 ; $0314 000002r 2 xx xx lCNBINV: .res 2 ; $0316 000004r 2 xx xx lNMINV: .res 2 ; $0318 000006r 2 xx xx lIOPEN: .res 2 ; $031A 000008r 2 xx xx lICLOSE: .res 2 ; $031C 00000Ar 2 xx xx lICHKIN: .res 2 ; $031E 00000Cr 2 xx xx lICKOUT: .res 2 ; $0320 00000Er 2 xx xx lICLRCH: .res 2 ; $0322 000010r 2 xx xx lIBASIN: .res 2 ; $0324 000012r 2 xx xx lIBSOUT: .res 2 ; $0326 000014r 2 xx xx lISTOP: .res 2 ; $0328 000016r 2 xx xx lIGETIN: .res 2 ; $032A 000018r 2 xx xx lICLALL: .res 2 ; $032C 00001Ar 2 xx xx lUSRCMD: .res 2 ; $032E 00001Cr 2 xx xx lILOAD: .res 2 ; $0330 00001Er 2 xx xx lISAVE: .res 2 ; $0332 000020r 2 000020r 2 xx xx xx xx .res 8 ; $0334 - $033B, unused 000024r 2 xx xx xx xx 000028r 2 000028r 2 lTBUFFR_SIZE := $00C0 000028r 2 xx xx xx xx lTBUFFR: .res lTBUFFR_SIZE ; $033C ; tape buffer. The pointer into this buffer can be found at zBUFPNT. 00002Cr 2 xx xx xx xx 000030r 2 xx xx xx xx 0000E8r 2 0000E8r 2 .if CompileComputer >= C64_GENERAL 0000E8r 2 lVIDEORAM := $0400 0000E8r 2 .if .defined(C64JAPAN) 0000E8r 2 lBASICRAM := $1000 0000E8r 2 .else 0000E8r 2 lBASICRAM := $0800 0000E8r 2 .endif 0000E8r 2 .endif 0000E8r 2 0000E8r 2 lVIDEORAM_SIZE := $03FF 0000E8r 2 0000E8r 2 .if CompileComputer = VIC20_02 0000E8r 2 zMEMUSS_2 := zC3PO 0000E8r 2 .else 0000E8r 2 zMEMUSS_2 := zMEMUSS 0000E8r 2 .endif 0000E8r 2 0000E8r 1 0000E8r 1 .include "../kernal/fileio_data.inc" 0000E8r 2 .macro LOAD_OVERWRITE_START_ADDRESS 0000E8r 2 txa 0000E8r 2 bne :+ 0000E8r 2 lda zMEMUSS 0000E8r 2 sta zEAL 0000E8r 2 lda zMEMUSS + 1 0000E8r 2 sta zEAL + 1 0000E8r 2 : 0000E8r 2 0000E8r 2 .endmacro 0000E8r 2 0000E8r 2 .macro FILEIO_PATCH_CLOSE_TAPE 0000E8r 2 0000E8r 2 jsr TapeWriteCompleteBuffer ; write out the tape buffer to tape 0000E8r 2 bcc FileIoPatch_NoError ; C = 0 -> no error -> branch 0000E8r 2 0000E8r 2 pla ; get back index into table of open files 0000E8r 2 lda #$00 0000E8r 2 0000E8r 2 .endmacro 0000E8r 2 0000E8r 2 0000E8r 1 .include "../kernal/iec_data.inc" 0000E8r 2 ; after calling IecGetDataClockIn, gets 0000E8r 2 ; - DATA IN in Carry 0000E8r 2 .macro IEC_GET_DATA_INTO_CARRY 0000E8r 2 .if CompileComputer < C64_GENERAL 0000E8r 2 lsr a 0000E8r 2 .endif 0000E8r 2 .endmacro 0000E8r 2 0000E8r 2 .macro IEC_REG__DATA_IN_INTO_CARRY 0000E8r 2 .if CompileComputer >= C64_GENERAL 0000E8r 2 asl a 0000E8r 2 .else 0000E8r 2 lsr a 0000E8r 2 lsr a 0000E8r 2 .endif 0000E8r 2 .endmacro 0000E8r 2 0000E8r 2 .macro IEC_REG__CLOCK_IN_INTO_CARRY 0000E8r 2 .if CompileComputer >= C64_GENERAL 0000E8r 2 .error IEC_REG__CLOCK_IN_INTO_CARRY not defined for C64! 0000E8r 2 .else 0000E8r 2 lsr a 0000E8r 2 .endif 0000E8r 2 .endmacro 0000E8r 2 0000E8r 1 0000E8r 1 .if CompileComputer >= VIC20_06 0000E8r 1 0000E8r 1 ; FillUntil $E4A0,FILL_FFXX 0000E8r 1 0000E8r 1 .segment "KERNALPATCH" 000000r 1 000000r 1 LE4BC: 000000r 1 A6 rr ldx zSA 000002r 1 4C rr rr jmp OutputSearchingFor 000005r 1 000005r 1 LE4C1: 000005r 1 8A D0 08 A5 LOAD_OVERWRITE_START_ADDRESS 000009r 1 rr 85 rr A5 00000Dr 1 rr 85 rr 000010r 1 4C rr rr jmp OutputLoadingOrVerify ; output LOADING or VERIFYING messages 000013r 1 000013r 1 FileIoPatchCloseTape: 000013r 1 20 rr rr 90 FILEIO_PATCH_CLOSE_TAPE 000017r 1 03 68 A9 00 00001Br 1 00001Br 1 FileIoPatch_NoError: 00001Br 1 4C rr rr jmp FileIoPatchCloseTape_Return 00001Er 1 00001Er 1 .endif 00001Er 1 00001Er 1 ; FillUntil $E500,FILL_FFXX 00001Er 1 00001Er 1 .segment "KERNAL" 000000r 1 000000r 1 .include "../kernal/editor.a65" 000000r 2 ; B-12. Function Name: IOBASE 000000r 2 ; 000000r 2 ; Purpose: Define I/O memory page 000000r 2 ; Call address: $FFF3 (hex) 65523 (decimal) 000000r 2 ; Communication registers: X, Y 000000r 2 ; Preparatory routines: None 000000r 2 ; Error returns: 000000r 2 ; Stack requirements: 2 000000r 2 ; Registers affected: X, Y 000000r 2 ; 000000r 2 ; 000000r 2 ; Description: This routine sets the X and Y registers to the address of 000000r 2 ; the memory section where the memory mapped 110 devices are located. This 000000r 2 ; address can then be used with an offset to access the memory mapped I/O 000000r 2 ; devices in the Commodore 64. The offset is the number of locations from 000000r 2 ; the beginning of the page on which the I/O register you want is located. 000000r 2 ; The X register contains the low order address byte, while the Y register 000000r 2 ; contains the high order address byte. 000000r 2 ; This routine exists to provide compatibility between the Commodore 64, 000000r 2 ; VIC-20, and future models of the Commodore 64. If the J/0 locations for 000000r 2 ; a machine language program are set by a call to this routine, they should 000000r 2 ; still remain compatible with future versions of the Commodore 64, the 000000r 2 ; KERNAL and BASIC. 000000r 2 ; 000000r 2 ; 000000r 2 ; How to Use: 000000r 2 ; 000000r 2 ; 1) Call this routine by using the JSR instruction. 000000r 2 ; 2) Store the X and the Y registers in consecutive locations. 000000r 2 ; 3) Load the Y register with the offset. 000000r 2 ; 4) Access that I/O location. 000000r 2 ; 000000r 2 ; EXAMPLE: 000000r 2 ; 000000r 2 ; ;SET THE DATA DIRECTION REGISTER OF THE USER PORT TO 0 (INPUT) 000000r 2 ; JSR IOBASE 000000r 2 ; STX POINT ;SET BASE REGISTERS 000000r 2 ; STY POINT+1 000000r 2 ; LDY #2 000000r 2 ; LDA #0 ;OFFSET FOR DDR OF THE USER PORT 000000r 2 ; STA (POINT),Y ;SET DDR TO 0 000000r 2 ; 000000r 2 ; 000000r 2 iIOBASE: 000000r 2 ; return IO base address in x/y 000000r 2 ; On the VIC-20 and C64, this is interpreted as 000000r 2 ; the base address of the first VIA/CIA. 000000r 2 000000r 2 A2 10 ldx #IOBASE 000004r 2 60 rts 000005r 2 000005r 2 ; B-26. Function Name: SCREEN 000005r 2 ; 000005r 2 ; Purpose: Return screen format 000005r 2 ; Call address: $FFED (hex) 65517 (decimal) 000005r 2 ; Communication registers: X, Y 000005r 2 ; Preparatory routines: None 000005r 2 ; Stack requirements: 2 000005r 2 ; Registers affected: X, Y 000005r 2 ; 000005r 2 ; Description: This routine returns the format of the screen, e.g., 40 000005r 2 ; columns in X and 25 lines in Y. The routine can be used to determine what 000005r 2 ; machine a program is running on. This function has been implemented on 000005r 2 ; the Commodore 64 to help upward compatibility of your programs. 000005r 2 ; 000005r 2 ; 000005r 2 ; 000005r 2 ; 000005r 2 ; How to Use: 000005r 2 ; 000005r 2 ; 1) Call this routine. 000005r 2 ; 000005r 2 ; EXAMPLE: 000005r 2 ; 000005r 2 ; JSR SCREEN 000005r 2 ; STX MAXCOL 000005r 2 ; STY MAXROW 000005r 2 ; 000005r 2 ; 000005r 2 iSCREEN: 000005r 2 ; return screen resolution in x / y 000005r 2 000005r 2 A2 16 ldx #EDITOR_COLS 000007r 2 A0 17 ldy #EDITOR_ROWS 000009r 2 60 rts 00000Ar 2 00000Ar 2 ; B-19. Function Name: PLOT 00000Ar 2 ; 00000Ar 2 ; Purpose: Set cursor location 00000Ar 2 ; Call address: $FFF0 (hex) 65520 (decimal) 00000Ar 2 ; Communication registers: A, X, Y 00000Ar 2 ; Preparatory routines: None 00000Ar 2 ; Error returns: None 00000Ar 2 ; Stack requirements: 2 00000Ar 2 ; Registers affected: A, X, Y 00000Ar 2 ; 00000Ar 2 ; Description: A call to this routine with the accumulator carry flag 00000Ar 2 ; set loads the current position of the cursor on the screen (in X,Y 00000Ar 2 ; coordinates) into the Y and X registers. Y is the column number of the 00000Ar 2 ; cursor location (0-39), and X is the row number of the location of the 00000Ar 2 ; cursor (0-24). A call with the carry bit clear moves the cursor to X,Y 00000Ar 2 ; as determined by the Y and X registers. 00000Ar 2 ; 00000Ar 2 ; How to Use: 00000Ar 2 ; 00000Ar 2 ; 00000Ar 2 ; READING CURSOR LOCATION 00000Ar 2 ; 00000Ar 2 ; 1) Set the carry flag. 00000Ar 2 ; 2) Call this routine. 00000Ar 2 ; 3) Get the X and Y position from the Y and X registers, respectively. 00000Ar 2 ; 00000Ar 2 ; 00000Ar 2 ; SETTING CURSOR LOCATION 00000Ar 2 ; 00000Ar 2 ; 1) Clear carry flag. 00000Ar 2 ; 2) Set the Y and X registers to the desired cursor location. 00000Ar 2 ; 3) Call this routine. 00000Ar 2 ; 00000Ar 2 ; 00000Ar 2 ; EXAMPLE: 00000Ar 2 ; 00000Ar 2 ; ;MOVE THE CURSOR TO ROW 10, COLUMN 5 (5,10) 00000Ar 2 ; LDX #10 00000Ar 2 ; LDY #5 00000Ar 2 ; CLC 00000Ar 2 ; JSR PLOT 00000Ar 2 ; 00000Ar 2 ; 00000Ar 2 iPLOT: 00000Ar 2 B0 07 bcs iPLOTReadOnly ; carry set -> read values 00000Cr 2 00000Cr 2 JDLE50C: 00000Cr 2 86 rr stx zTBLX ; save new cursor pos: y position from X 00000Er 2 84 rr sty zPNTR ; save new cursor pos: x position from Y 000010r 2 000010r 2 20 rr rr jsr SET_CURSORPOS ; update all other internal states to the new position 000013r 2 000013r 2 iPLOTReadOnly: 000013r 2 A6 rr ldx zTBLX ; get cursor position in x and y 000015r 2 A4 rr ldy zPNTR 000017r 2 000017r 2 60 rts 000018r 2 000018r 2 ; B-7. Function Name: CINT 000018r 2 ; 000018r 2 ; Purpose: Initialize screen editor & 6567 video chip 000018r 2 ; Call address: $FF81 (hex) 65409 (decimal) 000018r 2 ; Communication registers: None 000018r 2 ; Preparatory routines: None 000018r 2 ; Error returns: None 000018r 2 ; Stack requirements: 4 000018r 2 ; Registers affected: A, X, Y 000018r 2 ; 000018r 2 ; 000018r 2 ; Description: This routine sets up the 6567 video controller chip in the 000018r 2 ; Commodore 64 for normal operation. The KERNAL screen editor is also 000018r 2 ; initialized. This routine should be called by a Commodore 64 program 000018r 2 ; cartridge. 000018r 2 ; 000018r 2 ; How to Use: 000018r 2 ; 000018r 2 ; 1) Call this routine. 000018r 2 ; 000018r 2 ; EXAMPLE: 000018r 2 ; 000018r 2 ; JSR CINT 000018r 2 ; JMP RUN ;BEGIN EXECUTION 000018r 2 ; 000018r 2 ; 000018r 2 20 rr rr iCINT: jsr CLRCHN_AND_VIC_DEFAULTS 00001Br 2 00001Br 2 .if CompileComputer < C64_GENERAL 00001Br 2 00001Br 2 ; adjust the VIC-I to take the screen memory from the memory 00001Br 2 ; area that is configured in lHIBASE. 00001Br 2 00001Br 2 ; on the VIC-I, 00001Br 2 ; bits 13-10 of the video RAM address is stored in VICI_O_MemoryLocations.7-VICI_O_MemoryLocations.4, 00001Br 2 ; and bit 9 of the video RAM address is stored in VIC_02.7. 00001Br 2 00001Br 2 ; Now, bit 13 of the VIC-I is connected to the INVERSE of A15 of the 6502. 00001Br 2 ; Thus, the VIC-I sees another memory map than the 6502: 00001Br 2 ; 00001Br 2 ; VIC-I <-> 6502 00001Br 2 ; $0000-$1FFF <-> $8000-$9FFF 00001Br 2 ; $2000-$3FFF <-> $0000-$1FFF (*) 00001Br 2 ; 00001Br 2 ; (*) Note that the VIC-I cannot see $0400-$0FFF of the 6502 memory map 00001Br 2 ; ($2400-$2FFF in the VIC-I memory map) due to the way the memory 00001Br 2 ; is connected on the external RAM cartridge 00001Br 2 00001Br 2 00001Br 2 AD rr rr lda lHIBASE ; get high byte of video RAM address 00001Er 2 29 FD and #~$02 ; mask out bit 9 (bit 8-0 of the base address 000020r 2 ; must be 0, anyway) 000020r 2 000020r 2 0A asl a ; shift the address to the right position 000021r 2 0A asl a 000022r 2 000022r 2 ; here, A.7 - A.4 contain the address of the video RAM start, as needed in VICI_O_MemoryLocations 000022r 2 000022r 2 09 80 ora #$80 ; b13 of the VIC-I is connected to the INVERSE of A15 000024r 2 ; of the 6502 (cf. comment above). 000024r 2 ; Take this into account and make the VIC-I see 000024r 2 ; the 6502 memory area $0000-$1FFF. 000024r 2 000024r 2 8D 05 90 sta VIC + VICI_O_MemoryLocations ; store b 000027r 2 000027r 2 AD rr rr lda lHIBASE ; get back the high byte of the video RAM address 00002Ar 2 29 02 and #$02 ; is bit 9 set? 00002Cr 2 F0 08 beq @NoSetBit9 ; no, branch -> do not set VICI_O_VideoColumns.7 00002Er 2 ; (it has been already reset in CLRCHN_AND_VIC_DEFAULTS) 00002Er 2 00002Er 2 A9 80 lda #VICI_B_VideoColumns_ScreenMemoryB9 ; set bit 9 of video RAM address 000030r 2 0D 02 90 ora VIC + VICI_O_VideoColumns ; in VICI_O_02.7 000033r 2 8D 02 90 sta VIC + VICI_O_VideoColumns 000036r 2 000036r 2 @NoSetBit9: 000036r 2 000036r 2 .endif 000036r 2 000036r 2 A9 00 lda #$00 ; set editor mode 000038r 2 8D rr rr sta lMODE 00003Br 2 00003Br 2 85 rr sta zBLNON ; blink mode: Currently, the cursor is not on 00003Dr 2 00003Dr 2 A9 rr lda #CHECK_SHIFT_CTRL_CBM 000044r 2 8D rr rr sta lKEYLOG + 1 000047r 2 000047r 2 A9 0A lda #10 000049r 2 8D rr rr sta lXMAX ; maximum number of characters in the keyboard buffer is 10 00004Cr 2 8D rr rr sta lDELAY ; set delay for delay of the start of key repetition to default (10) 00004Fr 2 00004Fr 2 A9 06 lda #DEFAULT_COLOR ; set default color 000051r 2 8D rr rr sta lCOLOR 000054r 2 000054r 2 A9 04 lda #$04 ; set delay counter for key repetitions 000056r 2 8D rr rr sta lKOUNT 000059r 2 000059r 2 A9 0C lda #$0C 00005Br 2 85 rr sta zBLNCT ; set the blink counter 00005Dr 2 85 rr sta zBLNSW ; disable cursor 00005Fr 2 00005Fr 2 ; update the table of low bytes and link bits for the screen row 00005Fr 2 00005Fr 2 ClearScreen: 00005Fr 2 AD rr rr lda lHIBASE ; get the high byte of the start of the video RAM 000062r 2 09 80 ora #$80 ; set link bit -> this row is not connected to the previous one 000064r 2 A8 tay 000065r 2 A9 00 lda #$00 ; low byte of the start of the video RAM (A) := 0 000067r 2 AA tax ; row counter (X) := 0, start in row zero 000068r 2 000068r 2 94 rr @Next: sty zLDTB1,x ; store the high byte and the link bit of this line 00006Ar 2 00006Ar 2 ; proceed to next row by adding the number of columns in one row (EDITOR_COLS) 00006Ar 2 00006Ar 2 18 clc 00006Br 2 69 16 adc #EDITOR_COLS ; add the number of columns in a line to the low byte 00006Dr 2 90 01 bcc @NoHighByte ; no carry -> we do not need to increment the high byte 00006Fr 2 C8 iny ; increment the high byte 000070r 2 000070r 2 @NoHighByte: 000070r 2 E8 inx ; increment row counter 000071r 2 E0 18 cpx #EDITOR_ROWS + 1 ; did we reach the last row? 000073r 2 D0 F3 bne @Next ; not yet, store the next high byte and link bit 000075r 2 000075r 2 A9 FF lda #$FF ; write the "end marker" 000077r 2 95 rr sta zLDTB1,x ; into the location for the row past the last one 000079r 2 000079r 2 ; Erase the screen rows (overwrite with spaces) 000079r 2 000079r 2 A2 16 ldx #EDITOR_ROWS - 1 ; start in the last row 00007Br 2 @NextLine: 00007Br 2 20 rr rr jsr EraseScreenRow ; erase the row 00007Er 2 CA dex ; go to previous line 00007Fr 2 10 FA bpl @NextLine ; not all rows are processed, branch -> process previous one 000081r 2 000081r 2 CURSOR_HOME: 000081r 2 ; set cursor position to 0/0 000081r 2 000081r 2 A0 00 ldy #0 000083r 2 84 rr sty zPNTR ; column 000085r 2 84 rr sty zTBLX ; row 000087r 2 000087r 2 SET_CURSORPOS: 000087r 2 000087r 2 ; this routine updates the internal pointer to conform to the cursor 000087r 2 ; position set in zPNTR/zTBLX. As this function is used from other 000087r 2 ; places, for example from iPLOT, it is completely implemented, and it 000087r 2 ; does not use any hard-coded constants for CURSOR_HOME only. 000087r 2 000087r 2 A6 rr ldx zTBLX ; get row into X 000089r 2 A5 rr lda zPNTR ; get column into A 00008Br 2 00008Br 2 @AddLine: 00008Br 2 B4 rr ldy zLDTB1,x ; is this row combined with the previous one? 00008Dr 2 30 08 bmi @StandaloneLine ; no, branch 00008Fr 2 00008Fr 2 ; otherwise, add the number of columns to the col position 00008Fr 2 18 clc 000090r 2 69 16 adc #EDITOR_COLS 000092r 2 85 rr sta zPNTR ; store (updated) column position 000094r 2 CA dex ; ... and the row is one less 000095r 2 10 F4 bpl @AddLine ; unconditional jump (row 0 should never be combined with the previous row!) 000097r 2 ; -------------- 000097r 2 000097r 2 @StandaloneLine: 000097r 2 000097r 2 .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 000097r 2 jsr CalculateScreenPointerFromRowNumber ; This is essentially the same as the VIC20 (and C64-02 and earlier) implementation. Only the order in which high and low byte are calculated is changed. 000097r 2 ; This subroutine is used to gain memory for the later patch 000097r 2 .else 000097r 2 B5 rr lda zLDTB1,x ; get high byte of the starting address of this row 000099r 2 29 03 and #>lVIDEORAM_SIZE ; mask out additional bits used as flags 00009Br 2 0D rr rr ora lHIBASE ; add the video RAM base 00009Er 2 85 rr sta zPNT + 1 ; remember high byte 0000A0r 2 0000A0r 2 BD rr rr lda SCREEN_LOWBYTE,x ; get low byte of the starting address of this row 0000A3r 2 85 rr sta zPNT ; remember low byte 0000A5r 2 0000A5r 2 .endif 0000A5r 2 0000A5r 2 ; calculate the number of columns (more precisely: The last column number) 0000A5r 2 ; in this logical line 0000A5r 2 0000A5r 2 A9 15 lda #EDITOR_COLS - 1 ; start with one physical line 0000A7r 2 0000A7r 2 E8 inx ; Here, X points to the first line *before* the extended long line. Thus, go back into the long line area 0000A8r 2 0000A8r 2 B4 rr @Loop: ldy zLDTB1,x ; is this line combined with the previous one? 0000AAr 2 30 06 bmi @StoreLineLength ; no, branch -> quit loop 0000ACr 2 0000ACr 2 18 clc ; add a complete line length 0000ADr 2 69 16 adc #EDITOR_COLS 0000AFr 2 0000AFr 2 E8 inx ; proceed to the next line 0000B0r 2 10 F6 bpl @Loop ; (unconditional branch) 0000B2r 2 ; ----------------------------- 0000B2r 2 0000B2r 2 @StoreLineLength: 0000B2r 2 85 rr sta zLNMX ; store line length 0000B4r 2 0000B4r 2 .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 0000B4r 2 ; this fixes a bug in the C64 ROMs: 0000B4r 2 ; If the last row is combined to build a long line (80 chars), 0000B4r 2 ; and the last character is deleted afterwards with backspace, 0000B4r 2 ; the C64 will start a LOAD command and will not react 0000B4r 2 ; anymore unless there is an attached tape recorder. 0000B4r 2 0000B4r 2 ; This patch fixes this: 0000B4r 2 0000B4r 2 jmp UpdateColorRAMPointerToVideoramPointer ; also update the color RAM pointer (zUSER) 0000B4r 2 0000B4r 2 ; this is another patch on the C64-03 ROMs: 0000B4r 2 ; TODO: why? 0000B4r 2 ; 0000B4r 2 ; It is called after LDX zTBLX (get current cursor row) 0000B4r 2 0000B4r 2 Patch_CursorOneRowUp: 0000B4r 2 cpx zLXSP ; did the cursor row change while we were in the routine? 0000B4r 2 beq @Ret ; no -> branch, we're done 0000B4r 2 jmp CursorOneRowUp 0000B4r 2 @Ret: rts 0000B4r 2 0000B4r 2 nop 0000B4r 2 0000B4r 2 .else 0000B4r 2 60 rts 0000B5r 2 .endif 0000B5r 2 0000B5r 2 0000B5r 2 ; unused in VIC20 and C64 ROM! 0000B5r 2 0000B5r 2 20 rr rr jsr CLRCHN_AND_VIC_DEFAULTS 0000B8r 2 4C rr rr jmp CURSOR_HOME 0000BBr 2 0000BBr 2 0000BBr 2 CLRCHN_AND_VIC_DEFAULTS: 0000BBr 2 ; This routine restores input and output to the terminal 0000BBr 2 ; (screen and keyboard). 0000BBr 2 ; Afterwards, it initialises the VIC (or VIC-II) registers 0000BBr 2 0000BBr 2 A9 03 lda #FILE_SCREEN ; default output to screen 0000BDr 2 85 rr sta zDFLTO 0000BFr 2 A9 00 lda #FILE_KEYBOARD ; default input to keyboard 0000C1r 2 85 rr sta zDFLTN 0000C3r 2 0000C3r 2 SET_VIC_DEFAULTS: 0000C3r 2 0000C3r 2 ; This routine initialises the VIC (or VIC-II) registers 0000C3r 2 0000C3r 2 ; Loop throught the table and overwrite the VIC (-II) registers 0000C3r 2 ; with the table contents 0000C3r 2 0000C3r 2 A2 10 ldx #END_VIC_DEFAULTS - VIC_DEFAULTS + 1 ; number of register values in the table 0000C5r 2 BD rr rr @Loop: lda VIC_DEFAULTS - 1,x 0000C8r 2 9D FF 8F sta VIC - 1,x 0000CBr 2 CA dex 0000CCr 2 D0 F7 bne @Loop 0000CEr 2 60 rts 0000CFr 2 0000CFr 2 GETIN_KEYB: 0000CFr 2 0000CFr 2 ; Get a character from the keyboard buffer 0000CFr 2 ; this function returns a character from the keyboard buffer 0000CFr 2 ; It also deletes it from there. 0000CFr 2 ; 0000CFr 2 ; Prerequisites: 0000CFr 2 ; 0000CFr 2 ; - Before calling this function, the I flag must be set (SEI) 0000CFr 2 ; It will be cleared on exit 0000CFr 2 ; 0000CFr 2 ; - Make sure the keyboard buffer is not empty before calling this function! 0000CFr 2 0000CFr 2 AC rr rr ldy lKEYD ; remember first key press in the keyboard buffer 0000D2r 2 0000D2r 2 ; move all key presses in the keyboard buffer one step to the front 0000D2r 2 0000D2r 2 A2 00 ldx #0 0000D4r 2 BD rr rr @Loop: lda lKEYD + 1,x ; move entry one step ahead 0000D7r 2 9D rr rr sta lKEYD,x 0000DAr 2 E8 inx ; proceed to next one 0000DBr 2 E4 rr cpx zNDX ; did we already process all keys? 0000DDr 2 D0 F5 bne @Loop ; no, branch -> process the next key 0000DFr 2 0000DFr 2 C6 rr dec zNDX ; we just removed and key, thus, decrement the number of keys in the buffer 0000E1r 2 0000E1r 2 98 tya ; get back the first key press in the keyboard buffer 0000E2r 2 0000E2r 2 58 cli 0000E3r 2 18 clc ; quit with success 0000E4r 2 60 rts 0000E5r 2 0000E5r 2 OutputCharacterAndWaitForKeyPress: 0000E5r 2 20 rr rr jsr CHROUT_SCREEN 0000E8r 2 0000E8r 2 WaitForKeyPress: 0000E8r 2 A5 rr lda zNDX ; number of key presses in keyboard buffer 0000EAr 2 85 rr sta zBLNSW ; if > 0: disable cursor blinking, otherwise: Enable cursor blinking 0000ECr 2 8D rr rr sta lAUTODN ; If there was some key press, mark that any output that will combine two rows will scroll down the screen contents 0000EFr 2 ; (this loop cannot be quit with lAUTODN = 0) 0000EFr 2 F0 F7 beq WaitForKeyPress ; no key presses -> wait until some key has been pressed 0000F1r 2 0000F1r 2 ; now that one or more key has been pressed, output it/them 0000F1r 2 0000F1r 2 ; first, restore the character under the cursor (if the cursor has been visible) 0000F1r 2 0000F1r 2 78 sei 0000F2r 2 A5 rr lda zBLNON ; cursor currently visible? 0000F4r 2 F0 0C beq @CursorNotVisible ; no, skip restoring it 0000F6r 2 0000F6r 2 ; restore character under the cursor 0000F6r 2 0000F6r 2 A5 rr lda zGDBLN ; get character code 0000F8r 2 AE rr rr ldx lGDCOL ; and color of character under cursor 0000FBr 2 0000FBr 2 A0 00 ldy #0 0000FDr 2 84 rr sty zBLNON ; mark: Cursor is currently invisible 0000FFr 2 0000FFr 2 20 rr rr jsr StoreCharacterOnScreenAndDisableBlinking ; store the character under the cursor on the screen 000102r 2 000102r 2 @CursorNotVisible: 000102r 2 000102r 2 .ifdef JIFFY 000102r 2 jsr JDLF9E5 000102r 2 .else 000102r 2 20 rr rr jsr GETIN_KEYB ; get the next character 000105r 2 .endif 000105r 2 C9 83 cmp #KEY_SHIFTRUN ; was is Shift + Run/Stop? 000107r 2 D0 10 bne NoShiftRunStop ; no, branch -> jump special processing 000109r 2 000109r 2 ; If we reach here, the user pressed Shift + Run/Stop 000109r 2 ; Then, store the special text into the keyboard buffer and 000109r 2 ; process the characters, one after the other. 000109r 2 ; 000109r 2 ; Note that any other key presses that might have been 000109r 2 ; in the keyboard buffer are removed. 000109r 2 000109r 2 A2 09 ldx #END_TEXT_SHIFTRUNSTOP - TEXT_SHIFTRUNSTOP 00010Br 2 78 sei 00010Cr 2 86 rr stx zNDX ; set the count of characters 00010Er 2 00010Er 2 @ShiftRunStop: 00010Er 2 BD rr rr lda TEXT_SHIFTRUNSTOP - 1,x ; copy text 000111r 2 9D rr rr sta lKEYD - 1,x ; into the keyboard buffer 000114r 2 CA dex 000115r 2 D0 F7 bne @ShiftRunStop ; until all characters have been processed 000117r 2 F0 CF beq WaitForKeyPress ; now, process the key presses (uncond. branch) 000119r 2 ; ------------------------------- 000119r 2 000119r 2 NoShiftRunStop: 000119r 2 C9 0D cmp #ASC_CR ; was the key a CR? 00011Br 2 D0 C8 bne OutputCharacterAndWaitForKeyPress ; no, output the character and wait for the next key press 00011Dr 2 00011Dr 2 ; When we reach here, the user has entered anything and pressed CR. 00011Dr 2 ; Now, we process the input 00011Dr 2 00011Dr 2 A4 rr ldy zLNMX ; get the (logical) line length of the current line 00011Fr 2 84 rr sty zCRSW ; store it as number of characters to read 000121r 2 000121r 2 @CheckSpaceNext: 000121r 2 B1 rr lda (zPNT),y ; read the next character at the end of the line 000123r 2 C9 20 cmp #' ' ; is it a space? 000125r 2 D0 03 bne @NoSpace ; No -> branch, 000127r 2 88 dey ; Yes, it was a space: Test the previous character 000128r 2 D0 F7 bne @CheckSpaceNext ; until we have checked all characters in this line, branch 00012Ar 2 00012Ar 2 @NoSpace: 00012Ar 2 C8 iny 00012Br 2 84 rr sty zINDX ; remember the number of characters in the current line 00012Dr 2 A0 00 ldy #0 00012Fr 2 8C rr rr sty lAUTODN ; Mark: No key press yet, thus, any output will scroll down the screen contents if some rows will be combined 000132r 2 84 rr sty zPNTR ; start reading at the beginning of the line 000134r 2 84 rr sty zQTSW ; We are not in quotation mark mode 000136r 2 A5 rr lda zLXSP ; value of zTBLX before calling BASIN (zTBLX is not changed when calling GETIN 000138r 2 30 1D bmi BASIN_KEYB_PROCESS_KEY ; TODO what? 00013Ar 2 00013Ar 2 A6 rr ldx zTBLX ; current cursor row on screen 00013Cr 2 00013Cr 2 ; set the cursor one (virtual) row up 00013Cr 2 00013Cr 2 .if CompileComputer >= C64_03 .or .defined(C64JAPAN) 00013Cr 2 ; for -03 ROMs, it was decided that this the cursor row is only moved up 00013Cr 2 ; if it has already changed since this function began 00013Cr 2 ; TODO why? 00013Cr 2 ; 00013Cr 2 jsr Patch_CursorOneRowUp 00013Cr 2 .else 00013Cr 2 20 rr rr jsr CursorOneRowUp 00013Fr 2 .endif 00013Fr 2 00013Fr 2 ; here: with X := current row (modified in CursorOneRowUp / Patch_CursorOneRowUp) 00013Fr 2 00013Fr 2 E4 rr cpx zLXSP ; has the cursor row on screen changed? 000141r 2 D0 14 bne BASIN_KEYB_PROCESS_KEY ; yes -> branch, get keyboard input 000143r 2 000143r 2 .if CompileComputer < C64_GENERAL 000143r 2 D0 12 bne BASIN_KEYB_PROCESS_KEY ; some superfluous leftover 000145r 2 .endif 000145r 2 000145r 2 A5 rr lda zTEMP_zPNTR ; restore current cursor column (zPNTR) from zTEMP_zPNTR 000147r 2 85 rr sta zPNTR 000149r 2 C5 rr cmp zINDX ; did the column change while we were in the routine? 00014Br 2 90 0A bcc BASIN_KEYB_PROCESS_KEY ; we are now to the left of the column at the beginning -> branch, get new key input 00014Dr 2 B0 42 bcs BASIN_KEYB_END_LINE ; we are at the same column or right from it -> branch, done 00014Fr 2 ; ------------------------- 00014Fr 2 00014Fr 2 BASIN_KEYB: 00014Fr 2 00014Fr 2 ; remember Y and X on the stack 00014Fr 2 00014Fr 2 98 tya 000150r 2 48 pha 000151r 2 8A txa 000152r 2 48 pha 000153r 2 000153r 2 A5 rr lda zCRSW ; has CR been pressed already? 000155r 2 ; that is, are there already keys to 000155r 2 ; process on the screen? 000155r 2 F0 91 beq WaitForKeyPress ; No, wait for input of a complete line 000157r 2 000157r 2 BASIN_KEYB_PROCESS_KEY: 000157r 2 A4 rr ldy zPNTR ; get pointer into current line 000159r 2 B1 rr lda (zPNT),y ; get current character at that position 00015Br 2 00015Br 2 .if CompileComputer >= C64_GENERAL 00015Br 2 .elseif CompileComputer >= VIC20_06 00015Br 2 00015Br 2 ; FillUntil $E672,$EA 00015Br 2 EA EA EA EA FillNOP 23 00015Fr 2 EA EA EA EA 000163r 2 EA EA EA EA 000172r 2 000172r 2 .else 000172r 2 000172r 2 ; It seems the VIC20_0ß2 ROM has some kind of "cooked" screen codes. 000172r 2 ; This routine converts some characters into others, bypassing the 000172r 2 ; screen code to PETSCII conversion later 000172r 2 000172r 2 ldx lMODE ; if lMODE == 0 then we do not use the "cooked" mode 000172r 2 beq @End ; Thus, in this case, skip the conversion 000172r 2 000172r 2 ldx #SpecialScreenCodeHandleTable_END - SpecialScreenCodeHandleTable - 2 000172r 2 @FindChar: 000172r 2 cmp SpecialScreenCodeHandleTable,x ; is the current character a special one? 000172r 2 beq @FoundCharacter ; yes, branch -> convert it 000172r 2 dex ; no, proceed to previous special character 000172r 2 dex 000172r 2 bpl @FindChar ; test the next char 000172r 2 bmi @End ; table has completed -> branch, quit 000172r 2 ; --------------- 000172r 2 000172r 2 @FoundCharacter: 000172r 2 lda SpecialScreenCodeHandleTable + 1,x ; convert the screen code to the replacement 000172r 2 bne @ProceedToNextScreenLocation ; (uncond. branch) 000172r 2 ; -------------------------------------- 000172r 2 000172r 2 @End: 000172r 2 000172r 2 .endif 000172r 2 000172r 2 ; convert the character (in A) into PETSCII TODO 000172r 2 ; 000172r 2 ; Here, we convert the codes as follows: 000172r 2 ; 000172r 2 ; SCREEN CODE -> PETSCII 000172r 2 ; $00-$1F -> $40-$5F 000172r 2 ; $20-$3F -> $20-$3F 000172r 2 ; $40-$5F -> $60-$7F 000172r 2 ; TODO ??? 000172r 2 ; 000172r 2 000172r 2 85 rr sta zSCHAR ; store the character 000174r 2 000174r 2 29 3F and #$3F ; mask out the upper 2 bits (7, 6) 000176r 2 06 rr asl zSCHAR ; put bit 7 into C 000178r 2 24 rr bit zSCHAR ; test the remaining part 00017Ar 2 00017Ar 2 ; now, we have the following status of the flags: 00017Ar 2 ; C = bit 7 of A on input 00017Ar 2 ; N = bit 6 of A on input 00017Ar 2 ; V = bit 5 of A on input 00017Ar 2 00017Ar 2 10 02 bpl @DoNotSetBit7 ; N=0 -> bit 6 was 0, that is, we have $00-$3F or $80-$BF 00017Cr 2 00017Cr 2 09 80 ora #$80 ; otherwise, set bit 7 00017Er 2 00017Er 2 @DoNotSetBit7: 00017Er 2 90 04 bcc @Process0x00_To_0x7F ; was bit 7 == 0? --> branch 000180r 2 000180r 2 A6 rr ldx zQTSW ; Check quotation mark mode 000182r 2 D0 04 bne @ProceedToNextScreenLocation ; branch if we are in quotation mark mode 000184r 2 000184r 2 @Process0x00_To_0x7F: 000184r 2 70 02 bvs @ProceedToNextScreenLocation ; was bit 5 == 1? --> branch 000186r 2 09 40 ora #$40 ; otherwise, set bit 6 000188r 2 000188r 2 ; here, we converted: (TODO: check again!) 000188r 2 ; $00-$1F -> $40-$5F 000188r 2 ; $20-$3F -> $20-$3F 000188r 2 ; $40-$5F -> $80-$9F 000188r 2 ; $60-$7F -> $C0-$DF 000188r 2 000188r 2 @ProceedToNextScreenLocation: 000188r 2 E6 rr inc zPNTR ; proceed to next screen location 00018Ar 2 00018Ar 2 20 rr rr jsr CheckQuote ; update the quotation mark mode flag 00018Dr 2 00018Dr 2 C4 rr cpy zINDX ; have we reached the end of the line? 00018Fr 2 D0 17 bne BASIN_KEYB_QUIT ; no, return the current character 000191r 2 000191r 2 ; if we reach here, then we have read the complete line 000191r 2 ; Thus, clear all states and return the CR as marker for end-of-line 000191r 2 000191r 2 BASIN_KEYB_END_LINE: 000191r 2 A9 00 lda #0 000193r 2 85 rr sta zCRSW ; remember: We do not have any characters anymore 000195r 2 A9 0D lda #ASC_CR ; return a CR Value 000197r 2 000197r 2 A6 rr ldx zDFLTN 000199r 2 E0 03 cpx #FILE_SCREEN ; default input file = screen? 00019Br 2 F0 06 beq @OutputCharacter ; yes, output the CR 00019Dr 2 00019Dr 2 A6 rr ldx zDFLTO 00019Fr 2 E0 03 cpx #FILE_SCREEN ; default output file = screen? 0001A1r 2 F0 03 beq @QuitWithCR ; yes, quit 0001A3r 2 0001A3r 2 ; if we reach here, the input was from the keyboard, and the output was not the screen. 0001A3r 2 ; Thus, output the CR we got from the keyboard 0001A3r 2 0001A3r 2 @OutputCharacter: 0001A3r 2 20 rr rr jsr CHROUT_SCREEN ; output the character on the screen 0001A6r 2 0001A6r 2 @QuitWithCR: 0001A6r 2 A9 0D lda #ASC_CR ; return a CR value 0001A8r 2 0001A8r 2 BASIN_KEYB_QUIT: 0001A8r 2 85 rr sta zSCHAR ; remember read char 0001AAr 2 0001AAr 2 ; restore X and Y from stack 0001AAr 2 68 pla 0001ABr 2 AA tax 0001ACr 2 68 pla 0001ADr 2 A8 tay 0001AEr 2 0001AEr 2 A5 rr lda zSCHAR ; get back remembered read char 0001B0r 2 C9 DE cmp #ASC_PI ; is it the PETSCII code for PI? 0001B2r 2 D0 02 bne @ClcRts ; no, branch -> we are done 0001B4r 2 A9 FF lda #TokPi ; yes, replace it by the BASIC token for PI (TODO why did CBM choose this route?) 0001B6r 2 @ClcRts: 0001B6r 2 18 clc ; we successfully ended the routine 0001B7r 2 60 rts 0001B8r 2 ; -------------- 0001B8r 2 0001B8r 2 CheckQuote: 0001B8r 2 C9 22 cmp #'"' ; Is the current char a quotation mark? 0001BAr 2 D0 08 bne @Rts ; no, quit 0001BCr 2 0001BCr 2 ; invert the state of the quotation mark 0001BCr 2 A5 rr lda zQTSW 0001BEr 2 49 01 eor #$01 0001C0r 2 85 rr sta zQTSW 0001C2r 2 0001C2r 2 A9 22 lda #'"' ; restore the character 0001C4r 2 60 @Rts: rts 0001C5r 2 0001C5r 2 0001C5r 2 ; @@@@@ 0001C5r 2 0001C5r 2 09 40 LE691: ora #$40 0001C7r 2 0001C7r 2 CHROUT_SCREEN_OUTPUT_WITH_TEST_RVS: 0001C7r 2 A6 rr ldx zRVS ; Is the flag "output in reverse" set? 0001C9r 2 F0 02 beq CHROUT_OUTPUT_SCREEN_IN_NORMAL ; no -> branch, output in normal 0001CBr 2 0001CBr 2 CHROUT_SCREEN_OUTPUT_IN_RVS: 0001CBr 2 09 80 ora #$80 ; setting bit 7 of the char to output: reverse the char 0001CDr 2 0001CDr 2 CHROUT_OUTPUT_SCREEN_IN_NORMAL: 0001CDr 2 A6 rr ldx zINSRT ; Number of characters to output in "insert mode" 0001CFr 2 F0 02 beq @NoInsertMode ; none -> we are not in insert mode -> branch 0001D1r 2 C6 rr dec zINSRT ; decrement number of characters to output in revers mode 0001D3r 2 0001D3r 2 @NoInsertMode: 0001D3r 2 AE rr rr ldx lCOLOR ; get the current color 0001D6r 2 20 rr rr jsr StoreCharacterOnScreenAndDisableBlinking ; output character in A, color in X 0001D9r 2 20 rr rr jsr MoveCursorRightAfterOutput ; move the cursor to the next output position 0001DCr 2 0001DCr 2 CHROUT_SCREEN_END: 0001DCr 2 68 pla ; restore Y from stack 0001DDr 2 A8 tay 0001DEr 2 0001DEr 2 A5 rr lda zINSRT ; insert mode? 0001E0r 2 F0 02 beq @DontStopQuotationMode ; no, branch 0001E2r 2 46 rr lsr zQTSW ; end quotation mark mode 0001E4r 2 @DontStopQuotationMode: 0001E4r 2 68 pla ; restore X from stack 0001E5r 2 AA tax 0001E6r 2 0001E6r 2 68 pla ; restore A from stack 0001E7r 2 18 clc ; we ended successfully 0001E8r 2 58 cli 0001E9r 2 60 rts 0001EAr 2 ; -------------- 0001EAr 2 0001EAr 2 MoveCursorRightAfterOutput: 0001EAr 2 20 rr rr jsr AdjustCursorRowBeforeMovingRight ; if we will move to the next row, increment row number 0001EDr 2 E6 rr inc zPNTR ; increment column into current row -> move cursor to the right 0001EFr 2 A5 rr lda zLNMX ; get number of column in current row 0001F1r 2 C5 rr cmp zPNTR ; did we go past the last column? 0001F3r 2 B0 37 bcs EditorRts ; no -> branch, we do not need to adjust column 0001F5r 2 C9 57 cmp #(EDITOR_MAX_COMBINED_ROWS * EDITOR_COLS) - 1 ; did we reach the maximum length of a virtual row? 0001F7r 2 F0 2A beq SetCursorToTheBeginningOfTheNextLine ; yes -> branch, set cursor to the beginning of the next line 0001F9r 2 0001F9r 2 AD rr rr lda lAUTODN ; do we have to scroll down the screen contents? 0001FCr 2 F0 03 beq @CombineRows ; no, skip the scrolling 0001FEr 2 4C rr rr jmp LE967 ; (will return to LogicallyCombineTwoRows) 000201r 2 ; ------------------ 000201r 2 000201r 2 @CombineRows: 000201r 2 A6 rr ldx zTBLX 000203r 2 E0 17 cpx #EDITOR_ROWS 000205r 2 90 07 bcc LogicallyCombineTwoRows 000207r 2 20 rr rr jsr LE8EA 00020Ar 2 C6 rr dec zTBLX 00020Cr 2 A6 rr ldx zTBLX 00020Er 2 00020Er 2 LogicallyCombineTwoRows: 00020Er 2 16 rr asl zLDTB1,x ; clear bit 7 -> combine this phyiscal row with the previous one 000210r 2 56 rr lsr zLDTB1,x 000212r 2 000212r 2 .macro EDITOR_PATCH_LogicallyCombineTwoRows_FIX 000212r 2 000212r 2 ; only present on VIC20-06 ROMs and above, and C64 ROMs. 000212r 2 000212r 2 ; mark the next row as being stand-alone 000212r 2 000212r 2 ; TODO what exactly does this patch fix? 000212r 2 000212r 2 inx ; go to the next row 000212r 2 lda zLDTB1,x 000212r 2 ora #$80 ; set bit 7 --> this row is not combined with the previous one 000212r 2 sta zLDTB1,x 000212r 2 dex ; go back to the previous row 000212r 2 .endmacro 000212r 2 000212r 2 .macro EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 000212r 2 ; from here on, this is done for all variants, including the VIC20-2 000212r 2 000212r 2 lda zLNMX ; maximum number of columns on the current (virtual) row 000212r 2 clc 000212r 2 .endmacro 000212r 2 000212r 2 ; depending on the firmware built, 000212r 2 .if CompileComputer >= C64_GENERAL 000212r 2 EDITOR_PATCH_LogicallyCombineTwoRows_FIX 000212r 2 EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 000212r 2 .elseif CompileComputer >= VIC20_06 000212r 2 ; on the VIC20-06 and -07, this patch is really a patch. 000212r 2 ; We come back with a JMP 000212r 2 4C rr rr jmp EditorPatchLogicallyCombineTwoRows 000215r 2 EditorPatchLogicallyCombineTwoRows_Return: 000215r 2 000215r 2 .else 000215r 2 ; old implementation for VIC20-02 000215r 2 EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 000215r 2 .endif 000215r 2 000215r 2 69 16 adc #EDITOR_COLS ; add the number of column of one (physical) row 000217r 2 85 rr sta zLNMX ; and set it as the new maximum number of columns on the current (virtual) row 000219r 2 000219r 2 CursorOneRowUp: 000219r 2 ; input: X := Cursor row 000219r 2 ; 000219r 2 ; set the cursor row to point to the (virtual) row above us. 000219r 2 000219r 2 B5 rr lda zLDTB1,x ; is the current row combined with the previous one? 00021Br 2 30 03 bmi @NotCombined ; no, we're done 00021Dr 2 CA dex ; cursor on (physical) row up 00021Er 2 D0 F9 bne CursorOneRowUp ; not 0 -> not at top of screen -> branch, test the next (physical) row 000220r 2 000220r 2 @NotCombined: 000220r 2 4C rr rr jmp CalculateScreenPointerFromRowNumber ; adjust screen pointer 000223r 2 ; ----------------------------------------- 000223r 2 000223r 2 SetCursorToTheBeginningOfTheNextLine: 000223r 2 C6 rr dec zTBLX ; go up one row (will be undone in the next routine) 000225r 2 20 rr rr jsr GoDownOneVirtualRow ; go down one (virtual) row 000228r 2 A9 00 lda #0 00022Ar 2 85 rr sta zPNTR ; set column to the beginning of the row 00022Cr 2 EditorRts: 00022Cr 2 60 rts 00022Dr 2 ; ----------------------------------------- 00022Dr 2 00022Dr 2 00022Dr 2 ; Perform the wrap-around to the previous row of 00022Dr 2 ; INS/DEL or CRSR LEFT is pressed on the leftmost column. 00022Dr 2 ; 00022Dr 2 ; If the cursor is not at the home position, it 00022Dr 2 ; puts the cursor one row to the top, and on the last 00022Dr 2 ; column if that row. 00022Dr 2 ; 00022Dr 2 ; NOTE: 00022Dr 2 ; If the cursor is already at the home position, 00022Dr 2 ; this function removes the return address from the stack! 00022Dr 2 ; Instead, it jumps to CHROUT_SCREEN_END. 00022Dr 2 ; 00022Dr 2 CHROUT_SCREEN_WrapAroundToPreviousRow: 00022Dr 2 A6 rr ldx zTBLX ; get row of current cursor position 00022Fr 2 D0 06 bne @CanGoBack ; not zero -> branch 000231r 2 000231r 2 ; if we reach here, then we are already on the first ("0th") row, and we are in the first ("0th") column (as we were called in the first place). 000231r 2 ; Thus, we do not have an option to go more to the left. 000231r 2 000231r 2 86 rr stx zPNTR ; set column to 0 (TODO: should not be necessary, as it is already set to 0!) 000233r 2 000233r 2 ; Remove the return address from the stack: 000233r 2 ; we do not want to return to the caller; 000233r 2 ; instead, we will abort the output! 000233r 2 ; 000233r 2 68 pla 000234r 2 68 pla 000235r 2 000235r 2 D0 A5 bne CHROUT_SCREEN_END ; end the output (uncond. branch as long as the caller of the caller does not reside on the memory area $00xx.) 000237r 2 ; ----------------------- 000237r 2 000237r 2 @CanGoBack: 000237r 2 CA dex 000238r 2 86 rr stx zTBLX ; set the cursor one row to the top 00023Ar 2 00023Ar 2 20 rr rr jsr SET_CURSORPOS ; set the cursor position (and calculate the line length of the current line, in zLNMX) 00023Dr 2 00023Dr 2 ; set the cursor to the last column of the line 00023Dr 2 A4 rr ldy zLNMX ; get current (virtual) line length 00023Fr 2 84 rr sty zPNTR ; and set the cursor to that column 000241r 2 60 rts 000242r 2 000242r 2 ; CHROUT onto screen 000242r 2 ; 000242r 2 ; Output the character in A to the current cursor position on the screen 000242r 2 ; 000242r 2 CHROUT_SCREEN: 000242r 2 48 pha ; remember the character to output on stack 000243r 2 85 rr sta zSCHAR ; and in memory 000245r 2 000245r 2 ; remember X and Y on the stack 000245r 2 8A txa 000246r 2 48 pha 000247r 2 98 tya 000248r 2 48 pha 000249r 2 000249r 2 A9 00 lda #$00 ; no CR has been pressed yet 00024Br 2 85 rr sta zCRSW ; That is, on next BASIN, the routine will wait for an input again, regardless if the input has been completely used yet. 00024Dr 2 00024Dr 2 A4 rr ldy zPNTR ; get pointer into current (logical) line 00024Fr 2 A5 rr lda zSCHAR ; character to be output 000251r 2 10 03 bpl @PositiveChar ; is it positive (<= $7F) -> branch 000253r 2 4C rr rr jmp @NegativeChar 000256r 2 ; ------------ 000256r 2 000256r 2 @PositiveChar: 000256r 2 C9 0D cmp #ASC_CR ; is the character a CR? 000258r 2 D0 03 bne @NoCR ; No -> branch, next test 00025Ar 2 4C rr rr jmp CHROUT_SCREEN_CR ; Output a CR 00025Dr 2 00025Dr 2 @NoCR: 00025Dr 2 ; Here, we convert the codes as follows: 00025Dr 2 ; 00025Dr 2 ; PETSCII -> SCREEN CODE 00025Dr 2 ; $20-$3F -> $20-$3F 00025Dr 2 ; $40-$5F -> $00-$1F 00025Dr 2 ; $60-$7F -> $40-$5F 00025Dr 2 00025Dr 2 C9 20 cmp #$20 ; is the character a control code (< $20)? 00025Fr 2 90 10 bcc @TestControlCode ; yes, process the control code 000261r 2 000261r 2 C9 60 cmp #$60 ; is the character small than $60 (i.e., $20..$5F)? 000263r 2 90 04 bcc @Convert0x20_0x60 ; yes, branch -> convert char 000265r 2 29 DF and #~$20 ; convert $60-$7F --> $40-$5F 000267r 2 D0 02 bne @CheckQuoteAndOutput ; (uncond. branch) 000269r 2 ; ----------------- 000269r 2 000269r 2 @Convert0x20_0x60: 000269r 2 29 3F and #$3F ; converts $20-$3F --> $20-$3F, but $40-$5F -> $00-$1F 00026Br 2 00026Br 2 @CheckQuoteAndOutput: 00026Br 2 20 rr rr jsr CheckQuote ; update quote state, if necessary 00026Er 2 4C rr rr jmp CHROUT_SCREEN_OUTPUT_WITH_TEST_RVS 000271r 2 ; ----------------- 000271r 2 000271r 2 @TestControlCode: 000271r 2 A6 rr ldx zINSRT ; are we in insert mode? 000273r 2 F0 03 beq @ProcessControlCode ; no, branch -> process control codes 000275r 2 4C rr rr jmp CHROUT_SCREEN_OUTPUT_IN_RVS ; output the control codes in reverse (and quit), do not process them 000278r 2 ; ----------------- 000278r 2 000278r 2 @ProcessControlCode: 000278r 2 C9 14 cmp #ASC_INSDEL ; is the character an INS/DEL? 00027Ar 2 D0 2E bne @NoINSDEL ; no -> branch, skip special handling of INS/DEL 00027Cr 2 00027Cr 2 98 tya ; A := Y (zPNTR), offset of current column into current screen line 00027Dr 2 D0 06 bne @NotFirstColumn ; not the first column -> branch 00027Fr 2 00027Fr 2 20 rr rr jsr CHROUT_SCREEN_WrapAroundToPreviousRow ; Perform the wrap around to the previous row, putting the cursor on the rightmost column of the previous line. 000282r 2 ; If we are at the home position already, this function does NOT return, but goes to CHROUT_SCREEN_END instead. 000282r 2 4C rr rr jmp @AddBlankAtCurrentPosition 000285r 2 ; ----------------- 000285r 2 000285r 2 @NotFirstColumn: 000285r 2 20 rr rr jsr AdjustCursorRowBeforeMovingLeft ; we want to move the cursor to the left. If we will cross a row this way, decrement the row number. 000288r 2 000288r 2 ; move cursor one to the left 000288r 2 000288r 2 88 dey 000289r 2 84 rr sty zPNTR 00028Br 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer ; update color RAM pointer 00028Er 2 00028Er 2 ; move the screen parts to the right of the cursor one to the left 00028Er 2 00028Er 2 @MoveLoop: 00028Er 2 C8 iny ; get the char to the right 00028Fr 2 B1 rr lda (zPNT),y 000291r 2 88 dey ; and copy it one to the left 000292r 2 91 rr sta (zPNT),y 000294r 2 000294r 2 C8 iny ; get the color to the right 000295r 2 B1 rr lda (zUSER),y 000297r 2 88 dey ; and copy it one to the left 000298r 2 91 rr sta (zUSER),y 00029Ar 2 00029Ar 2 C8 iny ; proceed to the next position (to the right) 00029Br 2 C4 rr cpy zLNMX ; did we reach the end of the (logical) line? 00029Dr 2 D0 EF bne @MoveLoop ; no, move the next char 00029Fr 2 00029Fr 2 ; if we "fall through", then Y points to the last location on the current (logical) screen line 00029Fr 2 00029Fr 2 @AddBlankAtCurrentPosition: 00029Fr 2 A9 20 lda #' ' ; put a space char (blank) 0002A1r 2 91 rr sta (zPNT),y ; into the current screen location 0002A3r 2 AD rr rr lda lCOLOR ; put the default color 0002A6r 2 91 rr sta (zUSER),y ; into the current color location 0002A8r 2 10 4D bpl @End2 ; BUG: This is meant as an uncond. branch. It is one as long as no-one has the idea to put a negative color into lCOLOR! 0002AAr 2 ; ------------------ 0002AAr 2 0002AAr 2 @NoINSDEL: 0002AAr 2 A6 rr ldx zQTSW ; are we in quotation mark mode? 0002ACr 2 F0 03 beq @NoQuotationMode ; no -> branch 0002AEr 2 4C rr rr jmp CHROUT_SCREEN_OUTPUT_IN_RVS ; output the control codes in reverse 0002B1r 2 ; --------------------------------- 0002B1r 2 0002B1r 2 @NoQuotationMode: 0002B1r 2 C9 12 cmp #ASC_RVS ; character code for reverse (RVS) mode? 0002B3r 2 D0 02 bne @NotReverse ; no -> branch, next test 0002B5r 2 85 rr sta zRVS ; remember the reverse mode 0002B7r 2 0002B7r 2 @NotReverse: 0002B7r 2 C9 13 cmp #ASC_HOME ; character code for cursor home? 0002B9r 2 D0 03 bne @NoCrsrHome ; no -> branch, next test 0002BBr 2 20 rr rr jsr CURSOR_HOME ; put the cursor at the home position 0002BEr 2 0002BEr 2 @NoCrsrHome: 0002BEr 2 C9 1D cmp #ASC_CURSORLEFTRIGHT ; character code for cursor left/right? 0002C0r 2 D0 17 bne @NoCrsrLeftRight ; no -> branch, next test 0002C2r 2 0002C2r 2 C8 iny ; move cursor to the right 0002C3r 2 20 rr rr jsr AdjustCursorRowBeforeMovingRight ; if we will move to the next row, increment row number 0002C6r 2 84 rr sty zPNTR ; store cursor column 0002C8r 2 0002C8r 2 88 dey ; get old cursor position back 0002C9r 2 C4 rr cpy zLNMX ; was the cursor before the end of the (virtual) row? 0002CBr 2 90 09 bcc @End ; yes -> branch 0002CDr 2 0002CDr 2 ; If we reach here, we moved from the end of the previous row to the current row 0002CDr 2 0002CDr 2 C6 rr dec zTBLX ; decrement the row number (go up one row) 0002CFr 2 ; the first operation GoDownOneVirtualRow does is increment 0002CFr 2 ; the row number. This dec is a countermeasure 0002CFr 2 ; for this incrementing. 0002CFr 2 20 rr rr jsr GoDownOneVirtualRow ; go down one (virtual) row 0002D2r 2 A0 00 ldy #0 ; set cursor to the beginning of the row 0002D4r 2 @StoreColAndEnd: 0002D4r 2 84 rr sty zPNTR 0002D6r 2 0002D6r 2 4C rr rr @End: jmp CHROUT_SCREEN_END 0002D9r 2 ; ------------------------- 0002D9r 2 0002D9r 2 @NoCrsrLeftRight: 0002D9r 2 C9 11 cmp #ASC_CURSORUPDOWN ; character code for cursor up/down? 0002DBr 2 D0 1D bne @NoCrsrUpDown ; no -> branch, next test 0002DDr 2 0002DDr 2 ; In case we moved down one phyiscal row, but we are still in the 0002DDr 2 ; same (virtual) row, we calculate the new column we would be at 0002DDr 2 ; If this case is not true, the calculation will be thrown away. 0002DDr 2 ; Otherwise, we will use this value. 0002DDr 2 0002DDr 2 18 clc 0002DEr 2 98 tya ; A := Y (current column number) 0002DFr 2 69 16 adc #EDITOR_COLS ; add the number of columns in a physical row 0002E1r 2 A8 tay ; Y := A (column number if we are still in the same virtual row) 0002E2r 2 0002E2r 2 ; 0002E2r 2 E6 rr inc zTBLX ; go down one row 0002E4r 2 C5 rr cmp zLNMX ; compare just calculated column number with maximum number of column in the current row 0002E6r 2 90 EC bcc @StoreColAndEnd ; calculated row number is smaller -> we are still in the same virtual row -> branch, store column 0002E8r 2 F0 EA beq @StoreColAndEnd ; calculated row number is equal -> we are still in the same virtual row -> branch, store column 0002EAr 2 C6 rr dec zTBLX ; go up one row (again to where we started) 0002ECr 2 ; this is a preparation to the JSR GoDownOneVirtualRow below 0002ECr 2 0002ECr 2 ; "Normalise" the column (in zPNTR) 0002ECr 2 ; That is, calculate zPNTR MOD EDITOR_COLS with a loop 0002ECr 2 ; TODO why? 0002ECr 2 0002ECr 2 @Normalise: 0002ECr 2 ; sec, but we already have C=1: If we come from "above", then we would have branched in the bcc 0002ECr 2 ; if C=0 0002ECr 2 ; if we looped, then we would have branched in the other bcc from below 0002ECr 2 0002ECr 2 E9 16 sbc #EDITOR_COLS ; subtract the number of columns in a physical row 0002EEr 2 90 04 bcc @GoDown ; if we reached < 0, end the loop 0002F0r 2 85 rr sta zPNTR ; store the column 0002F2r 2 D0 F8 bne @Normalise ; if we did not reach 0 yet, loop again 0002F4r 2 0002F4r 2 @GoDown: 0002F4r 2 20 rr rr jsr GoDownOneVirtualRow ; go down one (virtual) row 0002F7r 2 @End2: 0002F7r 2 4C rr rr jmp CHROUT_SCREEN_END 0002FAr 2 0002FAr 2 @NoCrsrUpDown: 0002FAr 2 20 rr rr jsr EditorCheckColorCodeAndSetColor ; check if the current PETSCII code is a color. IF yes, set lCOLOR. Return anyway 0002FDr 2 0002FDr 2 .if CompileComputer >= VIC20_06 0002FDr 2 4C rr rr jmp EditorCheckForAscLowercase ; check for additional codes (change uppercase, change lowercase, allow changing uppercase/lowercase, disallow it) 000300r 2 .else 000300r 2 jmp CHROUT_SCREEN_END ; we're done 000300r 2 .endif 000300r 2 000300r 2 000300r 2 @NegativeChar: 000300r 2 000300r 2 .if CompileComputer >= C64_GENERAL 000300r 2 000300r 2 .elseif CompileComputer < VIC20_06 000300r 2 ; depending on lMODE, the old VIC20 KERNAL does some translation of 000300r 2 ; character codes to be output. 000300r 2 ; All of these codes being replaced have in common that their 000300r 2 ; 7th bit ($80) is set. 000300r 2 ; 000300r 2 ; TODO Why is this done? 000300r 2 000300r 2 ldx lMODE ; get lMODE 000300r 2 beq @LE815 ; is it 0? Then do NOT do any conversion 000300r 2 000300r 2 ldx #$31 000300r 2 @LE807: cmp CHROUT_REPLACEMENT_TABLE,x 000300r 2 beq @LE812 000300r 2 dex 000300r 2 dex 000300r 2 bpl @LE807 000300r 2 bmi @LE815 000300r 2 @LE812: lda CHROUT_REPLACEMENT_TABLE - 1,x 000300r 2 .else 000300r 2 000300r 2 ; FillUntil $E815, $EA 000300r 2 EA EA EA EA FillNOP 21 000304r 2 EA EA EA EA 000308r 2 EA EA EA EA 000315r 2 000315r 2 .endif 000315r 2 000315r 2 @LE815: 000315r 2 000315r 2 29 7F and #$7F 000317r 2 C9 7F cmp #TokPi - $80 000319r 2 D0 02 bne @LE7DC 00031Br 2 .if .defined(C64JAPAN) 00031Br 2 lda #ASC_PI - $40 ; @@@??? 00031Br 2 .else 00031Br 2 A9 5E lda #ASC_PI - $80 00031Dr 2 .endif 00031Dr 2 @LE7DC: 00031Dr 2 .if CompileComputer >= C64_GENERAL 00031Dr 2 00031Dr 2 .elseif CompileComputer >= VIC20_06 00031Dr 2 EA EA EA EA .repeat 6 000321r 2 EA EA 000323r 2 nop 000323r 2 .endrep 000323r 2 .else 000323r 2 cmp #$04 000323r 2 bne @LE823 000323r 2 lda #$7F 000323r 2 .endif 000323r 2 000323r 2 @LE823: 000323r 2 C9 20 cmp #' ' 000325r 2 90 03 bcc @LE7E3 000327r 2 4C rr rr jmp LE691 00032Ar 2 ; ---------------- 00032Ar 2 00032Ar 2 C9 0D @LE7E3: cmp #ASC_CR 00032Cr 2 D0 03 bne @LE7EA 00032Er 2 4C rr rr jmp CHROUT_SCREEN_CR 000331r 2 000331r 2 A6 rr @LE7EA: ldx zQTSW ; are we in quotation mark mode? 000333r 2 D0 3F bne @LE82D ; yes -> branch 000335r 2 C9 14 cmp #ASC_INSDEL 000337r 2 D0 37 bne @LE829 000339r 2 A4 rr ldy zLNMX 00033Br 2 B1 rr lda (zPNT),y 00033Dr 2 C9 20 cmp #' ' 00033Fr 2 D0 04 bne @LE7FE 000341r 2 C4 rr cpy zPNTR 000343r 2 D0 07 bne @LE805 000345r 2 C0 57 @LE7FE: cpy #(EDITOR_MAX_COMBINED_ROWS * EDITOR_COLS) - 1 000347r 2 F0 24 beq @LE826 000349r 2 20 rr rr jsr LE965 00034Cr 2 A4 rr @LE805: ldy zLNMX 00034Er 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer 000351r 2 88 @LE80A: dey 000352r 2 B1 rr lda (zPNT),y 000354r 2 C8 iny 000355r 2 91 rr sta (zPNT),y 000357r 2 88 dey 000358r 2 B1 rr lda (zUSER),y 00035Ar 2 C8 iny 00035Br 2 91 rr sta (zUSER),y 00035Dr 2 88 dey 00035Er 2 C4 rr cpy zPNTR 000360r 2 D0 EF bne @LE80A 000362r 2 A9 20 lda #' ' 000364r 2 91 rr sta (zPNT),y 000366r 2 AD rr rr lda lCOLOR 000369r 2 91 rr sta (zUSER),y 00036Br 2 E6 rr inc zINSRT ; increment number of characters to output in insert mode 00036Dr 2 4C rr rr @LE826: jmp CHROUT_SCREEN_END 000370r 2 ; ----------------------- 000370r 2 000370r 2 A6 rr @LE829: ldx zINSRT ; number of characters to output in insert mode 000372r 2 F0 05 beq @LE832 000374r 2 09 40 @LE82D: ora #$40 000376r 2 4C rr rr jmp CHROUT_SCREEN_OUTPUT_IN_RVS 000379r 2 000379r 2 C9 11 @LE832: cmp #ASC_CURSORUPDOWN 00037Br 2 D0 16 bne @LE84C 00037Dr 2 A6 rr ldx zTBLX 00037Fr 2 F0 37 beq @LE871 000381r 2 C6 rr dec zTBLX 000383r 2 A5 rr lda zPNTR 000385r 2 38 sec 000386r 2 E9 16 sbc #EDITOR_COLS 000388r 2 90 04 bcc @LE847 00038Ar 2 85 rr sta zPNTR 00038Cr 2 10 2A bpl @LE871 00038Er 2 20 rr rr @LE847: jsr SET_CURSORPOS 000391r 2 D0 25 bne @LE871 000393r 2 C9 12 @LE84C: cmp #ASC_RVS 000395r 2 D0 04 bne @LE854 000397r 2 A9 00 lda #$00 000399r 2 85 rr sta zRVS 00039Br 2 C9 1D @LE854: cmp #ASC_CURSORLEFTRIGHT 00039Dr 2 D0 12 bne @LE86A 00039Fr 2 98 tya 0003A0r 2 F0 09 beq @LE864 0003A2r 2 20 rr rr jsr AdjustCursorRowBeforeMovingLeft ; we want to move the cursor to the left. If we will cross a row this way, decrement the row number. 0003A5r 2 88 dey 0003A6r 2 84 rr sty zPNTR 0003A8r 2 4C rr rr jmp CHROUT_SCREEN_END 0003ABr 2 0003ABr 2 20 rr rr @LE864: jsr CHROUT_SCREEN_WrapAroundToPreviousRow 0003AEr 2 4C rr rr jmp CHROUT_SCREEN_END 0003B1r 2 C9 13 @LE86A: cmp #ASC_HOME 0003B3r 2 D0 06 bne @LE874 0003B5r 2 20 rr rr jsr ClearScreen 0003B8r 2 4C rr rr @LE871: jmp CHROUT_SCREEN_END 0003BBr 2 09 80 @LE874: ora #$80 0003BDr 2 20 rr rr jsr EditorCheckColorCodeAndSetColor 0003C0r 2 .if CompileComputer >= VIC20_06 0003C0r 2 4C rr rr jmp EditorCheckForAscUppercase 0003C3r 2 .else 0003C3r 2 jmp CHROUT_SCREEN_END 0003C3r 2 .endif 0003C3r 2 ; ----------------------- 0003C3r 2 0003C3r 2 GoDownOneVirtualRow: 0003C3r 2 46 rr lsr zLXSP 0003C5r 2 A6 rr ldx zTBLX 0003C7r 2 E8 @LE880: inx 0003C8r 2 E0 17 cpx #EDITOR_ROWS 0003CAr 2 D0 03 bne @LE888 0003CCr 2 20 rr rr jsr LE8EA 0003CFr 2 B5 rr @LE888: lda zLDTB1,x 0003D1r 2 10 F4 bpl @LE880 0003D3r 2 86 rr stx zTBLX 0003D5r 2 4C rr rr jmp SET_CURSORPOS 0003D8r 2 0003D8r 2 CHROUT_SCREEN_CR: 0003D8r 2 ; output a CR onto the screen at the current cursor position 0003D8r 2 0003D8r 2 A2 00 ldx #$00 0003DAr 2 86 rr stx zINSRT ; end INSERT mode 0003DCr 2 86 rr stx zRVS ; end REVERSE (RVS) mode 0003DEr 2 86 rr stx zQTSW ; end quotation mark mode 0003E0r 2 86 rr stx zPNTR ; put cursor to the beginning of the current line (that is, CR w/o NL, so to speak) 0003E2r 2 0003E2r 2 20 rr rr jsr GoDownOneVirtualRow ; go down one (virtual) row 0003E5r 2 4C rr rr jmp CHROUT_SCREEN_END 0003E8r 2 ; -------------- 0003E8r 2 0003E8r 2 ; If the cursor will be part of the previous row after being moved to the left 0003E8r 2 ; (that is, the cursor is at the beginning of the current row now), move 0003E8r 2 ; the cursor one row to the top. 0003E8r 2 0003E8r 2 AdjustCursorRowBeforeMovingLeft: 0003E8r 2 A2 04 ldx #EDITOR_MAX_COMBINED_ROWS ; maximum number of rows that can be combined in one virtual row 0003EAr 2 A9 00 lda #$00 ; start counter at column 0 0003ECr 2 @Loop: 0003ECr 2 C5 rr cmp zPNTR ; is current cursor column the same as our counter? 0003EEr 2 F0 07 beq @DecrementAndExit ; yes -> branch, decrement row and exit 0003F0r 2 18 clc 0003F1r 2 69 16 adc #EDITOR_COLS ; calculate next multiple of EDITOR_COLS to test against 0003F3r 2 CA dex ; still a row to handle? 0003F4r 2 D0 F6 bne @Loop ; yes -> branch, process next row 0003F6r 2 60 rts 0003F7r 2 0003F7r 2 @DecrementAndExit: 0003F7r 2 C6 rr dec zTBLX ; decrement current cursor row 0003F9r 2 60 rts 0003FAr 2 0003FAr 2 0003FAr 2 ; If the cursor will be part of the next row after being moved to the right 0003FAr 2 ; (that is, the cursor is at the end of the current row now), move 0003FAr 2 ; the cursor one row to the bottom. 0003FAr 2 0003FAr 2 AdjustCursorRowBeforeMovingRight: 0003FAr 2 A2 04 ldx #EDITOR_MAX_COMBINED_ROWS ; maximum number of rows that can be combined in one virtual row 0003FCr 2 A9 15 lda #EDITOR_COLS - 1 ; start counter at last column of a physical row 0003FEr 2 @Loop: 0003FEr 2 C5 rr cmp zPNTR ; is current cursor column the same as our counter? 000400r 2 F0 07 beq @IncrementAndExit ; yes -> branch, increment row and exit 000402r 2 18 clc 000403r 2 69 16 adc #EDITOR_COLS ; calculate next column to test against 000405r 2 CA dex ; still a row to handle? 000406r 2 D0 F6 bne @Loop ; yes -> branch, process next row 000408r 2 60 rts 000409r 2 000409r 2 @IncrementAndExit: 000409r 2 A6 rr ldx zTBLX ; is current cursor row 00040Br 2 E0 17 cpx #EDITOR_ROWS ; less than the maximum? 00040Dr 2 F0 02 beq @Rts ; no, we cannot increment as we are already at the last row -> branch, skip increment 00040Fr 2 E6 rr inc zTBLX ; increment cursor row 000411r 2 60 @Rts: rts 000412r 2 000412r 2 ; Check if the current PETSCII code is a color code 000412r 2 ; If it is, set lCOLOR accordingly. 000412r 2 ; Input: A := PETSCII code 000412r 2 ; Output: if A is a color code: 000412r 2 ; lCOLOR := X := color code 000412r 2 ; else 000412r 2 ; X := $FF, lCOLOR unchanged 000412r 2 ; Uses: X 000412r 2 ; 000412r 2 EditorCheckColorCodeAndSetColor: 000412r 2 A2 07 ldx #END_ColorCodes - ColorCodes - 1 ; get number of color codes 000414r 2 @CheckColor: 000414r 2 DD rr rr cmp ColorCodes,x ; is the current char a color code? 000417r 2 F0 04 beq @ColorFound ; yes -> branch, we found a color 000419r 2 CA dex ; test the next color 00041Ar 2 10 F8 bpl @CheckColor ; until there is not one left 00041Cr 2 60 rts 00041Dr 2 @ColorFound: 00041Dr 2 8E rr rr stx lCOLOR ; store the color code in lCOLOR 000420r 2 60 rts 000421r 2 000421r 2 ColorCodes: 000421r 2 000421r 2 ; These are the PETSCII values of the color codes 000421r 2 000421r 2 90 05 1C 9F .byte $90,$05,$1C,$9F,$9C,$1E,$1F,$9E ; colors no. 0-7 000425r 2 9C 1E 1F 9E 000429r 2 000429r 2 .if CompileComputer >= C64_GENERAL 000429r 2 .byte $81,$95,$96,$97,$98,$99,$9A,$9B ; The C64 has 8 additional colors defined here: colors no. 8-15 000429r 2 000429r 2 .endif 000429r 2 000429r 2 END_ColorCodes: 000429r 2 000429r 2 .if CompileComputer < C64_GENERAL 000429r 2 000429r 2 ; depending on lMODE, the old VIC20 KERNAL does some translation of 000429r 2 ; character codes to be output. 000429r 2 ; All of these codes being replaced have in common that their 000429r 2 ; 7th bit ($80) is set. 000429r 2 ; 000429r 2 ; TODO Why is this done? 000429r 2 000429r 2 ; this table is organised as follows: Each entry consists of a byte pair. 000429r 2 ; the byte at offset 1 is the character that is to be replaced, and 000429r 2 ; the byte at offset 0 is the character with which to replace. 000429r 2 000429r 2 ; This is only used in VIC20_02 ROMs, although the 000429r 2 ; table is also present in later ROMs. 000429r 2 000429r 2 CHROUT_REPLACEMENT_TABLE: 000429r 2 EF A1 .byte $EF,$A1 00042Br 2 DF A6 .byte $DF,$A6 00042Dr 2 E1 B1 .byte $E1,$B1 00042Fr 2 E2 B2 .byte $E2,$B2 000431r 2 E3 B3 .byte $E3,$B3 000433r 2 E4 B4 .byte $E4,$B4 000435r 2 E5 B5 .byte $E5,$B5 000437r 2 E6 B6 .byte $E6,$B6 000439r 2 E7 B7 .byte $E7,$B7 00043Br 2 E8 B8 .byte $E8,$B8 00043Dr 2 E9 B9 .byte $E9,$B9 00043Fr 2 FA BA .byte $FA,$BA 000441r 2 FB BB .byte $FB,$BB 000443r 2 FC BC .byte $FC,$BC 000445r 2 EC BD .byte $EC,$BD 000447r 2 FE BE .byte $FE,$BE 000449r 2 84 BF .byte $84,$BF 00044Br 2 F7 C0 .byte $F7,$C0 00044Dr 2 F8 DB .byte $F8,$DB 00044Fr 2 F9 DD .byte $F9,$DD 000451r 2 EA DE .byte $EA,$DE 000453r 2 000453r 2 SpecialScreenCodeHandleTable: 000453r 2 ; special screen code to PETSCII conversion table 000453r 2 ; the first character is the screen code to convert, 000453r 2 ; the second character is the PETSCII code to convert in 000453r 2 ; 000453r 2 ; This is only used in VIC20_02 ROMs, although the 000453r 2 ; table is also present in later ROMs. 000453r 2 000453r 2 5E E0 .byte $5E,$E0 000455r 2 5B E1 .byte $5B,$E1 000457r 2 5D E2 .byte $5D,$E2 000459r 2 40 B0 .byte $40,$B0 00045Br 2 61 B1 .byte $61,$B1 00045Dr 2 78 DB .byte $78,$DB 00045Fr 2 79 DD .byte $79,$DD 000461r 2 66 B6 .byte $66,$B6 000463r 2 77 C0 .byte $77,$C0 000465r 2 70 F0 .byte $70,$F0 000467r 2 71 F1 .byte $71,$F1 000469r 2 72 F2 .byte $72,$F2 00046Br 2 73 F3 .byte $73,$F3 00046Dr 2 74 F4 .byte $74,$F4 00046Fr 2 75 F5 .byte $75,$F5 000471r 2 76 F6 .byte $76,$F6 000473r 2 7D FD .byte $7D,$FD 000475r 2 000475r 2 SpecialScreenCodeHandleTable_END: 000475r 2 000475r 2 .endif 000475r 2 000475r 2 A5 rr LE8EA: lda zSAL 000477r 2 48 pha 000478r 2 A5 rr lda zSAL + 1 00047Ar 2 48 pha 00047Br 2 A5 rr lda zEAL 00047Dr 2 48 pha 00047Er 2 A5 rr lda zEAL + 1 000480r 2 48 pha 000481r 2 A2 FF @LE8F6: ldx #$FF 000483r 2 C6 rr dec zTBLX 000485r 2 C6 rr dec zLXSP 000487r 2 C6 F2 dec lTLNIDX 000489r 2 000489r 2 E8 @LE8FF: inx 00048Ar 2 20 rr rr jsr CalculateScreenPointerFromRowNumber 00048Dr 2 E0 16 cpx #EDITOR_ROWS - 1 00048Fr 2 B0 0C bcs @LE913 000491r 2 BD rr rr lda SCREEN_LOWBYTE + 1,x 000494r 2 85 rr sta zSAL 000496r 2 B5 rr lda zLDTB1 + 1,x 000498r 2 20 rr rr jsr CopyPhysicalScreenRow 00049Br 2 30 EC bmi @LE8FF ; => jmp, as CopyPhysicalScreenRow will not return with N=0 ("bpl loop") 00049Dr 2 ; ----------------- 00049Dr 2 00049Dr 2 @LE913: 00049Dr 2 20 rr rr jsr EraseScreenRow 0004A0r 2 A2 00 ldx #0 0004A2r 2 B5 rr @LE918: lda zLDTB1,x 0004A4r 2 29 7F and #$7F 0004A6r 2 B4 rr ldy zLDTB1 + 1,x 0004A8r 2 10 02 bpl @LE922 0004AAr 2 09 80 ora #$80 0004ACr 2 95 rr @LE922: sta zLDTB1,x 0004AEr 2 E8 inx 0004AFr 2 E0 16 cpx #EDITOR_ROWS - 1 0004B1r 2 D0 EF bne @LE918 0004B3r 2 A5 rr lda zLDTB1 + EDITOR_ROWS - 1 0004B5r 2 09 80 ora #$80 0004B7r 2 85 rr sta zLDTB1 + EDITOR_ROWS - 1 0004B9r 2 A5 rr lda zLDTB1 0004BBr 2 10 C4 bpl @LE8F6 0004BDr 2 E6 rr inc zTBLX 0004BFr 2 E6 F2 inc lTLNIDX 0004C1r 2 0004C1r 2 ; check for a pressed CTRL key: 0004C1r 2 ; If it is pressed, incorporate an additional delay 0004C1r 2 0004C1r 2 .ifdef JIFFY 0004C1r 2 0004C1r 2 JDLE938: 0004C1r 2 jsr RestoreKeyboardRowAndRet 0004C1r 2 0004C1r 2 .else 0004C1r 2 A9 FB lda #KEYB_ROW_CTRL ; set the keyboard row to the row that has the CTRL key 0004C3r 2 8D 20 91 sta KEYB_ROW 0004C6r 2 .endif 0004C6r 2 AD 21 91 lda KEYB_COL ; test the keyboard columns 0004C9r 2 C9 FE cmp #KEYB_COL_CTRL ; check the CTRL key specifically 0004CBr 2 0004CBr 2 .ifdef JIFFY 0004CBr 2 bne @SkipDelay 0004CBr 2 ldx zNDX 0004CBr 2 beq JDLE938 0004CBr 2 lda $0276,x 0004CBr 2 sbc #$13 0004CBr 2 bne @SkipDelay 0004CBr 2 sta zNDX 0004CBr 2 @JDLE94F: cli 0004CBr 2 cmp zNDX 0004CBr 2 beq @JDLE94F 0004CBr 2 sta zNDX 0004CBr 2 0004CBr 2 .else 0004CBr 2 08 php ; remember status 0004CCr 2 A9 F7 lda #KEYB_ROW_STANDARD ; restore the keyboard row 0004CEr 2 8D 20 91 sta KEYB_ROW 0004D1r 2 28 plp ; get back the status 0004D2r 2 D0 0B bne @SkipDelay ; Z=1 --> CTRL key not pressed --> branch, skip delay 0004D4r 2 0004D4r 2 ; create a delay of TODO clock cycles 0004D4r 2 A0 00 ldy #0 0004D6r 2 @Delay: 0004D6r 2 EA nop 0004D7r 2 CA dex 0004D8r 2 D0 FC bne @Delay 0004DAr 2 88 dey 0004DBr 2 D0 F9 bne @Delay 0004DDr 2 84 rr sty zNDX 0004DFr 2 0004DFr 2 .endif 0004DFr 2 0004DFr 2 @SkipDelay: 0004DFr 2 A6 rr ldx zTBLX 0004E1r 2 0004E1r 2 Restore_zEAL_and_zSAL: 0004E1r 2 68 pla 0004E2r 2 85 rr sta zEAL + 1 0004E4r 2 68 pla 0004E5r 2 85 rr sta zEAL 0004E7r 2 68 pla 0004E8r 2 85 rr sta zSAL + 1 0004EAr 2 68 pla 0004EBr 2 85 rr sta zSAL 0004EDr 2 60 rts 0004EEr 2 0004EEr 2 LE965: 0004EEr 2 A6 rr ldx zTBLX 0004F0r 2 LE967: 0004F0r 2 ; find next (virtual) row 0004F0r 2 E8 inx ; proceed to next (physical) row 0004F1r 2 B5 rr lda zLDTB1,x ; is it combined with the previous one (bit 7 = 0)? 0004F3r 2 10 FB bpl LE967 ; yes -> branch, loop to test the next row 0004F5r 2 0004F5r 2 86 F2 stx lTLNIDX ; remember the row number of the next (virtual) row 0004F7r 2 E0 16 cpx #EDITOR_ROWS - 1 ; is this the last (phyiscal) row? 0004F9r 2 F0 0D beq @LE981 ; yes -> branch 0004FBr 2 90 0B bcc @LE981 ; row number is less than last row -> also branch 0004FDr 2 0004FDr 2 20 rr rr jsr LE8EA 000500r 2 A6 F2 ldx lTLNIDX 000502r 2 CA dex 000503r 2 C6 rr dec zTBLX 000505r 2 4C rr rr jmp LogicallyCombineTwoRows 000508r 2 ; -------------------- 000508r 2 000508r 2 ; Make room on the screen for the extension of a logical screen row to comprise another 000508r 2 ; physical screen row. This involves scrolling every row below lTLNIDX down (to make 000508r 2 ; room), erasing the new row, and adjusting the pointers in zLDTB1. 000508r 2 000508r 2 @LE981: 000508r 2 ; save zEAL/zEAL+1 and zSAL/zSAL+1 on the stack as they will be used 000508r 2 ; as temporary storage for pointers. 000508r 2 ; These will be restored before leaving. 000508r 2 000508r 2 A5 rr lda zSAL 00050Ar 2 48 pha 00050Br 2 A5 rr lda zSAL + 1 00050Dr 2 48 pha 00050Er 2 A5 rr lda zEAL 000510r 2 48 pha 000511r 2 A5 rr lda zEAL + 1 000513r 2 48 pha 000514r 2 000514r 2 ; Move screen contents below the current cursor position downwards 000514r 2 000514r 2 A2 17 ldx #EDITOR_ROWS ; start at the last physical row 000516r 2 @CopyRow: 000516r 2 CA dex 000517r 2 20 rr rr jsr CalculateScreenPointerFromRowNumber ; update the destination pointer into video RAM (zPNT/zPNT+1) 00051Ar 2 E4 F2 cpx lTLNIDX ; have we already reached the current screen row? 00051Cr 2 90 0E bcc @EndMove ; we are above the current screen row -> branch, end the copy (TODO is this needed at all?) 00051Er 2 F0 0C beq @EndMove ; we are at the current screen row -> branch, end the copy 000520r 2 000520r 2 ; update the source pointers 000520r 2 BD rr rr lda SCREEN_LOWBYTE - 1,x ; get low byte of the starting address of this row 000523r 2 85 rr sta zSAL ; remember low byte 000525r 2 B5 rr lda zLDTB1 - 1,x ; get high byte of the starting address of this row 000527r 2 20 rr rr jsr CopyPhysicalScreenRow ; copy the current screen row from source to destination, moving it down 00052Ar 2 30 EA bmi @CopyRow ; => jmp, as CopyPhysicalScreenRow will not return with N=0 ("bpl loop") 00052Cr 2 ; --------------------------- 00052Cr 2 00052Cr 2 @EndMove: 00052Cr 2 20 rr rr jsr EraseScreenRow ; erase the (physical) screen row in X 00052Fr 2 00052Fr 2 ; update zLDTB1 to reflect the new situation 00052Fr 2 ; copy the high order (7th) bit of the byte for each row that has been moved 00052Fr 2 ; to the next row. 00052Fr 2 ; source row is the row that is copied, destination row is the next row 00052Fr 2 00052Fr 2 A2 15 ldx #EDITOR_ROWS - 2 ; start at 2nd to last row of source row 000531r 2 000531r 2 @MoveCombinationBits: 000531r 2 E4 F2 cpx lTLNIDX ; have we already reached (<=) the current row? 000533r 2 90 0F bcc @EndMoveCombinationBits ; yes, quit 000535r 2 000535r 2 B5 rr lda zLDTB1 + 1,x ; get the byte for the next row 000537r 2 29 7F and #~$80 ; clear bit 7 in all cases 000539r 2 B4 rr ldy zLDTB1,x ; read 7th bit of source row 00053Br 2 10 02 bpl @Positive ; if it is unset (positive), skip 00053Dr 2 09 80 ora #$80 ; set the 7th bit of destination row 00053Fr 2 @Positive: 00053Fr 2 95 rr sta zLDTB1 + 1,x ; store byte for destination row 000541r 2 CA dex ; proceed with previous row 000542r 2 D0 ED bne @MoveCombinationBits 000544r 2 000544r 2 @EndMoveCombinationBits: 000544r 2 A6 F2 ldx lTLNIDX 000546r 2 20 rr rr jsr LogicallyCombineTwoRows 000549r 2 000549r 2 ; restore zEAL/zEAL+1 and zSAL/zSAL+1 000549r 2 000549r 2 .if CompileComputer >= C64_GENERAL 000549r 2 jmp Restore_zEAL_and_zSAL ; same implementation like VIC-20, but we save memory as it is already there 000549r 2 .else 000549r 2 68 pla 00054Ar 2 85 rr sta zEAL + 1 00054Cr 2 68 pla 00054Dr 2 85 rr sta zEAL 00054Fr 2 68 pla 000550r 2 85 rr sta zSAL + 1 000552r 2 68 pla 000553r 2 85 rr sta zSAL 000555r 2 60 rts 000556r 2 .endif 000556r 2 000556r 2 ; Copy one (physical) screen row on screen to another screen row 000556r 2 000556r 2 ; This will copy a physical screen row in memory, including the video and the color RAM. 000556r 2 ; It is used to scroll the screen up or down, but it is not limited to this usage. 000556r 2 000556r 2 ; Input: A = high byte of start address of (logical TODO) screen row (cf. zLDTB1) from which to copy 000556r 2 ; zSAL = low byte of start address of (physical) screen row (cf. SCREEN_LOWBYTE) from which to copy 000556r 2 000556r 2 ; zPNT/zPNT+1 = Start address of physical screen row video RAM destination 000556r 2 ; zUSER/zUSER+1 = Start address of physical screen row color RAM destination 000556r 2 000556r 2 CopyPhysicalScreenRow: 000556r 2 29 03 and #>lVIDEORAM_SIZE ; make sure to let the start address 000558r 2 0D rr rr ora lHIBASE ; point into the current video RAM 00055Br 2 85 rr sta zSAL + 1 ; store the address as pointer 00055Dr 2 20 rr rr jsr @UpdateColorRamPointers 000560r 2 000560r 2 ; Copy one (physical) row 000560r 2 000560r 2 A0 15 ldy #EDITOR_COLS - 1 ; index of last character in a (physical) row 000562r 2 @CopyPreviousChar: 000562r 2 B1 rr lda (zSAL),y ; get character from source 000564r 2 91 rr sta (zPNT),y ; and store it at the destination 000566r 2 B1 rr lda (zEAL),y ; get color from source 000568r 2 91 rr sta (zUSER),y ; and store it at the destination 00056Ar 2 88 dey ; go to previous character 00056Br 2 10 F5 bpl @CopyPreviousChar ; non-negative -> branch, there is still a character to be processed 00056Dr 2 60 rts 00056Er 2 ; ----------------------- 00056Er 2 00056Er 2 ; Update the color RAM pointers in zUSER/zUSER+1 and zEAL/zEAL+1, respectively, 00056Er 2 ; to point to the same locations as the video RAM pointers 00056Er 2 ; in zPNT/zPNT+1 and zSAL/zSAL+1, respectively. 00056Er 2 00056Er 2 @UpdateColorRamPointers: 00056Er 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer ; update the color RAM pointer to match the video RAM pointer 000571r 2 000571r 2 ; adjust video RAM pointer in zSAL/zSAL+1 to point to the color RAM (in zEAL/zEAL+1) 000571r 2 A5 rr lda zSAL 000573r 2 85 rr sta zEAL 000575r 2 A5 rr lda zSAL + 1 000577r 2 29 03 and #>lVIDEORAM_SIZE 000579r 2 09 94 ora #>COLORRAM 00057Br 2 85 rr sta zEAL + 1 00057Dr 2 60 rts 00057Er 2 00057Er 2 CalculateScreenPointerFromRowNumber: 00057Er 2 ; calculate the start of the screen row of which the number 00057Er 2 ; is given in X. Store it in zPNT. 00057Er 2 00057Er 2 BD rr rr lda SCREEN_LOWBYTE,x ; get low byte of the starting address of this row 000581r 2 85 rr sta zPNT ; remember low byte 000583r 2 B5 rr lda zLDTB1,x ; get high byte of the starting address of this row 000585r 2 29 03 and #>lVIDEORAM_SIZE ; mask out additional bits used as flags 000587r 2 0D rr rr ora lHIBASE ; add the video RAM base 00058Ar 2 85 rr sta zPNT + 1 ; remember high byte 00058Cr 2 60 rts 00058Dr 2 00058Dr 2 00058Dr 2 EraseScreenRow: 00058Dr 2 00058Dr 2 ; this routine erases the screen row no. X 00058Dr 2 00058Dr 2 A0 15 ldy #EDITOR_COLS - 1 ; start in the last column 00058Fr 2 20 rr rr jsr CalculateScreenPointerFromRowNumber ; set the video RAM pointer in zPNT to the row we want to process 000592r 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer ; update the video RAM pointer in zUSER to correspond to zPNT 000595r 2 000595r 2 @Loop: 000595r 2 .if CompileComputer >= C64_03 .AND CompileComputer <> C64_4064 000595r 2 jsr Patch_StoreColor ; set the color of the location 000595r 2 .endif 000595r 2 A9 20 lda #' ' ; store a SPACE (' ') into the video RAM position 000597r 2 91 rr sta (zPNT),y 000599r 2 .if CompileComputer = C64_02 .OR CompileComputer = C64_4064 000599r 2 jsr Patch_StoreColor ; set the color of the location 000599r 2 nop 000599r 2 .elseif CompileComputer <= C64_01 000599r 2 A9 01 lda #COL_WHITE ; set the color of the location to white 00059Br 2 91 rr sta (zUSER),y 00059Dr 2 .endif 00059Dr 2 88 dey ; proceed to the previous column 00059Er 2 10 F5 bpl @Loop ; still >= 0, branch -> process the next column 0005A0r 2 60 rts 0005A1r 2 ; ---------------------------------- 0005A1r 2 0005A1r 2 .if CompileComputer >= C64_03 .AND CompileComputer <> C64_4064 0005A1r 2 nop 0005A1r 2 .endif 0005A1r 2 0005A1r 2 0005A1r 2 StoreCharacterOnScreenAndDisableBlinking: 0005A1r 2 A8 tay ; remember character to output 0005A2r 2 0005A2r 2 A9 02 lda #$02 ; set blink counter to $02 (TODO WHY?) 0005A4r 2 85 rr sta zBLNCT 0005A6r 2 0005A6r 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer ; set pointer to video RAM at cursor position 0005A9r 2 0005A9r 2 98 tya ; get back character to output 0005AAr 2 0005AAr 2 ; 0005AAr 2 ; Store character on screen at the current cursor position 0005AAr 2 ; 0005AAr 2 ; A = character 0005AAr 2 ; X = color 0005AAr 2 ; 0005AAr 2 StoreCharacterOnScreen: 0005AAr 2 A4 rr ldy zPNTR ; get column offset in of current screen position 0005ACr 2 91 rr sta (zPNT),y ; store character in video RAM 0005AEr 2 8A txa ; get color 0005AFr 2 91 rr sta (zUSER),y ; store color in color RAM 0005B1r 2 60 rts 0005B2r 2 0005B2r 2 UpdateColorRAMPointerToVideoramPointer: 0005B2r 2 A5 rr lda zPNT 0005B4r 2 85 rr sta zUSER 0005B6r 2 A5 rr lda zPNT + 1 0005B8r 2 29 03 and #>lVIDEORAM_SIZE 0005BAr 2 09 94 ora #>COLORRAM 0005BCr 2 85 rr sta zUSER + 1 0005BEr 2 60 rts 0005BFr 2 0005BFr 2 KIRQ: 0005BFr 2 20 rr rr jsr kUDTIM 0005C2r 2 A5 rr lda zBLNSW 0005C4r 2 D0 29 bne @LEA61 0005C6r 2 C6 rr dec zBLNCT 0005C8r 2 D0 25 bne @LEA61 0005CAr 2 A9 14 lda #$14 0005CCr 2 85 rr sta zBLNCT 0005CEr 2 A4 rr ldy zPNTR 0005D0r 2 46 rr lsr zBLNON 0005D2r 2 AE rr rr ldx lGDCOL 0005D5r 2 B1 rr lda (zPNT),y 0005D7r 2 B0 11 bcs @LEA5C 0005D9r 2 E6 rr inc zBLNON 0005DBr 2 85 rr sta zGDBLN 0005DDr 2 20 rr rr jsr UpdateColorRAMPointerToVideoramPointer 0005E0r 2 B1 rr lda (zUSER),y 0005E2r 2 8D rr rr sta lGDCOL 0005E5r 2 AE rr rr ldx lCOLOR 0005E8r 2 A5 rr lda zGDBLN 0005EAr 2 49 80 @LEA5C: eor #$80 0005ECr 2 20 rr rr jsr StoreCharacterOnScreen 0005EFr 2 0005EFr 2 @LEA61: 0005EFr 2 0005EFr 2 .ifdef JIFFY 0005EFr 2 0005EFr 2 LEA61: jmp LEA7B 0005EFr 2 LEA64: pla 0005EFr 2 pha 0005EFr 2 cmp #$98 0005EFr 2 beq JDLEA6D 0005EFr 2 JDLEA6A: jmp LA57C 0005EFr 2 JDLEA6D: jsr JDLF72C 0005EFr 2 bne JDLEA6A 0005EFr 2 ldx zTXTPTR 0005EFr 2 ldy #$04 0005EFr 2 tya 0005EFr 2 jmp JDLA5E3 0005EFr 2 .byte $01 0005EFr 2 0005EFr 2 .else 0005EFr 2 AD 1F 91 lda TAPE_REG_SENSE 0005F2r 2 29 40 and #TAPE_B_SENSE 0005F4r 2 F0 0B beq @LEA71 0005F6r 2 A0 00 ldy #$00 0005F8r 2 84 rr sty zCAS1 0005FAr 2 AD 1C 91 lda TAPE_REG_MOTOR 0005FDr 2 09 02 ora #TAPE_B_MOTOR_ON 0005FFr 2 D0 09 bne @LEA79 000601r 2 ; ------------------------- 000601r 2 000601r 2 A5 rr @LEA71: lda zCAS1 000603r 2 D0 0D bne LEA7B 000605r 2 AD 1C 91 lda TAPE_REG_MOTOR 000608r 2 29 FD and #TAPE_B_MOTOR_OFF_AND 00060Ar 2 @LEA79: 00060Ar 2 .if CompileComputer < C64_GENERAL 00060Ar 2 2C 1E 91 bit VIA1_IEC 00060Dr 2 70 03 bvs LEA7B 00060Fr 2 .endif 00060Fr 2 8D 1C 91 sta TAPE_REG_MOTOR 000612r 2 000612r 2 .endif 000612r 2 000612r 2 LEA7B: 000612r 2 .if CompileComputer = C64_4064 000612r 2 jsr LE4C8 000612r 2 .else 000612r 2 20 rr rr jsr iSCNKEY 000615r 2 .endif 000615r 2 000615r 2 .if CompileComputer >= C64_GENERAL 000615r 2 lda CIA1 + CIA_O_ICR 000615r 2 .else 000615r 2 2C 24 91 bit VIA2_T1CL 000618r 2 .endif 000618r 2 68 pla 000619r 2 A8 tay 00061Ar 2 68 pla 00061Br 2 AA tax 00061Cr 2 68 pla 00061Dr 2 40 rti 00061Er 2 00061Er 2 ; B-25. Function Name: SCNKEY 00061Er 2 ; 00061Er 2 ; Purpose: Scan the keyboard 00061Er 2 ; Call address: $FF9F (hex) 65439 (decimal) 00061Er 2 ; Communication registers: None 00061Er 2 ; Preparatory routines: IOINIT 00061Er 2 ; Error returns: None 00061Er 2 ; Stack requirements: 5 00061Er 2 ; Registers affected: A, X, Y 00061Er 2 ; 00061Er 2 ; Description: This routine scans the Commodore 64 keyboard and checks 00061Er 2 ; for pressed keys. It is the same routine called by the interrupt handler. 00061Er 2 ; If a key is down, its ASCII value is placed in the keyboard queue. This 00061Er 2 ; routine is called only if the normal IRQ interrupt is bypassed. 00061Er 2 ; 00061Er 2 ; How to Use: 00061Er 2 ; 00061Er 2 ; 1) Call this routine. 00061Er 2 ; 00061Er 2 ; EXAMPLE: 00061Er 2 ; 00061Er 2 ; GET JSR SCNKEY ;SCAN KEYBOARD 00061Er 2 ; JSR GETIN ;GET CHARACTER 00061Er 2 ; CMP #0 ;IS IT NULL? 00061Er 2 ; BEQ GET ;YES... SCAN AGAIN 00061Er 2 ; JSR CHROUT ;PRINT IT 00061Er 2 ; 00061Er 2 ; 00061Er 2 iSCNKEY: 00061Er 2 A9 00 lda #0 ; start with: No shift key (SHIFT, CTRL, CBM) is pressed 000620r 2 8D rr rr sta lSHFLAG 000623r 2 000623r 2 A0 40 ldy #KEY_NONE ; start with: No key pressed 000625r 2 84 rr sty zSFDX 000627r 2 000627r 2 ; check if any key is pressed at all 000627r 2 8D 20 91 sta KEYB_ROW ; set all rows to 0 00062Ar 2 AE 21 91 ldx KEYB_COL ; get columns 00062Dr 2 E0 FF cpx #$FF ; everything set? 00062Fr 2 F0 5E beq iSCNKEY_EndScan ; yes, no key is pressed, abort. 000631r 2 ; Note that X = $FF is crucial here, as iSCNKEY_EndScan checked for the keycode (in X). If there were anything else in X, then this would be used as keycode and stored into the keyboard buffer 000631r 2 000631r 2 .if CompileComputer >= C64_GENERAL 000631r 2 tay ; Place of the key pressed in the KEYTAB (stored in Y) = 0 000631r 2 .else 000631r 2 A9 FE lda #~$01 ; start at row 0 (2^0) 000633r 2 8D 20 91 sta KEYB_ROW 000636r 2 A0 00 ldy #$00 ; Place of the key pressed in the KEYTAB (stored in Y) = 0 000638r 2 .endif 000638r 2 A9 rr lda #KEYTAB_UNSHIFTED 00063Er 2 85 rr sta zKEYTAB + 1 000640r 2 000640r 2 .if CompileComputer >= C64_GENERAL 000640r 2 lda #~$01 ; start at row 0 (2^0) 000640r 2 sta KEYB_ROW 000640r 2 .endif 000640r 2 000640r 2 @CheckAllRows: 000640r 2 A2 08 ldx #8 ; process every of the 8 keyboard columns 000642r 2 000642r 2 .if CompileComputer >= C64_GENERAL 000642r 2 pha ; remember the mask we put into KEYB_ROW for later processing 000642r 2 .endif 000642r 2 000642r 2 @UnbounceColumns: 000642r 2 AD 21 91 lda KEYB_COL ; get column 000645r 2 CD 21 91 cmp KEYB_COL ; unbounce it 000648r 2 .if CompileComputer >= C64_GENERAL 000648r 2 bne @UnbounceColumns ; if it changed between reading, re-read it 000648r 2 .else 000648r 2 D0 F6 bne @CheckAllRows ; if colum changed between reading, re-read it. The LDX #8 does not do any harm here; however, for the additional PHA on the C64, we would corrupt the stack. Thus, the target of the branch was changed on the C64. 00064Ar 2 00064Ar 2 .endif 00064Ar 2 00064Ar 2 ; the following loop tests each column one after one if the bit was 0 00064Ar 2 ; if it was, the key on the row/column was pressed. 00064Ar 2 ; This is not completely right if more than one key was pressed, 00064Ar 2 ; but this is a hardware limitation we cannot handle. 00064Ar 2 00064Ar 2 @ProcessColumn: 00064Ar 2 4A lsr a ; get bit from column into C 00064Br 2 B0 16 bcs @KeyNotPressed ; C set -> jump, key was not pressed 00064Dr 2 00064Dr 2 48 pha ; remember current column mask 00064Er 2 00064Er 2 B1 rr lda (zKEYTAB),y ; get the key code that corresponds to the current row/column 000650r 2 C9 05 cmp #5 ; is it >= 5? 000652r 2 B0 0C bcs @StoreKey ; yes, it is a printable char, branch in order to store it 000654r 2 C9 03 cmp #KEY_STOP ; is it the Run/Stop key? 000656r 2 F0 08 beq @StoreKey ; yes, store it 000658r 2 000658r 2 ; if we reached here, the character code is 1, 2, or 4: One of the keys shift or CBM 000658r 2 ; thus, remember the shift flag 000658r 2 000658r 2 0D rr rr ora lSHFLAG ; set the corresponding flag 00065Br 2 8D rr rr sta lSHFLAG ; 00065Er 2 00065Er 2 10 02 bpl @DoNotStoreKey ; unconditional jump, as lSHFLAG.7 is never set. 000660r 2 ; ---------------------------- 000660r 2 000660r 2 @StoreKey: 000660r 2 84 rr sty zSFDX ; remember key code 000662r 2 000662r 2 @DoNotStoreKey: 000662r 2 68 pla ; get back column mask 000663r 2 000663r 2 @KeyNotPressed: 000663r 2 C8 iny ; this keytable entry was processed, go to the next one 000664r 2 C0 41 cpy #$41 ; did we already process all $40 entries? 000666r 2 B0 09 bcs @EndScanning ; yes, we are done (for now) 000668r 2 000668r 2 CA dex ; decrement the column counter 000669r 2 D0 DF bne @ProcessColumn ; and repeat scanning, if the counter did not reach 0. 00066Br 2 00066Br 2 ; The following code rotates the mask at KEYB_ROW to the left. 00066Br 2 ; This moves the "0" bit from right to left. 00066Br 2 ; Thus, every row is processed, one after the other. 00066Br 2 ; The implementation was changed between VIC20 and C64, though: 00066Br 2 ; While the VIC20 uses a ROL on the KEYB_ROW address directly, 00066Br 2 ; the C64 performs the ROL in a register and puts the value into 00066Br 2 ; KEYB_ROW afterwards. 00066Br 2 ; This change most likely occurred since ROL is a read-modify-write 00066Br 2 ; instruction. Thus, it will write to the location two times, in two 00066Br 2 ; consecutives cycles: First, it will write the old value, and after- 00066Br 2 ; wards, it will write the new one. This might generate some "spike" 00066Br 2 ; which could inadvertedly affect the reading. 00066Br 2 00066Br 2 38 sec ; make sure to ROL in a "1" bit 00066Cr 2 00066Cr 2 .if CompileComputer >= C64_GENERAL 00066Cr 2 pla ; get back the mask we put at KEYB_ROW last time 00066Cr 2 rol a ; rotate it to the left 00066Cr 2 sta KEYB_ROW ; and set the new mask 00066Cr 2 .else 00066Cr 2 2E 20 91 rol KEYB_ROW ; rotate to mask to the left 00066Fr 2 .endif 00066Fr 2 D0 CF bne @CheckAllRows 000671r 2 000671r 2 @EndScanning: 000671r 2 000671r 2 .if CompileComputer >= C64_GENERAL 000671r 2 pla ; we do not need the mask we put at KEYB_ROW last time anymore, remove it 000671r 2 .endif 000671r 2 000671r 2 ; Essentially, we are done with scanning here. However, we have to determine 000671r 2 ; if a shift key (SHIFT, C=, CTRL) was pressed, which changes the meaning of 000671r 2 ; some keys. Thus, process the shift keys now. 000671r 2 6C rr rr jmp (lKEYLOG) ; points to CHECK_SHIFT_CTRL_CBM 000674r 2 000674r 2 ConvertRawKeycodeToInterpretedKeycode: 000674r 2 A4 rr ldy zSFDX ; get the character code 000676r 2 B1 rr lda (zKEYTAB),y ; and read in the right ASCII value of it according to the right KEYTAB 000678r 2 AA tax 000679r 2 000679r 2 C4 rr cpy zLSTX 00067Br 2 F0 07 beq @CheckRepeat 00067Dr 2 A0 10 ldy #$10 00067Fr 2 8C rr rr sty lDELAY 000682r 2 D0 36 bne StoreKeyCodeIntoKeyBuffer 000684r 2 000684r 2 @CheckRepeat: 000684r 2 29 7F and #$7F ; ignore bit 7 of key (TODO why?) 000686r 2 000686r 2 ; determine if the key press is to be repeated 000686r 2 000686r 2 2C rr rr bit lRPTFLG ; check repeat flag 000689r 2 30 16 bmi RepeatKey ; bit 7 set, repeat all keys --> branch 00068Br 2 70 49 bvs RestoreKeyboardRowAndRet ; bit 6 set, do not repeat any key --> branch 00068Dr 2 00068Dr 2 C9 7F cmp #$7F ; Is this the key ... (TODO Which key is this?) 00068Fr 2 00068Fr 2 iSCNKEY_EndScan: 00068Fr 2 F0 29 beq StoreKeyCodeIntoKeyBuffer ; Yes, branch -> Store the key into the keyboard buffer 000691r 2 ; TODO Why this extra handling? 000691r 2 000691r 2 C9 14 cmp #ASC_INSDEL ; did the user press INS/DEL? 000693r 2 F0 0C beq RepeatKey ; yes, branch -> process repetition 000695r 2 000695r 2 C9 20 cmp #' ' ; did the user press SPACE (" "), or shifted SPACE ($A0)? 000697r 2 F0 08 beq RepeatKey ; yes, process the repetition 000699r 2 000699r 2 C9 1D cmp #ASC_CURSORLEFTRIGHT ; did the user press CRSR LEFT/CRSR RIGHT key? 00069Br 2 F0 04 beq RepeatKey ; yes, branch -> process the repetition 00069Dr 2 00069Dr 2 C9 11 cmp #ASC_CURSORUPDOWN ; did the user press CRSR LEFT/CRSR RIGHT key? 00069Fr 2 D0 35 bne RestoreKeyboardRowAndRet ; no, branch -> do not store the key at all 0006A1r 2 0006A1r 2 RepeatKey: 0006A1r 2 0006A1r 2 ; wait for the initial delay counter lDELAY 0006A1r 2 0006A1r 2 ; For key repetitions, there are two delay: One is the initial delay, that is, 0006A1r 2 ; how long must a key be pressed before the repetition takes place. 0006A1r 2 ; This is counted by lDELAY. 0006A1r 2 0006A1r 2 ; The other delay is the counter between repeated keys, if the key is hold 0006A1r 2 ; long enough. This is counted by lKOUNT. 0006A1r 2 0006A1r 2 AC rr rr ldy lDELAY ; is there an initial delay? 0006A4r 2 F0 05 beq @NoInitialDelay ; no, repeat immediately 0006A6r 2 0006A6r 2 CE rr rr dec lDELAY ; yes, decrement the initial delay counter 0006A9r 2 D0 2B bne RestoreKeyboardRowAndRet ; still not delayed enough -> branch, do nothing 0006ABr 2 0006ABr 2 @NoInitialDelay: 0006ABr 2 CE rr rr dec lKOUNT ; decrement the delay counter 0006AEr 2 D0 26 bne RestoreKeyboardRowAndRet ; not yet 0, do nothing 0006B0r 2 0006B0r 2 A0 04 ldy #$04 ; restore the delay counter 0006B2r 2 8C rr rr sty lKOUNT 0006B5r 2 0006B5r 2 ; test if the keyboard buffer is empty. 0006B5r 2 ; if it is not empty, no key repetition will take place. 0006B5r 2 0006B5r 2 ; this way, we prevent a full keyboard buffer with repeated keys, 0006B5r 2 ; which would not be a good user experience (we repeat keys faster 0006B5r 2 ; than the program can handle them) 0006B5r 2 0006B5r 2 A4 rr ldy zNDX ; number of keys in keyboard buffer 0006B7r 2 88 dey ; - 1 0006B8r 2 10 1C bpl RestoreKeyboardRowAndRet ; still > 0? Then, the buffer is not empty -> branch, do nothing 0006BAr 2 0006BAr 2 StoreKeyCodeIntoKeyBuffer: 0006BAr 2 0006BAr 2 ; Store key code in X into keybuffer 0006BAr 2 0006BAr 2 ; remember key code for the next call of the keyboard routines. 0006BAr 2 ; this is used for determining if a key was pressed for a longer time 0006BAr 2 ; and if it has to be repeated, or not. 0006BAr 2 A4 rr ldy zSFDX 0006BCr 2 84 rr sty zLSTX 0006BEr 2 0006BEr 2 ; remember shift states for the next call of the keyboard routines. 0006BEr 2 ; this way, we prevent that SHIFT-CBM is processed more than once, as 0006BEr 2 ;it is only processed if the shift state changed. 0006BEr 2 AC rr rr ldy lSHFLAG 0006C1r 2 8C rr rr sty lLSTSHF 0006C4r 2 0006C4r 2 E0 FF cpx #$FF ; is the key an invalid one ($FF in the keyboard tables?) 0006C6r 2 F0 0E beq RestoreKeyboardRowAndRet ; yes, branch -> do not store it 0006C8r 2 8A txa 0006C9r 2 0006C9r 2 ; here, we store the keycode that is in A into the keyboard buffer 0006C9r 2 ; Note that this routine will generate a race in case it is called w/o 0006C9r 2 ; interrupts disabled 0006C9r 2 0006C9r 2 A6 rr ldx zNDX ; get the index into the keyboard buffer 0006CBr 2 EC rr rr cpx lXMAX ; is the buffer full? 0006CEr 2 B0 06 bcs RestoreKeyboardRowAndRet ; yes, branch -> do not store the key 0006D0r 2 9D rr rr sta lKEYD,x ; store the keycode into the buffer 0006D3r 2 E8 inx ; increment the number of keys in the buffer 0006D4r 2 86 rr stx zNDX ; and store it 0006D6r 2 0006D6r 2 RestoreKeyboardRowAndRet: 0006D6r 2 A9 F7 lda #KEYB_ROW_STANDARD ; restore the keyboard row 0006D8r 2 8D 20 91 sta KEYB_ROW 0006DBr 2 60 rts 0006DCr 2 0006DCr 2 0006DCr 2 CHECK_SHIFT_CTRL_CBM: 0006DCr 2 0006DCr 2 ; Determine if a shift key (SHIFT, C=, CTRL) was pressed, which changes 0006DCr 2 ; the meaning of some keys. 0006DCr 2 0006DCr 2 AD rr rr lda lSHFLAG ; get the shift state 0006DFr 2 C9 03 cmp #lSHFLAG_SHIFT | lSHFLAG_CBM ; shift and commodore pressed? 0006E1r 2 D0 2C bne @SwitchToShiftedKeyTable ; no, branch -> process a shifted key table instead 0006E3r 2 0006E3r 2 CD rr rr cmp lLSTSHF ; yes, check if the state changed from the last scan 0006E6r 2 F0 EE beq RestoreKeyboardRowAndRet ; it's the same state, branch -> do nothing 0006E8r 2 0006E8r 2 ; If we reach here, SHIFT and C= were pressed simultaneously. 0006E8r 2 ; Thus, the user wants to switch between Uppercase+Graphics mode, 0006E8r 2 ; and Lowercase + Uppercase mode. 0006E8r 2 0006E8r 2 AD rr rr lda lMODE ; are we allowed to switch modes? 0006EBr 2 30 56 bmi @ConvertRawKeycodeToInterpretedKeycode ; no, branch -> skip 0006EDr 2 0006EDr 2 .if CompileComputer >= C64_GENERAL 0006EDr 2 0006EDr 2 ; we change mode by changing the base address of the character ROM in the VIC-II 0006EDr 2 0006EDr 2 lda VIC + VICII_O_MemControl 0006EDr 2 eor #$02 0006EDr 2 sta VIC + VICII_O_MemControl 0006EDr 2 .elseif CompileComputer >= VIC20_06 0006EDr 2 EA EA EA EA .repeat 19 0006F1r 2 EA EA EA EA 0006F5r 2 EA EA EA EA 000700r 2 nop 000700r 2 .endrep 000700r 2 000700r 2 ; we change mode by changing the base address of the character ROM in the VIC-II 000700r 2 000700r 2 AD 05 90 lda VIC + VICI_O_MemoryLocations 000703r 2 49 02 eor #$02 000705r 2 8D 05 90 sta VIC + VICI_O_MemoryLocations 000708r 2 000708r 2 EA EA EA EA .repeat 4 00070Cr 2 nop 00070Cr 2 .endrep 00070Cr 2 .else 00070Cr 2 ; this is just a complicated way to EOR VICI_O_MemoryLocations with $02 00070Cr 2 ; furthermore, it keeps track if the state in lMODE.4 ($10) 00070Cr 2 00070Cr 2 and #$18 ; determine current mode 00070Cr 2 beq @SwitchToLowercase ; it is uppercase, branch -> switch to lowercase 00070Cr 2 00070Cr 2 ; if we reach here, we are in lowercase mode and want to switch to uppercase mode 00070Cr 2 00070Cr 2 ; remember uppercase mode 00070Cr 2 lda #$00 00070Cr 2 sta lMODE 00070Cr 2 00070Cr 2 ; switch VIC to uppercase mode 00070Cr 2 lda VIC + VICI_O_MemoryLocations 00070Cr 2 and #~$02 00070Cr 2 sta VIC + VICI_O_MemoryLocations 00070Cr 2 00070Cr 2 bne @ConvertRawKeycodeToInterpretedKeycode ; unconditional branch 00070Cr 2 ; -------------- 00070Cr 2 00070Cr 2 @SwitchToLowercase: 00070Cr 2 ; switch VIC to lowercase mode 00070Cr 2 lda VIC + VICI_O_MemoryLocations 00070Cr 2 ora #$02 00070Cr 2 sta VIC + VICI_O_MemoryLocations 00070Cr 2 00070Cr 2 ; remember lowercase mode 00070Cr 2 lda #$08 00070Cr 2 sta lMODE 00070Cr 2 .endif 00070Cr 2 00070Cr 2 .if CompileComputer = VIC20_02 00070Cr 2 bne @ConvertRawKeycodeToInterpretedKeycode ; unconditional jump 00070Cr 2 .else 00070Cr 2 4C rr rr jmp @ConvertRawKeycodeToInterpretedKeycode 00070Fr 2 .endif 00070Fr 2 ; --------------------------- 00070Fr 2 00070Fr 2 @SwitchToShiftedKeyTable: 00070Fr 2 00070Fr 2 ; (here, we enter with A := lSHFLAG) 00070Fr 2 00070Fr 2 ; Calculate the offset of the key table for the shift flags 00070Fr 2 ; this is done by doubling the value of lSHFLAG, and special 00070Fr 2 ; handling of lSHFLAG_CTRL which would double to 8, but 6 is 00070Fr 2 ; the right offset 00070Fr 2 00070Fr 2 0A asl a ; double shift flag 000710r 2 C9 08 cmp #2 * lSHFLAG_CTRL ; is it CTRL? 000712r 2 90 04 bcc @UseOffset ; no, use the offset 000714r 2 A9 06 lda #$06 ; yes, correct the offset 000716r 2 000716r 2 .if CompileComputer >= C64_GENERAL 000716r 2 .elseif CompileComputer >= VIC20_06 000716r 2 EA nop 000717r 2 EA nop 000718r 2 .else 000718r 2 bne @VIC20_02_HandleOffsetDirectly ; for VIC-20-02, use this offset. (unconditional branch) 000718r 2 ; ------------------------------------ 000718r 2 .endif 000718r 2 000718r 2 @UseOffset: 000718r 2 000718r 2 .if CompileComputer >= C64_GENERAL 000718r 2 000718r 2 .elseif CompileComputer >= VIC20_06 000718r 2 EA EA EA EA .repeat 32 00071Cr 2 EA EA EA EA 000720r 2 EA EA EA EA 000738r 2 nop 000738r 2 .endrep 000738r 2 .else 000738r 2 000738r 2 ldx lMODE ; if lMODE = 0, use the offset 000738r 2 beq @VIC20_02_HandleOffsetDirectly 000738r 2 000738r 2 ldx lSHFLAG ; if C= key is not the only shift key pressed: 000738r 2 cpx #lSHFLAG_CBM 000738r 2 bne @VIC20_02_HandleOffsetDirectly ; branch -> handle the offset 000738r 2 000738r 2 ; if we reach here, the C= key is pressed (but not SHIFT or CTRL) 000738r 2 000738r 2 cpx lLSTSHF ; did the shift state change from the last time? 000738r 2 beq @ConvertRawKeycodeToInterpretedKeycode ; no, just convert the key code. 000738r 2 000738r 2 ; TODO 000738r 2 ; switch uppercase mode with lowercase mode (why?) 000738r 2 ; switch bit 4 (???) (why?) 000738r 2 ; but do not update the VIC itself (why?) 000738r 2 000738r 2 lda lMODE 000738r 2 eor #$18 000738r 2 sta lMODE 000738r 2 000738r 2 bpl @ConvertRawKeycodeToInterpretedKeycode ; branches if lMODE.7 is 0: switching between uppercase-mode and lowercase-mode is allowed. (TODO why?) 000738r 2 000738r 2 @VIC20_02_HandleOffsetDirectly: 000738r 2 ora lMODE ; get the offset into KEYTABS_VEC 000738r 2 and #$7F 000738r 2 .endif 000738r 2 000738r 2 AA tax ; X := offset into KEYTABS_VEC 000739r 2 000739r 2 ; switch to the right KEYTAB according to the shift states 000739r 2 000739r 2 BD rr rr lda @KEYTABS_VEC,x 00073Cr 2 85 rr sta zKEYTAB 00073Er 2 BD rr rr lda @KEYTABS_VEC + 1,x 000741r 2 85 rr sta zKEYTAB + 1 000743r 2 000743r 2 @ConvertRawKeycodeToInterpretedKeycode: 000743r 2 4C rr rr jmp ConvertRawKeycodeToInterpretedKeycode 000746r 2 000746r 2 @KEYTABS_VEC: 000746r 2 rr rr .addr KEYTAB_UNSHIFTED ; $00 000748r 2 rr rr .addr KEYTAB_SHIFT ; $02 (lSHFLAG=$01, SHIFT) 00074Ar 2 rr rr .addr KEYTAB_CBM ; $04 (lSHFLAG=$02, C=) 00074Cr 2 rr rr .addr KEYTAB_CTRL ; $06 (lSHFLAG=$04, CTRL) 00074Er 2 00074Er 2 .if CompileComputer < C64_GENERAL 00074Er 2 00074Er 2 ; these keytabs are only used in the VIC20-02 ROM, but they 00074Er 2 ; are still present in the later ones. 00074Er 2 00074Er 2 ; these 4 tables are used if we are in lowercase mode 00074Er 2 rr rr .addr KEYTAB_UNSHIFTED ; $08 000750r 2 rr rr .addr KEYTAB_SHIFT ; $0A 000752r 2 rr rr .addr KEYTAB6 ; $0C 000754r 2 rr rr .addr KEYTAB_CTRL ; $0E 000756r 2 000756r 2 rr rr .addr KEYTAB5 ; $10 000758r 2 rr rr .addr KEYTAB6 ; $12 00075Ar 2 rr rr .addr KEYTAB6 ; $14 00075Cr 2 rr rr .addr KEYTAB_CTRL ; $16 00075Er 2 00075Er 2 .endif 00075Er 2 00075Er 2 KEYTAB_UNSHIFTED: 00075Er 2 00075Er 2 .if CompileComputer >= C64_GENERAL 00075Er 2 00075Er 2 .byte $14,$0D,$1D,$88,$85,$86,$87,$11 00075Er 2 .byte $33,$57,$41,$34,$5A,$53,$45,$01 00075Er 2 .byte $35,$52,$44,$36,$43,$46,$54,$58 00075Er 2 .byte $37,$59,$47,$38,$42,$48,$55,$56 00075Er 2 00075Er 2 .byte $39,$49,$4A,$30,$4D,$4B,$4F,$4E 00075Er 2 .byte $2B,$50,$4C,$2D,$2E,$3A,$40,$2C 00075Er 2 .byte $5C,$2A,$3B,$13,$01,$3D,$5E,$2F 00075Er 2 .byte $31,$5F,$04,$32,$20,$02,$51,$03 00075Er 2 .byte $FF 00075Er 2 00075Er 2 .else 00075Er 2 00075Er 2 31 33 35 37 .byte $31,$33,$35,$37,$39,$2B,$5C,$14 000762r 2 39 2B 5C 14 000766r 2 5F 57 52 59 .byte $5F,$57,$52,$59,$49,$50,$2A,$0D 00076Ar 2 49 50 2A 0D 00076Er 2 04 41 44 47 .byte $04,$41,$44,$47,$4A,$4C,$3B,$1D 000772r 2 4A 4C 3B 1D 000776r 2 03 01 58 56 .byte $03,$01,$58,$56,$4E,$2C,$2F,$11 00077Ar 2 4E 2C 2F 11 00077Er 2 00077Er 2 20 5A 43 42 .byte $20,$5A,$43,$42,$4D,$2E,$01,$85 000782r 2 4D 2E 01 85 000786r 2 02 53 46 48 .byte $02,$53,$46,$48,$4B,$3A,$3D,$86 00078Ar 2 4B 3A 3D 86 00078Er 2 51 45 54 55 .byte $51,$45,$54,$55,$4F,$40,$5E,$87 000792r 2 4F 40 5E 87 000796r 2 32 34 36 38 .byte $32,$34,$36,$38,$30,$2D,$13,$88 00079Ar 2 30 2D 13 88 00079Er 2 00079Er 2 FF .byte $FF 00079Fr 2 00079Fr 2 .endif 00079Fr 2 00079Fr 2 KEYTAB_SHIFT: 00079Fr 2 00079Fr 2 .if CompileComputer >= C64_GENERAL 00079Fr 2 00079Fr 2 .if .defined(C64JAPAN) 00079Fr 2 .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 00079Fr 2 .byte $23,$A8,$AA,$24,$AD,$AB,$A9,$01 00079Fr 2 .byte $25,$A5,$AC,$26,$AF,$A4,$FF,$AE 00079Fr 2 .byte $27,$FF,$FF,$28,$FF,$FF,$FF,$FF 00079Fr 2 00079Fr 2 .byte $29,$FF,$FF,$30,$FF,$FF,$FF,$FF 00079Fr 2 .byte $A1,$FF,$FF,$A2,$3E,$5B,$FF,$3C 00079Fr 2 .byte $A3,$FF,$5D,$93,$01,$3D,$B0,$3F 00079Fr 2 .byte $21,$5F,$04,$22,$A0,$02,$A7,$83 00079Fr 2 .byte $FF 00079Fr 2 .else 00079Fr 2 .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 00079Fr 2 .byte $23,$D7,$C1,$24,$DA,$D3,$C5,$01 00079Fr 2 .byte $25,$D2,$C4,$26,$C3,$C6,$D4,$D8 00079Fr 2 .byte $27,$D9,$C7,$28,$C2,$C8,$D5,$D6 00079Fr 2 00079Fr 2 .byte $29,$C9,$CA,$30,$CD,$CB,$CF,$CE 00079Fr 2 .byte $DB,$D0,$CC,$DD,$3E,$5B,$BA,$3C 00079Fr 2 .byte $A9,$C0,$5D,$93,$01,$3D,$DE,$3F 00079Fr 2 .byte $21,$5F,$04,$22,$A0,$02,$D1,$83 00079Fr 2 .byte $FF 00079Fr 2 .endif 00079Fr 2 00079Fr 2 00079Fr 2 .else 00079Fr 2 00079Fr 2 21 23 25 27 .byte $21,$23,$25,$27,$29 0007A3r 2 29 0007A4r 2 .if CompileComputer >= VIC20_06 0007A4r 2 DB A9 .byte $DB,$A9 0007A6r 2 .else 0007A6r 2 .byte $AB,$DC 0007A6r 2 .endif 0007A6r 2 94 .byte $94 0007A7r 2 0007A7r 2 .if CompileComputer >= VIC20_06 0007A7r 2 5F .byte $5F 0007A8r 2 .else 0007A8r 2 .byte $DF 0007A8r 2 .endif 0007A8r 2 D7 D2 D9 C9 .byte $D7,$D2,$D9,$C9,$D0 0007ACr 2 D0 0007ADr 2 .if CompileComputer >= VIC20_06 0007ADr 2 C0 .byte $C0 0007AEr 2 .else 0007AEr 2 .byte $AA 0007AEr 2 .endif 0007AEr 2 8D .byte $8D 0007AFr 2 0007AFr 2 04 C1 C4 C7 .byte $04,$C1,$C4,$C7,$CA,$CC,$5D,$9D 0007B3r 2 CA CC 5D 9D 0007B7r 2 83 01 D8 D6 .byte $83,$01,$D8,$D6,$CE,$3C,$3F,$91 0007BBr 2 CE 3C 3F 91 0007BFr 2 0007BFr 2 A0 DA C3 C2 .byte $A0,$DA,$C3,$C2,$CD,$3E,$01,$89 0007C3r 2 CD 3E 01 89 0007C7r 2 02 D3 C6 C8 .byte $02,$D3,$C6,$C8,$CB,$5B 0007CBr 2 CB 5B 0007CDr 2 .if CompileComputer >= VIC20_06 0007CDr 2 3D .byte $3D 0007CEr 2 .else 0007CEr 2 .byte $BD 0007CEr 2 .endif 0007CEr 2 8A .byte $8A 0007CFr 2 0007CFr 2 D1 C5 D4 D5 .byte $D1,$C5,$D4,$D5,$CF 0007D3r 2 CF 0007D4r 2 .if CompileComputer >= VIC20_06 0007D4r 2 BA .byte $BA 0007D5r 2 .else 0007D5r 2 .byte $C0 0007D5r 2 .endif 0007D5r 2 DE 8B .byte $DE,$8B 0007D7r 2 0007D7r 2 22 24 26 28 .byte $22,$24,$26,$28 0007DBr 2 .if CompileComputer >= VIC20_06 0007DBr 2 30 DD .byte $30,$DD 0007DDr 2 .else 0007DDr 2 .byte $B0,$AD 0007DDr 2 .endif 0007DDr 2 93 8C .byte $93,$8C 0007DFr 2 0007DFr 2 FF .byte $FF 0007E0r 2 0007E0r 2 .endif 0007E0r 2 0007E0r 2 KEYTAB_CBM: 0007E0r 2 0007E0r 2 .if CompileComputer >= C64_GENERAL 0007E0r 2 0007E0r 2 .if .defined(C64JAPAN) 0007E0r 2 .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 0007E0r 2 .byte $B1,$C3,$C1,$B3,$C2,$C4,$B2,$01 0007E0r 2 .byte $B4,$BD,$BC,$B5,$BF,$CA,$B6,$BB 0007E0r 2 .byte $D4,$DD,$B7,$D5,$BA,$B8,$C5,$CB 0007E0r 2 0007E0r 2 .byte $D6,$C6,$CF,$DC,$D3,$C9,$D7,$D0 0007E0r 2 .byte $CE,$BE,$D8,$CD,$D9,$DA,$DB,$C8 0007E0r 2 .byte $A6,$DE,$B9,$93,$01,$D1,$DF,$D2 0007E0r 2 .byte $C7,$5F,$04,$CC,$A0,$02,$C0,$83 0007E0r 2 .byte $FF 0007E0r 2 .else 0007E0r 2 .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 0007E0r 2 .byte $96,$B3,$B0,$97,$AD,$AE,$B1,$01 0007E0r 2 .byte $98,$B2,$AC,$99,$BC,$BB,$A3,$BD 0007E0r 2 .byte $9A,$B7,$A5,$9B,$BF,$B4,$B8,$BE 0007E0r 2 0007E0r 2 .byte $29,$A2,$B5,$30,$A7,$A1,$B9,$AA 0007E0r 2 .byte $A6,$AF,$B6,$DC,$3E,$5B,$A4,$3C 0007E0r 2 .byte $A8,$DF,$5D,$93,$01,$3D,$DE,$3F 0007E0r 2 .byte $81,$5F,$04,$95,$A0,$02,$AB,$83 0007E0r 2 .byte $FF 0007E0r 2 .endif 0007E0r 2 0007E0r 2 .elseif CompileComputer = VIC20_02 0007E0r 2 .byte $B1,$B3,$B5,$B7,$B9,$AB,$DC,$94 0007E0r 2 .byte $DF,$D7,$D2,$D9,$C9,$D0,$AA,$8D 0007E0r 2 .byte $04,$C1,$C4,$C7,$CA,$CC,$BB,$9D 0007E0r 2 .byte $83,$01,$D8,$D6,$CE,$AC,$AF,$91 0007E0r 2 0007E0r 2 .byte $0A,$DA,$C3,$C2,$CD,$AE,$01,$FF 0007E0r 2 .byte $02,$D3,$C6,$C8,$CB,$BA,$BD,$FF 0007E0r 2 .byte $D1,$C5,$D4,$D5,$CF,$C0,$DE,$FF 0007E0r 2 .byte $B2,$B4,$B6,$B8,$B0,$AD,$93,$FF 0007E0r 2 .byte $FF 0007E0r 2 .else 0007E0r 2 21 23 25 27 .byte $21,$23,$25,$27,$29,$A6,$A8,$94 0007E4r 2 29 A6 A8 94 0007E8r 2 5F B3 B2 B7 .byte $5F,$B3,$B2,$B7,$A2,$AF,$DF,$8D 0007ECr 2 A2 AF DF 8D 0007F0r 2 04 B0 AC A5 .byte $04,$B0,$AC,$A5,$B5,$B6,$5D,$9D 0007F4r 2 B5 B6 5D 9D 0007F8r 2 83 01 BD BE .byte $83,$01,$BD,$BE,$AA,$3C,$3F,$91 0007FCr 2 AA 3C 3F 91 000800r 2 000800r 2 A0 AD BC BF .byte $A0,$AD,$BC,$BF,$A7,$3E,$01,$89 000804r 2 A7 3E 01 89 000808r 2 02 AE BB B4 .byte $02,$AE,$BB,$B4,$A1,$5B,$3D,$8A 00080Cr 2 A1 5B 3D 8A 000810r 2 AB B1 A3 B8 .byte $AB,$B1,$A3,$B8,$B9,$A4,$DE,$8B 000814r 2 B9 A4 DE 8B 000818r 2 22 24 26 28 .byte $22,$24,$26,$28,$30,$DC,$93,$8C 00081Cr 2 30 DC 93 8C 000820r 2 FF .byte $FF 000821r 2 .endif 000821r 2 000821r 2 .if CompileComputer >= VIC20_06 000821r 2 000821r 2 KEYTAB5: ; unused, but references for VIC20-06 and -07 000821r 2 000821r 2 EditorCheckForAscLowercase: 000821r 2 C9 0E cmp #ASC_LOWERCASE ; if this the code to change to lowercase chars? 000823r 2 D0 0B bne EditorCheckForAscUppercase ; no, test for the next code 000825r 2 000825r 2 ; set the VIC memory control byte to point to the lowercase characters: 000825r 2 000825r 2 .if CompileComputer >= C64_GENERAL 000825r 2 lda VIC + VICII_O_MemControl 000825r 2 ora #2 000825r 2 bne EditorSta_vMemControl ; sta VIC + VICII_O_MemControl ; this bne saves one byte 000825r 2 .else 000825r 2 A9 02 lda #2 000827r 2 0D 05 90 ora VIC + VICI_O_MemoryLocations 00082Ar 2 8D 05 90 sta VIC + VICI_O_MemoryLocations 00082Dr 2 4C rr rr jmp CHROUT_SCREEN_END ; we're done 000830r 2 ; this JMP is not necessary, but does not do any harm, either. 000830r 2 ; It has been removed from the C64 ROMs, presumably to save space. 000830r 2 .endif 000830r 2 000830r 2 EditorCheckForAscUppercase: 000830r 2 C9 8E cmp #ASC_UPPERCASE ; if this the code to change to lowercase chars? 000832r 2 D0 0B bne EditorCheckForDisallowLowercase ; no, test for the next code 000834r 2 000834r 2 ; set the VIC memory control byte to point to the uppercase characters: 000834r 2 000834r 2 .if CompileComputer >= C64_GENERAL 000834r 2 lda VIC + VICII_O_MemControl 000834r 2 and #~2 000834r 2 EditorSta_vMemControl: 000834r 2 sta VIC + VICII_O_MemControl 000834r 2 .else 000834r 2 A9 FD lda #~2 000836r 2 2D 05 90 and VIC + VICI_O_MemoryLocations 000839r 2 8D 05 90 sta VIC + VICI_O_MemoryLocations 00083Cr 2 .endif 00083Cr 2 00083Cr 2 EditorChroutScreenEnd: 00083Cr 2 4C rr rr jmp CHROUT_SCREEN_END 00083Fr 2 ; ---------------------------- 00083Fr 2 00083Fr 2 EditorCheckForDisallowLowercase: 00083Fr 2 C9 08 cmp #ASC_DISALLOW_LOWERCASE ; if this the code to disallow changing to lowercase mode via keyboard? 000841r 2 D0 0A bne @CheckForAllowLowercase ; no, test for the next code 000843r 2 000843r 2 ; disallow changing mode with SHIFT + C= by setting bit 7 of lMODE: 000843r 2 000843r 2 A9 80 lda #$80 000845r 2 0D rr rr ora lMODE 000848r 2 .if CompileComputer >= C64_GENERAL 000848r 2 bmi @Sta_lMODE ; sta lMODE (uncond. branch) 000848r 2 ; ------------------ 000848r 2 .else 000848r 2 8D rr rr sta lMODE 00084Br 2 30 EF bmi EditorChroutScreenEnd 00084Dr 2 .endif 00084Dr 2 @CheckForAllowLowercase: 00084Dr 2 C9 09 cmp #ASC_ALLOW_LOWERCASE ; if this the code to allow changing to lowercase mode via keyboard? 00084Fr 2 D0 EB bne EditorChroutScreenEnd ; no -> branch, this is no special code (or it has been already handled) 000851r 2 000851r 2 ; (re-)allow changing mode with SHIFT + C= by clearing bit 7 of lMODE: 000851r 2 000851r 2 A9 7F lda #$7F 000853r 2 2D rr rr and lMODE 000856r 2 @Sta_lMODE: 000856r 2 8D rr rr sta lMODE 000859r 2 000859r 2 ; end chrout to the screen. 000859r 2 ; the VIC-20 and C64 do exactly the same. 000859r 2 000859r 2 .if CompileComputer >= C64_GENERAL 000859r 2 jmp CHROUT_SCREEN_END 000859r 2 .else 000859r 2 10 E1 bpl EditorChroutScreenEnd ; branches to a "JMP CHROUT_SCREEN_END" (uncond. branch) 00085Br 2 ; ------------------------------ 00085Br 2 00085Br 2 ; a patch: cf. directly before EditorPatchLogicallyCombineTwoRows_Return 00085Br 2 00085Br 2 EditorPatchLogicallyCombineTwoRows: 00085Br 2 E8 B5 rr 09 EDITOR_PATCH_LogicallyCombineTwoRows_FIX 00085Fr 2 80 95 rr CA 000863r 2 A5 rr 18 EDITOR_PATCH_LogicallyCombineTwoRows_COMMON 000866r 2 4C rr rr jmp EditorPatchLogicallyCombineTwoRows_Return 000869r 2 000869r 2 .endif 000869r 2 .endif 000869r 2 000869r 2 .if CompileComputer = VIC20_02 000869r 2 000869r 2 KEYTAB5: 000869r 2 000869r 2 .byte $C7,$B1,$B4,$D4,$D6,$CE,$A6,$14 000869r 2 .byte $FF,$C3,$EC,$DD,$C6,$BE,$EA,$0D 000869r 2 .byte $04,$C1,$BC,$B7,$CF,$D8,$B9,$1D 000869r 2 .byte $03,$01,$BB,$CB,$D0,$C8,$D2,$11 000869r 2 .byte $20,$C2,$BF,$BA,$D3,$D9,$01,$85 000869r 2 .byte $02,$C4,$CA,$B8,$C9,$DA,$D1,$86 000869r 2 .byte $C0,$B2,$B6,$C5,$D7,$DB,$A1,$87 000869r 2 .byte $CC,$B3,$B5,$D5,$DC,$CD,$13,$88 000869r 2 .byte $FF 000869r 2 .endif 000869r 2 000869r 2 KEYTAB6: 000869r 2 000869r 2 .if CompileComputer = VIC20_02 000869r 2 000869r 2 .byte $F1,$F3,$F5,$FF,$FF,$EB,$FF,$94 000869r 2 .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$8D 000869r 2 .byte $04,$FF,$FF,$FF,$FF,$FF,$E2,$9D 000869r 2 .byte $83,$01,$FF,$FF,$FF,$FF,$FF,$91 000869r 2 .byte $A0,$FF,$FF,$FF,$FF,$EE,$01,$89 000869r 2 .byte $02,$FF,$FF,$FF,$FF,$E1,$FD,$8A 000869r 2 .byte $FF,$FF,$FF,$FF,$FF,$B0,$E0,$8B 000869r 2 .byte $F2,$F4,$F6,$FF,$F0,$ED,$93,$8C 000869r 2 .byte $FF 000869r 2 000869r 2 .elseif CompileComputer < C64_GENERAL 000869r 2 000869r 2 ; unused, but present 000869r 2 000869r 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 00086Dr 2 FF FF FF FF 000871r 2 FF 04 FF FF .byte $FF,$04,$FF,$FF,$FF,$FF,$FF,$E2 000875r 2 FF FF FF E2 000879r 2 9D 83 01 FF .byte $9D,$83,$01,$FF,$FF,$FF,$FF,$FF 00087Dr 2 FF FF FF FF 000881r 2 91 A0 FF FF .byte $91,$A0,$FF,$FF,$FF,$FF,$EE,$01 000885r 2 FF FF EE 01 000889r 2 89 02 FF FF .byte $89,$02,$FF,$FF,$FF,$FF,$E1,$FD 00088Dr 2 FF FF E1 FD 000891r 2 8A FF FF FF .byte $8A,$FF,$FF,$FF,$FF,$FF,$B0,$E0 000895r 2 FF FF B0 E0 000899r 2 8B F2 F4 F6 .byte $8B,$F2,$F4,$F6,$FF,$F0,$ED,$93 00089Dr 2 FF F0 ED 93 0008A1r 2 8C FF .byte $8C,$FF 0008A3r 2 0008A3r 2 .endif 0008A3r 2 0008A3r 2 KEYTAB_CTRL: 0008A3r 2 0008A3r 2 .if CompileComputer >= C64_GENERAL 0008A3r 2 0008A3r 2 .if .defined(C64JAPAN) 0008A3r 2 .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008A3r 2 .byte $1C,$95,$01,$9F,$1A,$13,$96,$FF 0008A3r 2 .byte $9C,$97,$04,$1E,$03,$06,$98,$18 0008A3r 2 .byte $1F,$99,$07,$9E,$02,$08,$9A,$16 0008A3r 2 0008A3r 2 .byte $12,$9B,$0A,$92,$0D,$0B,$0F,$0E 0008A3r 2 .byte $08,$10,$0C,$09,$11,$14,$00,$09 0008A3r 2 .byte $FF,$05,$15,$FF,$FF,$17,$19,$12 0008A3r 2 .byte $90,$06,$FF,$05,$FF,$FF,$81,$FF 0008A3r 2 .byte $FF 0008A3r 2 .else 0008A3r 2 .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008A3r 2 .byte $1C,$17,$01,$9F,$1A,$13,$05,$FF 0008A3r 2 .byte $9C,$12,$04,$1E,$03,$06,$14,$18 0008A3r 2 .byte $1F,$19,$07,$9E,$02,$08,$15,$16 0008A3r 2 0008A3r 2 .byte $12,$09,$0A,$92,$0D,$0B,$0F,$0E 0008A3r 2 .byte $FF,$10,$0C,$FF,$FF,$1B,$00,$FF 0008A3r 2 .byte $1C,$FF,$1D,$FF,$FF,$1F,$1E,$FF 0008A3r 2 .byte $90,$06,$FF,$05,$FF,$FF,$11,$FF 0008A3r 2 .byte $FF 0008A3r 2 .endif 0008A3r 2 0008A3r 2 .else 0008A3r 2 0008A3r 2 90 1C 9C 1F .byte $90,$1C,$9C,$1F 0008A7r 2 .if CompileComputer = VIC20_02 0008A7r 2 .byte $FF 0008A7r 2 .else 0008A7r 2 12 .byte $12 0008A8r 2 .endif 0008A8r 2 FF FF FF .byte $FF,$FF,$FF 0008ABr 2 .if CompileComputer = VIC20_02 0008ABr 2 .byte $FF 0008ABr 2 .else 0008ABr 2 06 .byte $06 0008ACr 2 .endif 0008ACr 2 FF 12 FF FF .byte $FF,$12,$FF,$FF,$FF,$FF,$FF 0008B0r 2 FF FF FF 0008B3r 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008B7r 2 FF FF FF FF 0008BBr 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008BFr 2 FF FF FF FF 0008C3r 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008C7r 2 FF FF FF FF 0008CBr 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008CFr 2 FF FF FF FF 0008D3r 2 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 0008D7r 2 FF FF FF FF 0008DBr 2 05 9F 1E 9E .byte $05,$9F,$1E,$9E,$92,$FF,$FF,$FF 0008DFr 2 92 FF FF FF 0008E3r 2 FF .byte $FF 0008E4r 2 0008E4r 2 .endif 0008E4r 2 0008E4r 2 VIC_DEFAULTS: 0008E4r 2 0008E4r 2 ; the default values for the VIC or VIC-II 0008E4r 2 ; these will be copied in a loop into the 0008E4r 2 ; VIC or VIC-II register when initialising the VIC(-II) 0008E4r 2 ; 0008E4r 2 0008E4r 2 .if CompileComputer >= C64_GENERAL 0008E4r 2 0008E4r 2 .byte $00,$00,$00,$00,$00,$00,$00,$00 0008E4r 2 .byte $00,$00,$00,$00,$00,$00,$00,$00 0008E4r 2 .byte $00 0008E4r 2 .if CompileComputer >= C64_02 0008E4r 2 .byte $1B | (>311 .SHL 7) ,<311 0008E4r 2 .else 0008E4r 2 .byte $1B,$00 0008E4r 2 .endif 0008E4r 2 .byte $00,$00,$00,$08,$00 0008E4r 2 .byte $14 0008E4r 2 .if CompileComputer >= C64_02 0008E4r 2 .byte $0F 0008E4r 2 .else 0008E4r 2 .byte $00 0008E4r 2 .endif 0008E4r 2 .byte $00,$00,$00,$00,$00,$00 0008E4r 2 0008E4r 2 .byte SET_COLOR_FRAME,SET_COLOR_BACKGROUND 0008E4r 2 .if CompileComputer = C64_4064 0008E4r 2 .byte $00,$00,$00,$00,$00 0008E4r 2 .byte $00,$00,$00,$00,$00,$00,$00 0008E4r 2 .else 0008E4r 2 .byte $01,$02,$03,$04,$00 0008E4r 2 .byte $01,$02,$03,$04,$05,$06,$07 0008E4r 2 .endif 0008E4r 2 0008E4r 2 .else 0008E4r 2 0008E4r 2 .if CompileComputer >= VIC20_07 0008E4r 2 .byte $0C,$26 0008E4r 2 .else 0008E4r 2 05 19 .byte $05,$19 0008E6r 2 .endif 0008E6r 2 16 2E 00 C0 .byte $16,$2E,$00,$C0,$00,$00 0008EAr 2 00 00 0008ECr 2 00 00 00 00 .byte $00,$00,$00,$00,$00,$00,$00 0008F0r 2 00 00 00 0008F3r 2 0008F3r 2 .endif 0008F3r 2 0008F3r 2 END_VIC_DEFAULTS: 0008F3r 2 0008F3r 2 .if CompileComputer < C64_GENERAL 0008F3r 2 0008F3r 2 1B .byte $1B ; TODO unused? 0008F4r 2 0008F4r 2 .endif 0008F4r 2 0008F4r 2 TEXT_LOADRUN: 0008F4r 2 4C 4F 41 44 .byte "LOAD",ASC_CR 0008F8r 2 0D 0008F9r 2 52 55 4E 0D .byte "RUN",ASC_CR 0008FDr 2 END_TEXT_LOADRUN: 0008FDr 2 0008FDr 2 SCREEN_LOWBYTE: 0008FDr 2 0008FDr 2 ; the low bytes of the screen addresses 0008FDr 2 0008FDr 2 00 16 2C 42 .repeat EDITOR_ROWS,i 000901r 2 58 6E 84 9A 000905r 2 B0 C6 DC F2 000914r 2 .byte <(i*EDITOR_COLS) 000914r 2 .endrep 000914r 2 000914r 2 000914r 1 .include "../kernal/iec.a65" 000914r 2 ; B-34. Function Name: TALK 000914r 2 ; 000914r 2 ; Purpose: Command a device on the serial bus to TALK 000914r 2 ; Call address: $FFB4 (hex) 65460 (decimal) 000914r 2 ; Communication registers: A 000914r 2 ; Preparatory routines: None 000914r 2 ; Error returns: See READST 000914r 2 ; Stack requirements: 8 000914r 2 ; Registers affected: A 000914r 2 ; 000914r 2 ; Description: To use this routine the accumulator must first be loaded 000914r 2 ; with a device number between 0 and 31. When called, this routine then 000914r 2 ; ORs bit by bit to convert this device number to a talk address. Then this 000914r 2 ; data is transmitted as a command on the serial bus. 000914r 2 ; 000914r 2 ; How to Use: 000914r 2 ; 000914r 2 ; 1) Load the accumulator with the device number. 000914r 2 ; 2) Call this routine. 000914r 2 ; 000914r 2 ; EXAMPLE: 000914r 2 ; 000914r 2 ; ;COMMAND DEVICE #4 TO TALK 000914r 2 ; LDA #4 000914r 2 ; JSR TALK 000914r 2 ; 000914r 2 iTALK: 000914r 2 09 40 ora #IEEE_TALK ; create primary address for TALK 000916r 2 000916r 2 2C .byte ASM_BIT3 ; hide next instruction 000917r 2 000917r 2 ; B-14. Function Name: LISTEN 000917r 2 ; 000917r 2 ; Purpose: Command a device on the serial bus to listen 000917r 2 ; Call Address: $FFB1 (hex) 65457 (decimal) 000917r 2 ; Communication registers: A 000917r 2 ; Preparatory routines: None 000917r 2 ; Error returns: See READST 000917r 2 ; Stack requirements: None 000917r 2 ; Registers affected: A 000917r 2 ; 000917r 2 ; Description: This routine will command a device on the serial bus to 000917r 2 ; receive data. The accumulator must be loaded with a device number between 000917r 2 ; 0 and 31 before calling the routine. LISTEN will OR the number bit by bit 000917r 2 ; to convert to a listen address, then transmits this data as a command on 000917r 2 ; the serial bus. The specified device will then go into listen mode, and 000917r 2 ; be ready to accept information. 000917r 2 ; 000917r 2 ; How to Use: 000917r 2 ; 1) Load the accumulator with the number of the device to command 000917r 2 ; to LISTEN. 000917r 2 ; 2) Call this routine using the JSR instruction. 000917r 2 ; 000917r 2 ; EXAMPLE: 000917r 2 ; ;COMMAND DEVICE #8 TO LISTEN 000917r 2 ; LDA #8 000917r 2 ; JSR LISTEN 000917r 2 ; 000917r 2 ; 000917r 2 iLISTEN: 000917r 2 09 20 ora #IEEE_LISTEN ; create primary address for TALK 000919r 2 20 rr rr jsr LF0A4 ; TODO (assumed: Wait for RS232 transmission to stop) 00091Cr 2 00091Cr 2 IecOutputCommand: 00091Cr 2 48 pha ; remember byte to be output 00091Dr 2 00091Dr 2 24 rr bit zC3PO ; test: Is there already some character in the output buffer? 00091Fr 2 10 0A bpl @BufferByte ; no -> branch, do not output but put the byte into the buffer instead 000921r 2 000921r 2 ; there is some byte in the output buffer. 000921r 2 ; output it on the IEC bus. 000921r 2 000921r 2 38 sec 000922r 2 66 rr ror zTSFCNT ; set zTSFCNT.7, thus: Signal an EOI on output 000924r 2 000924r 2 .ifdef JIFFY 000924r 2 jsr JDLFBFE 000924r 2 .else 000924r 2 20 rr rr jsr IecOutputByte ; output a byte on IEC bus 000927r 2 .endif 000927r 2 000927r 2 ; IecOutputByte returns with C == 0 000927r 2 46 rr lsr zC3PO ; unset zC3PO.7, thus: 000929r 2 ; mark: There is no byte in the buffer 000929r 2 46 rr lsr zTSFCNT ; unset zTSFCNT.7. Subsequent bytes will not be signalled with EOI 00092Br 2 00092Br 2 @BufferByte: 00092Br 2 ; here, zC3PO.7 is unset. 00092Br 2 ; Either we jumped here because of the bpl, or it was specifically unset two lines above 00092Br 2 00092Br 2 ; Thus, the buffer is already marked as empty 00092Br 2 00092Br 2 68 pla ; get back the byte to be output 00092Cr 2 85 rr sta zBSOUR ; and store it into the output buffer 00092Er 2 00092Er 2 .if CompileComputer >= C64_GENERAL 00092Er 2 sei ; make sure the interrupt does not disturb our timing 00092Er 2 00092Er 2 ; it is not completely clear if this command is missing 00092Er 2 ; on the VIC20, or if it is not critical there, as the VIC20 00092Er 2 ; does not have badlines, which might help the timing here. 00092Er 2 .endif 00092Er 2 00092Er 2 ; TODO: document 00092Er 2 .ifdef JIFFY 00092Er 2 jsr JDLF0ED 00092Er 2 .else 00092Er 2 20 rr rr jsr IecDataClear 000931r 2 .endif 000931r 2 000931r 2 C9 3F cmp #IEEE_UNLISTEN 000933r 2 D0 03 bne @NotUNLISTEN 000935r 2 000935r 2 20 rr rr jsr IecClkClear 000938r 2 000938r 2 @NotUNLISTEN: 000938r 2 000938r 2 ; set ATN state 000938r 2 000938r 2 AD 1F 91 lda IEC_REG_ATN_OUT 00093Br 2 09 80 ora #IEC_B_ATN_OUT 00093Dr 2 8D 1F 91 sta IEC_REG_ATN_OUT 000940r 2 000940r 2 IecOutputByte2: 000940r 2 .if CompileComputer >= C64_GENERAL 000940r 2 sei ; make sure the interrupt does not disturb our timing 000940r 2 000940r 2 ; it is not completely clear if this command is missing 000940r 2 ; on the VIC20, or if it is not critical there, as the VIC20 000940r 2 ; does not have badlines, which might help the timing here. 000940r 2 .endif 000940r 2 20 rr rr jsr IecClkSet 000943r 2 20 rr rr jsr IecDataClear 000946r 2 20 rr rr jsr IecDelay1ms 000949r 2 000949r 2 000949r 2 000949r 2 IecOutputByte: 000949r 2 78 sei ; make sure the interrupt does not disturb our timing 00094Ar 2 00094Ar 2 .if CompileComputer >= VIC20_06 00094Ar 2 20 rr rr jsr IecDataClear 00094Dr 2 .endif 00094Dr 2 00094Dr 2 20 rr rr jsr IecGetDataClockIn 000950r 2 4A IEC_GET_DATA_INTO_CARRY 000951r 2 B0 61 bcs @DeviceNotPresent 000953r 2 20 rr rr jsr IecClkClear 000956r 2 24 rr bit zTSFCNT 000958r 2 10 0C bpl @LED5A 00095Ar 2 00095Ar 2 @WaitDataInactive: 00095Ar 2 20 rr rr jsr IecGetDataClockIn 00095Dr 2 4A IEC_GET_DATA_INTO_CARRY 00095Er 2 90 FA bcc @WaitDataInactive 000960r 2 000960r 2 @WaitDataActive: 000960r 2 20 rr rr jsr IecGetDataClockIn 000963r 2 4A IEC_GET_DATA_INTO_CARRY 000964r 2 B0 FA bcs @WaitDataActive 000966r 2 000966r 2 @LED5A: 000966r 2 20 rr rr jsr IecGetDataClockIn 000969r 2 4A IEC_GET_DATA_INTO_CARRY 00096Ar 2 90 FA bcc @LED5A 00096Cr 2 00096Cr 2 20 rr rr jsr IecClkSet 00096Fr 2 00096Fr 2 .ifdef JIFFY 00096Fr 2 txa 00096Fr 2 pha 00096Fr 2 ldx #8 00096Fr 2 .else 00096Fr 2 A9 08 lda #8 ; number of bits to be output 000971r 2 85 rr sta zCNTDN 000973r 2 .endif 000973r 2 000973r 2 @NextBit: 000973r 2 000973r 2 .ifdef JIFFY 000973r 2 pha 000973r 2 pla 000973r 2 bit IEC_REG 000973r 2 bmi @JDLED72 000973r 2 pla 000973r 2 tax 000973r 2 jmp SendTimeout 000973r 2 000973r 2 @JDLED72: 000973r 2 jsr IecDataClear 000973r 2 ror zBSOUR 000973r 2 bcs @JDLED7C 000973r 2 jsr IecDataSet 000973r 2 000973r 2 @JDLED7C: 000973r 2 jsr IecClkClear 000973r 2 lda IEC_REG 000973r 2 and # ~ IEC_B_DATA_OUT 000973r 2 ora #IEC_B_CLK_OUT 000973r 2 php 000973r 2 pha 000973r 2 jsr JDLF8EA 000973r 2 pla 000973r 2 plp 000973r 2 dex 000973r 2 bne @NextBit 000973r 2 pla 000973r 2 tax 000973r 2 000973r 2 .else 000973r 2 AD 1F 91 lda IEC_REG_DATA_CLK_IN 000976r 2 CD 1F 91 cmp IEC_REG_DATA_CLK_IN 000979r 2 D0 F8 bne @NextBit ; wait for IEC register to settle (TODO entprellen) 00097Br 2 4A 4A IEC_REG__DATA_IN_INTO_CARRY 00097Dr 2 90 38 bcc SendTimeout ; data set (inactive) -> something/someone else is messing with us, there is a transmission problem -> branch 00097Fr 2 00097Fr 2 66 rr ror zBSOUR ; next bit to output (LSB) into C 000981r 2 B0 05 bcs @OutputData1 ; is it set -> output a "1" (inactive) on the IEC bus data line 000983r 2 20 rr rr jsr IecDataSet ; it was not set -> output a "0" (active) on the IEC bus data line 000986r 2 D0 03 bne @ContinueAfterOutputData ; skip next command 000988r 2 000988r 2 @OutputData1: 000988r 2 20 rr rr jsr IecDataClear ; output a "1" (inactive) on the IEC bus data line 00098Br 2 00098Br 2 @ContinueAfterOutputData: 00098Br 2 20 rr rr jsr IecClkClear ; clear clock to indicate: Data has been set accordingly 00098Er 2 00098Er 2 ; delay 8 (4*2) clock cycles, giving the other side time to read the value in 00098Er 2 EA nop 00098Fr 2 EA nop 000990r 2 EA nop 000991r 2 EA nop 000992r 2 000992r 2 ; clear DATA and set Clock again, indicating the bit is not available anymore 000992r 2 AD 2C 91 lda IEC_REG_DATA_CLK_OUT 000995r 2 29 DF and #~IEC_B_DATA_OUT 000997r 2 09 02 ora #IEC_B_CLK_OUT 000999r 2 8D 2C 91 sta IEC_REG_DATA_CLK_OUT 00099Cr 2 00099Cr 2 C6 rr dec zCNTDN ; still bits to be output? 00099Er 2 D0 D3 bne @NextBit ; yes -> branch -> process the next bit 0009A0r 2 .endif 0009A0r 2 0009A0r 2 ; TODO document 0009A0r 2 0009A0r 2 ; wait for acknowledgement from other side 0009A0r 2 0009A0r 2 A9 04 lda #>$0400 ; set timer to approx. 1000 µs ( = 1 ms) 0009A2r 2 8D 29 91 sta IEC_TIMER_HI 0009A5r 2 0009A5r 2 .if CompileComputer >= C64_GENERAL 0009A5r 2 0009A5r 2 ; start timer B with one-shot mode, no PB7, counting PHI2 0009A5r 2 lda #CIA_CRB_B_START | CIA_CRB_B_ONESHOT | CIA_CRB_B_FORCE_LOAD 0009A5r 2 sta CIA1 + CIA_O_CRB 0009A5r 2 0009A5r 2 lda IEC_TIMER_FLAG_REG ; make sure the ICR is cleared, so we do not 0009A5r 2 ; immediately stop the following loop because 0009A5r 2 ; some other TB underflow condition has occurred before 0009A5r 2 .endif 0009A5r 2 0009A5r 2 0009A5r 2 @WaitForAck: 0009A5r 2 AD 2D 91 lda IEC_TIMER_FLAG_REG 0009A8r 2 29 20 and #IEC_TIMER_FLAG_B 0009AAr 2 D0 0B bne SendTimeout 0009ACr 2 20 rr rr jsr IecGetDataClockIn 0009AFr 2 4A IEC_GET_DATA_INTO_CARRY 0009B0r 2 B0 F3 bcs @WaitForAck 0009B2r 2 58 cli 0009B3r 2 60 rts 0009B4r 2 0009B4r 2 0009B4r 2 @DeviceNotPresent: 0009B4r 2 A9 80 lda #$80 ; set bit: device not present error 0009B6r 2 0009B6r 2 2C .byte ASM_BIT3 ; hide the next instruction 0009B7r 2 0009B7r 2 SendTimeout: 0009B7r 2 A9 03 lda #$03 ; set bits: read timeout and write timeout 0009B9r 2 0009B9r 2 IecSetStatusAndFreeBus: 0009B9r 2 20 rr rr jsr SetStatus ; set the status bits 0009BCr 2 0009BCr 2 .if CompileComputer = VIC20_02 0009BCr 2 jsr IEC_CLR_ATN 0009BCr 2 jsr IecClkSet 0009BCr 2 .endif 0009BCr 2 0009BCr 2 58 cli 0009BDr 2 .if CompileComputer >= VIC20_06 0009BDr 2 18 clc 0009BEr 2 90 49 bcc IecClearAtnAndClockAndDataAfterDelay 0009C0r 2 ; ------------------ 0009C0r 2 .else 0009C0r 2 jmp IecDataClear 0009C0r 2 ; ------------------ 0009C0r 2 .endif 0009C0r 2 0009C0r 2 ; B-27. Function Name: SECOND 0009C0r 2 ; 0009C0r 2 ; Purpose: Send secondary address for LISTEN 0009C0r 2 ; Call address: $FF93 (hex) 65427 (decimal) 0009C0r 2 ; Communication registers: A 0009C0r 2 ; Preparatory routines: LISTEN 0009C0r 2 ; Error returns: See READST 0009C0r 2 ; Stack requirements: 8 0009C0r 2 ; Registers affected: A 0009C0r 2 ; 0009C0r 2 ; Description: This routine is used to send a secondary address to an 0009C0r 2 ; I/O device after a call to the LISTEN routine is made, and the device is 0009C0r 2 ; commanded to LISTEN. The routine canNOT be used to send a secondary 0009C0r 2 ; address after a call to the TALK routine. 0009C0r 2 ; A secondary address is usually used to give setup information to a 0009C0r 2 ; device before I/O operations begin. 0009C0r 2 ; When a secondary address is to be sent to a device on the serial bus, 0009C0r 2 ; the address must first be ORed with $60. 0009C0r 2 ; 0009C0r 2 ; How to Use: 0009C0r 2 ; 0009C0r 2 ; 1) load the accumulator with the secondary address to be sent. 0009C0r 2 ; 2) Call this routine. 0009C0r 2 ; 0009C0r 2 ; EXAMPLE: 0009C0r 2 ; 0009C0r 2 ; ;ADDRESS DEVICE #8 WITH COMMAND (SECONDARY ADDRESS) #15 0009C0r 2 ; LDA #8 0009C0r 2 ; JSR LISTEN 0009C0r 2 ; LDA #15 0009C0r 2 ; JSR SECOND 0009C0r 2 ; 0009C0r 2 ; 0009C0r 2 iSECOND: 0009C0r 2 85 rr sta zBSOUR ; byte (secondary address after LISTEN) to be output 0009C2r 2 20 rr rr jsr IecOutputByte2 0009C5r 2 0009C5r 2 IEC_CLR_ATN: 0009C5r 2 0009C5r 2 ; clear ATN state 0009C5r 2 AD 1F 91 lda IEC_REG_ATN_OUT 0009C8r 2 29 7F and #~IEC_B_ATN_OUT 0009CAr 2 8D 1F 91 sta IEC_REG_ATN_OUT 0009CDr 2 0009CDr 2 60 rts 0009CEr 2 0009CEr 2 ; B-35. Function Name: TKSA 0009CEr 2 ; 0009CEr 2 ; Purpose: Send a secondary address to a device commanded to TALK 0009CEr 2 ; Call address: $FF96 (hex) 65430 (decimal) 0009CEr 2 ; Communication registers: A 0009CEr 2 ; Preparatory routines: TALK 0009CEr 2 ; Error returns: See READST 0009CEr 2 ; Stack requirements: 8 0009CEr 2 ; Registers affected: A 0009CEr 2 ; 0009CEr 2 ; 0009CEr 2 ; 0009CEr 2 ; Description: This routine transmits a secondary address on the serial 0009CEr 2 ; bus for a TALK device. This routine must be called with a number between 0009CEr 2 ; 0 and 31 in the accumulator. The routine sends this number as a secondary 0009CEr 2 ; address command over the serial bus. This routine can only be called 0009CEr 2 ; after a call to the TALK routine. It will not work after a LISTEN. 0009CEr 2 ; 0009CEr 2 ; How to Use: 0009CEr 2 ; 0009CEr 2 ; 0) Use the TALK routine. 0009CEr 2 ; 1) Load the accumulator with the secondary address. 0009CEr 2 ; 2) Call this routine. 0009CEr 2 ; 0009CEr 2 ; EXAMPLE: 0009CEr 2 ; 0009CEr 2 ; ;TELL DEVICE #4 TO TALK WITH COMMAND #7 0009CEr 2 ; LDA #4 0009CEr 2 ; JSR TALK 0009CEr 2 ; LDA #7 0009CEr 2 ; JSR TALKSA 0009CEr 2 ; 0009CEr 2 iTKSA: 0009CEr 2 85 rr sta zBSOUR ; byte (secondary address after TALK) to be output 0009D0r 2 20 rr rr jsr IecOutputByte2 0009D3r 2 0009D3r 2 ; perform talk - listener - change (TODO) 0009D3r 2 0009D3r 2 iTKSA2: 0009D3r 2 78 sei 0009D4r 2 20 rr rr jsr IecDataSet 0009D7r 2 20 rr rr jsr IEC_CLR_ATN 0009DAr 2 20 rr rr jsr IecClkClear 0009DDr 2 0009DDr 2 @LEDD6: 0009DDr 2 .ifdef JIFFY 0009DDr 2 bit IEC_REG 0009DDr 2 .else 0009DDr 2 20 rr rr jsr IecGetDataClockIn 0009E0r 2 .endif 0009E0r 2 0009E0r 2 .ifdef JIFFY 0009E0r 2 bvs @LEDD6 0009E0r 2 .elseif CompileComputer >= C64_GENERAL 0009E0r 2 bmi @LEDD6 0009E0r 2 .else 0009E0r 2 B0 FB bcs @LEDD6 0009E2r 2 .endif 0009E2r 2 58 cli 0009E3r 2 60 rts 0009E4r 2 0009E4r 2 ; B-6. Function Name: CIOUT 0009E4r 2 ; 0009E4r 2 ; Purpose: Transmit a byte over the serial bus 0009E4r 2 ; Call address: $FFA8 (hex) 65448 (decimal) 0009E4r 2 ; Communication registers: A 0009E4r 2 ; Preparatory routines: LISTEN, [SECOND] 0009E4r 2 ; Error returns: See READST 0009E4r 2 ; Stack requirements: 5 0009E4r 2 ; Registers affected: None 0009E4r 2 ; 0009E4r 2 ; Description: This routine is used to send information to devices on the 0009E4r 2 ; serial bus. A call to this routine will put a data byte onto the serial 0009E4r 2 ; bus using full serial handshaking. Before this routine is called, the 0009E4r 2 ; LISTEN KERNAL routine must be used to command a device on the serial bus 0009E4r 2 ; to get ready to receive data. (If a device needs a secondary address, it 0009E4r 2 ; must also be sent by using the SECOND KERNAL routine.) The accumulator is 0009E4r 2 ; loaded with a byte to handshake as data on the serial bus. A device must 0009E4r 2 ; be listening or the status word will return a timeout. This routine 0009E4r 2 ; always buffers one character. (The routine holds the previous character 0009E4r 2 ; to be sent back.) So when a call to the KERNAL UNLSN routine is made to 0009E4r 2 ; end the data transmission, the buffered character is sent with an End Or 0009E4r 2 ; Identify (EOI) set. Then the UNLSN command is sent to the device. 0009E4r 2 ; 0009E4r 2 ; How to Use: 0009E4r 2 ; 0009E4r 2 ; 0) Use the LISTEN KERNAL routine (and the SECOND routine if needed). 0009E4r 2 ; 1) Load the accumulator with a byte of data. 0009E4r 2 ; 2) Call this routine to send the data byte. 0009E4r 2 ; 0009E4r 2 ; EXAMPLE: 0009E4r 2 ; 0009E4r 2 ; 0009E4r 2 ; LDA #'X ;SEND AN X TO THE SERIAL BUS 0009E4r 2 ; JSR CIOUT 0009E4r 2 ; 0009E4r 2 ; 0009E4r 2 iCIOUT: 0009E4r 2 24 rr bit zC3PO ; check if there is already a byte buffered to be output 0009E6r 2 30 05 bmi @SendBufferedChar ; there is one -> branch, send it 0009E8r 2 0009E8r 2 38 sec ; there was none -> set bit 7 to mark that we now have a byte to be output 0009E9r 2 66 rr ror zC3PO 0009EBr 2 0009EBr 2 D0 05 bne @NoCached ; uncond. branch: store the next byte to be output 0009EDr 2 ; ------------------ 0009EDr 2 0009EDr 2 @SendBufferedChar: 0009EDr 2 48 pha ; remember the new byte to be output 0009EEr 2 .ifdef JIFFY 0009EEr 2 jsr $FBFE 0009EEr 2 .else 0009EEr 2 20 rr rr jsr IecOutputByte ; output the old buffered byte 0009F1r 2 .endif 0009F1r 2 68 pla ; get back the new byte to be output 0009F2r 2 0009F2r 2 @NoCached: 0009F2r 2 85 rr sta zBSOUR ; store the new byte to be output on the next call 0009F4r 2 0009F4r 2 18 clc ; mark: no error 0009F5r 2 60 rts 0009F6r 2 ; ------------------ 0009F6r 2 0009F6r 2 0009F6r 2 ; B-38. Function Name: UNTLK 0009F6r 2 ; 0009F6r 2 ; Purpose: Send an UNTALK command 0009F6r 2 ; Call address: $FFAB (hex) 65451 (decimal) 0009F6r 2 ; Communication registers: None 0009F6r 2 ; Preparatory routines: None 0009F6r 2 ; Error returns: See READST 0009F6r 2 ; Stack requirements: 8 0009F6r 2 ; Registers affected: A 0009F6r 2 ; 0009F6r 2 ; Description: This routine transmits an UNTALK command on the serial 0009F6r 2 ; bus. All devices previously set to TALK will stop sending data when this 0009F6r 2 ; command is received. 0009F6r 2 ; 0009F6r 2 ; How to Use: 0009F6r 2 ; 1) Call this routine. 0009F6r 2 ; 0009F6r 2 ; 0009F6r 2 ; EXAMPLE: 0009F6r 2 ; JSR UNTALK 0009F6r 2 ; 0009F6r 2 iUNTLK: 0009F6r 2 .if CompileComputer >= C64_GENERAL 0009F6r 2 sei 0009F6r 2 .endif 0009F6r 2 0009F6r 2 ; make sure to signal the talker that we will take over the bus now! 0009F6r 2 0009F6r 2 .ifdef JIFFY 0009F6r 2 .else 0009F6r 2 20 rr rr jsr IecClkSet 0009F9r 2 .endif 0009F9r 2 0009F9r 2 ; set ATN state 0009F9r 2 0009F9r 2 AD 1F 91 lda IEC_REG_ATN_OUT 0009FCr 2 09 80 ora #IEC_B_ATN_OUT 0009FEr 2 8D 1F 91 sta IEC_REG_ATN_OUT 000A01r 2 000A01r 2 .ifdef JIFFY 000A01r 2 jsr IecClkSet 000A01r 2 .endif 000A01r 2 000A01r 2 A9 5F lda #IEEE_UNTALK ; set command byte: UNTALK 000A03r 2 000A03r 2 2C .byte ASM_BIT3 ; hide the next instruction 000A04r 2 000A04r 2 ; B-37. Function Name: UNLSN 000A04r 2 ; 000A04r 2 ; Purpose: Send an UNLISTEN command 000A04r 2 ; Call address: $FFAE (hex) 65454 (decimal) 000A04r 2 ; Communication registers: None 000A04r 2 ; Preparatory routines: None 000A04r 2 ; Error returns: See READST 000A04r 2 ; Stack requirements: 8 000A04r 2 ; Registers affected: A 000A04r 2 ; 000A04r 2 ; Description: This routine commands all devices on the serial bus to 000A04r 2 ; stop receiving data from the Commodore 64 (i.e., UNLISTEN). Calling this 000A04r 2 ; routine results in an UNLISTEN command being transmitted on the serial 000A04r 2 ; bus. Only devices previously commanded to listen are affected. This 000A04r 2 ; routine is normally used after the Commodore 64 is finished sending data 000A04r 2 ; to external devices. Sending the UNLISTEN commands the listening devices 000A04r 2 ; to get off the serial bus so it can be used for other purposes. 000A04r 2 ; 000A04r 2 ; How to Use: 000A04r 2 ; 1) Call this routine. 000A04r 2 ; 000A04r 2 ; EXAMPLE: 000A04r 2 ; JSR UNLSN 000A04r 2 ; 000A04r 2 iUNLSN: 000A04r 2 A9 3F lda #IEEE_UNLISTEN ; set command byte: UNLISTEN 000A06r 2 000A06r 2 20 rr rr jsr IecOutputCommand ; output the command byte on the IEC bus 000A09r 2 000A09r 2 .if CompileComputer = VIC20_02 000A09r 2 bne IEC_CLR_ATN ; done (bug) 000A09r 2 ; --------------------- 000A09r 2 .else 000A09r 2 000A09r 2 IecClearAtnAndClockAndDataAfterDelay: 000A09r 2 20 rr rr jsr IEC_CLR_ATN ; clear ATN 000A0Cr 2 000A0Cr 2 ; TODO document 000A0Cr 2 000A0Cr 2 IecClearClockAndDataAfterDelay: 000A0Cr 2 8A txa 000A0Dr 2 .if CompileComputer >= C64_GENERAL 000A0Dr 2 ; TODO define 000A0Dr 2 ldx #10 000A0Dr 2 .else 000A0Dr 2 A2 0B ldx #11 000A0Fr 2 .endif 000A0Fr 2 CA @Delay: dex 000A10r 2 D0 FD bne @Delay 000A12r 2 AA tax 000A13r 2 20 rr rr jsr IecClkClear 000A16r 2 4C rr rr jmp IecDataClear 000A19r 2 .endif 000A19r 2 000A19r 2 ; B-1. Function Name: ACPTR 000A19r 2 ; 000A19r 2 ; Purpose: Get data from the serial bus 000A19r 2 ; Call address: $FFA5 (hex) 65445 (decimal) 000A19r 2 ; Communication registers: A 000A19r 2 ; Preparatory routines: TALK, TKSA 000A19r 2 ; Error returns: See READST 000A19r 2 ; Stack requirements: 13 000A19r 2 ; Registers affected: A, X 000A19r 2 ; 000A19r 2 ; 000A19r 2 ; 000A19r 2 ; Description: This is the routine to use when you want to get informa- 000A19r 2 ; tion from a device on the serial bus, like a disk. This routine gets a 000A19r 2 ; byte of data off the serial bus using full handshaking. The data is 000A19r 2 ; returned in the accumulator. To prepare for this routine the TALK routine 000A19r 2 ; must be called first to command the device on the serial bus to send data 000A19r 2 ; through the bus. If the input device needs a secondary command, it must 000A19r 2 ; be sent by using the TKSA KERNAL routine before calling this routine. 000A19r 2 ; Errors are returned in the status word. The READST routine is used to 000A19r 2 ; read the status word. 000A19r 2 ; 000A19r 2 ; 000A19r 2 ; How to Use: 000A19r 2 ; 000A19r 2 ; 0) Command a device on the serial bus to prepare to send data to 000A19r 2 ; the Commodore 64. (Use the TALK and TKSA KERNAL routines.) 000A19r 2 ; 1) Call this routine (using JSR). 000A19r 2 ; 2) Store or otherwise use the data. 000A19r 2 ; 000A19r 2 ; 000A19r 2 ; EXAMPLE: 000A19r 2 ; 000A19r 2 ; ;GET A BYTE FROM THE BUS 000A19r 2 ; JSR ACPTR 000A19r 2 ; STA DATA 000A19r 2 ; 000A19r 2 ; 000A19r 2 ; 000A19r 2 iACPTR: 000A19r 2 .ifdef JIFFY 000A19r 2 jmp $FBAA 000A19r 2 000A19r 2 .else 000A19r 2 000A19r 2 78 sei ; make sure to be able to hold the timing 000A1Ar 2 000A1Ar 2 .if CompileComputer < VIC20_06 000A1Ar 2 lda #8 ; 8 bits to be input 000A1Ar 2 .else 000A1Ar 2 A9 00 lda #0 ; TODO: ??? 000A1Cr 2 .endif 000A1Cr 2 .endif 000A1Cr 2 000A1Cr 2 JDiACPTR: 000A1Cr 2 85 rr sta zCNTDN ; and store it as counter 000A1Er 2 000A1Er 2 000A1Er 2 000A1Er 2 .if CompileComputer >= VIC20_06 000A1Er 2 20 rr rr jsr IecClkClear ; clear CLOCK to signal: We are ready to handle the byte 000A21r 2 .endif 000A21r 2 000A21r 2 000A21r 2 @WaitDataInactive: 000A21r 2 000A21r 2 ; wait for DATA to become inactive: 000A21r 2 ; That is, wait for the other side to be ready to send a byte 000A21r 2 000A21r 2 20 rr rr jsr IecGetDataClockIn 000A24r 2 .if CompileComputer >= C64_GENERAL 000A24r 2 bpl @WaitDataInactive 000A24r 2 .else 000A24r 2 90 FB bcc @WaitDataInactive 000A26r 2 20 rr rr jsr IecDataClear ; clear DATA (unnecessary, as the loop would not terminate if we would not have data cleared!) 000A29r 2 .endif 000A29r 2 000A29r 2 @LEE20: 000A29r 2 000A29r 2 A9 01 lda #>$0100 ; set timer to approx. 250 µs 000A2Br 2 8D 29 91 sta IEC_TIMER_HI 000A2Er 2 000A2Er 2 .if CompileComputer >= C64_GENERAL 000A2Er 2 ; start timer B with one-shot mode, no PB7, counting PHI2 000A2Er 2 lda #CIA_CRB_B_START | CIA_CRB_B_ONESHOT | CIA_CRB_B_FORCE_LOAD 000A2Er 2 sta CIA1 + CIA_O_CRB 000A2Er 2 000A2Er 2 jsr IecDataClear ; clear DATA 000A2Er 2 000A2Er 2 lda IEC_TIMER_FLAG_REG ; make sure the ICR is cleared, so we do not 000A2Er 2 ; immediately stop the following loop because 000A2Er 2 ; some other TB underflow condition has occurred before 000A2Er 2 000A2Er 2 .endif 000A2Er 2 000A2Er 2 AD 2D 91 @LEE30: lda IEC_TIMER_FLAG_REG 000A31r 2 29 20 and #IEC_TIMER_FLAG_B 000A33r 2 D0 07 bne @LEE3E 000A35r 2 000A35r 2 20 rr rr jsr IecGetDataClockIn 000A38r 2 000A38r 2 .if CompileComputer >= C64_GENERAL 000A38r 2 bmi @LEE30 000A38r 2 bpl @LEE56 000A38r 2 .else 000A38r 2 B0 F4 bcs @LEE30 000A3Ar 2 90 18 bcc @LEE56 000A3Cr 2 .endif 000A3Cr 2 000A3Cr 2 000A3Cr 2 @LEE3E: 000A3Cr 2 000A3Cr 2 .if CompileComputer = VIC20_02 000A3Cr 2 000A3Cr 2 jsr IecDataSet 000A3Cr 2 txa 000A3Cr 2 ldx #$10 000A3Cr 2 @Delay: dex 000A3Cr 2 bne @Delay 000A3Cr 2 tax 000A3Cr 2 jsr IecDataClear 000A3Cr 2 jsr IecGetDataClockIn 000A3Cr 2 000A3Cr 2 lda #$40 ; status bit: EOI 000A3Cr 2 jsr SetStatus ; set the status to EOI 000A3Cr 2 000A3Cr 2 @LEE56: lda IEC_REG_DATA_CLK_IN 000A3Cr 2 cmp IEC_REG_DATA_CLK_IN 000A3Cr 2 bne @LEE56 000A3Cr 2 IEC_REG__CLOCK_IN_INTO_CARRY 000A3Cr 2 bcc @LEE56 000A3Cr 2 lsr a 000A3Cr 2 ror zTBTCNT 000A3Cr 2 000A3Cr 2 @WaitClkInactive: 000A3Cr 2 lda IEC_REG_DATA_CLK_IN 000A3Cr 2 cmp IEC_REG_DATA_CLK_IN 000A3Cr 2 bne @WaitClkInactive 000A3Cr 2 000A3Cr 2 IEC_REG__CLOCK_IN_INTO_CARRY 000A3Cr 2 bcs @WaitClkInactive 000A3Cr 2 dec zCNTDN 000A3Cr 2 bne @LEE56 000A3Cr 2 jsr IecDataSet 000A3Cr 2 lda zTBTCNT 000A3Cr 2 cli 000A3Cr 2 clc 000A3Cr 2 rts 000A3Cr 2 000A3Cr 2 .else 000A3Cr 2 000A3Cr 2 A5 rr lda zCNTDN 000A3Er 2 F0 05 beq @Proceed 000A40r 2 000A40r 2 A9 02 lda #$02 ; set status: read timeout 000A42r 2 4C rr rr jmp IecSetStatusAndFreeBus ; ... and free the bus and exit 000A45r 2 ; ------------------ 000A45r 2 000A45r 2 @Proceed: 000A45r 2 20 rr rr jsr IecDataSet 000A48r 2 .if CompileComputer >= C64_GENERAL 000A48r 2 jsr IecClkClear 000A48r 2 .else 000A48r 2 20 rr rr jsr IecClearClockAndDataAfterDelay 000A4Br 2 .endif 000A4Br 2 A9 40 lda #$40 000A4Dr 2 20 rr rr jsr SetStatus 000A50r 2 E6 rr inc zCNTDN 000A52r 2 D0 D5 bne @LEE20 000A54r 2 000A54r 2 A9 08 @LEE56: lda #8 ; number of bits to be input 000A56r 2 85 rr sta zCNTDN 000A58r 2 @LEE5A: 000A58r 2 AD 1F 91 lda IEC_REG_DATA_CLK_IN 000A5Br 2 CD 1F 91 cmp IEC_REG_DATA_CLK_IN 000A5Er 2 D0 F8 bne @LEE5A 000A60r 2 000A60r 2 .if CompileComputer >= C64_GENERAL 000A60r 2 asl a 000A60r 2 bpl @LEE5A 000A60r 2 .else 000A60r 2 4A lsr a 000A61r 2 90 F5 bcc @LEE5A 000A63r 2 4A lsr a 000A64r 2 .endif 000A64r 2 66 rr ror zTBTCNT 000A66r 2 @LEE67: 000A66r 2 AD 1F 91 lda IEC_REG_DATA_CLK_IN 000A69r 2 CD 1F 91 cmp IEC_REG_DATA_CLK_IN 000A6Cr 2 D0 F8 bne @LEE67 000A6Er 2 .if CompileComputer >= C64_GENERAL 000A6Er 2 asl a 000A6Er 2 bmi @LEE67 000A6Er 2 .else 000A6Er 2 4A lsr a 000A6Fr 2 B0 F5 bcs @LEE67 000A71r 2 .endif 000A71r 2 000A71r 2 C6 rr dec zCNTDN 000A73r 2 D0 E3 bne @LEE5A 000A75r 2 20 rr rr jsr IecDataSet 000A78r 2 .if CompileComputer >= C64_GENERAL 000A78r 2 bit zSTATUS 000A78r 2 bvc @LEE80 000A78r 2 .else 000A78r 2 A5 rr lda zSTATUS 000A7Ar 2 F0 03 beq @LEE80 000A7Cr 2 .endif 000A7Cr 2 20 rr rr jsr IecClearClockAndDataAfterDelay 000A7Fr 2 A5 rr @LEE80: lda zTBTCNT 000A81r 2 58 cli 000A82r 2 18 clc 000A83r 2 60 rts 000A84r 2 .endif 000A84r 2 000A84r 2 IecClkClear: 000A84r 2 ; clear (set inactive) the clock line 000A84r 2 AD 2C 91 lda IEC_REG_DATA_CLK_OUT 000A87r 2 29 FD and #~IEC_B_CLK_OUT 000A89r 2 8D 2C 91 sta IEC_REG_DATA_CLK_OUT 000A8Cr 2 60 rts 000A8Dr 2 000A8Dr 2 IecClkSet: 000A8Dr 2 ; set (set active) the clock line 000A8Dr 2 AD 2C 91 lda IEC_REG_DATA_CLK_OUT 000A90r 2 09 02 ora #IEC_B_CLK_OUT 000A92r 2 8D 2C 91 sta IEC_REG_DATA_CLK_OUT 000A95r 2 60 rts 000A96r 2 000A96r 2 .segment "KERNAL_IEC_DATA" 000000r 2 000000r 2 IecDataClear: 000000r 2 AD 2C 91 lda IEC_REG_DATA_CLK_OUT 000003r 2 29 DF and #~IEC_B_DATA_OUT 000005r 2 8D 2C 91 sta IEC_REG_DATA_CLK_OUT 000008r 2 60 rts 000009r 2 IecDataSet: 000009r 2 AD 2C 91 lda IEC_REG_DATA_CLK_OUT 00000Cr 2 09 20 ora #IEC_B_DATA_OUT 00000Er 2 8D 2C 91 sta IEC_REG_DATA_CLK_OUT 000011r 2 60 rts 000012r 2 000012r 2 ; reads in IEC register and returns 000012r 2 ; * C64: 000012r 2 ; - DATA IN in Carry 000012r 2 ; - CLOCK IN in A & 0x80 000012r 2 ; * VIC20: 000012r 2 ; - CLOCK IN in Carry 000012r 2 ; - DATA IN in A & 0x01 000012r 2 ; 000012r 2 IecGetDataClockIn: 000012r 2 AD 1F 91 lda IEC_REG_DATA_CLK_IN 000015r 2 CD 1F 91 cmp IEC_REG_DATA_CLK_IN 000018r 2 D0 F8 bne IecGetDataClockIn 00001Ar 2 .if CompileComputer >= C64_GENERAL 00001Ar 2 asl a 00001Ar 2 .else 00001Ar 2 4A lsr a 00001Br 2 .endif 00001Br 2 60 rts 00001Cr 2 00001Cr 2 00001Cr 2 .segment "KERNAL_IEC_DELAY" 000000r 2 000000r 2 IecDelay1ms: 000000r 2 000000r 2 .if CompileComputer >= C64_GENERAL 000000r 2 txa 000000r 2 ldx #184 000000r 2 @Delay: dex 000000r 2 bne @Delay 000000r 2 tax 000000r 2 .else 000000r 2 A9 04 lda #>$0400 ; program T2 for $0400 = 1024 cycles (approx. 1 ms) 000002r 2 8D 29 91 sta VIA2_T2CH ; (low byte is not written, thus, should be 0) 000005r 2 000005r 2 ; wait for T2 flag being set in the IFR, 000005r 2 ; telling us that the timer expired 000005r 2 @Wait: 000005r 2 AD 2D 91 lda VIA2_IFR 000008r 2 29 20 and #VIA_IFR_B_T2 00000Ar 2 F0 F9 beq @Wait 00000Cr 2 .endif 00000Cr 2 60 rts 00000Dr 2 00000Dr 2 00000Dr 1 .include "../kernal/rs232.a65" 00000Dr 2 LEEBB: 00000Dr 2 A5 rr lda zBITTS 00000Fr 2 F0 47 beq LEF06 000011r 2 30 3F bmi @LEF00 000013r 2 46 rr lsr zRODATA 000015r 2 A2 00 ldx #$00 000017r 2 90 01 bcc @LEEC8 000019r 2 CA dex 00001Ar 2 @LEEC8: 00001Ar 2 8A txa 00001Br 2 45 rr eor zROPRTY 00001Dr 2 85 rr sta zROPRTY 00001Fr 2 C6 rr dec zBITTS 000021r 2 F0 06 beq @LEED7 000023r 2 @LEED1: 000023r 2 8A txa 000024r 2 .if CompileComputer >= C64_GENERAL 000024r 2 and #$04 000024r 2 .else 000024r 2 29 20 and #$20 000026r 2 .endif 000026r 2 85 rr sta zNXTBIT 000028r 2 60 rts 000029r 2 000029r 2 @LEED7: 000029r 2 A9 20 lda #$20 00002Br 2 2C rr rr bit lM51CDR 00002Er 2 F0 14 beq @LEEF2 000030r 2 30 1C bmi @LEEFC 000032r 2 70 14 bvs @LEEF6 000034r 2 A5 rr lda zROPRTY 000036r 2 D0 01 bne @LEEE7 000038r 2 @LEEE6: 000038r 2 CA dex 000039r 2 @LEEE7: 000039r 2 C6 rr dec zBITTS 00003Br 2 AD rr rr lda lM51CTR 00003Er 2 10 E3 bpl @LEED1 000040r 2 C6 rr dec zBITTS 000042r 2 D0 DF bne @LEED1 000044r 2 @LEEF2: 000044r 2 E6 rr inc zBITTS 000046r 2 D0 F0 bne @LEEE6 000048r 2 @LEEF6: 000048r 2 A5 rr lda zROPRTY 00004Ar 2 F0 ED beq @LEEE7 00004Cr 2 D0 EA bne @LEEE6 00004Er 2 @LEEFC: 00004Er 2 70 E9 bvs @LEEE7 000050r 2 50 E6 bvc @LEEE6 000052r 2 ; ------------------ 000052r 2 000052r 2 @LEF00: 000052r 2 E6 rr inc zBITTS 000054r 2 A2 FF ldx #$FF 000056r 2 D0 CB bne @LEED1 000058r 2 000058r 2 LEF06: 000058r 2 AD rr rr lda lM51CDR 00005Br 2 4A lsr a 00005Cr 2 90 07 bcc @LEF13 00005Er 2 2C 20 91 bit RS232_REG_2 000061r 2 10 1D bpl LF016 000063r 2 50 1E bvc LEF31 000065r 2 @LEF13: 000065r 2 A9 00 lda #$00 000067r 2 85 rr sta zROPRTY 000069r 2 85 rr sta zNXTBIT 00006Br 2 AE rr rr ldx lBITNUM 00006Er 2 86 rr stx zBITTS 000070r 2 AC rr rr ldy lRODBS 000073r 2 CC rr rr cpy lRODBE 000076r 2 F0 13 beq LEF39 000078r 2 B1 rr lda (zROBUF),y 00007Ar 2 85 rr sta zRODATA 00007Cr 2 EE rr rr inc lRODBS 00007Fr 2 60 rts 000080r 2 000080r 2 LF016: 000080r 2 A9 40 lda #$40 000082r 2 2C .byte ASM_BIT3 000083r 2 LEF31: 000083r 2 A9 10 lda #$10 000085r 2 0D rr rr ora lRSSTAT 000088r 2 8D rr rr sta lRSSTAT 00008Br 2 LEF39: 00008Br 2 .if CompileComputer >= C64_GENERAL 00008Br 2 lda #CIA_ICR_B_TA 00008Br 2 LEF3B: sta CIA2 + CIA_O_ICR 00008Br 2 eor lENABL 00008Br 2 ora #CIA_ICR_BW_SET 00008Br 2 sta lENABL 00008Br 2 sta CIA2 + CIA_O_ICR 00008Br 2 .else 00008Br 2 A9 40 lda #$40 00008Dr 2 8D 1E 91 sta VIA1_IEC 000090r 2 .endif 000090r 2 60 rts 000091r 2 000091r 2 ; get number of bits to transmit 000091r 2 ; 000091r 2 LEF4A: 000091r 2 A2 09 ldx #$09 000093r 2 A9 20 lda #$20 000095r 2 2C rr rr bit lM51CTR 000098r 2 F0 01 beq @LEF54 00009Ar 2 CA dex 00009Br 2 @LEF54: 00009Br 2 50 02 bvc @LEF58 00009Dr 2 CA dex 00009Er 2 CA dex 00009Fr 2 @LEF58: 00009Fr 2 60 rts 0000A0r 2 ; --------------- 0000A0r 2 0000A0r 2 A6 rr LEF59: ldx zRINONE 0000A2r 2 D0 2E bne LEF90 0000A4r 2 C6 rr dec zBITC1 0000A6r 2 F0 31 beq LEF97 0000A8r 2 30 0D bmi LEF70 0000AAr 2 A5 rr lda zINBIT 0000ACr 2 45 rr eor zRIPRTY 0000AEr 2 85 rr sta zRIPRTY 0000B0r 2 46 rr lsr zINBIT 0000B2r 2 66 rr ror zRIDATA 0000B4r 2 60 LEF6D: rts 0000B5r 2 0000B5r 2 C6 rr LEF6E: dec zBITC1 0000B7r 2 A5 rr LEF70: lda zINBIT 0000B9r 2 F0 62 beq LEFDB 0000BBr 2 AD rr rr lda lM51CTR 0000BEr 2 0A asl a 0000BFr 2 A9 01 lda #$01 0000C1r 2 65 rr adc zBITC1 0000C3r 2 D0 EF bne LEF6D 0000C5r 2 LEF7E: 0000C5r 2 .if CompileComputer >= C64_GENERAL 0000C5r 2 lda #CIA_ICR_B_FLAG | CIA_ICR_BW_SET 0000C5r 2 sta CIA2 + CIA_O_ICR 0000C5r 2 ora lENABL 0000C5r 2 sta lENABL 0000C5r 2 .else 0000C5r 2 A9 90 lda #$90 0000C7r 2 8D 1E 91 sta VIA1_IEC 0000CAr 2 .endif 0000CAr 2 85 rr sta zRINONE 0000CCr 2 .if CompileComputer >= C64_GENERAL 0000CCr 2 lda #$02 0000CCr 2 jmp LEF3B 0000CCr 2 .else 0000CCr 2 A9 20 lda #$20 0000CEr 2 8D 1E 91 sta VIA1_IEC 0000D1r 2 60 rts 0000D2r 2 .endif 0000D2r 2 0000D2r 2 A5 rr LEF90: lda zINBIT 0000D4r 2 D0 EF bne LEF7E 0000D6r 2 .if CompileComputer >= C64_03 .AND CompileComputer <> C64_4064 0000D6r 2 jmp LE4D3 0000D6r 2 .else 0000D6r 2 85 rr sta zRINONE 0000D8r 2 60 rts 0000D9r 2 .endif 0000D9r 2 0000D9r 2 AC rr rr LEF97: ldy lRIDBE 0000DCr 2 C8 iny 0000DDr 2 CC rr rr cpy lRIDBS 0000E0r 2 F0 2A beq @LEFCA 0000E2r 2 8C rr rr sty lRIDBE 0000E5r 2 88 dey 0000E6r 2 A5 rr lda zRIDATA 0000E8r 2 AE rr rr ldx lBITNUM 0000EBr 2 E0 09 @LEFA9: cpx #$09 0000EDr 2 F0 04 beq @LEFB1 0000EFr 2 4A lsr a 0000F0r 2 E8 inx 0000F1r 2 D0 F8 bne @LEFA9 0000F3r 2 91 rr @LEFB1: sta (zRIBUF),y 0000F5r 2 A9 20 lda #$20 0000F7r 2 2C rr rr bit lM51CDR 0000FAr 2 F0 B9 beq LEF6E 0000FCr 2 30 B6 bmi LEF6D 0000FEr 2 A5 rr lda zINBIT 000100r 2 45 rr eor zRIPRTY 000102r 2 F0 03 beq @LEFC5 000104r 2 70 AE bvs LEF6D 000106r 2 2C .byte ASM_BIT3 000107r 2 50 AB @LEFC5: bvc LEF6D 000109r 2 A9 01 lda #$01 00010Br 2 2C .byte ASM_BIT3 00010Cr 2 A9 04 @LEFCA: lda #$04 00010Er 2 2C .byte ASM_BIT3 00010Fr 2 A9 80 LEFCD: lda #$80 000111r 2 2C .byte ASM_BIT3 000112r 2 A9 02 LEFD0: lda #$02 000114r 2 0D rr rr ora lRSSTAT 000117r 2 8D rr rr sta lRSSTAT 00011Ar 2 4C rr rr jmp LEF7E 00011Dr 2 00011Dr 2 A5 rr LEFDB: lda zRIDATA 00011Fr 2 D0 F1 bne LEFD0 000121r 2 F0 EC beq LEFCD 000123r 2 .if CompileComputer < C64_GENERAL 000123r 2 Rs232ErrIllegalDeviceNumber: 000123r 2 4C rr rr jmp KErrIllegalDeviceNumber 000126r 2 .endif 000126r 2 000126r 2 RS232_CHKOUT: 000126r 2 85 rr sta zDFLTO 000128r 2 AD rr rr lda lM51CDR 00012Br 2 4A lsr a 00012Cr 2 90 27 bcc LF012 00012Er 2 A9 02 lda #$02 000130r 2 2C 10 91 bit RS232_REG_1 000133r 2 10 1D bpl LF00D 000135r 2 D0 1E bne LF012 000137r 2 000137r 2 @LEFF2: 000137r 2 .if CompileComputer >= C64_GENERAL 000137r 2 lda lENABL 000137r 2 and #CIA_ICR_B_TB 000137r 2 .else 000137r 2 AD 1E 91 lda VIA1_IEC 00013Ar 2 29 30 and #$30 00013Cr 2 .endif 00013Cr 2 D0 F9 bne @LEFF2 00013Er 2 @LEFF9: 00013Er 2 2C 10 91 bit RS232_REG_1 000141r 2 70 FB bvs @LEFF9 000143r 2 AD 10 91 lda RS232_REG_1 000146r 2 09 02 ora #$02 000148r 2 8D 10 91 sta RS232_REG_1 00014Br 2 @LF006: 00014Br 2 2C 10 91 bit RS232_REG_1 00014Er 2 70 05 bvs LF012 000150r 2 30 F9 bmi @LF006 000152r 2 000152r 2 LF00D: 000152r 2 .if CompileComputer >= C64_GENERAL 000152r 2 lda #$40 000152r 2 sta lRSSTAT 000152r 2 .else 000152r 2 20 rr rr jsr LF016 000155r 2 .endif 000155r 2 18 LF012: clc 000156r 2 60 rts 000157r 2 000157r 2 000157r 2 LF014: 000157r 2 000157r 2 .if CompileComputer >= C64_GENERAL 000157r 2 jsr LF028 000157r 2 .endif 000157r 2 000157r 2 ; Write a character to the RS232 output buffer 000157r 2 ; 000157r 2 ; The character is returned in A. If there is 000157r 2 ; no character in the buffer, A will contain 0. 000157r 2 ; 000157r 2 ; For C64 and above, this function also 000157r 2 ; sets lRSSTAT.3 (TODO: "buffer empty"?) 000157r 2 ; 000157r 2 RS232_PUTCHAR: 000157r 2 AC rr rr ldy lRODBE ; is the output buffer read pointer 00015Ar 2 C8 iny ; + 1 00015Br 2 CC rr rr cpy lRODBS ; equal to the output buffer write pointer? 00015Er 2 F0 F7 beq LF014 ; yes -> ring buffer is full -> wait until it is empty again 000160r 2 000160r 2 8C rr rr sty lRODBE ; advance the output buffer write pointer, leaving room for the character to be written 000163r 2 000163r 2 88 dey ; the location we reserved the space for is one before, thus, decrement Y again 000164r 2 000164r 2 .if CompileComputer >= C64_GENERAL 000164r 2 lda zPTR1 000164r 2 .endif 000164r 2 91 rr sta (zROBUF),y ; store the output character into the output buffer 000166r 2 000166r 2 .if CompileComputer >= C64_GENERAL 000166r 2 LF028: lda lENABL 000166r 2 lsr a ; test CIA_ICR_B_TA 000166r 2 bcs @Rts 000166r 2 lda #CIA_CRA_B_FORCE_LOAD 000166r 2 sta CIA2 + CIA_O_CRA 000166r 2 .else 000166r 2 2C 1E 91 bit VIA1_IEC 000169r 2 50 01 bvc @LF102 00016Br 2 60 rts 00016Cr 2 @LF102: 00016Cr 2 00016Cr 2 .endif 00016Cr 2 00016Cr 2 AD rr rr lda lBAUDOF 00016Fr 2 8D 14 91 sta RS232_TIMER_LO 000172r 2 AD rr rr lda lBAUDOF + 1 000175r 2 8D 15 91 sta RS232_TIMER_HI 000178r 2 000178r 2 .if CompileComputer >= C64_GENERAL 000178r 2 lda #$81 000178r 2 jsr LEF3B 000178r 2 jsr LEF06 000178r 2 lda #$11 000178r 2 sta CIA2 + CIA_O_CRA 000178r 2 @Rts: rts 000178r 2 .else 000178r 2 A9 C0 lda #$C0 00017Ar 2 8D 1E 91 sta VIA1_IEC 00017Dr 2 4C rr rr jmp LEF06 000180r 2 .endif 000180r 2 000180r 2 RS232_CHKIN: 000180r 2 85 rr sta zDFLTN ; set default output device 000182r 2 AD rr rr lda lM51CDR 000185r 2 4A lsr a 000186r 2 90 28 bcc @LF07D 000188r 2 29 08 and #$08 00018Ar 2 F0 24 beq @LF07D 00018Cr 2 A9 02 lda #$02 00018Er 2 2C 10 91 bit RS232_REG_1 000191r 2 10 BF bpl LF00D 000193r 2 F0 19 beq @ClcRts 000195r 2 000195r 2 @LF062: 000195r 2 .if CompileComputer >= C64_GENERAL 000195r 2 lda lENABL 000195r 2 lsr a ; test CIA_ICR_B_TA 000195r 2 bcs @LF062 000195r 2 .else 000195r 2 2C 1E 91 bit VIA1_IEC 000198r 2 70 FB bvs @LF062 00019Ar 2 .endif 00019Ar 2 00019Ar 2 AD 10 91 lda RS232_REG_1 00019Dr 2 29 FD and #~$02 00019Fr 2 8D 10 91 sta RS232_REG_1 0001A2r 2 @LF070: 0001A2r 2 AD 10 91 lda RS232_REG_1 0001A5r 2 29 04 and #$04 0001A7r 2 F0 F9 beq @LF070 0001A9r 2 A9 90 @LF077: lda #$90 0001ABr 2 .if CompileComputer >= C64_GENERAL 0001ABr 2 clc 0001ABr 2 jmp LEF3B 0001ABr 2 .else 0001ABr 2 8D 1E 91 sta VIA1_IEC 0001AEr 2 @ClcRts: 0001AEr 2 18 clc 0001AFr 2 60 rts 0001B0r 2 .endif 0001B0r 2 0001B0r 2 @LF07D: 0001B0r 2 0001B0r 2 .if CompileComputer >= C64_GENERAL 0001B0r 2 lda lENABL 0001B0r 2 and #CIA_ICR_B_FLAG | CIA_ICR_B_TB 0001B0r 2 .else 0001B0r 2 AD 1E 91 lda VIA1_IEC 0001B3r 2 29 30 and #$30 0001B5r 2 .endif 0001B5r 2 F0 F2 beq @LF077 0001B7r 2 0001B7r 2 .if CompileComputer >= C64_GENERAL 0001B7r 2 @ClcRts: 0001B7r 2 .endif 0001B7r 2 18 clc 0001B8r 2 60 rts 0001B9r 2 0001B9r 2 ; Read a character from the RS232 input buffer 0001B9r 2 ; 0001B9r 2 ; The character is returned in A. If there is 0001B9r 2 ; no character in the buffer, A will contain 0. 0001B9r 2 ; 0001B9r 2 ; For C64 and above, this function also 0001B9r 2 ; sets lRSSTAT.3 (TODO: "buffer empty"?) 0001B9r 2 ; 0001B9r 2 RS232_GETCHAR: 0001B9r 2 0001B9r 2 .if CompileComputer >= C64_GENERAL 0001B9r 2 lda lRSSTAT ; as we modifiy lRSSTAT, make its value available for both if() cases. 0001B9r 2 .endif 0001B9r 2 0001B9r 2 AC rr rr ldy lRIDBS ; get read buffer into RS232 input buffer 0001BCr 2 CC rr rr cpy lRIDBE ; compare with write buffer 0001BFr 2 F0 06 beq @BufferEmpty ; they are the same -> input buffer empty -> skip reading 0001C1r 2 0001C1r 2 .if CompileComputer >= C64_GENERAL 0001C1r 2 and #~$08 0001C1r 2 sta lRSSTAT ; clear bit: buffer is not empty (TODO?) 0001C1r 2 .endif 0001C1r 2 B1 rr lda (zRIBUF),y ; get character from buffer 0001C3r 2 EE rr rr inc lRIDBS ; increment read pointer 0001C6r 2 60 rts 0001C7r 2 ; --------------- 0001C7r 2 0001C7r 2 @BufferEmpty: 0001C7r 2 0001C7r 2 .if CompileComputer >= C64_GENERAL 0001C7r 2 ora #$08 0001C7r 2 sta lRSSTAT ; set bit: buffer empty (TODO?) 0001C7r 2 .endif 0001C7r 2 A9 00 lda #$00 ; return: no character in buffer 0001C9r 2 60 rts 0001CAr 2 ; --------------- 0001CAr 2 0001CAr 2 0001CAr 2 LF0A4: 0001CAr 2 0001CAr 2 48 pha 0001CBr 2 .if CompileComputer >= C64_GENERAL 0001CBr 2 lda lENABL 0001CBr 2 .else 0001CBr 2 AD 1E 91 lda VIA1_IEC 0001CEr 2 .endif 0001CEr 2 F0 0C beq @PlaRts 0001D0r 2 0001D0r 2 @Wait: 0001D0r 2 0001D0r 2 .if CompileComputer >= C64_GENERAL 0001D0r 2 lda lENABL 0001D0r 2 and #CIA_ICR_B_TA | CIA_ICR_B_TB 0001D0r 2 .else 0001D0r 2 AD 1E 91 lda VIA1_IEC 0001D3r 2 29 60 and #VIA_IER_B_T1 | VIA_IER_B_T2 0001D5r 2 .endif 0001D5r 2 D0 F9 bne @Wait 0001D7r 2 0001D7r 2 .if CompileComputer >= C64_GENERAL 0001D7r 2 lda #CIA_ICR_B_FLAG 0001D7r 2 sta CIA2 + CIA_O_ICR 0001D7r 2 .else 0001D7r 2 A9 10 lda #VIA_IER_B_CB1 0001D9r 2 8D 1E 91 sta VIA1_IEC 0001DCr 2 .endif 0001DCr 2 0001DCr 2 .if CompileComputer >= C64_GENERAL 0001DCr 2 lda #$00 0001DCr 2 sta lENABL 0001DCr 2 .endif 0001DCr 2 0001DCr 2 @PlaRts: 0001DCr 2 68 pla 0001DDr 2 60 rts 0001DEr 2 0001DEr 2 0001DEr 1 .include "../kernal/message.a65" 0001DEr 2 ; KERNAL system essages 0001DEr 2 0001DEr 2 LMESSAGES: 0001DEr 2 0001DEr 2 StrIoError: 0001DEr 2 0D .byte ASC_CR 0001DFr 2 49 2F 4F 20 htasc "I/O ERROR #" ; used in case an I/O error occurs in a KERNAL routine, and zNSGFLG.6 is set 0001E3r 2 45 52 52 4F 0001E7r 2 52 20 A3 0001EAr 2 0001EAr 2 StrSearching: 0001EAr 2 0D .byte ASC_CR 0001EBr 2 53 45 41 52 htasc "SEARCHING " ; used when loading, and zNSGFLG.7 is set 0001EFr 2 43 48 49 4E 0001F3r 2 47 A0 0001F5r 2 0001F5r 2 StrFor: 0001F5r 2 46 4F 52 A0 htasc "FOR " ; used when loading with a file name, and zNSGFLG.7 is set 0001F9r 2 0001F9r 2 StrPlay: 0001F9r 2 0001F9r 2 .ifdef JIFFY 0001F9r 2 0001F9r 2 StrRecPlay = $F0EB 0001F9r 2 0001F9r 2 JDLF0D8: 0001F9r 2 lda #$00 0001F9r 2 sta VIC + VICII_O_SprEnable 0001F9r 2 @JDLF0DD: 0001F9r 2 adc #$01 0001F9r 2 bne @JDLF0DD 0001F9r 2 rts 0001F9r 2 0001F9r 2 JDLF0E2: 0001F9r 2 lda zPTR2 0001F9r 2 JDLF0E4: 0001F9r 2 pha 0001F9r 2 jsr kCLRCHN 0001F9r 2 pla 0001F9r 2 tax 0001F9r 2 jmp kCHKIN 0001F9r 2 0001F9r 2 JDLF0ED: 0001F9r 2 lda #$00 0001F9r 2 sta zTSFCNT 0001F9r 2 jmp IecDataClear 0001F9r 2 0001F9r 2 JDLF0F4: 0001F9r 2 txa 0001F9r 2 pha 0001F9r 2 jsr JDLF7A2 0001F9r 2 pla 0001F9r 2 tax 0001F9r 2 @JDLF0FB: 0001F9r 2 lda JDLF398,x 0001F9r 2 jsr kCHROUT 0001F9r 2 inx 0001F9r 2 dey 0001F9r 2 bne @JDLF0FB 0001F9r 2 rts 0001F9r 2 0001F9r 2 .else 0001F9r 2 0001F9r 2 .if CompileComputer = C64_SX64 0001F9r 2 0001F9r 2 ; the SX64 does not have a tape, thus, "PRESS PLAY ON TAPE" is not needed there 0001F9r 2 ; However, it redefines the Shift+Run/STOP message. This alternative message 0001F9r 2 ; can be found here: 0001F9r 2 0001F9r 2 TEXT_LOAD_8_RUN: 0001F9r 2 .byte "LOAD",'"',":*",'"',",8",ASC_CR 0001F9r 2 .byte "RUN",ASC_CR 0001F9r 2 END_TEXT_LOAD_8_RUN: 0001F9r 2 0001F9r 2 .else 0001F9r 2 0D 50 52 45 .byte ASC_CR,"PRESS PLAY ON " ; used when loading from tape (on the 4064, zNSGFLG.7 has to be set, too) 0001FDr 2 53 53 20 50 000201r 2 4C 41 59 20 000208r 2 .endif 000208r 2 54 41 50 C5 htasc "TAPE" ; remaining part of the "PRESS PLAY ON TAPE" message 00020Cr 2 00020Cr 2 StrRecPlay: 00020Cr 2 50 52 45 53 htasc "PRESS RECORD & PLAY ON TAPE" ; used when storing to tape (on the 4064, zNSGFLG.7 has to be set, too) 000210r 2 53 20 52 45 000214r 2 43 4F 52 44 000227r 2 000227r 2 .endif 000227r 2 000227r 2 StrLoading: 000227r 2 0D .byte ASC_CR 000228r 2 4C 4F 41 44 htasc "LOADING" ; used when KERNAL LOAD is executed, and zNSGFLG.7 is set 00022Cr 2 49 4E C7 00022Fr 2 00022Fr 2 StrSaving: 00022Fr 2 0D .byte ASC_CR 000230r 2 53 41 56 49 htasc "SAVING " ; used when KERNAL SAVE is executed, and zNSGFLG.7 is set 000234r 2 4E 47 A0 000237r 2 000237r 2 StrVerifying: 000237r 2 0D .byte ASC_CR 000238r 2 56 45 52 49 htasc "VERIFYING" ; used when KERNAL VERIFY is executed, and zNSGFLG.7 is set 00023Cr 2 46 59 49 4E 000240r 2 C7 000241r 2 000241r 2 StrFound: 000241r 2 0D .byte ASC_CR 000242r 2 46 4F 55 4E htasc "FOUND " ; used when loading from tape 000246r 2 44 A0 000248r 2 StrOk: 000248r 2 0D 4F 4B 8D .byte ASC_CR,"OK",ASC_CR + $80 ; used when loading from or storing to tape (on the 4064, zNSGFLG.7 has to be set, too) 00024Cr 2 00024Cr 2 00024Cr 2 OutputMessageIfAllowed: 00024Cr 2 24 rr bit zNSGFLG ; check KERNAL output policy 00024Er 2 10 0D bpl OutputMessage_ClcRts ; bit 7 unset -> policy forbids output -> branch, all done 000250r 2 000250r 2 OutputMessage: 000250r 2 B9 rr rr lda LMESSAGES,y ; get character from message 000253r 2 08 php ; remember status (especially N, which represents bit 7 of the message) 000254r 2 000254r 2 29 7F and #$7F ; delete bit 7 (which acts as an end marker) 000256r 2 20 rr rr jsr kCHROUT ; output the character 000259r 2 C8 iny ; proceed to next character 00025Ar 2 00025Ar 2 28 plp ; get back N as indicator for bit 7 of the message 00025Br 2 10 F3 bpl OutputMessage ; bit 7 was not set -> process to next character 00025Dr 2 00025Dr 2 OutputMessage_ClcRts: 00025Dr 2 18 clc ; mark: no error 00025Er 2 60 rts 00025Fr 2 ; ------------------- 00025Fr 2 00025Fr 1 .include "../kernal/fileio.a65" 00025Fr 2 ; B-11. Function Name: GETIN 00025Fr 2 ; 00025Fr 2 ; 00025Fr 2 ; Purpose: Get a character 00025Fr 2 ; Call address: $FFE4 (hex) 65508 (decimal) 00025Fr 2 ; Communication registers: A 00025Fr 2 ; Preparatory routines: CHKIN, OPEN 00025Fr 2 ; Error returns: See READST 00025Fr 2 ; Stack requirements: 7+ 00025Fr 2 ; Registers affected: A (X, Y) 00025Fr 2 ; 00025Fr 2 ; Description: If the channel is the keyboard, this subroutine removes 00025Fr 2 ; one character from the keyboard queue and returns it as an ASCII value in 00025Fr 2 ; the accumulator. If the queue is empty, the value returned in the 00025Fr 2 ; accumulator will be zero. Characters are put into the queue automatically 00025Fr 2 ; by an interrupt driven keyboard scan routine which calls the SCNKEY 00025Fr 2 ; routine. The keyboard buffer can hold up to ten characters. After the 00025Fr 2 ; buffer is filled, additional characters are ignored until at least one 00025Fr 2 ; character has been removed from the queue. If the channel is RS-232, then 00025Fr 2 ; only the A register is used and a single character is returned. See 00025Fr 2 ; READST to check validity. If the channel is serial, cassette, or screen, 00025Fr 2 ; call BASIN routine. 00025Fr 2 ; 00025Fr 2 ; 00025Fr 2 ; How to Use: 00025Fr 2 ; 00025Fr 2 ; 1) Call this routine using a JSR instruction. 00025Fr 2 ; 2) Check for a zero in the accumulator (empty buffer). 00025Fr 2 ; 3) Process the data. 00025Fr 2 ; 00025Fr 2 ; 00025Fr 2 ; EXAMPLE: 00025Fr 2 ; 00025Fr 2 ; ;WAIT FOR A CHARACTER 00025Fr 2 ; WAIT JSR GETIN 00025Fr 2 ; CMP #0 00025Fr 2 ; BEQ WAIT 00025Fr 2 ; 00025Fr 2 00025Fr 2 KGETIN: 00025Fr 2 A5 rr lda zDFLTN ; get device address 000261r 2 D0 08 bne @NoKeyboard ; != 0 --> not the keyboard 000263r 2 A5 rr lda zNDX ; are there characters in the key buffer? 000265r 2 F0 6D beq ClcRts1 ; no, next test 000267r 2 78 sei ; protect the keyboard buffer 000268r 2 4C rr rr jmp GETIN_KEYB ; get key from keyboard buffer 00026Br 2 00026Br 2 @NoKeyboard: 00026Br 2 C9 02 cmp #FILE_RS232 ; device address = RS232 device? 00026Dr 2 D0 18 bne LF166 ; no, next test 00026Fr 2 00026Fr 2 KGETIN_RS232: 00026Fr 2 84 rr sty zTEMPX ; save Y in order to leave it unchanged 000271r 2 20 rr rr jsr RS232_GETCHAR ; get a character from RS232 000274r 2 A4 rr ldy zTEMPX ; restore Y 000276r 2 000276r 2 .if CompileComputer >= C64_GENERAL 000276r 2 ClcRts1: 000276r 2 .endif 000276r 2 000276r 2 18 clc 000277r 2 60 rts 000278r 2 000278r 2 ; B-4. Function Name: CHRIN a.k.a. BASIN 000278r 2 ; 000278r 2 ; Purpose: Get a character from the input channel 000278r 2 ; Call address: $FFCF (hex) 65487 (decimal) 000278r 2 ; Communication registers: A 000278r 2 ; Preparatory routines: (OPEN, CHKIN) 000278r 2 ; Error returns: 0 (See READST) 000278r 2 ; Stack requirements: 7+ 000278r 2 ; Registers affected: A, X 000278r 2 ; 000278r 2 ; Description: This routine gets a byte of data from a channel already 000278r 2 ; set up as the input channel by the KERNAL routine CHKIN. If the CHKIN has 000278r 2 ; NOT been used to define another input channel, then all your data is 000278r 2 ; expected from the keyboard. The data byte is returned in the accumulator. 000278r 2 ; The channel remains open after the call. 000278r 2 ; Input from the keyboard is handled in a special way. First, the cursor 000278r 2 ; is turned on, and blinks until a carriage return is typed on the 000278r 2 ; keyboard. All characters on the line (up to 88 characters) are stored in 000278r 2 ; the BASIC input buffer. These characters can be retrieved one at a time 000278r 2 ; by calling this routine once for each character. When the carriage return 000278r 2 ; is retrieved, the entire line has been processed. The next time this 000278r 2 ; routine is called, the whole process begins again, i.e., by flashing the 000278r 2 ; cursor. 000278r 2 ; 000278r 2 ; How to Use: 000278r 2 ; 000278r 2 ; FROM THE KEYBOARD 000278r 2 ; 000278r 2 ; 1) Retrieve a byte of data by calling this routine. 000278r 2 ; 2) Store the data byte. 000278r 2 ; 3) Check if it is the last data byte (is it a CR?) 000278r 2 ; 4) If not, go to step 1. 000278r 2 ; 000278r 2 ; EXAMPLE: 000278r 2 ; 000278r 2 ; LDY $#00 ;PREPARE THE Y REGISTER TO STORE THE DATA 000278r 2 ; RD JSR CHRIN 000278r 2 ; STA DATA,Y ;STORE THE YTH DATA BYTE IN THE YTH 000278r 2 ; ;LOCATION IN THE DATA AREA. 000278r 2 ; INY 000278r 2 ; CMP #CR ;IS IT A CARRIAGE RETURN? 000278r 2 ; BNE RD ;NO, GET ANOTHER DATA BYTE 000278r 2 ; 000278r 2 ; 000278r 2 ; 000278r 2 ; EXAMPLE: 000278r 2 ; 000278r 2 ; JSR CHRIN 000278r 2 ; STA DATA 000278r 2 ; 000278r 2 ; FROM OTHER DEVICES 000278r 2 ; 000278r 2 ; 0) Use the KERNAL OPEN and CHKIN routines. 000278r 2 ; 1) Call this routine (using a JSR instruction). 000278r 2 ; 2) Store the data. 000278r 2 ; 000278r 2 ; EXAMPLE: 000278r 2 ; 000278r 2 ; JSR CHRIN 000278r 2 ; STA DATA 000278r 2 ; 000278r 2 ; 000278r 2 KBASIN: 000278r 2 A5 rr lda zDFLTN ; get device address 00027Ar 2 .ifdef JIFFY 00027Ar 2 bne JDLF1A9 00027Ar 2 .else 00027Ar 2 D0 0B bne LF166 ; not keyboard --> jump 00027Cr 2 .endif 00027Cr 2 00027Cr 2 ; TODO 00027Cr 2 A5 rr lda zPNTR ; remember zPNTR (current column on screen) in zTEMP_zPNTR 00027Er 2 85 rr sta zTEMP_zPNTR ; for later restoration 000280r 2 000280r 2 A5 rr lda zTBLX ; remember zTBLX (current row on screen) in zLXSP 000282r 2 85 rr sta zLXSP 000284r 2 000284r 2 4C rr rr jmp BASIN_KEYB ; input character from the screen 000287r 2 ; --------------------- 000287r 2 000287r 2 C9 03 LF166: cmp #FILE_SCREEN ; device address == screen? 000289r 2 D0 09 bne KBASIN_NoScreen ; no, next test 00028Br 2 00028Br 2 ; TODO 00028Br 2 JDLF16A: 00028Br 2 85 rr sta zCRSW ; zCRSW := 3 --> mark that we do not wait for key pressed until CR has been pressed 00028Dr 2 00028Dr 2 A5 rr lda zLNMX ; logical line length of the current line 00028Fr 2 85 rr sta zINDX ; is the number of characters in this line 000291r 2 000291r 2 4C rr rr jmp BASIN_KEYB ; input character from the screen 000294r 2 ; --------------------- 000294r 2 000294r 2 KBASIN_NoScreen: 000294r 2 B0 38 bcs KBASIN_TestIec ; greater than screen (that is, IEC bus) --> jump 000296r 2 C9 02 cmp #FILE_RS232 ; is it from RS232? 000298r 2 F0 3F beq BASIN_RS232 ; Yes, process RS232 00029Ar 2 00029Ar 2 .ifdef JIFFY 00029Ar 2 JDLF179: 00029Ar 2 jsr JDLFBAA 00029Ar 2 pha 00029Ar 2 bit zTSFCNT 00029Ar 2 bvc LF19C 00029Ar 2 cpx #$00 00029Ar 2 bne LF187 00029Ar 2 lda $C4 00029Ar 2 LF187: cmp #$04 00029Ar 2 bcc LF19C 00029Ar 2 ldy #$00 00029Ar 2 lda (zFNADR),y 00029Ar 2 cmp #$24 00029Ar 2 beq LF19C 00029Ar 2 inc zSA 00029Ar 2 jsr JDLF38B 00029Ar 2 dec zSA 00029Ar 2 asl zTSFCNT 00029Ar 2 LF19C: pla 00029Ar 2 rts 00029Ar 2 LF19E: lda #$10 00029Ar 2 jmp SetStatus 00029Ar 2 00029Ar 2 LF1A3: .addr PatchErrorOut 00029Ar 2 .addr IMAIN 00029Ar 2 .addr LA57C 00029Ar 2 00029Ar 2 JDLF1A9: 00029Ar 2 cmp #$04 00029Ar 2 bcc LF166 00029Ar 2 00029Ar 2 .else 00029Ar 2 ; if we are here, we want to get input from TAPE 00029Ar 2 00029Ar 2 86 rr stx zTEMPX ; remember X 00029Cr 2 20 rr rr jsr @GetNextTapeCharacterFromBuffer ; read in the next character from the tape buffer 00029Fr 2 B0 16 bcs @Ret_No_PLA ; if an error occurred, stop here 0002A1r 2 0002A1r 2 ; Find out if we can read even one more character, and that character is not 0. 0002A1r 2 ; Note that we only test for it. The value will be disregarded, and the tape buffer pointer 0002A1r 2 ; will be set backwards afterwards! 0002A1r 2 0002A1r 2 48 pha ; remember the read character 0002A2r 2 20 rr rr jsr @GetNextTapeCharacterFromBuffer ; read in the next character from the tape buffer 0002A5r 2 B0 0D bcs @Ret_With_PLA ; if an error occurred, stop here, making sure to PLA the remembered character 0002A7r 2 0002A7r 2 D0 05 bne @NoNulCharacter ; no NUL ($00) character -> branch, skip setting the status flag 0002A9r 2 0002A9r 2 ; mark an end-of-file status 0002A9r 2 A9 40 lda #STATUS_TAPE_EOF 0002ABr 2 20 rr rr jsr SetStatus 0002AEr 2 0002AEr 2 @NoNulCharacter: 0002AEr 2 C6 rr dec zBUFPNT ; put tape buffer pointer backwards, so we will read the same byte again in the next call 0002B0r 2 0002B0r 2 A6 rr ldx zTEMPX ; get back (remembered) X 0002B2r 2 68 pla ; get back remembered character 0002B3r 2 60 rts 0002B4r 2 ; ---------------------- 0002B4r 2 0002B4r 2 @Ret_With_PLA: 0002B4r 2 AA tax 0002B5r 2 68 pla 0002B6r 2 8A txa 0002B7r 2 0002B7r 2 @Ret_No_PLA: 0002B7r 2 A6 rr ldx zTEMPX ; get back (remembered) X 0002B9r 2 60 rts 0002BAr 2 ; ---------------------- 0002BAr 2 0002BAr 2 @GetNextTapeCharacterFromBuffer: 0002BAr 2 20 rr rr jsr TAPE_INCREMENT_WRITE_POINTER ; increment the pointer into the tape buffer 0002BDr 2 D0 0B bne @ReadTapeBuffer ; Z = 0 --> there are still bytes to read --> branch, read bytes 0002BFr 2 0002BFr 2 ; we must read in the next tape buffer from tape 0002BFr 2 0002BFr 2 20 rr rr jsr TapeReadNextBuffer ; read in the next tape buffer 0002C2r 2 B0 11 bcs BASIN_RTS1 ; C = 1 --> an error occurred -> branch, return with C = 1 indicating an error 0002C4r 2 0002C4r 2 A9 00 lda #0 ; set tape buffer pointer to 0 (will be incremented directly afterwards) 0002C6r 2 85 rr sta zBUFPNT ; this ensures we skip the tape buffer type marker at position 0. 0002C8r 2 0002C8r 2 F0 F0 beq @GetNextTapeCharacterFromBuffer ; (uncond. branch) retry reading the tape buffer 0002CAr 2 ; ------------------ 0002CAr 2 0002CAr 2 @ReadTapeBuffer: 0002CAr 2 B1 rr lda (zTAPE1),y 0002CCr 2 18 clc 0002CDr 2 60 rts 0002CEr 2 .endif 0002CEr 2 0002CEr 2 KBASIN_TestIec: 0002CEr 2 ; Input from IEC bus 0002CEr 2 A5 rr lda zSTATUS ; current status 0002D0r 2 F0 04 beq BASIN_IEC ; == 0 --> jump, get byte from IEC bus 0002D2r 2 0002D2r 2 ReturnCR: 0002D2r 2 A9 0D lda #ASC_CR ; an error or EOI occurred on the IEC bus, return CR 0002D4r 2 0002D4r 2 .if CompileComputer < C64_GENERAL 0002D4r 2 ClcRts1: 0002D4r 2 .endif 0002D4r 2 ClcRts2: 0002D4r 2 18 clc 0002D5r 2 .if CompileComputer >= C64_GENERAL 0002D5r 2 BASIN_RTS2: 0002D5r 2 .endif 0002D5r 2 BASIN_RTS1: 0002D5r 2 60 rts 0002D6r 2 0002D6r 2 BASIN_IEC: 0002D6r 2 .ifdef JIFFY 0002D6r 2 jmp JDLFBAA 0002D6r 2 .else 0002D6r 2 4C rr rr jmp iACPTR 0002D9r 2 .endif 0002D9r 2 0002D9r 2 BASIN_RS232: 0002D9r 2 ; get data from RS232 0002D9r 2 20 rr rr jsr KGETIN_RS232 ; get character from RS232, or 0 if empty 0002DCr 2 B0 05 bcs BASIN_RTS2 0002DEr 2 0002DEr 2 C9 00 cmp #0 ; did we read a 0 (buffer empty)? 0002E0r 2 0002E0r 2 .if CompileComputer >= C64_GENERAL 0002E0r 2 bne ClcRts2 ; no -> return with the current character 0002E0r 2 0002E0r 2 lda lRSSTAT ; check lRSSTAT (TODO) 0002E0r 2 and #$60 ; TODO: Meaning of the bits? 0002E0r 2 bne ReturnCR ; bits are not null -> return with ASCII CR instead of waiting 0002E0r 2 beq BASIN_RS232 ; wait until there is a character received from RS232 0002E0r 2 ; ------------------- 0002E0r 2 .else 0002E0r 2 F0 F7 beq BASIN_RS232 ; yes, wait until there is a character received from RS232 0002E2r 2 18 clc ; return: No error 0002E3r 2 0002E3r 2 BASIN_RTS2: 0002E3r 2 60 rts 0002E4r 2 ; -------------------- 0002E4r 2 .endif 0002E4r 2 ; -------------------- 0002E4r 2 0002E4r 2 ; B-5. Function Name: CHROUT a.k.a. BSOUT 0002E4r 2 ; 0002E4r 2 ; Purpose: Output a character 0002E4r 2 ; Call address: $FFD2 (hex) 65490 (decimal) 0002E4r 2 ; Communication registers: A 0002E4r 2 ; Preparatory routines: (CHKOUT,OPEN) 0002E4r 2 ; Error returns: 0 (See READST) 0002E4r 2 ; Stack requirements: 8+ 0002E4r 2 ; Registers affected: A 0002E4r 2 ; 0002E4r 2 ; Description: This routine outputs a character to an already opened 0002E4r 2 ; channel. Use the KERNAL OPEN and CHKOUT routines to set up the output 0002E4r 2 ; channel before calling this routine, If this call is omitted, data is 0002E4r 2 ; sent to the default output device (number 3, the screen). The data byte 0002E4r 2 ; to be output is loaded into the accumulator, and this routine is called. 0002E4r 2 ; The data is then sent to the specified output device. The channel is left 0002E4r 2 ; open after the call. 0002E4r 2 ; 0002E4r 2 ; +-----------------------------------------------------------------------+ 0002E4r 2 ; | NOTE: Care must be taken when using this routine to send data to a | 0002E4r 2 ; | specific serial device since data will be sent to all open output | 0002E4r 2 ; | channels on the bus. Unless this is desired, all open output channels | 0002E4r 2 ; | on the serial bus other than the intended destination channel must be | 0002E4r 2 ; | closed by a call to the KERNAL CLRCHN routine. | 0002E4r 2 ; +-----------------------------------------------------------------------+ 0002E4r 2 ; 0002E4r 2 ; 0002E4r 2 ; 0002E4r 2 ; How to Use: 0002E4r 2 ; 0002E4r 2 ; 0) Use the CHKOUT KERNAL routine if needed, (see description above). 0002E4r 2 ; 1) Load the data to be output into the accumulator. 0002E4r 2 ; 2) Call this routine. 0002E4r 2 ; 0002E4r 2 ; EXAMPLE: 0002E4r 2 ; 0002E4r 2 ; ;DUPLICATE THE BASIC INSTRUCTION CMD 4,"A"; 0002E4r 2 ; LDX #4 ;LOGICAL FILE #4 0002E4r 2 ; JSR CHKOUT ;OPEN CHANNEL OUT 0002E4r 2 ; LDA #'A 0002E4r 2 ; JSR CHROUT ;SEND CHARACTER 0002E4r 2 ; 0002E4r 2 ; 0002E4r 2 KBSOUT: 0002E4r 2 48 pha ; remember character to be output 0002E5r 2 A5 rr lda zDFLTO ; get output device 0002E7r 2 C9 03 cmp #FILE_SCREEN ; is it the screen? 0002E9r 2 D0 04 bne @NoScreen ; no -> jump, test other devices 0002EBr 2 68 pla ; get back the character to be output 0002ECr 2 4C rr rr jmp CHROUT_SCREEN ; output to screen 0002EFr 2 ; ---------------------- 0002EFr 2 0002EFr 2 @NoScreen: 0002EFr 2 90 04 bcc @NoIec ; device number is less than (or equal, but this cannot be here) than screen (3) -> jump, output is not on the IEC bus 0002F1r 2 68 pla ; get back the character to be output 0002F2r 2 4C rr rr jmp iCIOUT ; output character to the IEC bus 0002F5r 2 0002F5r 2 @NoIec: 0002F5r 2 .if CompileComputer >= C64_GENERAL 0002F5r 2 ; here, A can only contain 0, 1 or 2. "1" is tape, "2" is RS232. 0002F5r 2 ; TODO: Can it contain 0 at all? 0002F5r 2 0002F5r 2 lsr a ; prepare comparison with RS232 device 0002F5r 2 ; if C == 1, than output is to tape. If C == 0, then output is to console (0 - TODO) or RS232 (2). 0002F5r 2 0002F5r 2 .else 0002F5r 2 C9 02 cmp #FILE_RS232 ; output device = RS232? 0002F7r 2 F0 2A beq KBSOUT_RS232 ; yes -> jump, output to RS232 0002F9r 2 .endif 0002F9r 2 0002F9r 2 68 pla ; get back the character to be output 0002FAr 2 0002FAr 2 KBSOUT_TAPE: 0002FAr 2 0002FAr 2 85 rr sta zPTR1 ; remember character to be output 0002FCr 2 0002FCr 2 .if CompileComputer < C64_GENERAL 0002FCr 2 48 pha ; remember character to be output on stack 0002FDr 2 .endif 0002FDr 2 8A txa ; remember X 0002FEr 2 48 pha ; on stack 0002FFr 2 98 tya ; remember Y 000300r 2 48 pha ; on stack 000301r 2 000301r 2 .if CompileComputer >= C64_GENERAL 000301r 2 bcc KBSOUT_RS232 ; we want to output onto RS232 (TODO: Or console (0)?) --> jump 000301r 2 .endif 000301r 2 000301r 2 ; if we reached here, it is BSOUT on tape 000301r 2 000301r 2 .ifdef JIFFY 000301r 2 jmp JDLF3F1 000301r 2 000301r 2 JDLF1E8: 000301r 2 jsr JDLF8BF 000301r 2 jsr JDLE4C6 000301r 2 cmp #$30 000301r 2 rts 000301r 2 jsr bGTBYTC 000301r 2 stx zFA 000301r 2 jsr JDLF75C 000301r 2 stx zFSBLK 000301r 2 rts 000301r 2 000301r 2 .else 000301r 2 20 rr rr jsr TAPE_INCREMENT_WRITE_POINTER ; increment pointer into tape buffer, and return it in Y 000304r 2 D0 0E bne @BufferNotYetFull ; buffer not yet full -> jump 000306r 2 000306r 2 ; the tape buffer is full, write out the buffer and create a new one 000306r 2 ; 000306r 2 20 rr rr jsr TapeWriteCompleteBuffer ; write out the tape buffer to tape 000309r 2 B0 0E bcs BSOUT_Quit ; C = 1 -> error -> quit 00030Br 2 00030Br 2 A9 02 lda #TAPE_BUFFER_TYPE_CONTINUATION ; mark the buffer: It is a continuation buffer 00030Dr 2 A0 00 ldy #TAPE_BUFFER_OFFSET_TYPE ; new pointer into the tape buffer 00030Fr 2 91 rr sta (zTAPE1),y ; store the mark for the buffer that it is a continuation buffer 000311r 2 C8 iny ; advance buffer pointer 000312r 2 84 rr sty zBUFPNT ; and remember it 000314r 2 000314r 2 @BufferNotYetFull: 000314r 2 A5 rr lda zPTR1 ; get character to be output 000316r 2 91 rr sta (zTAPE1),y ; put it into the tape buffer 000318r 2 000318r 2 .endif 000318r 2 000318r 2 BSOUT_QuitSuccess: 000318r 2 18 clc ; mark: We quit with success 000319r 2 000319r 2 BSOUT_Quit: 000319r 2 68 pla ; restore Y from stack 00031Ar 2 A8 tay 00031Br 2 68 pla ; restore X from stack 00031Cr 2 AA tax 00031Dr 2 .if CompileComputer >= C64_GENERAL 00031Dr 2 lda zPTR1 ; restore A (character to be output) 00031Dr 2 .else 00031Dr 2 68 pla ; restore A (character to be output) from stack 00031Er 2 .endif 00031Er 2 00031Er 2 90 02 bcc @Rts ; if routine was successfull, skip next instruction 000320r 2 A9 00 lda #0 ; set error number to 0 (TODO: why 0?) 000322r 2 60 @Rts: rts 000323r 2 000323r 2 KBSOUT_RS232: 000323r 2 000323r 2 .if CompileComputer < C64_GENERAL 000323r 2 68 pla ; restore A (character to be output) from stack 000324r 2 86 rr stx zTEMPX ; remember X 000326r 2 84 rr sty zPTR1 ; and Y 000328r 2 .endif 000328r 2 000328r 2 20 rr rr jsr RS232_PUTCHAR ; put character in A into RS232 output buffer 00032Br 2 00032Br 2 .if CompileComputer >= C64_GENERAL 00032Br 2 jmp BSOUT_QuitSuccess 00032Br 2 ; ----------------------- 00032Br 2 .else 00032Br 2 A6 rr ldx zTEMPX ; restore X 00032Dr 2 A4 rr ldy zPTR1 ; and Y 00032Fr 2 18 clc ; mark: success 000330r 2 60 rts 000331r 2 ; ----------------------- 000331r 2 .endif 000331r 2 ; ----------------------- 000331r 2 000331r 2 ; B-2. Function Name: CHKIN 000331r 2 ; 000331r 2 ; Purpose: Open a channel for input 000331r 2 ; Call address: $FFC6 (hex) 65478 (decimal) 000331r 2 ; Communication registers: X 000331r 2 ; Preparatory routines: (OPEN) 000331r 2 ; Error returns: 000331r 2 ; Stack requirements: None 000331r 2 ; Registers affected: A, X 000331r 2 ; 000331r 2 ; 000331r 2 ; Description: Any logical file that has already been opened by the 000331r 2 ; KERNAL OPEN routine can be defined as an input channel by this routine. 000331r 2 ; Naturally, the device on the channel must be an input device. Otherwise 000331r 2 ; an error will occur, and the routine will abort. 000331r 2 ; If you are getting data from anywhere other than the keyboard, this 000331r 2 ; routine must be called before using either the CHRIN or the GETIN KERNAL 000331r 2 ; routines for data input. If you want to use the input from the keyboard, 000331r 2 ; and no other input channels are opened, then the calls to this routine, 000331r 2 ; and to the OPEN routine are not needed. 000331r 2 ; When this routine is used with a device on the serial bus, it auto- 000331r 2 ; matically sends the talk address (and the secondary address if one was 000331r 2 ; specified by the OPEN routine) over the bus. 000331r 2 ; 000331r 2 ; How to Use: 000331r 2 ; 000331r 2 ; 0) OPEN the logical file (if necessary; see description above). 000331r 2 ; 1) Load the X register with number of the logical file to be used. 000331r 2 ; 2) Call this routine (using a JSR command). 000331r 2 ; 000331r 2 ; 000331r 2 ; Possible errors are: 000331r 2 ; 000331r 2 ; #3: File not open 000331r 2 ; #5: Device not present 000331r 2 ; #6: File not an input file 000331r 2 ; 000331r 2 ; EXAMPLE: 000331r 2 ; 000331r 2 ; ;PREPARE FOR INPUT FROM LOGICAL FILE 2 000331r 2 ; LDX #2 000331r 2 ; JSR CHKIN 000331r 2 ; 000331r 2 KCHKIN: 000331r 2 20 rr rr jsr FindFileAndClearStatus ; find index for file no. in X, return in X 000334r 2 F0 03 beq @Found ; Z=1 -> has been found, branch and process 000336r 2 4C rr rr jmp KErrFileNotOpen ; return with "file not open" error 000339r 2 000339r 2 @Found: 000339r 2 20 rr rr jsr SetActiveFile ; set the active file to the parameters of the file just found 00033Cr 2 A5 rr lda zFA ; get device number (of output file) 00033Er 2 F0 16 beq @SetDefault ; console (0) --> set it, quit with success 000340r 2 000340r 2 C9 03 cmp #FILE_SCREEN 000342r 2 F0 12 beq @SetDefault ; screen (3) --> set it, quit with success 000344r 2 000344r 2 B0 14 bcs @Iec ; > 3 ( = some IEC device) -> special processing for IEC device 000346r 2 000346r 2 C9 02 cmp #FILE_RS232 ; rs232 (2)? 000348r 2 D0 03 bne @Tape ; no -> only tape left -> process tapes 00034Ar 2 00034Ar 2 4C rr rr jmp RS232_CHKIN ; special processing for RS232 CHKIN 00034Dr 2 00034Dr 2 ; special processing for TAPE: 00034Dr 2 ; check if the tape file is opened as input 00034Dr 2 00034Dr 2 @Tape: 00034Dr 2 A6 rr ldx zSA ; check secondary address 00034Fr 2 E0 60 cpx #$60 ; = $60 (output file)? 000351r 2 F0 03 beq @SetDefault ; yes, set it as default device 000353r 2 4C rr rr jmp KErrNotInputFile ; return with error: Not Input File 000356r 2 000356r 2 @SetDefault: 000356r 2 85 rr sta zDFLTN ; set default output device 000358r 2 18 clc ; mark: success 000359r 2 60 rts 00035Ar 2 ; ----------------- 00035Ar 2 00035Ar 2 ; Special processing for IEC: 00035Ar 2 ; tell device to talk to use (TALK) 00035Ar 2 00035Ar 2 @Iec: 00035Ar 2 AA tax ; remember device address in X 00035Br 2 20 rr rr jsr iTALK ; give device in A a TALK command 00035Er 2 00035Er 2 A5 rr lda zSA ; get secondary address 000360r 2 10 06 bpl @SecondaryAddress ; In range $00..$7F? -> give secondary address 000362r 2 000362r 2 20 rr rr jsr iTKSA2 ; no secondary address, but perform talker - listener - exchange 000365r 2 4C rr rr jmp @CheckStatus 000368r 2 000368r 2 @SecondaryAddress: 000368r 2 20 rr rr jsr iTKSA ; set secondary address after TALK 00036Br 2 00036Br 2 @CheckStatus: 00036Br 2 8A txa ; get back device number 00036Cr 2 00036Cr 2 24 rr bit zSTATUS ; check status 00036Er 2 10 E6 bpl @SetDefault ; bit 7 (device not present) unset -> success -> set device as default input device 000370r 2 000370r 2 4C rr rr jmp KErrDeviceNotPresent ; return with error: Device Not Present 000373r 2 ; ----------------------------- 000373r 2 000373r 2 ; B-3. Function Name: CHKOUT 000373r 2 ; 000373r 2 ; Purpose: Open a channel for output 000373r 2 ; Call address: $FFC9 (hex) 65481 (decimal) 000373r 2 ; Communication registers: X 000373r 2 ; Preparatory routines: (OPEN) 000373r 2 ; Error returns: 0,3,5,7 (See READST) 000373r 2 ; Stack requirements: 4+ 000373r 2 ; Registers affected: A, X 000373r 2 ; 000373r 2 ; Description: Any logical file number that has been created by the 000373r 2 ; KERNAL routine OPEN can be defined as an output channel. Of course, the 000373r 2 ; device you intend opening a channel to must be an output device. 000373r 2 ; Otherwise an error will occur, and the routine will be aborted. 000373r 2 ; This routine must be called before any data is sent to any output 000373r 2 ; device unless you want to use the Commodore 64 screen as your output 000373r 2 ; device. If screen output is desired, and there are no other output chan- 000373r 2 ; nels already defined, then calls to this routine, and to the OPEN routine 000373r 2 ; are not needed. 000373r 2 ; When used to open a channel to a device on the serial bus, this routine 000373r 2 ; will automatically send the LISTEN address specified by the OPEN routine 000373r 2 ; (and a secondary address if there was one). 000373r 2 ; 000373r 2 ; How to Use: 000373r 2 ; +-----------------------------------------------------------------------+ 000373r 2 ; | REMEMBER: this routine is NOT NEEDED to send data to the screen. | 000373r 2 ; +-----------------------------------------------------------------------+ 000373r 2 ; 0) Use the KERNAL OPEN routine to specify a logical file number, a 000373r 2 ; LISTEN address, and a secondary address (if needed). 000373r 2 ; 1) Load the X register with the logical file number used in the open 000373r 2 ; statement. 000373r 2 ; 2) Call this routine (by using the JSR instruction). 000373r 2 ; 000373r 2 ; EXAMPLE: 000373r 2 ; 000373r 2 ; LDX #3 ;DEFINE LOGICAL FILE 3 AS AN OUTPUT CHANNEL 000373r 2 ; JSR CHKOUT 000373r 2 ; 000373r 2 ; Possible errors are: 000373r 2 ; #3: File not open 000373r 2 ; #5: Device not present 000373r 2 ; #7: Not an output file 000373r 2 ; 000373r 2 ; 000373r 2 ; 000373r 2 KCHKOUT: 000373r 2 20 rr rr jsr FindFileAndClearStatus ; find index for file no. in X, return in X 000376r 2 F0 03 beq @Found ; Z=1 -> has been found, branch and process 000378r 2 4C rr rr jmp KErrFileNotOpen ; return with "file not open" error 00037Br 2 00037Br 2 @Found: 00037Br 2 20 rr rr jsr SetActiveFile ; set the active file to the parameters of the file just found 00037Er 2 A5 rr lda zFA ; get device number (of input file) 000380r 2 D0 03 bne @NoScreen ; not screen (0) -> check for other devices 000382r 2 000382r 2 000382r 2 @NotInputFile: 000382r 2 4C rr rr jmp KErrNotOutputFile ; return with error: Not Output File (screen cannot be output file) 000385r 2 000385r 2 @NoScreen: 000385r 2 C9 03 cmp #FILE_SCREEN ; is output file screen (3)? 000387r 2 F0 0F beq @SetDefault ; yes -> jump, set it as default device 000389r 2 000389r 2 B0 11 bcs @Iec ; > 3 ( = some IEC device) -> special processing for IEC device 00038Br 2 00038Br 2 C9 02 cmp #FILE_RS232 ; rs232 (2)? 00038Dr 2 D0 03 bne @Tape ; no -> only tape left -> process tapes 00038Fr 2 00038Fr 2 4C rr rr jmp RS232_CHKOUT ; special processing for RS232 CHKIN 000392r 2 000392r 2 @Tape: 000392r 2 A6 rr ldx zSA ; check secondary address 000394r 2 E0 60 cpx #$60 ; = $60 (output file)? 000396r 2 F0 EA beq @NotInputFile ; yes -> return with error: Not Input File 000398r 2 000398r 2 @SetDefault: 000398r 2 85 rr sta zDFLTO ; set default output device 00039Ar 2 18 clc ; mark: success 00039Br 2 60 rts 00039Cr 2 ; -------------------- 00039Cr 2 00039Cr 2 @Iec: 00039Cr 2 AA tax ; remember device address in X 00039Dr 2 20 rr rr jsr iLISTEN ; give device in A a LISTEN command 0003A0r 2 0003A0r 2 A5 rr lda zSA ; get secondary address 0003A2r 2 10 05 bpl @SecondaryAddress ; In range $00..$7F? -> give secondary address 0003A4r 2 0003A4r 2 20 rr rr jsr IEC_CLR_ATN ; only clear ATN status of IEC device 0003A7r 2 D0 03 bne @CheckStatus 0003A9r 2 ; ---------------------- 0003A9r 2 0003A9r 2 @SecondaryAddress: 0003A9r 2 20 rr rr jsr iSECOND ; set secondary address after LISTEN 0003ACr 2 0003ACr 2 @CheckStatus: 0003ACr 2 8A txa ; get back device number 0003ADr 2 0003ADr 2 24 rr bit zSTATUS ; check status 0003AFr 2 10 E7 bpl @SetDefault ; bit 7 (device not present) unset -> success -> set device as default output device 0003B1r 2 0003B1r 2 4C rr rr jmp KErrDeviceNotPresent ; return with error: Device Not Present 0003B4r 2 ; ----------------------------- 0003B4r 2 0003B4r 2 0003B4r 2 ; B-9. Function Name: CLOSE 0003B4r 2 ; 0003B4r 2 ; Purpose: Close a logical file 0003B4r 2 ; Call address: $FFC3 (hex) 65475 (decimal) 0003B4r 2 ; Communication registers: A 0003B4r 2 ; Preparatory routines: None 0003B4r 2 ; Error returns: 0,240 (See READST) 0003B4r 2 ; Stack requirements: 2+ 0003B4r 2 ; Registers affected: A, X, Y 0003B4r 2 ; 0003B4r 2 ; Description: This routine is used to close a logical file after all I/O 0003B4r 2 ; operations have been completed on that file. This routine is called after 0003B4r 2 ; the accumulator is loaded with the logical file number to be closed (the 0003B4r 2 ; same number used when the file was opened using the OPEN routine). 0003B4r 2 ; 0003B4r 2 ; 0003B4r 2 ; 0003B4r 2 ; 0003B4r 2 ; 0003B4r 2 ; 0003B4r 2 ; How to Use: 0003B4r 2 ; 0003B4r 2 ; 1) Load the accumulator with the number of the logical file to be 0003B4r 2 ; closed. 0003B4r 2 ; 2) Call this routine. 0003B4r 2 ; 0003B4r 2 ; EXAMPLE: 0003B4r 2 ; 0003B4r 2 ; ;CLOSE 15 0003B4r 2 ; LDA #15 0003B4r 2 ; JSR CLOSE 0003B4r 2 ; 0003B4r 2 KCLOSE: 0003B4r 2 20 rr rr jsr FindFile ; find index for file no. in A, return in X 0003B7r 2 F0 02 beq @DoClose ; z=1 -> file index exists -> branch, close file 0003B9r 2 0003B9r 2 ; if we reach here, the file did not exist 0003B9r 2 18 clc ; report success (closing a non-existing file is not an error!) 0003BAr 2 60 rts 0003BBr 2 ; ------------ 0003BBr 2 0003BBr 2 @DoClose: 0003BBr 2 20 rr rr jsr SetActiveFile ; set the active file to the parameters of the file just found 0003BEr 2 0003BEr 2 8A txa ; put current index into table of open files into A 0003BFr 2 48 pha ; and store it on the stack 0003C0r 2 0003C0r 2 A5 rr lda zFA ; get device address 0003C2r 2 F0 57 beq CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE ; console (0) --> get back index into table and set file parameters into table of open files 0003C4r 2 C9 03 cmp #FILE_SCREEN 0003C6r 2 F0 53 beq CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE ; screen (3) --> get back index into table and set file parameters into table of open files 0003C8r 2 0003C8r 2 B0 4E bcs CLOSE_FILE_ON_IEC ; > 3 (IEC device) --> perform open on IEC 0003CAr 2 0003CAr 2 C9 02 cmp #FILE_RS232 0003CCr 2 D0 29 bne @Tape ; not RS232 (2) --> only TAPE left --> open TAPE 0003CEr 2 0003CEr 2 0003CEr 2 ; if we reach here, we want to open a RS232 file 0003CEr 2 0003CEr 2 ; the following 2 instructions could be replaced with jsr CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE 0003CEr 2 68 pla ; get back index into table of open files 0003CFr 2 20 rr rr jsr CLOSE_DELETE_FROM_TABLE ; set file parameters in table of open files 0003D2r 2 0003D2r 2 .if CompileComputer >= C64_GENERAL 0003D2r 2 jsr LF483 0003D2r 2 .else 0003D2r 2 A9 7D lda #$7D 0003D4r 2 8D 1E 91 sta VIA1_IEC 0003D7r 2 A9 06 lda #$06 0003D9r 2 8D 10 91 sta VIA1_PB 0003DCr 2 A9 EE lda #$EE 0003DEr 2 8D 1C 91 sta VIA1_PCR 0003E1r 2 .endif 0003E1r 2 0003E1r 2 ; manipulate MEMTOP in order to release the memory of (2*) 256 byte each for 0003E1r 2 ; the RS232 input and output buffers 0003E1r 2 ; 0003E1r 2 20 rr rr jsr iMEMTOP_Get ; get current memory top into (X/Y) 0003E4r 2 A5 rr lda zRIBUF + 1 ; current RS232 input ring buffer high address set? 0003E6r 2 F0 01 beq :+ ; no, skip, we do not need to free memory for it 0003E8r 2 0003E8r 2 C8 iny ; free memory by incrementing MEMTOP high byte 0003E9r 2 0003E9r 2 : 0003E9r 2 A5 rr lda zROBUF + 1 ; current RS232 output ring buffer high address set? 0003EBr 2 F0 01 beq :+ ; no, skip, we do not need to free memory for it 0003EDr 2 0003EDr 2 C8 iny ; free memory by incrementing MEMTOP high byte 0003EEr 2 0003EEr 2 : 0003EEr 2 A9 00 lda #0 ; in order to mark that they do not exist anymore, 0003F0r 2 85 rr sta zRIBUF + 1 ; clear high bytes of RS232 input buffer 0003F2r 2 85 rr sta zROBUF + 1 ; and rS232 output buffer 0003F4r 2 0003F4r 2 4C rr rr jmp SetMemtop_And_Return_With_F0 ; set memory top and return with error code $F0, which indicates the memory top has been changed 0003F7r 2 ; -------------- 0003F7r 2 0003F7r 2 0003F7r 2 ; TODO: Comment tape close routine 0003F7r 2 0003F7r 2 @Tape: 0003F7r 2 .ifdef JIFFY 0003F7r 2 pla 0003F7r 2 jmp KErrIllegalDeviceNumber 0003F7r 2 0003F7r 2 LF2CC: jsr kCLRCHN 0003F7r 2 LF2CF: lda #$6F 0003F7r 2 jsr FindFile 0003F7r 2 bne CLOSE_Rts 0003F7r 2 jmp JDLF2F3 0003F7r 2 0003F7r 2 LF2D9: stx zFA 0003F7r 2 LF2DB: tya 0003F7r 2 pha 0003F7r 2 jsr JDLF8B2 0003F7r 2 jsr JDLF7A2 0003F7r 2 php 0003F7r 2 jsr LF2CC 0003F7r 2 plp 0003F7r 2 pla 0003F7r 2 tay 0003F7r 2 ldx zFA 0003F7r 2 rts 0003F7r 2 .byte $F2 0003F7r 2 0003F7r 2 .else 0003F7r 2 0003F7r 2 A5 rr lda zSA ; get secondary address 0003F9r 2 29 0F and #$0F ; (only the lower 4 bit, as the value has been ORed with IEEE_OPEN) 0003FBr 2 F0 1E beq CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE ; == 0 -> tape was opened for read --> branch, we do not need to write out the rest of the tape buffer --> get back index into table and set file parameters into table of open files 0003FDr 2 0003FDr 2 20 rr rr jsr TapeGetPointer ; get pointer to tape buffer into (X/Y) (unused, but flags important) 000400r 2 A9 00 lda #0 000402r 2 000402r 2 .if CompileComputer >= C64_GENERAL 000402r 2 sec ; set C = 1 to make sure the output is not send to RS232 in KBSOUT_TAPE! 000402r 2 ; (C=0 would output to RS232 instead; the C64 implementation differs from the VIC20 one in this aspect!) 000402r 2 000402r 2 .endif 000402r 2 000402r 2 20 rr rr jsr KBSOUT_TAPE ; output to TAPE 000405r 2 000405r 2 .if 0 000405r 2 ; this macro is defined in fileio_data.inc 000405r 2 000405r 2 .macro FILEIO_PATCH_CLOSE_TAPE 000405r 2 000405r 2 jsr TapeWriteCompleteBuffer ; write out the tape buffer to tape 000405r 2 bcc FileIoPatch_NoError ; C = 0 -> no error -> branch 000405r 2 000405r 2 pla ; get back index into table of open files 000405r 2 lda #$00 000405r 2 000405r 2 .endmacro 000405r 2 .endif 000405r 2 000405r 2 .if CompileComputer >= C64_GENERAL 000405r 2 000405r 2 FILEIO_PATCH_CLOSE_TAPE 000405r 2 000405r 2 rts 000405r 2 000405r 2 FileIoPatch_NoError: 000405r 2 000405r 2 .elseif CompileComputer = VIC20_02 000405r 2 000405r 2 jsr TapeWriteCompleteBuffer ; write out the tape buffer to tape 000405r 2 bcs CLOSE_ClcRts ; C = 1 -> error -> quit 000405r 2 000405r 2 .else 000405r 2 4C rr rr jmp FileIoPatchCloseTape 000408r 2 000408r 2 FileIoPatchCloseTape_Return: 000408r 2 000408r 2 B0 2E bcs CLOSE_Rts ; if error, quit with RTS 00040Ar 2 ; not needed on C64, as the RTS is directly after the patch there. 00040Ar 2 00040Ar 2 .endif 00040Ar 2 00040Ar 2 A5 rr lda zSA ; secondary address 00040Cr 2 C9 62 cmp #$62 ; $62 (that is, bit 1 set: "Write end-of-tape (EOT) marker" 00040Er 2 D0 0B bne CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE ; not $62 --> get back index into table and set file parameters into table of open files 000410r 2 000410r 2 ; Special processing for secondary address $62: Write an end-of-tape marker on the tape 000410r 2 000410r 2 A9 05 lda #TAPE_BUFFER_TYPE_EOT ; tape buffer type: END-OF-TAPE (EOT) 000412r 2 20 rr rr jsr TapeCreateFileBuffer ; create the file buffer and write it on tape 000415r 2 000415r 2 4C rr rr jmp CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE ; get back index into table and set file parameters into table of open files 000418r 2 000418r 2 .endif 000418r 2 000418r 2 CLOSE_FILE_ON_IEC: 000418r 2 20 rr rr jsr IecClose ; if zSA.7 is not set, close the file on the IEC bus. 00041Br 2 00041Br 2 CLOSE_GET_BACK_INDEX_AND_DELETE_FROM_TABLE: 00041Br 2 68 pla ; get back index into table of open files 00041Cr 2 00041Cr 2 CLOSE_DELETE_FROM_TABLE: 00041Cr 2 AA tax ; X := index of entry to close 00041Dr 2 00041Dr 2 JDLF2F3: 00041Dr 2 C6 rr dec zLDTND ; decrement number of entries in table of open files 00041Fr 2 00041Fr 2 E4 rr cpx zLDTND ; have we found 0 open files? 000421r 2 F0 14 beq CLOSE_ClcRts ; yes, nothing to do 000423r 2 000423r 2 ; replace entry to be closed with last entry in table 000423r 2 A4 rr ldy zLDTND ; get index of last entry 000425r 2 000425r 2 B9 rr rr lda lLAT,y ; replace logical file number (LA) 000428r 2 9D rr rr sta lLAT,x 00042Br 2 B9 rr rr lda lFAT,y ; replace device address (FA) 00042Er 2 9D rr rr sta lFAT,x 000431r 2 B9 rr rr lda lSAT,y ; replace secondary address (SA) 000434r 2 9D rr rr sta lSAT,x 000437r 2 000437r 2 CLOSE_ClcRts: 000437r 2 18 clc ; mark: success 000438r 2 CLOSE_Rts: 000438r 2 60 rts 000439r 2 ; ------------ 000439r 2 000439r 2 000439r 2 ; Clear status and perform FindFile afterwards 000439r 2 ; 000439r 2 ; Input: X := file no 000439r 2 ; Output: X := index into the tables (>= 0), or $FF if not found 000439r 2 ; Z = 1, N = 0 if index found, 000439r 2 ; Z = 0, N = 1 otherwise 000439r 2 ; Uses: X, A 000439r 2 ; 000439r 2 ; This function is often followed by a call to SetActiveFile 000439r 2 ; to get the data of lLAT, lFAT and lSAT into zLA, zFA and zSA. 000439r 2 ; 000439r 2 ; Note that register inputs differ from FindFile! 000439r 2 ; 000439r 2 FindFileAndClearStatus: 000439r 2 A9 00 lda #0 00043Br 2 85 rr sta zSTATUS 00043Dr 2 8A txa 00043Er 2 00043Er 2 ; Find the index into the lLAT, lFAT and lSAT tables 00043Er 2 ; for a specific file number. 00043Er 2 ; 00043Er 2 ; That is, if a file is opened with (BASIC) 00043Er 2 ; open 1,2,3 00043Er 2 ; then find the index into these tables for the given "1". 00043Er 2 ; 00043Er 2 ; Input: A := file no 00043Er 2 ; Output: X := index into the tables (>= 0), or $FF if not found 00043Er 2 ; Z = 1, N = 0 if index found, 00043Er 2 ; Z = 0, N = 1 otherwise 00043Er 2 ; Uses: X 00043Er 2 ; 00043Er 2 ; This function is often followed by a call to SetActiveFile 00043Er 2 ; to get the data of lLAT, lFAT and lSAT into zLA, zFA and zSA. 00043Er 2 ; 00043Er 2 FindFile: 00043Er 2 A6 rr ldx zLDTND ; get number of entries in the table 000440r 2 CA @Next: dex 000441r 2 30 15 bmi FindFileRts ; all searched? Then quit 000443r 2 DD rr rr cmp lLAT,x ; is this the right file no? 000446r 2 D0 F8 bne @Next ; no -> branch, try the next index 000448r 2 60 rts 000449r 2 ; -------------------- 000449r 2 000449r 2 000449r 2 ; Set the file parameters (zLA, zFA and zSA) for a given file 000449r 2 ; 000449r 2 ; Input: X := index into the tables lLAT, lFAT and LSAT, as returned by 000449r 2 ; FindFile or FindFileAndClearStatus 000449r 2 ; Output: 000449r 2 ; Z = 1, N = 0 if index found, 000449r 2 ; Z = 0, N = 1 otherwise 000449r 2 ; Uses: A 000449r 2 ; 000449r 2 SetActiveFile: 000449r 2 BD rr rr lda lLAT,x ; get file no from table 00044Cr 2 85 rr sta zLA ; into current value 00044Er 2 00044Er 2 BD rr rr lda lFAT,x ; get device number from table 000451r 2 85 rr sta zFA ; into current value 000453r 2 000453r 2 BD rr rr lda lSAT,x ; get secondary address from table 000456r 2 85 rr sta zSA ; into current value 000458r 2 000458r 2 FindFileRts: 000458r 2 60 rts 000459r 2 ; --------------------- 000459r 2 000459r 2 ; B-8. Function Name: CLALL 000459r 2 ; 000459r 2 ; Purpose: Close all files 000459r 2 ; Call address: $FFE7 (hex) 65511 (decimal) 000459r 2 ; Communication registers: None 000459r 2 ; Preparatory routines: None 000459r 2 ; Error returns: None 000459r 2 ; Stack requirements: 11 000459r 2 ; Registers affected: A, X 000459r 2 ; 000459r 2 ; Description: This routine closes all open files. When this routine is 000459r 2 ; called, the pointers into the open file table are reset, closing all 000459r 2 ; files. Also, the CLRCHN routine is automatically called to reset the I/O 000459r 2 ; channels. 000459r 2 ; 000459r 2 ; How to Use: 000459r 2 ; 000459r 2 ; 1) Call this routine. 000459r 2 ; 000459r 2 ; EXAMPLE: 000459r 2 ; 000459r 2 ; JSR CLALL ;CLOSE ALL FILES AND SELECT DEFAULT I/O CHANNELS 000459r 2 ; JMP RUN ;BEGIN EXECUTION 000459r 2 ; 000459r 2 ; 000459r 2 KCLALL: 000459r 2 A9 00 lda #$00 00045Br 2 85 rr sta zLDTND ; set number of open files to 0 00045Dr 2 00045Dr 2 ; "fall through" to CLRCHN 00045Dr 2 00045Dr 2 ; B-10. Function Name: CLRCHN a.k.a. CLRCH 00045Dr 2 ; 00045Dr 2 ; Purpose: Clear I/O channels 00045Dr 2 ; Call address: $FFCC (hex) 65484 (decimal) 00045Dr 2 ; Communication registers: None 00045Dr 2 ; Preparatory routines: None 00045Dr 2 ; Error returns: 00045Dr 2 ; Stack requirements: 9 00045Dr 2 ; Registers affected: A, X 00045Dr 2 ; 00045Dr 2 ; Description: This routine is called to clear all open channels and re- 00045Dr 2 ; store the I/O channels to their original default values. It is usually 00045Dr 2 ; called after opening other I/O channels (like a tape or disk drive) and 00045Dr 2 ; using them for input/output operations. The default input device is 0 00045Dr 2 ; (keyboard). The default output device is 3 (the Commodore 64 screen). 00045Dr 2 ; If one of the channels to be closed is to the serial port, an UNTALK 00045Dr 2 ; signal is sent first to clear the input channel or an UNLISTEN is sent to 00045Dr 2 ; clear the output channel. By not calling this routine (and leaving lis- 00045Dr 2 ; tener(s) active on the serial bus) several devices can receive the same 00045Dr 2 ; data from the Commodore 64 at the same time. One way to take advantage 00045Dr 2 ; of this would be to command the printer to TALK and the disk to LISTEN. 00045Dr 2 ; This would allow direct printing of a disk file. 00045Dr 2 ; This routine is automatically called when the KERNAL CLALL routine is 00045Dr 2 ; executed. 00045Dr 2 ; 00045Dr 2 ; How to Use: 00045Dr 2 ; 1) Call this routine using the JSR instruction. 00045Dr 2 ; 00045Dr 2 ; EXAMPLE: 00045Dr 2 ; JSR CLRCHN 00045Dr 2 ; 00045Dr 2 KCLRCH: 00045Dr 2 A2 03 ldx #FILE_SCREEN ; device address for screen (3) 00045Fr 2 00045Fr 2 E4 rr cpx zDFLTO ; compare current default output device to 3? 000461r 2 B0 03 bcs :+ ; <= 3, skip next step 000463r 2 000463r 2 20 rr rr jsr iUNLSN ; send UNLISTEN on IEC bus 000466r 2 000466r 2 E4 rr : cpx zDFLTN ; compare current default input device to 3? 000468r 2 B0 03 bcs :+ ; <= 3, skip next step 00046Ar 2 00046Ar 2 20 rr rr jsr iUNTLK ; send UNTALK on IEC bus 00046Dr 2 00046Dr 2 86 rr : stx zDFLTO ; set default output device to screen 00046Fr 2 00046Fr 2 A9 00 lda #FILE_KEYBOARD 000471r 2 85 rr sta zDFLTN ; set default input device to keyboard 000473r 2 60 rts 000474r 2 ; --------------- 000474r 2 000474r 2 ; B-18. Function Name: OPEN 000474r 2 ; 000474r 2 ; 000474r 2 ; Purpose: Open a logical file 000474r 2 ; Call address: $FFC0 (hex) 65472 (decimal) 000474r 2 ; Communication registers: None 000474r 2 ; Preparatory routines: SETLFS, SETNAM 000474r 2 ; Error returns: 1,2,4,5,6,240, READST 000474r 2 ; Stack requirements: None 000474r 2 ; Registers affected: A, X, Y 000474r 2 ; 000474r 2 ; Description: This routine is used to OPEN a logical file. Once the 000474r 2 ; logical file is set up, it can be used for input/output operations. Most 000474r 2 ; of the I/O KERNAL routines call on this routine to create the logical 000474r 2 ; files to operate on. No arguments need to be set up to use this routine, 000474r 2 ; but both the SETLFS and SETNAM KERNAL routines must be called before 000474r 2 ; using this routine. 000474r 2 ; 000474r 2 ; 000474r 2 ; How to Use: 000474r 2 ; 000474r 2 ; 0) Use the SETLFS routine. 000474r 2 ; 1) Use the SETNAM routine. 000474r 2 ; 2) Call this routine. 000474r 2 ; 000474r 2 ; EXAMPLE: 000474r 2 ; 000474r 2 ; This is an implementation of the BASIC statement: OPEN 15,8,15,"I/O" 000474r 2 ; 000474r 2 ; 000474r 2 ; LDA #NAME2-NAME ;LENGTH OF FILE NAME FOR SETLFS 000474r 2 ; LDY #>NAME ;ADDRESS OF FILE NAME 000474r 2 ; LDX # ok, can be opened 000478r 2 4C rr rr jmp KErrNotInputFile ; return with error: "Not Input File" 00047Br 2 ; --------------------- 00047Br 2 00047Br 2 20 rr rr : jsr FindFileAndClearStatus ; find index for file no. in X 00047Er 2 D0 03 bne :+ ; Z=0 -> file does not exist yet -> branch -> process this open 000480r 2 4C rr rr jmp KErrFileOpen ; return with "file open" error 000483r 2 000483r 2 A6 rr : ldx zLDTND ; get number of open files 000485r 2 E0 0A cpx #lLAT_Size ; limit not yet reached? 000487r 2 90 03 bcc :+ ; no -> continue 000489r 2 4C rr rr jmp KErrTooManyOpenFiles ; return with error: "Too many files error" 00048Cr 2 00048Cr 2 E6 rr : inc zLDTND ; increment number of open files 00048Er 2 00048Er 2 A5 rr lda zLA ; store logical file number 000490r 2 9D rr rr sta lLAT,x ; in table 000493r 2 000493r 2 A5 rr lda zSA ; modify secondary address 000495r 2 09 60 ora #IEEE_OPEN ; to mean "for OPEN" on the IEC Bus 000497r 2 85 rr sta zSA ; store it back 000499r 2 9D rr rr sta lSAT,x ; and in the table 00049Cr 2 00049Cr 2 A5 rr lda zFA ; store device (primary) address 00049Er 2 9D rr rr sta lFAT,x ; in table 0004A1r 2 0004A1r 2 F0 5A beq KOPEN_ClcRts ; open of the keyboard -> branch -> quit function with success, nothing else to do 0004A3r 2 0004A3r 2 C9 03 cmp #FILE_SCREEN 0004A5r 2 F0 56 beq KOPEN_ClcRts ; open of the screen -> branch -> quit function with success, nothing else to do 0004A7r 2 0004A7r 2 90 05 bcc @NoIec ; open of something else but IEC (tape, rs232) -> test for it 0004A9r 2 0004A9r 2 20 rr rr jsr KOPEN_IEC ; open the IEC file 0004ACr 2 90 4F bcc KOPEN_ClcRts ; if we succeeded in opening the IEC file, succeed this call, too 0004AEr 2 0004AEr 2 ; TODO: what if KOPEN_IEC (calling iUNLSN as last command) ended with C=1? Is this a BUG? 0004AEr 2 0004AEr 2 @NoIec: 0004AEr 2 0004AEr 2 .ifdef JIFFY 0004AEr 2 cmp #$01 0004AEr 2 beq JDLF3F3 0004AEr 2 jmp OPEN_RS232 0004AEr 2 0004AEr 2 JDLF38B: 0004AEr 2 jsr kUNTLK 0004AEr 2 lda zFA 0004AEr 2 jsr kTALK 0004AEr 2 lda zSA 0004AEr 2 jmp kTKSA 0004AEr 2 0004AEr 2 JDLF398: 0004AEr 2 ; @@@todo some table? 0004AEr 2 0004AEr 2 eor $572D 0004AEr 2 brk 0004AEr 2 asl $1C 0004AEr 2 lda $0261 0004AEr 2 sta zCHARAC 0004AEr 2 lda #$12 0004AEr 2 sta $06 0004AEr 2 ldx #$00 0004AEr 2 stx zROBUF 0004AEr 2 jsr $D586 0004AEr 2 ldy $0267 0004AEr 2 lda ($30),y 0004AEr 2 eor #$40 0004AEr 2 sta ($30),y 0004AEr 2 jmp $D58A 0004AEr 2 eor $452D 0004AEr 2 brk 0004AEr 2 asl zOPMASK 0004AEr 2 and $6A57 0004AEr 2 brk 0004AEr 2 ora (zOPMASK,x) 0004AEr 2 and $6957 0004AEr 2 brk 0004AEr 2 ora ($50,x) 0004AEr 2 ror a:zR6510 0004AEr 2 .byte $53 0004AEr 2 .byte $3A 0004AEr 2 0004AEr 2 .else 0004AEr 2 C9 02 cmp #FILE_RS232 ; is it an RS232 device? 0004B0r 2 0004B0r 2 .if CompileComputer = C64_SX64 0004B0r 2 bne @ErrIllegalDeviceNumber ; no -> tape -> the SX64 does not have a tape -> report an error 0004B0r 2 .else 0004B0r 2 D0 03 bne @Tape ; no -> tape -> process opening a tape file 0004B2r 2 .endif 0004B2r 2 4C rr rr jmp OPEN_RS232 ; open the RS232 device 0004B5r 2 ; ------------------ 0004B5r 2 0004B5r 2 ; TODO: Document 0004B5r 2 0004B5r 2 @Tape: 0004B5r 2 20 rr rr jsr TapeGetPointer ; get pointer to tape buffer into (X/Y) (unused, but flags important) 0004B8r 2 B0 03 bcs @TapeAllowed ; C = 1 -> tape buffer does NOT point to stack page or zero page -> proceed, we do not overwrite essential data! 0004BAr 2 0004BAr 2 @ErrIllegalDeviceNumber: 0004BAr 2 4C rr rr jmp KErrIllegalDeviceNumber 0004BDr 2 0004BDr 2 @TapeAllowed: 0004BDr 2 A5 rr lda zSA ; check secondary address of the file 0004BFr 2 29 0F and #$0F ; (only the lower 4 bit, as the value has been ORed with IEEE_OPEN) 0004C1r 2 D0 1F bne KLOAD_OpenTapeForWrite ; anything but 0 means: WRITE. Thus, branch if we have a write operation 0004C3r 2 0004C3r 2 ; Open the tape for a read operation 0004C3r 2 0004C3r 2 20 rr rr jsr TapePressPlayOnTape ; output "PRESS PLAY ON TAPE" and wait for PLAY to be pressd 0004C6r 2 B0 36 bcs KOPEN_Rts ; C=1 -> an error occurred (i.e., STOP was pressed) -> branch, abort 0004C8r 2 0004C8r 2 20 rr rr jsr OutputSearchingFor ; output the text "SEARCHING" or "SEARCHING FOR " 0004CBr 2 0004CBr 2 A5 rr lda zFNLEN ; test file name length 0004CDr 2 F0 0A beq KLOAD_NoFilenameGiven ; == 0 -> no file name given -> branch, skip finding the right file 0004CFr 2 0004CFr 2 ; try to find the specified file 0004CFr 2 0004CFr 2 20 rr rr jsr TapeFindSpecificFile ; try to find the specified file 0004D2r 2 90 18 bcc KLOAD_PrepareTapeBuffer ; C = 0 -> no error occurred -> branch, proceed with operation 0004D4r 2 0004D4r 2 F0 28 beq KOPEN_Rts ; Z = 1 --> EOT was found, abort (TODO can this branch happen actually?) 0004D6r 2 0004D6r 2 KLOAD_ErrFileNotFound: 0004D6r 2 4C rr rr jmp KErrFileNotFound ; return with FILE NOT FOUND error 0004D9r 2 ; ------------------------ 0004D9r 2 0004D9r 2 0004D9r 2 KLOAD_NoFilenameGiven: 0004D9r 2 ; there was no file name given, just search for any file 0004D9r 2 0004D9r 2 20 rr rr jsr TapeReadTapeHeaderOfNextFile ; try to find ANY file header 0004DCr 2 F0 20 beq KOPEN_Rts ; TODO what? 0004DEr 2 90 0C bcc KLOAD_PrepareTapeBuffer ; C = 0 --> no error occurred -> branch, proceed with operation 0004E0r 2 0004E0r 2 B0 F4 bcs KLOAD_ErrFileNotFound ; (uncond. branch) return with FILE NOT FOUND error 0004E2r 2 ; --------------------------- 0004E2r 2 0004E2r 2 KLOAD_OpenTapeForWrite: 0004E2r 2 20 rr rr jsr TapePressRecordAndPlayOnTape ; output "PRESS RECORD + PLAY ON TAPE" and wait for PLAY to be pressd 0004E5r 2 B0 17 bcs KOPEN_Rts ; C=1 -> an error occurred (i.e., STOP was pressed) -> branch, abort 0004E7r 2 0004E7r 2 A9 04 lda #TAPE_BUFFER_TYPE_DATA ; tape buffer type: a data file 0004E9r 2 20 rr rr jsr TapeCreateFileBuffer ; create the file buffer (including start and end address and file name) and write it on tape 0004ECr 2 0004ECr 2 KLOAD_PrepareTapeBuffer: 0004ECr 2 ; depending upon if the tape file is opened for read or write, the tape 0004ECr 2 ; buffer has to be prepared differently. 0004ECr 2 ; 0004ECr 2 ; For reading, the tape buffer pointer has to point to the last address (lTBUFFR_SIZE - 1) 0004ECr 2 ; in order to generate an overflow on the first call to read a character. 0004ECr 2 ; The buffer itself does not need to be changed. 0004ECr 2 ; 0004ECr 2 ; For writing, however, the pointer must be set to the beginning of the buffer, 0004ECr 2 ; and the beginning must be initialized to "2" (TODO: List of values with defines). 0004ECr 2 ; 0004ECr 2 A9 BF lda #lTBUFFR_SIZE - 1 ; assumed value for the tape buffer pointer: Assume reading of the tape 0004EEr 2 0004EEr 2 A4 rr ldy zSA ; check secondary address 0004F0r 2 C0 60 cpy #$60 ; is it 0 ( | IEEE_OPEN)? 0004F2r 2 F0 07 beq @NoWrite ; yes -> branch, we want to read the tape 0004F4r 2 0004F4r 2 ; process tape buffer for writing: 0004F4r 2 0004F4r 2 A0 00 ldy #0 ; index into tape buffer = 0 (start at the beginning) 0004F6r 2 A9 02 lda #TAPE_BUFFER_TYPE_CONTINUATION 0004F8r 2 91 rr sta (zTAPE1),y ; mark the block as continuation buffer 0004FAr 2 0004FAr 2 98 tya ; set tape buffer pointer to 0 0004FBr 2 0004FBr 2 .endif 0004FBr 2 0004FBr 2 @NoWrite: 0004FBr 2 85 rr sta zBUFPNT ; and store it. 0004FDr 2 0004FDr 2 .if CompileComputer >= C64_GENERAL 0004FDr 2 KOPEN_ClcRts2: 0004FDr 2 .endif 0004FDr 2 0004FDr 2 KOPEN_ClcRts: 0004FDr 2 18 clc 0004FEr 2 0004FEr 2 KOPEN_Rts: 0004FEr 2 60 rts 0004FFr 2 ; ------------------------------- 0004FFr 2 0004FFr 2 0004FFr 2 0004FFr 2 ; Remark: 0004FFr 2 ; In case the device does not exist, thus function will not return to the caller, 0004FFr 2 ; but to the caller of the caller (in case there was no manipulation of the stack in between!) 0004FFr 2 0004FFr 2 KOPEN_IEC: ; Open a file on the IEC bus 0004FFr 2 A5 rr lda zSA ; get secondary address 000501r 2 30 2C bmi KOPEN_ClcRts2 ; bit 7 set -> nothing to do, we're done 000503r 2 000503r 2 A4 rr ldy zFNLEN ; get length of the file name 000505r 2 F0 28 beq KOPEN_ClcRts2 ; is it 0 -> nothing to do, we're done 000507r 2 000507r 2 .if CompileComputer >= C64_GENERAL 000507r 2 lda #0 ; clear the status byte, that is, start with a clean status 000507r 2 sta zSTATUS 000507r 2 .endif 000507r 2 000507r 2 A5 rr lda zFA 000509r 2 20 rr rr jsr iLISTEN ; send LISTEN to the device 00050Cr 2 00050Cr 2 A5 rr lda zSA 00050Er 2 09 F0 ora #IEEE_SECONDARY 000510r 2 20 rr rr jsr iSECOND ; send secondary address after LISTEN 000513r 2 000513r 2 A5 rr lda zSTATUS ; check device status 000515r 2 10 05 bpl KOPEN_Iec_DeviceExists ; bit 7 (device not present) unset -> device exists -> proceed 000517r 2 000517r 2 JDLF3F1: 000517r 2 ; if we reach here, zSTATUS.7 was set. Thus, we got a timeout -> the device does not exist 000517r 2 ; 000517r 2 68 pla ; remove return address of caller from the stack (!) 000518r 2 68 pla 000519r 2 000519r 2 JDLF3F3: 000519r 2 4C rr rr jmp KErrDeviceNotPresent ; return to the caller of the caller with "Device not Present" error 00051Cr 2 ; -------------------------- 00051Cr 2 00051Cr 2 KOPEN_Iec_DeviceExists: 00051Cr 2 A5 rr lda zFNLEN ; get length of the file name 00051Er 2 F0 0C beq @NoName ; if 0, we're done. (UNNECCESSARY, as this has already been tested above!) 000520r 2 000520r 2 ; now, the file name is output to the IEC bus, one byte after the other 000520r 2 000520r 2 A0 00 ldy #0 000522r 2 B1 rr : lda (zFNADR),y ; get next character of the file name 000524r 2 20 rr rr jsr iCIOUT ; output it to the IEC bus 000527r 2 C8 iny ; proceed to next character 000528r 2 C4 rr cpy zFNLEN ; have we reached the end yet? 00052Ar 2 D0 F6 bne :- ; now, process this character, too. 00052Cr 2 00052Cr 2 @NoName: 00052Cr 2 .if CompileComputer >= C64_GENERAL 00052Cr 2 ; for C64, this functionality has been implemented by jumping to another place with the same implementation as here: 00052Cr 2 00052Cr 2 jmp DoUnlistenClcRts 00052Cr 2 .else 00052Cr 2 ; the VIC-20 does it itself here, which results in duplicate code: 00052Cr 2 00052Cr 2 20 rr rr jsr iUNLSN 00052Fr 2 00052Fr 2 .if CompileComputer < C64_GENERAL 00052Fr 2 KOPEN_ClcRts2: 00052Fr 2 .endif 00052Fr 2 18 clc 000530r 2 60 rts 000531r 2 .endif 000531r 2 000531r 2 OPEN_RS232: 000531r 2 000531r 2 ; TODO: Initialize RS232 000531r 2 000531r 2 .if CompileComputer >= C64_GENERAL 000531r 2 jsr LF483 000531r 2 .else 000531r 2 A9 06 lda #$06 000533r 2 8D 12 91 sta VIA1_DDRB 000536r 2 8D 10 91 sta VIA1_PB 000539r 2 A9 EE lda #$EE 00053Br 2 8D 1C 91 sta VIA1_PCR 00053Er 2 A0 00 ldy #0 000540r 2 .endif 000540r 2 8C rr rr sty lRSSTAT 000543r 2 C4 rr @LF40F: cpy zFNLEN 000545r 2 F0 0A beq @LF41D 000547r 2 B1 rr lda (zFNADR),y 000549r 2 99 rr rr sta lM51CTR,y 00054Cr 2 C8 iny 00054Dr 2 C0 04 cpy #$04 00054Fr 2 D0 F2 bne @LF40F 000551r 2 @LF41D: 000551r 2 20 rr rr jsr LEF4A 000554r 2 8E rr rr stx lBITNUM 000557r 2 AD rr rr lda lM51CTR 00055Ar 2 29 0F and #$0F 00055Cr 2 00055Cr 2 .if CompileComputer >= C64_02 00055Cr 2 beq @LF446 00055Cr 2 asl a 00055Cr 2 tax 00055Cr 2 lda lTVSFLG 00055Cr 2 bne @LF43A 00055Cr 2 ldy LFEC2 - 1,x 00055Cr 2 lda LFEC2 - 2,x 00055Cr 2 jmp @LF440 00055Cr 2 @LF43A: 00055Cr 2 ldy LE4EC-1,x 00055Cr 2 lda LE4EC-2,x 00055Cr 2 @LF440: 00055Cr 2 sty lM51AJB + 1 00055Cr 2 sta lM51AJB 00055Cr 2 @LF446: 00055Cr 2 lda lM51AJB 00055Cr 2 asl a 00055Cr 2 jsr LFF2E 00055Cr 2 lda lM51CDR 00055Cr 2 lsr a 00055Cr 2 bcc @LF45C 00055Cr 2 lda CIA2 + CIA_O_PB 00055Cr 2 asl a 00055Cr 2 bcs @LF45C 00055Cr 2 jsr LF00D 00055Cr 2 .else 00055Cr 2 D0 00 bne @LF435 00055Er 2 .if CompileComputer >= C64_GENERAL 00055Er 2 lda lM51AJB 00055Er 2 asl a 00055Er 2 tay 00055Er 2 lda lM51AJB + 1 00055Er 2 jmp @LF43F 00055Er 2 .endif 00055Er 2 0A @LF435: asl a 00055Fr 2 AA tax 000560r 2 BD rr rr lda LFEC2 - 2,x 000563r 2 0A asl a 000564r 2 A8 tay 000565r 2 BD rr rr lda LFEC2 - 1,x 000568r 2 2A @LF43F: rol a 000569r 2 48 pha 00056Ar 2 98 tya 00056Br 2 69 C8 adc #<200 00056Dr 2 8D rr rr sta lBAUDOF 000570r 2 68 pla 000571r 2 69 00 adc #>200 000573r 2 8D rr rr sta lBAUDOF + 1 000576r 2 AD rr rr lda lM51CDR 000579r 2 4A lsr a 00057Ar 2 90 09 bcc @LF45C 00057Cr 2 .if CompileComputer >= C64_GENERAL 00057Cr 2 lda CIA2 + CIA_O_PB 00057Cr 2 .else 00057Cr 2 AD 20 91 lda VIA2_PB 00057Fr 2 .endif 00057Fr 2 0A asl a 000580r 2 B0 03 bcs @LF45C 000582r 2 .if CompileComputer >= C64_GENERAL 000582r 2 jmp LF00D 000582r 2 .else 000582r 2 4C rr rr jmp LF016 000585r 2 .endif 000585r 2 .endif 000585r 2 000585r 2 AD rr rr @LF45C: lda lRIDBE 000588r 2 8D rr rr sta lRIDBS 00058Br 2 AD rr rr lda lRODBE 00058Er 2 8D rr rr sta lRODBS 000591r 2 20 rr rr jsr iMEMTOP_Get 000594r 2 A5 rr lda zRIBUF + 1 000596r 2 D0 05 bne @LF474 000598r 2 88 dey 000599r 2 84 rr sty zRIBUF + 1 00059Br 2 86 rr stx zRIBUF 00059Dr 2 @LF474: 00059Dr 2 A5 rr lda zROBUF + 1 00059Fr 2 D0 05 bne SetMemtop_And_Return_With_F0 0005A1r 2 88 dey 0005A2r 2 84 rr sty zROBUF + 1 0005A4r 2 86 rr stx zROBUF 0005A6r 2 0005A6r 2 SetMemtop_And_Return_With_F0: 0005A6r 2 38 sec 0005A7r 2 A9 F0 lda #$F0 0005A9r 2 4C rr rr jmp iMEMTOP_Set 0005ACr 2 0005ACr 2 .if CompileComputer >= C64_GENERAL 0005ACr 2 LF483: lda #$7F 0005ACr 2 sta CIA2 + CIA_O_ICR 0005ACr 2 lda #$06 0005ACr 2 sta CIA2 + CIA_O_DDRB 0005ACr 2 sta CIA2 + CIA_O_PB 0005ACr 2 lda #$04 0005ACr 2 ora IEC_REG 0005ACr 2 sta IEC_REG 0005ACr 2 ldy #$00 0005ACr 2 sty lENABL 0005ACr 2 rts 0005ACr 2 .endif 0005ACr 2 0005ACr 2 0005ACr 2 ; B-15. Function Name: LOAD 0005ACr 2 ; 0005ACr 2 ; Purpose: Load RAM from device 0005ACr 2 ; Call address: $FFD5 (hex) 65493 (decimal) 0005ACr 2 ; Communication registers: A, X, Y 0005ACr 2 ; Preparatory routines: SETLFS, SETNAM 0005ACr 2 ; Error returns: 0,4,5,8,9, READST 0005ACr 2 ; Stack requirements: None 0005ACr 2 ; Registers affected: A, X, Y 0005ACr 2 ; 0005ACr 2 ; Description: This routine LOADs data bytes from any input device di- 0005ACr 2 ; rectly into the memory of the Commodore 64. It can also be used for a 0005ACr 2 ; verify operation, comparing data from a device with the data already in 0005ACr 2 ; memory, while leaving the data stored in RAM unchanged. 0005ACr 2 ; The accumulator (.A) must be set to 0 for a LOAD operation, or 1 for a 0005ACr 2 ; verify, If the input device is OPENed with a secondary address (SA) of 0 0005ACr 2 ; the header information from the device is ignored. In this case, the X 0005ACr 2 ; and Y registers must contain the starting address for the load. If the 0005ACr 2 ; device is addressed with a secondary address of 1, then the data is 0005ACr 2 ; loaded into memory starting at the location specified by the header. This 0005ACr 2 ; routine returns the address of the highest RAM location loaded. 0005ACr 2 ; Before this routine can be called, the KERNAL SETLFS, and SETNAM 0005ACr 2 ; routines must be called. 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; +-----------------------------------------------------------------------+ 0005ACr 2 ; | NOTE: You can NOT LOAD from the keyboard (0), RS-232 (2), or the | 0005ACr 2 ; | screen (3). | 0005ACr 2 ; +-----------------------------------------------------------------------+ 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; How to Use: 0005ACr 2 ; 0005ACr 2 ; 0) Call the SETLFS, and SETNAM routines. If a relocated load is de- 0005ACr 2 ; sired, use the SETLFS routine to send a secondary address of 0. 0005ACr 2 ; 1) Set the A register to 0 for load, 1 for verify. 0005ACr 2 ; 2) If a relocated load is desired, the X and Y registers must be set 0005ACr 2 ; to the start address for the load. 0005ACr 2 ; 3) Call the routine using the JSR instruction. 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; 0005ACr 2 ; EXAMPLE: 0005ACr 2 ; 0005ACr 2 ; ;LOAD A FILE FROM TAPE 0005ACr 2 ; 0005ACr 2 ; LDA #DEVICE1 ;SET DEVICE NUMBER 0005ACr 2 ; LDX #FILENO ;SET LOGICAL FILE NUMBER 0005ACr 2 ; LDY CMD1 ;SET SECONDARY ADDRESS 0005ACr 2 ; JSR SETLFS 0005ACr 2 ; LDA #NAME1-NAME ;LOAD A WITH NUMBER OF 0005ACr 2 ; ;CHARACTERS IN FILE NAME 0005ACr 2 ; LDX #NAME ;FILE NAME 0005ACr 2 ; JSR SETNAM 0005ACr 2 ; LDA #0 ;SET FLAG FOR A LOAD 0005ACr 2 ; LDX #$FF ;ALTERNATE START 0005ACr 2 ; LDY #$FF 0005ACr 2 ; JSR LOAD 0005ACr 2 ; STX VARTAB ;END OF LOAD 0005ACr 2 ; STY VARTA B+1 0005ACr 2 ; JMP START 0005ACr 2 ; NAME .BYT 'FILE NAME' 0005ACr 2 ; NAME1 ; 0005ACr 2 ; 0005ACr 2 86 rr iLOAD: stx zMEMUSS_2 ; remember alternate start at (zMEMUSS_2/zMEMUSS_2+1) 0005AEr 2 84 rr sty zMEMUSS_2 + 1 0005B0r 2 6C rr rr jmp (lILOAD) ; normally points to KLOAD 0005B3r 2 0005B3r 2 KLOAD: 0005B3r 2 85 rr sta zVERCKK ; remember if LOAD (= 0) or VERIFY (= 1) 0005B5r 2 0005B5r 2 A9 00 lda #0 ; clear status 0005B7r 2 85 rr sta zSTATUS 0005B9r 2 0005B9r 2 A5 rr lda zFA ; get device address 0005BBr 2 D0 03 bne @NotKeyboard ; not keyboard (0) -> test for other devices 0005BDr 2 0005BDr 2 @ErrIllegalDeviceNumber: 0005BDr 2 4C rr rr jmp KErrIllegalDeviceNumber ; exit with "Illegal Device Number" error 0005C0r 2 ; ----------------------------- 0005C0r 2 0005C0r 2 @NotKeyboard: 0005C0r 2 C9 03 cmp #FILE_SCREEN 0005C2r 2 F0 F9 beq @ErrIllegalDeviceNumber ; load from screen --> exit with "Illegal Device Number" error 0005C4r 2 0005C4r 2 ; if C = 0, only tape and RS232 have been left. 0005C4r 2 0005C4r 2 .ifdef JIFFY 0005C4r 2 ; JiffyDOS does not support a tape, and load from RS232 is not possible. 0005C4r 2 ; thus, if C=0, we are not able to load. Thus: 0005C4r 2 0005C4r 2 bcc @ErrIllegalDeviceNumber ; RS232 or TAPE --> exit with "Illegal Device Number" error 0005C4r 2 .elseif CompileComputer = C64_SX64 0005C4r 2 ; the SX64 does not have a tape, and load from RS232 is not possible. 0005C4r 2 ; thus, if C=0, we are not able to load. Thus: 0005C4r 2 0005C4r 2 bcc @ErrIllegalDeviceNumber ; RS232 or TAPE --> exit with "Illegal Device Number" error 0005C4r 2 .else 0005C4r 2 90 6E bcc KLOAD_TapeOrRS232 ; RS232 or TAPE --> try further tests 0005C6r 2 .endif 0005C6r 2 0005C6r 2 0005C6r 2 ; if we reach here, we want to load a file from IEC 0005C6r 2 0005C6r 2 .if CompileComputer = VIC20_02 0005C6r 2 lda #IEEE_OPEN ; set secondary address: LOAD 0005C6r 2 sta zSA 0005C6r 2 .endif 0005C6r 2 0005C6r 2 A4 rr ldy zFNLEN ; get length of file name 0005C8r 2 D0 03 bne KLOAD_FileNameGiven ; not 0 -> branch, name was given -> proceed 0005CAr 2 .ifdef JIFFY 0005CAr 2 jmp $F659 0005CAr 2 .else 0005CAr 2 4C rr rr jmp KErrFileNameMissing ; error: We need a file name for IEC load --> return with "File Name Missing" error 0005CDr 2 .endif 0005CDr 2 ; ------------------------- 0005CDr 2 0005CDr 2 KLOAD_FileNameGiven: 0005CDr 2 0005CDr 2 .if CompileComputer = VIC20_02 0005CDr 2 0005CDr 2 ; on the VIC20-02 ROM, a "ldx zSA" is missing: 0005CDr 2 ; TODO: Is this "ldx" needed at all? 0005CDr 2 0005CDr 2 jsr OutputSearchingFor ; output the "Searching [for ]" message 0005CDr 2 0005CDr 2 .elseif CompileComputer >= C64_GENERAL 0005CDr 2 0005CDr 2 ; the C64 ROMs contain this ldx: 0005CDr 2 0005CDr 2 ldx zSA ; TODO: why? 0005CDr 2 jsr OutputSearchingFor ; output the "Searching [for ]" message 0005CDr 2 .else 0005CDr 2 ; for the VIC20 ROMs (other than -02), the same sequence as in the C64 case is done in a patch that is called here: 0005CDr 2 0005CDr 2 20 rr rr jsr LE4BC 0005D0r 2 .endif 0005D0r 2 0005D0r 2 .if CompileComputer <> VIC20_02 0005D0r 2 A9 60 lda #IEEE_LOAD ; set secondary address: LOAD 0005D2r 2 85 rr sta zSA 0005D4r 2 .endif 0005D4r 2 0005D4r 2 20 rr rr jsr KOPEN_IEC ; open the file on the IEC bus. In case of a timeout, this function will not return here, but return to our caller! 0005D7r 2 0005D7r 2 ; send a TALK command 0005D7r 2 A5 rr lda zFA 0005D9r 2 20 rr rr jsr iTALK ; send TALK 0005DCr 2 A5 rr lda zSA 0005DEr 2 20 rr rr jsr iTKSA ; and secondary address after TALK 0005E1r 2 0005E1r 2 20 rr rr jsr iACPTR ; read 1st byte from IEC 0005E4r 2 85 rr sta zEAL ; and store it as low byte of start address 0005E6r 2 0005E6r 2 A5 rr lda zSTATUS ; check status bit 6 (EOI) 0005E8r 2 4A lsr a 0005E9r 2 4A lsr a 0005EAr 2 B0 45 bcs KLOAD_ErrFileNotFound2 ; EOI -> return with "File Not Found" error 0005ECr 2 0005ECr 2 .ifdef JIFFY 0005ECr 2 jsr JDLF179 0005ECr 2 .else 0005ECr 2 20 rr rr jsr iACPTR ; read 2nd byte from IEC 0005EFr 2 .endif 0005EFr 2 85 rr sta zEAL + 1 ; and store it as high byte of start address 0005F1r 2 0005F1r 2 .if 0 0005F1r 2 ; this macro is defined in fileio_data.inc 0005F1r 2 0005F1r 2 .macro LOAD_OVERWRITE_START_ADDRESS 0005F1r 2 txa 0005F1r 2 bne :+ 0005F1r 2 lda zMEMUSS 0005F1r 2 sta zEAL 0005F1r 2 lda zMEMUSS + 1 0005F1r 2 sta zEAL + 1 0005F1r 2 : 0005F1r 2 0005F1r 2 .endmacro 0005F1r 2 .endif 0005F1r 2 0005F1r 2 .if CompileComputer >= C64_GENERAL 0005F1r 2 LOAD_OVERWRITE_START_ADDRESS 0005F1r 2 .endif 0005F1r 2 0005F1r 2 0005F1r 2 .ifdef JIFFY 0005F1r 2 @LF4F0: 0005F1r 2 jmp JDLFAC4 0005F1r 2 0005F1r 2 LF4F3: 0005F1r 2 jsr kSTOP 0005F1r 2 bne @LF4FB 0005F1r 2 jmp IecCloseBecauseStopKey 0005F1r 2 @LF4FB: 0005F1r 2 jsr JDLFBAA 0005F1r 2 lda zSTATUS 0005F1r 2 and #$FD 0005F1r 2 cmp zSTATUS 0005F1r 2 sta zSTATUS 0005F1r 2 bne LF4F3 0005F1r 2 ldy #$00 0005F1r 2 ldx zTSFCNT 0005F1r 2 lda zTBTCNT 0005F1r 2 cpy zVERCKK 0005F1r 2 beq @LF51A 0005F1r 2 cmp (zEAL),y 0005F1r 2 beq @LF51C 0005F1r 2 jsr LF19E 0005F1r 2 .byte $2C 0005F1r 2 @LF51A: 0005F1r 2 sta (zEAL),y 0005F1r 2 @LF51C: 0005F1r 2 stx zTSFCNT 0005F1r 2 0005F1r 2 .else 0005F1r 2 0005F1r 2 .if CompileComputer >= C64_GENERAL .or CompileComputer = VIC20_02 0005F1r 2 jsr OutputLoadingOrVerify ; output LOADING or VERIFYING messages 0005F1r 2 .else 0005F1r 2 ; the following patch contains: 0005F1r 2 ; LOAD_OVERWRITE_START_ADDRESS 0005F1r 2 ; jsr OutputLoadingOrVerify 0005F1r 2 0005F1r 2 ; Thus, the implementation is identical to the C64 0005F1r 2 0005F1r 2 20 rr rr jsr LE4C1 0005F4r 2 .endif 0005F4r 2 0005F4r 2 LF4F3: 0005F4r 2 A9 FD lda #~STATUS_IEC_TIMEOUT_READ ; clear read timeout 0005F6r 2 25 rr and zSTATUS ; TODO: why? 0005F8r 2 85 rr sta zSTATUS 0005FAr 2 0005FAr 2 20 rr rr jsr kSTOP ; check if the stop key has been pressed 0005FDr 2 D0 03 bne @ReadByte ; no stop key, proceed 0005FFr 2 0005FFr 2 4C rr rr jmp IecCloseBecauseStopKey ; close file and return with error: Stopped because user pressed key 000602r 2 000602r 2 @ReadByte: 000602r 2 20 rr rr jsr iACPTR ; get data byte from IEC bus 000605r 2 AA tax ; remember it in X 000606r 2 000606r 2 A5 rr lda zSTATUS ; check status bit 6 (EOI) 000608r 2 4A lsr a 000609r 2 4A lsr a 00060Ar 2 B0 E8 bcs LF4F3 ; EOI -> there is no data to process -> branch 00060Cr 2 00060Cr 2 8A txa ; get back the data byte from the IEC bus 00060Dr 2 00060Dr 2 A4 rr ldy zVERCKK ; test verify flag 00060Fr 2 F0 0C beq @Load ; =0 --> LOAD --> Store data byte in memory 000611r 2 000611r 2 A0 00 ldy #0 ; make sure to compare the first byte 000613r 2 D1 rr cmp (zEAL),y ; compare data byte 000615r 2 F0 08 beq @IncrementAddress ; it's the same -> everything ok -> branch 000617r 2 000617r 2 A9 10 lda #STATUS_VERIFY ; set "verify error" bit 000619r 2 20 rr rr jsr SetStatus 00061Cr 2 00061Cr 2 2C .byte ASM_BIT3 ; mask next instruction so it is not executed 00061Dr 2 00061Dr 2 @Load: 00061Dr 2 ; Y is already 0 here, as this is only executed when beq @Load after ldy zVERCKK has been taken... 00061Dr 2 91 rr sta (zEAL),y ; store data byte in memory 00061Fr 2 00061Fr 2 .endif 00061Fr 2 00061Fr 2 @IncrementAddress: 00061Fr 2 E6 rr inc zEAL ; increment low address 000621r 2 D0 02 bne :+ ; if not zero, skip incrementing high address 000623r 2 E6 rr inc zEAL + 1 ; increment high address 000625r 2 000625r 2 24 rr : bit zSTATUS ; test status bit 6 (EOI) 000627r 2 50 CB bvc LF4F3 ; unset -> proceed with next byte 000629r 2 000629r 2 KLOAD_UntalkClose: 000629r 2 20 rr rr jsr iUNTLK ; send UNTALK to device 00062Cr 2 20 rr rr jsr IecClose ; close the file 00062Fr 2 90 7A bcc LoadEndSuccess ; C=0 -> no error occurred -> quit with success 000631r 2 000631r 2 KLOAD_ErrFileNotFound2: 000631r 2 4C rr rr jmp KErrFileNotFound ; return with "File Not Found" error 000634r 2 ; ------------------------- 000634r 2 000634r 2 KLOAD_TapeOrRS232: 000634r 2 ; if we reach here, either a LOAD from TAPE (A=1) or from RS232 (=2) has been 000634r 2 ; asked for 000634r 2 000634r 2 .ifdef JIFFY 000634r 2 000634r 2 lda zFNLEN 000634r 2 beq LF546 000634r 2 lda (zFNADR),y 000634r 2 cmp #$24 000634r 2 beq LF56C 000634r 2 jmp JDLFC9A 000634r 2 tya 000634r 2 LF541: pha 000634r 2 jsr JDLF8BF 000634r 2 pla 000634r 2 LF546: sta zBUFPNT 000634r 2 LF548: jsr JDLF911 000634r 2 bne LF568 000634r 2 lda zBUFPNT 000634r 2 php 000634r 2 beq LF557 000634r 2 jsr JDLE4C6 000634r 2 beq LF567 000634r 2 LF557: jsr JDLF79A 000634r 2 jsr OutputFilename 000634r 2 bit zSTKEY 000634r 2 bpl LF567 000634r 2 plp 000634r 2 bne LF548 000634r 2 bvc LF548 000634r 2 .byte $24 000634r 2 LF567: plp 000634r 2 LF568: rts 000634r 2 ldx #$6C 000634r 2 .byte $2C 000634r 2 LF56C: ldx #$60 000634r 2 jsr JDLF8C1 000634r 2 lda #$39 000634r 2 sta lIERROR 000634r 2 ldy #$FC 000634r 2 jsr JDLFCA6 000634r 2 LF57B: ldy #$00 000634r 2 LF57D: jsr JDLFCA6 000634r 2 bvs LF5A3 000634r 2 cpy #$02 000634r 2 beq LF5A3 000634r 2 cpy #$06 000634r 2 bcc LF57D 000634r 2 ldx zFNADR 000634r 2 stx $5F 000634r 2 ldx $BC 000634r 2 stx $60 000634r 2 ldy #$01 000634r 2 sta ($5F),y 000634r 2 jsr JDLA6C3 000634r 2 jsr JDLF79A 000634r 2 jsr JDLA6D4 000634r 2 bit zSTKEY 000634r 2 bmi LF57B 000634r 2 LF5A3: lda #$63 000634r 2 sta lIERROR 000634r 2 rts 000634r 2 000634r 2 .else 000634r 2 000634r 2 .if CompileComputer >= C64_GENERAL 000634r 2 lsr a ; check if bit 0 of the device number is 1 000634r 2 bcs @Tape ; yes -> it is the tape -> branch, process LOAD from tape 000634r 2 jmp KErrIllegalDeviceNumber ; load from RS232 not possible, quit with "Illegal Device Number" error 000634r 2 .else 000634r 2 C9 02 cmp #FILE_RS232 ; test if the device number is the number of RS232 000636r 2 D0 03 bne @Tape ; no -> it is the tape -> branch, process LOAD from tape 000638r 2 4C rr rr jmp Rs232ErrIllegalDeviceNumber ; load from RS232 not possible, quit with "Illegal Device Number" error 00063Br 2 .endif 00063Br 2 00063Br 2 ; TODO document load from TAPE 00063Br 2 @Tape: 00063Br 2 20 rr rr jsr TapeGetPointer ; get pointer to tape buffer into (X/Y) (unused, but flags important) 00063Er 2 B0 03 bcs :+ ; C = 1 -> tape buffer does NOT point to stack page or zero page -> proceed, we do not overwrite essential data! 000640r 2 4C rr rr jmp KErrIllegalDeviceNumber 000643r 2 000643r 2 : 000643r 2 20 rr rr jsr TapePressPlayOnTape ; output "PRESS PLAY ON TAPE" and wait for the PLAY key to be pressed 000646r 2 B0 68 bcs LoadRts ; C = 1 --> an error occurred (STOP key) --> branch, quit 000648r 2 000648r 2 20 rr rr jsr OutputSearchingFor ; output "SEARCHING FOR ..." 00064Br 2 00064Br 2 A5 rr @LF549: lda zFNLEN ; length of file name 00064Dr 2 F0 09 beq :+ ; 0 --> no file name specified -> skip 00064Fr 2 20 rr rr jsr TapeFindSpecificFile ; try to find the specified file 000652r 2 90 0B bcc @FoundFile ; C = 0 -> no error occurred -> branch, proceed with operation 000654r 2 F0 5A beq LoadRts ; Z = 1 --> an EOT was found 000656r 2 B0 D9 bcs KLOAD_ErrFileNotFound2 ; return with FILE NOT FOUND error 000658r 2 ; ------------------------ 000658r 2 000658r 2 : 000658r 2 20 rr rr jsr TapeReadTapeHeaderOfNextFile ; try to find ANY file header 00065Br 2 F0 53 beq LoadRts ; Z = 1 --> an EOT was found (BUG or TODO?: This is only valid if C=0, thus, this test would have to be the first one!) 00065Dr 2 B0 D2 bcs KLOAD_ErrFileNotFound2 ; C = 1 --> an error occurred -> branch, quit with FILE NOT FOUND error 00065Fr 2 00065Fr 2 @FoundFile: 00065Fr 2 A5 rr lda zSTATUS 000661r 2 29 10 and #STATUS_VERIFY ; TODO: STATUS_VERIFY or STATUS_TAPE_UNRECOVERABLE_READ_ERROR? The latter seems not to be generated (or I missed it until now) 000663r 2 38 sec 000664r 2 D0 4A bne LoadRts ; if the status indicated the error -> branch, we're done 000666r 2 000666r 2 E0 01 cpx #TAPE_BUFFER_TYPE_BASIC ; is this file a BASIC program? 000668r 2 F0 11 beq @BASIC_Program ; yes -> branch, process the BASIC program 00066Ar 2 00066Ar 2 E0 03 cpx #TAPE_BUFFER_TYPE_ABSOLUTE ; is this file an absolute program? 00066Cr 2 D0 DD bne @LF549 ; no -> branch, search for the next file (there is a data file with the same name, skip it) 00066Er 2 00066Er 2 @Absolute_Program: 00066Er 2 A0 01 ldy #TAPE_BUFFER_OFFSET_SAL_LOW ; offset of start address low in tape buffer 000670r 2 B1 rr lda (zTAPE1),y ; read the start address low 000672r 2 85 rr sta zMEMUSS_2 ; and store it 000674r 2 C8 iny ; advance offset to start address high 000675r 2 B1 rr lda (zTAPE1),y ; read the start address high 000677r 2 85 rr sta zMEMUSS_2 + 1 ; and store it 000679r 2 B0 04 bcs @LoadFile ; (uncond. branch: TAPE_BUFFER_TYPE_DATA or TAPE_BUFFER_TYPE_EOT can be ruled out here, thus, the CPX resulted in a C=1) 00067Br 2 ; ------------------- 00067Br 2 00067Br 2 @BASIC_Program: 00067Br 2 A5 rr lda zSA ; get secondary address used to open the file 00067Dr 2 D0 EF bne @Absolute_Program ; not 0 --> we want to read the file absolute, ignore that it is written as BASIC program and load it absolute instead 00067Fr 2 00067Fr 2 ; If the above branch did not branch and we reach this place from above (not via bcs @LoadFile), then we have a BASIC program. 00067Fr 2 ; The start address to load it to is already at zMEMUSS_2/zMEMUSS_2 + 1. 00067Fr 2 00067Fr 2 @LoadFile: 00067Fr 2 ; Calculate the end address and write it into zEAL/zEAL+1 00067Fr 2 00067Fr 2 ; sec ; C=1 is always true here, thus, no need for an SEC 00067Fr 2 00067Fr 2 A0 03 ldy #TAPE_BUFFER_OFFSET_EAL_LOW ; (offset of end address low in tape buffer) 000681r 2 B1 rr lda (zTAPE1),y ; get end address low 000683r 2 A0 01 ldy #TAPE_BUFFER_OFFSET_SAL_LOW ; (offset of start address low in tape buffer) 000685r 2 F1 rr sbc (zTAPE1),y ; subtract end address low - start address low 000687r 2 AA tax ; remember the result in X 000688r 2 000688r 2 A0 04 ldy #TAPE_BUFFER_OFFSET_EAL_HIGH ; (offset of end address high in tape buffer) 00068Ar 2 B1 rr lda (zTAPE1),y ; get end address high 00068Cr 2 A0 02 ldy #TAPE_BUFFER_OFFSET_SAL_HIGH ; (offset of start address high in tape buffer) 00068Er 2 F1 rr sbc (zTAPE1),y ; subtract end address high - start address high 000690r 2 A8 tay ; remember the result in Y 000691r 2 000691r 2 ; now, add the length (in X/Y) t zMEMUSS_2/zMEMUSS_2+1, and store the result in zEAL/zEAL+1 000691r 2 18 clc 000692r 2 8A txa ; get length low 000693r 2 65 rr adc zMEMUSS_2 ; add it to the start address low 000695r 2 85 rr sta zEAL ; and store it as end address low 000697r 2 000697r 2 98 tya ; get length high 000698r 2 65 rr adc zMEMUSS_2 + 1 ; add it to the start address high 00069Ar 2 85 rr sta zEAL + 1 ; and store it as end address high 00069Cr 2 00069Cr 2 ; copy the start address from zMEMUSS_2/zMEMUSS_2+1 to zSTAL/zSTAL+1 00069Cr 2 00069Cr 2 A5 rr lda zMEMUSS_2 00069Er 2 85 rr sta zSTAL 0006A0r 2 A5 rr lda zMEMUSS_2 + 1 0006A2r 2 85 rr sta zSTAL + 1 0006A4r 2 0006A4r 2 20 rr rr jsr OutputLoadingOrVerify ; output LOADING or VERIFYING messages 0006A7r 2 0006A7r 2 20 rr rr jsr TapeReadFileContents ; read in the next buffer from the tape 0006AAr 2 24 .byte ASM_BIT2 ; make 0006ABr 2 0006ABr 2 .endif 0006ABr 2 0006ABr 2 LoadEndSuccess: 0006ABr 2 18 clc ; mark: success 0006ACr 2 A6 rr ldx zEAL ; return end address (+1) in X/Y 0006AEr 2 A4 rr ldy zEAL + 1 0006B0r 2 LoadRts: 0006B0r 2 60 rts 0006B1r 2 ; -------------- 0006B1r 2 0006B1r 2 OutputSearchingFor: 0006B1r 2 A5 rr lda zNSGFLG ; do we output messages "searching for", or is it prohibited? 0006B3r 2 10 1E bpl OutputSearchingFor_Rts ; no -> branch -> quit, we don't want to output anything 0006B5r 2 0006B5r 2 A0 0C ldy #StrSearching - LMESSAGES ; offset of "Searching" message 0006B7r 2 20 rr rr jsr OutputMessage ; output it 0006BAr 2 0006BAr 2 A5 rr lda zFNLEN ; test length of file name 0006BCr 2 F0 15 beq OutputSearchingFor_Rts ; length = 0 -> no filename -> branch -> quit, nothing else to do 0006BEr 2 0006BEr 2 A0 17 ldy #StrFor - LMESSAGES ; offset of " for " message 0006C0r 2 20 rr rr jsr OutputMessage ; output it 0006C3r 2 0006C3r 2 OutputFilename: 0006C3r 2 A4 rr ldy zFNLEN ; test length of file name 0006C5r 2 F0 0C beq OutputSearchingFor_Rts ; length = 0 -> no filename -> branch -> quit, nothing else to do 0006C7r 2 0006C7r 2 A0 00 ldy #0 ; start with first character 0006C9r 2 B1 rr : lda (zFNADR),y ; get character of file name 0006CBr 2 20 rr rr jsr kCHROUT ; and output it 0006CEr 2 C8 iny ; advance to next character 0006CFr 2 C4 rr cpy zFNLEN ; did we reach the end of the file name? 0006D1r 2 D0 F6 bne :- ; no, process next character 0006D3r 2 0006D3r 2 OutputSearchingFor_Rts: 0006D3r 2 60 rts 0006D4r 2 ; -------------------- 0006D4r 2 0006D4r 2 OutputLoadingOrVerify: 0006D4r 2 A0 49 ldy #StrLoading - LMESSAGES ; offset of "LOADING" message 0006D6r 2 A5 rr lda zVERCKK ; check verify flag 0006D8r 2 F0 02 beq @Output ; 0 -> LOAD -> output LOADING" 0006DAr 2 A0 59 ldy #StrVerifying - LMESSAGES ; otherwise, it is a VERIFY: Get offset of "VERIFYING" message 0006DCr 2 @Output: 0006DCr 2 4C rr rr jmp OutputMessageIfAllowed ; output the message, if not prohibited 0006DFr 2 0006DFr 2 0006DFr 2 0006DFr 2 ; B-24. Function Name: SAVE 0006DFr 2 ; 0006DFr 2 ; Purpose: Save memory to a device 0006DFr 2 ; Call address: $FFD8 (hex) 65496 (decimal) 0006DFr 2 ; Communication registers: A, X, Y 0006DFr 2 ; Preparatory routines: SETLFS, SETNAM 0006DFr 2 ; Error returns: 5,8,9, READST 0006DFr 2 ; Stack requirements: None 0006DFr 2 ; Registers affected: A, X, Y 0006DFr 2 ; 0006DFr 2 ; 0006DFr 2 ; 0006DFr 2 ; Description: This routine saves a section of memory. Memory is saved 0006DFr 2 ; from an indirect address on page 0 specified by the accumulator to the 0006DFr 2 ; address stored in the X and Y registers. It is then sent to a logical 0006DFr 2 ; file on an input/output device. The SETLFS and SETNAM routines must be 0006DFr 2 ; used before calling this routine. However, a file name is not required to 0006DFr 2 ; SAVE to device 1 (the Datassette(TM) recorder). Any attempt to save to 0006DFr 2 ; other devices without using a file name results in an error. 0006DFr 2 ; 0006DFr 2 ; +-----------------------------------------------------------------------+ 0006DFr 2 ; | NOTE: Device 0 (the keyboard), device 2 (RS-232), and device 3 (the | 0006DFr 2 ; | screen) cannot be SAVEd to. If the attempt is made, an error occurs, | 0006DFr 2 ; | and the SAVE is stopped. | 0006DFr 2 ; +-----------------------------------------------------------------------+ 0006DFr 2 ; 0006DFr 2 ; How to Use: 0006DFr 2 ; 0006DFr 2 ; 0) Use the SETLFS routine and the SETNAM routine (unless a SAVE with no 0006DFr 2 ; file name is desired on "a save to the tape recorder"), 0006DFr 2 ; 1) Load two consecutive locations on page 0 with a pointer to the start 0006DFr 2 ; of your save (in standard 6502 low byte first, high byte next 0006DFr 2 ; format). 0006DFr 2 ; 2) Load the accumulator with the single byte page zero offset to the 0006DFr 2 ; pointer. 0006DFr 2 ; 3) Load the X and Y registers with the low byte and high byte re- 0006DFr 2 ; spectively of the location of the end of the save. 0006DFr 2 ; 4) Call this routine. 0006DFr 2 ; 0006DFr 2 ; EXAMPLE: 0006DFr 2 ; 0006DFr 2 ; LDA #1 ;DEVICE = 1:CASSETTE 0006DFr 2 ; JSR SETLFS 0006DFr 2 ; LDA #0 ;NO FILE NAME 0006DFr 2 ; JSR SETNAM 0006DFr 2 ; LDA PROG ;LOAD START ADDRESS OF SAVE 0006DFr 2 ; STA TXTTAB ;(LOW BYTE) 0006DFr 2 ; LDA PROG+1 0006DFr 2 ; STA TXTTA B+1 ;(HIGH BYTE) 0006DFr 2 ; LDX VARTAB ;LOAD X WITH LOW BYTE OF END OF SAVE 0006DFr 2 ; LDY VARTAB+1 ;LOAD Y WITH HIGH BYTE 0006DFr 2 ; LDA # branch, test for other devices 0006F3r 2 0006F3r 2 SaveErrIllegalDeviceNumber: 0006F3r 2 4C rr rr jmp KErrIllegalDeviceNumber ; return with "Illegal Device Number" error 0006F6r 2 0006F6r 2 SaveNotKeyboard: 0006F6r 2 C9 03 cmp #FILE_SCREEN ; device number screen (3)? 0006F8r 2 F0 F9 beq SaveErrIllegalDeviceNumber ; yes -> return with "Illegal Device Number" error 0006FAr 2 0006FAr 2 ; if we reach here, only tape and RS232 are left with C=0 0006FAr 2 ; (and IEC with C=1) 0006FAr 2 .ifdef JIFFY 0006FAr 2 bcc SaveErrIllegalDeviceNumber ; on the SX64, tape and RS232 are both illegal -> return with error 0006FAr 2 .elseif CompileComputer = C64_SX64 0006FAr 2 bcc SaveErrIllegalDeviceNumber ; on the SX64, tape and RS232 are both illegal -> return with error 0006FAr 2 .else 0006FAr 2 90 5F bcc SaveTapeOrRs232 ; check if tape or RS232 0006FCr 2 .endif 0006FCr 2 0006FCr 2 ; if we reach here, we want to save on IEC bus 0006FCr 2 0006FCr 2 A9 61 lda #IEEE_SAVE ; set the secondary address 0006FEr 2 85 rr sta zSA ; to the address of a save 000700r 2 000700r 2 A4 rr ldy zFNLEN ; is there a file name? 000702r 2 D0 03 bne LF605 ; yes -> everything ok, proceed 000704r 2 000704r 2 SAVE_KErrFileNameMissing: 000704r 2 4C rr rr jmp KErrFileNameMissing ; return with "File Name Missing" error 000707r 2 000707r 2 LF605: 000707r 2 20 rr rr jsr KOPEN_IEC ; open the file on the IEC bus 00070Ar 2 20 rr rr jsr OutputSaving ; output the "SAVING" message 00070Dr 2 00070Dr 2 A5 rr lda zFA ; send LISTEN to device 00070Fr 2 20 rr rr jsr iLISTEN 000712r 2 A5 rr lda zSA ; with correspondig SA 000714r 2 20 rr rr jsr iSECOND 000717r 2 000717r 2 A0 00 ldy #0 ; index for writing data (for later, when receiving data) 000719r 2 000719r 2 20 rr rr jsr Copy_zSTAL_to_zSAL ; save start address into pointer which will be used for saving 00071Cr 2 00071Cr 2 ; output the start address as two first bytes 00071Cr 2 A5 rr lda zSAL ; low byte 00071Er 2 20 rr rr jsr iCIOUT 000721r 2 A5 rr lda zSAL + 1 ; high byte 000723r 2 20 rr rr jsr iCIOUT 000726r 2 000726r 2 SAVE_Loop: 000726r 2 20 rr rr jsr HasEndAddressBeenReached ; check if working address (zSAL/zSAL+1) has reached end address (zEAL/zEAL+1) 000729r 2 B0 16 bcs SAVE_End ; reached -> branch 00072Br 2 00072Br 2 B1 rr lda (zSAL),y ; byte to be saved 00072Dr 2 20 rr rr jsr iCIOUT ; output to IEC 000730r 2 000730r 2 20 rr rr jsr kSTOP ; check if has been pressed 000733r 2 D0 07 bne SAVE_NoStop ; no -> branch, process next byte (if any) 000735r 2 000735r 2 IecCloseBecauseStopKey: 000735r 2 20 rr rr jsr IecClose ; close the file on the IEC bus 000738r 2 000738r 2 A9 00 lda #0 ; error: Routine terminated by the key 00073Ar 2 38 sec ; mark: error return 00073Br 2 60 rts 00073Cr 2 ; -------------- 00073Cr 2 00073Cr 2 SAVE_NoStop: 00073Cr 2 20 rr rr jsr Increment_zSAL_Address ; increment working address 00073Fr 2 D0 E5 bne SAVE_Loop ; if no "wrap around" to address 0, save the next byte 000741r 2 000741r 2 000741r 2 SAVE_End: 000741r 2 20 rr rr jsr iUNLSN ; send UNLISTEN to device 000744r 2 000744r 2 IecClose: 000744r 2 ; Close an IEC file by sending a LISTEN with the secondary address specifying "CLOSE" 000744r 2 24 rr bit zSA ; secondary address 000746r 2 30 11 bmi SAVE_ClcRts ; bit 7 set -> branch, we are done 000748r 2 000748r 2 A5 rr lda zFA ; send listen to device 00074Ar 2 20 rr rr jsr iLISTEN 00074Dr 2 00074Dr 2 A5 rr lda zSA ; send secondary address "CLOSE" 00074Fr 2 29 EF and #$EF 000751r 2 09 E0 ora #IEEE_CLOSE 000753r 2 20 rr rr jsr iSECOND 000756r 2 000756r 2 DoUnlistenClcRts: 000756r 2 20 rr rr jsr iUNLSN ; send UNLISTEN 000759r 2 000759r 2 SAVE_ClcRts: 000759r 2 18 clc 00075Ar 2 60 rts 00075Br 2 ; -------------- 00075Br 2 00075Br 2 SaveTapeOrRs232: 00075Br 2 00075Br 2 .ifdef JIFFY 00075Br 2 00075Br 2 LF659: lda zNDX 00075Br 2 beq SAVE_KErrFileNameMissing 00075Br 2 lda #$02 00075Br 2 sta zSA 00075Br 2 ldx #$74 00075Br 2 ldy #$F6 00075Br 2 jsr kSETNAM 00075Br 2 jmp KLOAD_FileNameGiven 00075Br 2 LF66B: ldx #$33 00075Br 2 ldy #$04 00075Br 2 jmp JDLF932 00075Br 2 00075Br 2 .byte $40, $24, $3a, $2a, $0d, $00, $2f, $00 00075Br 2 .byte $5e, $00, $25, $00, $40, $44, $00, $40 00075Br 2 .byte $54, $00, $5f, $00, $40, $20, $20, $22 00075Br 2 .byte $53, $3a, $00 00075Br 2 00075Br 2 .else 00075Br 2 00075Br 2 ; if we reach here, either a SAVE from TAPE (A=1) or from RS232 (=2) has been 00075Br 2 ; asked for 00075Br 2 00075Br 2 .if CompileComputer >= C64_GENERAL 00075Br 2 lsr a ; check if bit 0 of the device number is 1 00075Br 2 bcs @Tape ; yes -> it is the tape -> branch, process SAVE from tape 00075Br 2 jmp KErrIllegalDeviceNumber ; save to RS232 not possible, quit with "Illegal Device Number" error 00075Br 2 .else 00075Br 2 C9 02 cmp #FILE_RS232 ; test if the device number is the number of RS232 00075Dr 2 D0 03 bne @Tape ; no -> it is the tape -> branch, process SAVE to tape 00075Fr 2 4C rr rr jmp Rs232ErrIllegalDeviceNumber ; save to RS232 not possible, quit with "Illegal Device Number" error 000762r 2 .endif 000762r 2 000762r 2 @Tape: 000762r 2 20 rr rr jsr TapeGetPointer ; is the tape buffer set (high byte >= 2)? 000765r 2 90 8C bcc SaveErrIllegalDeviceNumber ; no -> abort operation, as we would overwrite ZP or stack 000767r 2 000767r 2 20 rr rr jsr TapePressRecordAndPlayOnTape ; output "PRESS RECORD + PLAY ON TAPE" and wait for PLAY to be pressd 00076Ar 2 B0 25 bcs SAVE_Rts ; C=1 -> an error occurred (i.e., STOP was pressed) -> branch, abort 00076Cr 2 00076Cr 2 20 rr rr jsr OutputSaving ; Output the text "SAVING " 00076Fr 2 00076Fr 2 ; determine the tape buffer type to generate for the first block (filename) 00076Fr 2 00076Fr 2 A2 03 ldx #TAPE_BUFFER_TYPE_ABSOLUTE ; assume: file is a absolute loading program (not BASIC) 000771r 2 000771r 2 A5 rr lda zSA ; check secondary address 000773r 2 29 01 and #$01 ; bit 0 set? 000775r 2 D0 02 bne :+ ; yes -> branch, skip 000777r 2 000777r 2 A2 01 ldx #TAPE_BUFFER_TYPE_BASIC ; no -> file is a BASIC program 000779r 2 000779r 2 8A : txa 00077Ar 2 20 rr rr jsr TapeCreateFileBuffer ; create the file buffer (including start and end address and file name) and write it on tape 00077Dr 2 B0 12 bcs SAVE_Rts ; C = 1 -> an error occurred -> branch, quit save with an error 00077Fr 2 00077Fr 2 20 rr rr jsr TapeWriteCompleteFile ; write out the file to tape 000782r 2 B0 0D bcs SAVE_Rts ; C = 1 -> an error occurred -> branch, quit save with an error 000784r 2 000784r 2 ; check if bit 1 of the secondary address is set. If so, we have to write an end-of-tape (EOT) marker on the tape 000784r 2 A5 rr lda zSA ; get secondary address 000786r 2 29 02 and #$02 ; is bit 1 set? 000788r 2 F0 06 beq @ClcRts ; no -> branch, we're done 00078Ar 2 00078Ar 2 A9 05 lda #TAPE_BUFFER_TYPE_EOT ; tape buffer type: END-OF-TAPE (EOT) 00078Cr 2 20 rr rr jsr TapeCreateFileBuffer ; create the file buffer and write it on tape 00078Fr 2 00078Fr 2 24 .byte ASM_BIT2 ; make sure not to loose the status of C by hiding the next instruction 000790r 2 000790r 2 .endif 000790r 2 000790r 2 @ClcRts: 000790r 2 18 clc 000791r 2 SAVE_Rts: 000791r 2 60 rts 000792r 2 ; --------------------- 000792r 2 000792r 2 OutputSaving: 000792r 2 A5 rr lda zNSGFLG ; do we output messages "searching for", or is it prohibited? 000794r 2 10 FB bpl SAVE_Rts ; no -> branch -> quit, we don't want to output anything 000796r 2 000796r 2 A0 51 ldy #StrSaving - LMESSAGES ; offset of "Saving" message 000798r 2 20 rr rr jsr OutputMessage ; output it 00079Br 2 00079Br 2 4C rr rr jmp OutputFilename ; output the file name of file to be saved 00079Er 2 ; --------------------- 00079Er 2 00079Er 2 00079Er 2 ; B-36. Function Name: UDTIM 00079Er 2 ; 00079Er 2 ; Purpose: Update the system clock 00079Er 2 ; Call address: $FFEA (hex) 65514 (decimal) 00079Er 2 ; Communication registers: None 00079Er 2 ; Preparatory routines: None 00079Er 2 ; Error returns: None 00079Er 2 ; Stack requirements: 2 00079Er 2 ; Registers affected: A, X 00079Er 2 ; 00079Er 2 ; Description: This routine updates the system clock. Normally this 00079Er 2 ; routine is called by the normal KERNAL interrupt routine every 1/60th of 00079Er 2 ; a second. If the user program processes its own interrupts this routine 00079Er 2 ; must be called to update the time. In addition, the key routine 00079Er 2 ; must be called, if the key is to remain functional. 00079Er 2 ; 00079Er 2 ; How to Use: 00079Er 2 ; 1) Call this routine. 00079Er 2 ; 00079Er 2 ; EXAMPLE: 00079Er 2 ; 00079Er 2 ; JSR UDTIM 00079Er 2 ; 00079Er 2 ; 00079Er 2 iUDTIM: 00079Er 2 A2 00 ldx #0 ; will be used in the case of a wrap-around of the timer for setting the timer back to zero. 0007A0r 2 0007A0r 2 E6 rr inc zTIME + 2 ; increment lowest byte 0007A2r 2 D0 06 bne @CheckOverflow ; no overflow -> done incrementing 0007A4r 2 0007A4r 2 E6 rr inc zTIME + 1 ; increment middle byte 0007A6r 2 D0 02 bne @CheckOverflow ; no overflow -> done incrementing 0007A8r 2 0007A8r 2 E6 rr inc zTIME ; increment highest byte 0007AAr 2 0007AAr 2 @CheckOverflow: 0007AAr 2 0007AAr 2 ; now, check if the timer overflowed, that is, 24h have been reached 0007AAr 2 ; for this, subtract the constant for 24h (24*60*60*60)+1 from the 0007AAr 2 ; current value 0007AAr 2 0007AAr 2 38 sec 0007ABr 2 A5 rr lda zTIME + 2 0007ADr 2 E9 01 sbc #<((24*60*60*60)+1) 0007AFr 2 A5 rr lda zTIME + 1 0007B1r 2 E9 1A sbc #>((24*60*60*60)+1) 0007B3r 2 A5 rr lda zTIME 0007B5r 2 E9 4F sbc #^((24*60*60*60)+1) 0007B7r 2 0007B7r 2 ; if carry is not set, the timer value is smaller -> branch, no need to perform wrap-around 0007B7r 2 90 06 bcc iUDTIM_CheckRunStop 0007B9r 2 0007B9r 2 ; we had a wrap-around, set timer value to 0 0007B9r 2 86 rr stx zTIME 0007BBr 2 86 rr stx zTIME + 1 0007BDr 2 86 rr stx zTIME + 2 0007BFr 2 0007BFr 2 iUDTIM_CheckRunStop: 0007BFr 2 ; check if the Run/STOP key has been pressed 0007BFr 2 0007BFr 2 ; TODO document 0007BFr 2 0007BFr 2 AD 2F 91 lda KEYB_COL_FOR_STOP 0007C2r 2 CD 2F 91 cmp KEYB_COL_FOR_STOP 0007C5r 2 D0 F8 bne iUDTIM_CheckRunStop 0007C7r 2 0007C7r 2 .if CompileComputer >= C64_GENERAL 0007C7r 2 tax 0007C7r 2 bmi @StoreStop 0007C7r 2 ldx #KEYB_ROW_STOP 0007C7r 2 stx KEYB_ROW 0007C7r 2 @Debounce: 0007C7r 2 ldx KEYB_COL_FOR_STOP 0007C7r 2 cpx KEYB_COL_FOR_STOP 0007C7r 2 bne @Debounce 0007C7r 2 sta KEYB_ROW 0007C7r 2 inx 0007C7r 2 bne @Rts 0007C7r 2 .endif 0007C7r 2 0007C7r 2 @StoreStop: 0007C7r 2 85 rr sta zSTKEY 0007C9r 2 @Rts: 0007C9r 2 60 rts 0007CAr 2 0007CAr 2 0007CAr 2 ; B-21. Function Name: RDTIM 0007CAr 2 ; 0007CAr 2 ; Purpose: Read system clock 0007CAr 2 ; Call address: $FFDE (hex) 65502 (decimal) 0007CAr 2 ; Communication registers: A, X, Y 0007CAr 2 ; Preparatory routines: None 0007CAr 2 ; Error returns: None 0007CAr 2 ; Stack requirements: 2 0007CAr 2 ; Registers affected: A, X, Y 0007CAr 2 ; 0007CAr 2 ; Description: This routine is used to read the system clock. The clock's 0007CAr 2 ; resolution is a 60th of a second. Three bytes are returned by the 0007CAr 2 ; routine. The accumulator contains the most significant byte, the X index 0007CAr 2 ; register contains the next most significant byte, and the Y index 0007CAr 2 ; register contains the least significant byte. 0007CAr 2 ; 0007CAr 2 ; EXAMPLE: 0007CAr 2 ; 0007CAr 2 ; JSR RDTIM 0007CAr 2 ; STY TIME 0007CAr 2 ; STX TIME+1 0007CAr 2 ; STA TIME+2 0007CAr 2 ; ... 0007CAr 2 ; TIME *=*+3 0007CAr 2 ; 0007CAr 2 ; 0007CAr 2 iRDTIM: 0007CAr 2 78 sei ; make sure we get not interrupted (atomicity) 0007CBr 2 0007CBr 2 ; read the values of the time 0007CBr 2 A5 rr lda zTIME + 2 ; high byte 0007CDr 2 A6 rr ldx zTIME + 1 ; middle byte 0007CFr 2 A4 rr ldy zTIME ; low byte 0007D1r 2 0007D1r 2 ; B-31. Function Name: SETTIM 0007D1r 2 ; 0007D1r 2 ; Purpose: Set the system clock 0007D1r 2 ; Call address: $FFDB (hex) 65499 (decimal) 0007D1r 2 ; Communication registers: A, X, Y 0007D1r 2 ; Preparatory routines: None 0007D1r 2 ; Error returns: None 0007D1r 2 ; Stack requirements: 2 0007D1r 2 ; Registers affected: None 0007D1r 2 ; 0007D1r 2 ; 0007D1r 2 ; 0007D1r 2 ; Description: A system clock is maintained by an interrupt routine that 0007D1r 2 ; updates the clock every 1/60th of a second (one "jiffy"). The clock is 0007D1r 2 ; three bytes long, which gives it the capability to count up to 5,184,000 0007D1r 2 ; jiffies (24 hours). At that point the clock resets to zero. Before 0007D1r 2 ; calling this routine to set the clock, the accumulator must contain the 0007D1r 2 ; most significant byte, the X index register the next most significant 0007D1r 2 ; byte, and the Y index register the least significant byte of the initial 0007D1r 2 ; time setting (in jiffies). 0007D1r 2 ; 0007D1r 2 ; How to Use: 0007D1r 2 ; 1) Load the accumulator with the MSB of the 3-byte number to set the 0007D1r 2 ; clock. 0007D1r 2 ; 2) Load the X register with the next byte. 0007D1r 2 ; 3) Load the Y register with the LSB. 0007D1r 2 ; 4) Call this routine. 0007D1r 2 ; 0007D1r 2 ; EXAMPLE: 0007D1r 2 ; ;SET THE CLOCK TO 10 MINUTES = 3600 JIFFIES 0007D1r 2 ; LDA #0 ;MOST SIGNIFICANT 0007D1r 2 ; LDX #>3600 0007D1r 2 ; LDY #<3600 ;LEAST SIGNIFICANT 0007D1r 2 ; JSR SETTIM 0007D1r 2 ; 0007D1r 2 iSETTIM: 0007D1r 2 78 sei ; make sure we get not interrupted (atomicity) 0007D2r 2 0007D2r 2 ; set the values of the time 0007D2r 2 85 rr sta zTIME + 2 ; high byte 0007D4r 2 86 rr stx zTIME + 1 ; middle byte 0007D6r 2 84 rr sty zTIME ; low byte 0007D8r 2 0007D8r 2 58 cli ; the critical section is over 0007D9r 2 0007D9r 2 60 rts 0007DAr 2 ; ---------------- 0007DAr 2 0007DAr 2 ; B-33. Function Name: STOP 0007DAr 2 ; 0007DAr 2 ; Purpose: Check if key is pressed 0007DAr 2 ; Call address: $FFE1 (hex) 65505 (decimal) 0007DAr 2 ; Communication registers: A 0007DAr 2 ; Preparatory routines: None 0007DAr 2 ; Error returns: None 0007DAr 2 ; Stack requirements: None 0007DAr 2 ; Registers affected: A, X 0007DAr 2 ; 0007DAr 2 ; Description: If the key on the keyboard was pressed during a 0007DAr 2 ; UDTIM call, this call returns the Z flag set. In addition, the channels 0007DAr 2 ; will be reset to default values. All other flags remain unchanged. If the 0007DAr 2 ; key is not pressed then the accumulator will contain a byte 0007DAr 2 ; representing the lost row of the keyboard scan. The user can also check 0007DAr 2 ; for certain other keys this way. 0007DAr 2 ; 0007DAr 2 ; How to Use: 0007DAr 2 ; 0) UDTIM should be called before this routine. 0007DAr 2 ; 1) Call this routine. 0007DAr 2 ; 2) Test for the zero flag. 0007DAr 2 ; 0007DAr 2 ; 0007DAr 2 ; EXAMPLE: 0007DAr 2 ; 0007DAr 2 ; JSR UDTIM ;SCAN FOR STOP 0007DAr 2 ; JSR STOP 0007DAr 2 ; BNE *+5 ;KEY NOT DOWN 0007DAr 2 ; JMP READY ;=... STOP 0007DAr 2 ; 0007DAr 2 KSTOP: 0007DAr 2 A5 rr lda zSTKEY 0007DCr 2 C9 FE cmp #KEYB_CHECK_STOP ; was key pressed? 0007DEr 2 D0 07 bne @Rts ; no -> branch, quit 0007E0r 2 0007E0r 2 08 php ; make sure to preserve the status of Z (=1) 0007E1r 2 0007E1r 2 20 rr rr jsr kCLRCHN ; clear default input and output devices 0007E4r 2 ; (returns with A=0) 0007E4r 2 85 rr sta zNDX ; mark: No characters in the keyboard buffer 0007E6r 2 0007E6r 2 28 plp ; get back the status of Z (=1) 0007E7r 2 0007E7r 2 60 @Rts: rts 0007E8r 2 ; ----------------- 0007E8r 2 0007E8r 2 ; ERROR CODES 0007E8r 2 ; 0007E8r 2 ; The following is a list of error messages which can occur when using 0007E8r 2 ; the KERNAL routines. If an error occurs during a KERNAL routine , the 0007E8r 2 ; carry bit of the accumulator is set, and the number of the error message 0007E8r 2 ; is returned in the accumulator. 0007E8r 2 ; +-----------------------------------------------------------------------+ 0007E8r 2 ; | NOTE: Some KERNAL I/O routines do not use these codes for error | 0007E8r 2 ; | messages. Instead, errors are identified using the KERNAL READST | 0007E8r 2 ; | routine. | 0007E8r 2 ; +-----------------------------------------------------------------------+ 0007E8r 2 ; +-------+---------------------------------------------------------------+ 0007E8r 2 ; | NUMBER| MEANING | 0007E8r 2 ; +-------+---------------------------------------------------------------+ 0007E8r 2 ; | 0 | Routine terminated by the key | 0007E8r 2 ; | 1 | Too many open files | 0007E8r 2 ; | 2 | File already open | 0007E8r 2 ; | 3 | File not open | 0007E8r 2 ; | 4 | File not found | 0007E8r 2 ; | 5 | Device not present | 0007E8r 2 ; | 6 | File is not an input file | 0007E8r 2 ; | 7 | File is not an output file | 0007E8r 2 ; | 8 | File name is missing | 0007E8r 2 ; | 9 | Illegal device number | 0007E8r 2 ; | 240 | Top-of-memory change RS-232 buffer allocation/deallocation | 0007E8r 2 ; +-------+---------------------------------------------------------------+ 0007E8r 2 KErrTooManyOpenFiles: 0007E8r 2 A9 01 lda #$01 0007EAr 2 2C .byte ASM_BIT3 0007EBr 2 0007EBr 2 KErrFileOpen: 0007EBr 2 A9 02 lda #$02 0007EDr 2 2C .byte ASM_BIT3 0007EEr 2 0007EEr 2 KErrFileNotOpen: 0007EEr 2 A9 03 lda #$03 0007F0r 2 2C .byte ASM_BIT3 0007F1r 2 0007F1r 2 KErrFileNotFound: 0007F1r 2 A9 04 lda #$04 0007F3r 2 2C .byte ASM_BIT3 0007F4r 2 0007F4r 2 KErrDeviceNotPresent: 0007F4r 2 A9 05 lda #$05 0007F6r 2 2C .byte ASM_BIT3 0007F7r 2 0007F7r 2 KErrNotInputFile: 0007F7r 2 A9 06 lda #$06 0007F9r 2 2C .byte ASM_BIT3 0007FAr 2 0007FAr 2 KErrNotOutputFile: 0007FAr 2 A9 07 lda #$07 0007FCr 2 2C .byte ASM_BIT3 0007FDr 2 0007FDr 2 KErrFileNameMissing: 0007FDr 2 A9 08 lda #$08 0007FFr 2 2C .byte ASM_BIT3 000800r 2 000800r 2 KErrIllegalDeviceNumber: 000800r 2 A9 09 lda #$09 000802r 2 000802r 2 48 pha ; remember error number 000803r 2 20 rr rr jsr kCLRCHN ; restore output and input to console 000806r 2 A0 00 ldy #StrIoError - LMESSAGES ; prepare to output "I/O ERROR #" by getting its index 000808r 2 000808r 2 24 rr bit zNSGFLG ; check the flag which has the message output policy 00080Ar 2 50 0A bvc @NoOutput ; test bit 6: Output error message. If not set -> branch, do not output text 00080Cr 2 00080Cr 2 20 rr rr jsr OutputMessage ; output the message with index in Y 00080Fr 2 00080Fr 2 68 pla ; get back error number 000810r 2 48 pha ; and remember it again 000811r 2 000811r 2 09 30 ora #'0' ; convert it to ASCII ('0' - '9') 000813r 2 20 rr rr jsr kCHROUT ; and output it 000816r 2 000816r 2 @NoOutput: 000816r 2 68 pla ; get back the error number 000817r 2 38 sec ; mark: An error occurred 000818r 2 60 rts 000819r 2 ; -------------- 000819r 2 000819r 1 .include "../kernal/tape.a65" 000819r 2 TAPE_BUFFER_TYPE_BASIC = $01 000819r 2 TAPE_BUFFER_TYPE_CONTINUATION = $02 000819r 2 TAPE_BUFFER_TYPE_ABSOLUTE = $03 000819r 2 TAPE_BUFFER_TYPE_DATA = $04 000819r 2 TAPE_BUFFER_TYPE_EOT = $05 000819r 2 000819r 2 TAPE_BUFFER_OFFSET_TYPE = $00 000819r 2 TAPE_BUFFER_OFFSET_SAL_LOW = $01 000819r 2 TAPE_BUFFER_OFFSET_SAL_HIGH = $02 000819r 2 TAPE_BUFFER_OFFSET_EAL_LOW = $03 000819r 2 TAPE_BUFFER_OFFSET_EAL_HIGH = $04 000819r 2 TAPE_BUFFER_OFFSET_FILENAME = $05 ; start of file name in every tape buffer but TAPE_BUFFER_TYPE_CONTINUATION 000819r 2 TAPE_BUFFER_OFFSET_ENDFILENAME = $15 ; one after the end of the file name in every tape buffer but TAPE_BUFFER_TYPE_CONTINUATION 000819r 2 000819r 2 000819r 2 TAPE_TIMER_CONSTANT_BIT0 := $60 000819r 2 TAPE_TIMER_CONSTANT_BIT1 := $B0 000819r 2 TAPE_TIMER_CONSTANT_PREAMBLE := $78 000819r 2 TAPE_TIMER_CONSTANT_WRITE := $0110 000819r 2 000819r 2 TAPE_RIPRTY_69 := $69 000819r 2 TAPE_RIPRTY_14 := $14 000819r 2 000819r 2 ; Define some aliases for understandability 000819r 2 000819r 2 Pass1ReadErrors = zPTR1 000819r 2 Pass2ReadErrors = zPTR2 000819r 2 ReadCharacterError = zRODATA 000819r 2 ReadCharacterIn = zROPRTY 000819r 2 WriteCharacterOut = zROPRTY 000819r 2 NrBlocksRemaining = zINBIT 000819r 2 ByteReceivedFlag = zDPSW 000819r 2 SerialWordBuffer = zMYCH 000819r 2 ReadBitSequenceErrors = zRINONE 000819r 2 ErrorFlagOnTapeRead = zBITC1 000819r 2 000819r 2 000819r 2 ; Tape buffer format on tape (cf. TapeCreateFileBuffer): 000819r 2 ; $00: type of block (cf. TAPE_BUFFER_TYPE_... constants above) 000819r 2 ; 000819r 2 ; if type of block == $01, $03, $04 or $05: 000819r 2 ; $01: start address low 000819r 2 ; $02: start address high 000819r 2 ; $03: end address low 000819r 2 ; $04: end address high 000819r 2 ; $05 - $14: name of file 000819r 2 ; 000819r 2 000819r 2 000819r 2 .if CompileComputer = C64_GS 000819r 2 000819r 2 .include "../c64/c64gs.inc" 000819r 2 000819r 2 .else ; .if CompileComputer = C64_GS 000819r 2 000819r 2 ; Find the next file on tape 000819r 2 ; 000819r 2 ; Output: 000819r 2 ; C = 1 --> an error occurred 000819r 2 ; C = 0 --> no error occurred 000819r 2 ; Z = 1 --> EOT was found 000819r 2 ; Z = 0 --> no EOT was found 000819r 2 ; X = tape buffer type if no error occurred 000819r 2 ; 000819r 2 ; BUG: 000819r 2 ; If the buffer could not be read at all, Z = 1 will be true if zVERCKK contains a 0. 000819r 2 ; Thus, Z will not represent the status of the EOT. 000819r 2 ; 000819r 2 TapeReadTapeHeaderOfNextFile: 000819r 2 000819r 2 @ReadNextHeader: 000819r 2 A5 rr lda zVERCKK ; remember verify (=1) or load (=0) flag 00081Br 2 48 pha ; onto stack 00081Cr 2 00081Cr 2 20 rr rr jsr TapeReadNextBuffer ; get next buffer from tape 00081Fr 2 00081Fr 2 68 pla 000820r 2 85 rr sta zVERCKK ; restore verify (=1) or load (=0) flag 000822r 2 000822r 2 B0 2C bcs @Rts ; if an error occurred, we are done 000824r 2 000824r 2 A0 00 ldy #TAPE_BUFFER_OFFSET_TYPE ; start reading buffer at tape buffer type byte 000826r 2 B1 rr lda (zTAPE1),y ; get tape buffer type byte into A 000828r 2 000828r 2 C9 05 cmp #TAPE_BUFFER_TYPE_EOT ; is it of type "end-of-tape, EOT"? 00082Ar 2 F0 24 beq @Rts ; yes, we are done 00082Cr 2 00082Cr 2 C9 01 cmp #TAPE_BUFFER_TYPE_BASIC ; is it of type "BASIC program"? 00082Er 2 F0 08 beq @FoundFile ; yes -> branch, process it 000830r 2 000830r 2 C9 03 cmp #TAPE_BUFFER_TYPE_ABSOLUTE ; is it of type "ABSOLUTE loading program, i.e., machine language program"? 000832r 2 F0 04 beq @FoundFile ; yes -> branch, process it 000834r 2 000834r 2 C9 04 cmp #TAPE_BUFFER_TYPE_DATA ; is it of type "DATA file, that is, no program"? 000836r 2 D0 E1 bne @ReadNextHeader ; no -> branch, get next tape buffer from tape 000838r 2 000838r 2 @FoundFile: 000838r 2 AA tax ; remember tape buffer type in X 000839r 2 24 rr bit zNSGFLG ; kernal message output policy: do we want to output "Loading", "Saving", "Verifying", "Found", ... messages? 00083Br 2 10 11 bpl @ClcRts ; no --> skip output, return without an error 00083Dr 2 00083Dr 2 A0 63 ldy #StrFound - LMESSAGES ; offset of "FOUND " message 00083Fr 2 20 rr rr jsr OutputMessage ; output it 000842r 2 000842r 2 000842r 2 A0 05 ldy #TAPE_BUFFER_OFFSET_FILENAME ; offset of file name in buffer 000844r 2 000844r 2 @OutputFilename: 000844r 2 B1 rr lda (zTAPE1),y ; get character from the file name 000846r 2 20 rr rr jsr kCHROUT ; and output it (onto screen) 000849r 2 C8 iny ; proceed to next character 00084Ar 2 C0 15 cpy #TAPE_BUFFER_OFFSET_ENDFILENAME ; already at end of file name? 00084Cr 2 D0 F6 bne @OutputFilename ; no -> branch, output next character 00084Er 2 00084Er 2 .if CompileComputer >= C64_02 00084Er 2 00084Er 2 ; introduce a delay so the user has the option to actually see the output 00084Er 2 ; This is necessary on the C64, as it disables the VIC-II output on tape operations. 00084Er 2 ; On the VIC-20, this is not the case, thus, the user can see the output anyway 00084Er 2 00084Er 2 lda zTIME + 1 ; get the current time (middle byte) 00084Er 2 jsr TapeKeyOrTimeout ; delay the output until a timeout happens, or the user presses a key 00084Er 2 nop ; fill-byte 00084Er 2 00084Er 2 .elseif CompileComputer >= C64_GENERAL 00084Er 2 00084Er 2 ; on the C64-01, the delay was until some key was pressed. 00084Er 2 ; This is quite large and most probably the reason why the C64-02 KERNAL (cf. above) 00084Er 2 ; introduced a timeout 00084Er 2 00084Er 2 @WaitKeyPress: 00084Er 2 lda zSTKEY ; get the status of the keyboard column at the time the keyboard was checked the last time 00084Er 2 cmp #$FF ; no key pressed? 00084Er 2 beq @WaitKeyPress ; yes -> branch -> loop until a key is pressed 00084Er 2 .endif 00084Er 2 00084Er 2 @ClcRts: 00084Er 2 18 clc 00084Fr 2 88 dey ; put Y to point at the last byte of the filename 000850r 2 ; (thus, a subsequent INY will point it to the next data byte) 000850r 2 60 @Rts: rts 000851r 2 000851r 2 000851r 2 ; Create an empty tape buffer 000851r 2 ; Input: A = type of tape buffer (one of TAPE_BUFFER_TYPE_...) 000851r 2 ; 000851r 2 TapeCreateFileBuffer: 000851r 2 85 rr sta zPTR1 ; remember tape buffer type 000853r 2 000853r 2 20 rr rr jsr TapeGetPointer ; get pointer to tape buffer into (X/Y) (unused, but flags important) 000856r 2 90 5E bcc @Rts ; C = 0 -> tape buffer points to stack page or zero page -> quit, we do not want to overwrite essential data! 000858r 2 000858r 2 A5 rr lda zSTAL + 1 ; remember start address high 00085Ar 2 48 pha 00085Br 2 A5 rr lda zSTAL ; remember start address low 00085Dr 2 48 pha 00085Er 2 A5 rr lda zEAL + 1 ; remember end address high 000860r 2 48 pha 000861r 2 A5 rr lda zEAL ; remember end address low 000863r 2 48 pha 000864r 2 000864r 2 ; Delete complete tape buffer, overwriting it with $20 (SPACE) 000864r 2 A0 BF ldy #lTBUFFR_SIZE - 1 ; size of buffer to erase 000866r 2 A9 20 lda #$20 ; empty buffer pattern 000868r 2 : 000868r 2 91 rr sta (zTAPE1),y 00086Ar 2 88 dey 00086Br 2 D0 FB bne :- 00086Dr 2 00086Dr 2 A5 rr lda zPTR1 ; store tape buffer type 00086Fr 2 91 rr sta (zTAPE1),y ; into position $00 000871r 2 C8 iny 000872r 2 000872r 2 A5 rr lda zSTAL ; store start address low 000874r 2 91 rr sta (zTAPE1),y ; into position $01 000876r 2 C8 iny 000877r 2 000877r 2 A5 rr lda zSTAL + 1 ; store start address high 000879r 2 91 rr sta (zTAPE1),y ; into position $02 00087Br 2 C8 iny 00087Cr 2 00087Cr 2 A5 rr lda zEAL ; store end address low 00087Er 2 91 rr sta (zTAPE1),y ; into position $03 000880r 2 C8 iny 000881r 2 000881r 2 A5 rr lda zEAL + 1 ; store end address high 000883r 2 91 rr sta (zTAPE1),y ; into position $04 000885r 2 C8 iny 000886r 2 000886r 2 84 rr sty zPTR2 ; remember write pointer 000888r 2 000888r 2 ; store file name into buffer 000888r 2 000888r 2 A0 00 ldy #0 ; pointer into file name 00088Ar 2 84 rr sty zPTR1 00088Cr 2 00088Cr 2 @CopyFilename: 00088Cr 2 A4 rr ldy zPTR1 ; check if we reached end of file name 00088Er 2 C4 rr cpy zFNLEN 000890r 2 F0 0C beq @CopyFilenameQuit ; yes -> quit loop 000892r 2 000892r 2 B1 rr lda (zFNADR),y ; get next file name character 000894r 2 A4 rr ldy zPTR2 ; (write pointer into tape buffer) 000896r 2 91 rr sta (zTAPE1),y ; store file name character into tape buffer 000898r 2 000898r 2 E6 rr inc zPTR1 ; increment file name read pointer 00089Ar 2 E6 rr inc zPTR2 ; increment tape write pointer 00089Cr 2 D0 EE bne @CopyFilename ; (unconditional) 00089Er 2 ; ----------------------- 00089Er 2 00089Er 2 @CopyFilenameQuit: 00089Er 2 20 rr rr jsr TapeSetStartAndEndToBuffer ; set zSTAL/zSTAL + 1 to begin of tape buffer, and zEAL/zEAL+1 to end of it 0008A1r 2 0008A1r 2 A9 69 lda #TAPE_RIPRTY_69 0008A3r 2 85 rr sta zRIPRTY ; Write TAPE_RIPRTY_69 * $100 pulses for the preamble 0008A5r 2 0008A5r 2 20 rr rr jsr TapeWriteCompleteFileCustomPreamble ; write buffer onto tape, using the set preamble length 0008A8r 2 0008A8r 2 A8 tay ; remember A in Y (TODO why? What content does A have here?) 0008A9r 2 0008A9r 2 ; restore start adn end addresses 0008A9r 2 68 pla ; restore end address low 0008AAr 2 85 rr sta zEAL 0008ACr 2 68 pla ; restore end address high 0008ADr 2 85 rr sta zEAL + 1 0008AFr 2 68 pla ; restore start address low 0008B0r 2 85 rr sta zSTAL 0008B2r 2 68 pla ; restore start address high 0008B3r 2 85 rr sta zSTAL + 1 0008B5r 2 0008B5r 2 98 tya ; restore A from Y (TODO why? What content does A have here?) 0008B6r 2 @Rts: 0008B6r 2 60 rts 0008B7r 2 0008B7r 2 ; Get tape buffer pointer into X/Y 0008B7r 2 ; 0008B7r 2 ; Return: 0008B7r 2 ; C = 0 if tape buffer points into stack page or zero page 0008B7r 2 ; C = 1 if not 0008B7r 2 ; 0008B7r 2 TapeGetPointer: 0008B7r 2 A6 rr ldx zTAPE1 0008B9r 2 A4 rr ldy zTAPE1 + 1 0008BBr 2 C0 rr cpy #>lBUF 0008BDr 2 60 rts 0008BEr 2 0008BEr 2 ; set zSTAL/zSTAL + 1 to begin of tape buffer, and zEAL/zEAL+1 to end of it 0008BEr 2 0008BEr 2 TapeSetStartAndEndToBuffer: 0008BEr 2 20 rr rr jsr TapeGetPointer ; get tape buffer pointer into x/y 0008C1r 2 0008C1r 2 8A txa ; get address low 0008C2r 2 85 rr sta zSTAL ; and store it as start address low 0008C4r 2 0008C4r 2 18 clc 0008C5r 2 69 C0 adc #lTBUFFR_SIZE ; add size of tape buffer 0008C7r 2 85 rr sta zEAL ; and store it as end address 0008C9r 2 0008C9r 2 98 tya ; get address high 0008CAr 2 85 rr sta zSTAL + 1 ; and store it as end address high 0008CCr 2 69 00 adc #0 ; add carry from previous addition 0008CEr 2 85 rr sta zEAL + 1 ; store the result as end address high 0008D0r 2 60 rts 0008D1r 2 ; ----------------- 0008D1r 2 0008D1r 2 0008D1r 2 ; Find a specific file on tape 0008D1r 2 ; 0008D1r 2 ; Input: 0008D1r 2 ; zFNLEN: Length of the file name 0008D1r 2 ; zFNADR/zFNADR+1: Pointer to file name (if zFNLEN != 0) 0008D1r 2 ; 0008D1r 2 ; Output: 0008D1r 2 ; C = 1 --> an error occurred 0008D1r 2 ; C = 0 --> no error occurred 0008D1r 2 ; Z = 1 --> EOT was found 0008D1r 2 ; Z = 0 --> no EOT was found 0008D1r 2 ; X = tape buffer type if no error occurred 0008D1r 2 ; 0008D1r 2 ; BUG: 0008D1r 2 ; If the buffer could not be read at all, Z = 1 will be true if zVERCKK contains a 0. 0008D1r 2 ; Thus, Z will not represent the status of the EOT. 0008D1r 2 ; 0008D1r 2 TapeFindSpecificFile: 0008D1r 2 0008D1r 2 @NextFile: 0008D1r 2 20 rr rr jsr TapeReadTapeHeaderOfNextFile ; read in the next header on tape 0008D4r 2 B0 1D bcs @Rts ; C == 1 --> an error occurred --> branch --> quit (This will also happen if Z=1) 0008D6r 2 0008D6r 2 A0 05 ldy #TAPE_BUFFER_OFFSET_FILENAME ; offset of file name in tape buffer 0008D8r 2 84 rr sty zPTR2 0008DAr 2 0008DAr 2 A0 00 ldy #0 ; offset of requested file name 0008DCr 2 84 rr sty zPTR1 0008DEr 2 0008DEr 2 @TestNextChar: 0008DEr 2 C4 rr cpy zFNLEN ; check if we reached the end of the file name 0008E0r 2 F0 10 beq @ClcRts ; yes -> branch, return with c = 0 0008E2r 2 0008E2r 2 B1 rr lda (zFNADR),y ; read in character from requested file name 0008E4r 2 A4 rr ldy zPTR2 0008E6r 2 D1 rr cmp (zTAPE1),y ; compare with character from file name in tape buffer 0008E8r 2 D0 E7 bne @NextFile ; not equal -> file name differes -> branch -> check next file on tape 0008EAr 2 0008EAr 2 E6 rr inc zPTR1 ; increment pointers for file name characters 0008ECr 2 E6 rr inc zPTR2 0008EEr 2 0008EEr 2 A4 rr ldy zPTR1 ; make sure Y has the offset of the current character of the requested file name 0008F0r 2 D0 EC bne @TestNextChar ; uncond. branch 0008F2r 2 ; ---------------------- 0008F2r 2 0008F2r 2 @ClcRts: 0008F2r 2 18 clc ; mark: no error (i.e., we found the requested file) 0008F3r 2 @Rts: 0008F3r 2 60 rts 0008F4r 2 ; ------------------- 0008F4r 2 0008F4r 2 ; increment the pointer into the tape buffer 0008F4r 2 ; 0008F4r 2 ; Return: 0008F4r 2 ; Y = the tape pointer 0008F4r 2 ; 0008F4r 2 ; Z = 1 if the buffer is full / completely read 0008F4r 2 ; Z = 0 otherwise 0008F4r 2 ; 0008F4r 2 TAPE_INCREMENT_WRITE_POINTER: 0008F4r 2 20 rr rr jsr TapeGetPointer 0008F7r 2 E6 rr inc zBUFPNT ; increment the pointer into the tape buffer 0008F9r 2 A4 rr ldy zBUFPNT ; read i 0008FBr 2 C0 C0 cpy #lTBUFFR_SIZE 0008FDr 2 60 rts 0008FEr 2 0008FEr 2 ; Wait for the PLAY key to be pressed 0008FEr 2 ; If it is not, output "PRESS PLAY ON TAPE" and wait for it to be pressed 0008FEr 2 ; 0008FEr 2 TapePressPlayOnTape: 0008FEr 2 20 rr rr jsr TapeCheckPlayPressed ; check if play key is pressed 000901r 2 F0 1C beq TapeClcRts ; yes -> branch, we're done 000903r 2 000903r 2 A0 1B ldy #StrPlay - LMESSAGES ; get offset of "PRESS PLAY ON TAPE" string to output the text 000905r 2 000905r 2 TapePressPlayCommon: 000905r 2 000905r 2 .if CompileComputer = C64_4064 000905r 2 jsr OutputMessageIfAllowed ; output the text, only if allowed 000905r 2 .else 000905r 2 20 rr rr jsr OutputMessage ; output the text 000908r 2 .endif 000908r 2 000908r 2 ; Wait for PLAY key to be pressed 000908r 2 000908r 2 @WaitForPlay: 000908r 2 20 rr rr jsr TapeCheckForStop ; check if stop key was pressed. If so, do not return here, but to our caller! 00090Br 2 00090Br 2 20 rr rr jsr TapeCheckPlayPressed ; has PLAY been pressed on the tape? 00090Er 2 D0 F8 bne @WaitForPlay ; no -> branch --> test again 000910r 2 000910r 2 A0 6A ldy #StrOk - LMESSAGES ; get offset of "OK" text to output it 000912r 2 000912r 2 .if CompileComputer = C64_4064 000912r 2 jmp OutputMessageIfAllowed ; output the text, only if allowed 000912r 2 ; ------------------------------ 000912r 2 .else 000912r 2 4C rr rr jmp OutputMessage ; output the text 000915r 2 ; ------------------------------ 000915r 2 .endif 000915r 2 000915r 2 ; Find out if the PLAY key 000915r 2 ; is pressed on the tape 000915r 2 ; 000915r 2 ; This includes the combination of RECORD + PLAY 000915r 2 ; 000915r 2 ; Output: 000915r 2 ; Z = 0: not pressed 000915r 2 ; Z = 1: pressed 000915r 2 ; 000915r 2 TapeCheckPlayPressed: 000915r 2 A9 40 lda #TAPE_B_SENSE 000917r 2 2C 1F 91 bit TAPE_REG_SENSE 00091Ar 2 D0 03 bne TapeClcRts 00091Cr 2 2C 1F 91 bit TAPE_REG_SENSE 00091Fr 2 00091Fr 2 TapeClcRts: 00091Fr 2 18 clc 000920r 2 60 rts 000921r 2 000921r 2 ; Wait for the PLAY key to be pressed 000921r 2 ; If it is not, output "PRESS RECORD & PLAY ON TAPE" and wait for it to be pressed 000921r 2 000921r 2 TapePressRecordAndPlayOnTape: 000921r 2 20 rr rr jsr TapeCheckPlayPressed ; check if play key is pressed 000924r 2 F0 F9 beq TapeClcRts ; yes -> branch, we're done 000926r 2 000926r 2 A0 2E ldy #StrRecPlay - LMESSAGES ; get offset of "PRESS RECORD & PLAY ON TAPE" string to output the text 000928r 2 000928r 2 D0 DB bne TapePressPlayCommon ; (other than the text, this routine is identical to TapePressPlayOnTape. Thus, handle it over there) 00092Ar 2 ; --------------------------- 00092Ar 2 00092Ar 2 00092Ar 2 TapeReadNextBuffer: 00092Ar 2 A9 00 lda #0 00092Cr 2 85 rr sta zSTATUS ; clear status, no error yet 00092Er 2 00092Er 2 85 rr sta zVERCKK ; mark: we are loading (not verifying) from tape 000930r 2 000930r 2 20 rr rr jsr TapeSetStartAndEndToBuffer ; set zSTAL/zSTAL + 1 to begin of tape buffer, and zEAL/zEAL+1 to end of it 000933r 2 000933r 2 TapeReadFileContents: 000933r 2 20 rr rr jsr TapePressPlayOnTape ; output "PRESS PLAY ON TAPE" and wait for the PLAY key to be pressed 000936r 2 B0 1F bcs LF86E ; C = 1 --> an error occurred (STOP was pressed) --> branch --> quit (this address is used as a trampoline, as the real target is too far away) 000938r 2 000938r 2 78 sei 000939r 2 000939r 2 ; clear some essential variables 000939r 2 000939r 2 A9 00 lda #$00 00093Br 2 85 rr sta zRIDATA 00093Dr 2 85 rr sta zBITTS 00093Fr 2 85 rr sta zCMPO 000941r 2 85 rr sta zPTR1 ; or Pass1ReadErrors 000943r 2 85 rr sta zPTR2 ; or Pass2ReadErrors 000945r 2 85 rr sta zDPSW ; or ByteReceivedFlag 000947r 2 000947r 2 A9 82 lda #TAPE_REG_ICR_B_CASSREAD 000949r 2 A2 0E ldx #(VecTapeIrqRead - TapeIrqVectors) + 8 ; IRQ vector number to be set: Reading from tape 00094Br 2 D0 11 bne LF875 ; everything but the IRQ vector is identical to recording, thus, use the code there 00094Dr 2 ; ------------------------------ 00094Dr 2 00094Dr 2 ; write out the tape buffer to tape 00094Dr 2 ; TODO 00094Dr 2 00094Dr 2 TapeWriteCompleteBuffer: 00094Dr 2 20 rr rr jsr TapeSetStartAndEndToBuffer ; set zSTAL/zSTAL + 1 to begin of tape buffer, and zEAL/zEAL+1 to end of it 000950r 2 000950r 2 TapeWriteCompleteFile: 000950r 2 A9 14 lda #TAPE_RIPRTY_14 000952r 2 85 rr sta zRIPRTY ; Write TAPE_RIPRTY_14 * TODO pulses for the preamble 000954r 2 TapeWriteCompleteFileCustomPreamble: 000954r 2 20 rr rr jsr TapePressRecordAndPlayOnTape ; output "PRESS RECORD & PLAY ON TAPE" and wait for the PLAY key to be pressed 000957r 2 LF86E: 000957r 2 B0 68 bcs TapeSave_ClearIRQtmp_and_RTS ; C = 1 --> an error occurred (STOP was pressed) --> branch, quit 000959r 2 000959r 2 78 sei 00095Ar 2 00095Ar 2 A9 A0 lda #TAPE_REG_ICR_B_WR_TIMER ; start the write timer after setting the IRQ vector 00095Cr 2 A2 08 ldx #(VecTapeIrqWritePreamble - TapeIrqVectors) + 8 ; IRQ vector number to be set 00095Er 2 00095Er 2 LF875: 00095Er 2 A0 7F ldy #TAPE_REG_ICR_B_CLEARALL ; mask: clear all interrupt sources 000960r 2 8C 2E 91 sty TAPE_REG_ICR ; clear all interrupt sources 000963r 2 000963r 2 8D 2E 91 sta TAPE_REG_ICR ; and set the needed interrupt source (given in A) 000966r 2 000966r 2 .if CompileComputer >= C64_GENERAL 000966r 2 ; TODO: what? 000966r 2 lda CIA1 + CIA_O_CRA 000966r 2 ora #CIA_CRB_B_FORCE_LOAD | CIA_CRB_B_ONESHOT | CIA_CRB_B_START 000966r 2 sta CIA1 + CIA_O_CRB 000966r 2 and #CIA_CRA_B_50HZ | CIA_CRA_B_FORCE_LOAD | CIA_CRA_B_START 000966r 2 sta lTODSNS 000966r 2 .endif 000966r 2 000966r 2 20 rr rr jsr LF0A4 ; TODO 000969r 2 000969r 2 .if CompileComputer >= C64_GENERAL 000969r 2 ; switch off display 000969r 2 lda VIC + VICII_O_ControlReg1 000969r 2 and # ~ VICII_B_ControlReg1_DEN 000969r 2 sta VIC + VICII_O_ControlReg1 000969r 2 .endif 000969r 2 000969r 2 ; save IRQ vector in order to be able to restore it after the tape operation 000969r 2 AD rr rr lda lCINV ; IRQ vector low byte 00096Cr 2 8D rr rr sta lIRQTMP 00096Fr 2 AD rr rr lda lCINV + 1 ; IRQ vector high byte 000972r 2 8D rr rr sta lIRQTMP + 1 000975r 2 000975r 2 20 rr rr jsr TapeSetIrqVector 000978r 2 000978r 2 A9 02 lda #$02 00097Ar 2 85 rr sta zFSBLK ; set number of copies to write = 2. 00097Cr 2 00097Cr 2 20 rr rr jsr TapeInitInputOutputOfByte ; prepare output of a byte by initialising zTSFCNT, zTBTCNT, zBITC1, zPRTY and zRINONE 00097Fr 2 00097Fr 2 00097Fr 2 ; switch on the tape motor 00097Fr 2 AD 1C 91 lda TAPE_REG_MOTOR 000982r 2 29 FD and #TAPE_B_MOTOR_OFF_AND 000984r 2 .if CompileComputer < C64_GENERAL 000984r 2 09 0C ora #TAPE_B_MOTOR_OFF_OR 000986r 2 .endif 000986r 2 8D 1C 91 sta TAPE_REG_MOTOR 000989r 2 000989r 2 85 rr sta zCAS1 ; mark: tape operation in progress. 00098Br 2 00098Br 2 ; delay of TODO ms to allow tape motor for stable operation 00098Br 2 A2 FF ldx #$FF 00098Dr 2 @LF8B5: 00098Dr 2 A0 FF ldy #$FF 00098Fr 2 @LF8B7: 00098Fr 2 88 dey 000990r 2 D0 FD bne @LF8B7 000992r 2 CA dex 000993r 2 D0 F8 bne @LF8B5 000995r 2 000995r 2 .if CompileComputer < C64_GENERAL 000995r 2 8D 29 91 sta TAPE_TIMER1_HI ; TODO why? 000998r 2 .endif 000998r 2 58 cli ; allow interrupts: From now on, writing to the tape is controlled by the IRQ routine only! 000999r 2 000999r 2 ; Wait for the recording to have quit. For this, we compare the IRQ vector. When it is restored to be original vector 000999r 2 ; stored in lIRQTMP/lIRQTMP+1, then the recording has finished. 000999r 2 ; 000999r 2 ; Also check for STOP, as the user might want to stop the recording prematurely. 000999r 2 ; 000999r 2 @WaitForFinish: 000999r 2 AD rr rr lda lIRQTMP + 1 ; compare stored IRQ vector high 00099Cr 2 CD rr rr cmp lCINV + 1 ; with current IRQ vector high 00099Fr 2 18 clc ; (in case we finish the loop: mark "no error") 0009A0r 2 F0 1F beq TapeSave_ClearIRQtmp_and_RTS ; if they are the same, the recording has finished -> quit this loop 0009A2r 2 0009A2r 2 20 rr rr jsr TapeCheckForStop ; check if stop key was pressed. If so, do not return here, but to our caller! 0009A5r 2 0009A5r 2 ; (physically) check if RUN/STOP has been pressed 0009A5r 2 0009A5r 2 .if CompileComputer >= C64_GENERAL 0009A5r 2 ; on the C64, we just check for RUN/STOP. Note that the time is not updated while storing to TAPE 0009A5r 2 jsr iUDTIM_CheckRunStop 0009A5r 2 .else 0009A5r 2 AD 2D 91 lda VIA2_IFR ; check interrupt flag register: Would T1 (the ticker) generate an event? 0009A8r 2 29 40 and #VIA_IFR_B_T1 0009AAr 2 F0 ED beq @WaitForFinish ; no -> loop 0009ACr 2 AD 14 91 lda VIA1_T1CL ; clear the IFR state by reading T1 0009AFr 2 20 rr rr jsr iUDTIM ; update time. This function also checks for RUN/STOP 0009B2r 2 .endif 0009B2r 2 4C rr rr jmp @WaitForFinish ; loop, wait for finishing 0009B5r 2 ; ------------------ 0009B5r 2 0009B5r 2 ; Check for stop key 0009B5r 2 ; 0009B5r 2 ; This function checks if the STOP key has been pressed. 0009B5r 2 ; If so, it does not return to its caller, but to the caller of its caller! 0009B5r 2 ; 0009B5r 2 TapeCheckForStop: 0009B5r 2 20 rr rr jsr kSTOP ; check for stop key (returns: Z = 1 <--> STOP key was pressed) 0009B8r 2 18 clc 0009B9r 2 D0 0B bne TapeSaveRts ; no stop key -> branch, we're done. 0009BBr 2 0009BBr 2 20 rr rr jsr TapeStopMotor_and_InitTimer ; stop cass. motor, restore timer, restore IRQ vector 0009BEr 2 38 sec ; mark: an error occurred 0009BFr 2 0009BFr 2 ; remove return address of our caller from the stack 0009BFr 2 68 pla 0009C0r 2 68 pla 0009C1r 2 0009C1r 2 TapeSave_ClearIRQtmp_and_RTS: 0009C1r 2 ; mark: we do not have an IRQ vector to restore 0009C1r 2 A9 00 lda #$00 0009C3r 2 8D rr rr sta lIRQTMP + 1 ; high byte of IRQ vector to restore (if any) 0009C6r 2 0009C6r 2 TapeSaveRts: 0009C6r 2 60 rts 0009C7r 2 ; ------------------------ 0009C7r 2 0009C7r 2 0009C7r 2 0009C7r 2 0009C7r 2 0009C7r 2 TapeBitTimingAdjust: 0009C7r 2 ; TODO what does this function do? 0009C7r 2 ; Set expected tape timing. (according to some ROM description list) 0009C7r 2 0009C7r 2 86 rr stx zCMPO + 1 0009C9r 2 0009C9r 2 ; Calculate: A := zCMPO * 5 0009C9r 2 A5 rr lda zCMPO 0009CBr 2 0A asl a ; multiply by 2 0009CCr 2 0A asl a ; multiply by 2 0009CDr 2 18 clc 0009CEr 2 65 rr adc zCMPO ; add old value of zCMPO 0009D0r 2 0009D0r 2 ; calculate: [zCMPO+1] := [zCMPO+1] + zCMPO * 5 0009D0r 2 18 clc 0009D1r 2 65 rr adc zCMPO + 1 0009D3r 2 85 rr sta zCMPO + 1 0009D5r 2 0009D5r 2 A9 00 lda #$00 0009D7r 2 24 rr bit zCMPO 0009D9r 2 30 01 bmi @LF8F7 0009DBr 2 2A rol a 0009DCr 2 @LF8F7: 0009DCr 2 06 rr asl zCMPO + 1 0009DEr 2 2A rol a 0009DFr 2 06 rr asl zCMPO + 1 0009E1r 2 2A rol a 0009E2r 2 AA tax 0009E3r 2 0009E3r 2 @LF8FE: 0009E3r 2 AD 28 91 lda TAPE_TIMER1_LO 0009E6r 2 C9 15 cmp #TAPE_TIMER1_CONST 0009E8r 2 90 F9 bcc @LF8FE 0009EAr 2 65 rr adc zCMPO + 1 0009ECr 2 8D 24 91 sta TAPE_TIMER2_LO 0009EFr 2 8A txa 0009F0r 2 6D 29 91 adc TAPE_TIMER1_HI 0009F3r 2 8D 25 91 sta TAPE_TIMER2_HI 0009F6r 2 0009F6r 2 .if CompileComputer >= C64_GENERAL 0009F6r 2 lda lTODSNS 0009F6r 2 sta CIA1 + CIA_O_CRA 0009F6r 2 sta lTD1IRQ 0009F6r 2 lda CIA1 + CIA_O_ICR 0009F6r 2 and #CIA_ICR_B_FLAG 0009F6r 2 beq @RetCli 0009F6r 2 lda #>(@Ret-1) 0009F6r 2 pha 0009F6r 2 lda #<(@Ret-1) 0009F6r 2 pha 0009F6r 2 jmp FakeIRQ 0009F6r 2 .endif 0009F6r 2 0009F6r 2 @RetCli: 0009F6r 2 58 cli 0009F7r 2 @Ret: 0009F7r 2 60 rts 0009F8r 2 0009F8r 2 ;****************************************************************************** 0009F8r 2 ; 0009F8r 2 ;; [[According to "The almost completely commented Vic 20 ROM disassembly. 0009F8r 2 ;; V1.01 Lee Davison 2005-2012, amended by Ruud Baltissen; I relabeled the 0009F8r 2 ;; cases from A B C D to X S M L:]] 0009F8r 2 ;; 0009F8r 2 ;; On Commodore computers, the streams consist of four kinds of symbols 0009F8r 2 ;; that denote different kinds of low-to-high-to-low transitions on the 0009F8r 2 ;; read or write signals of the Commodore cassette interface. 0009F8r 2 ;; 0009F8r 2 ;; X A break in the communications, or a pulse with very long cycle 0009F8r 2 ;; time. 0009F8r 2 ;; 0009F8r 2 ;; S A short pulse, whose cycle time typically ranges from 296 to 424 0009F8r 2 ;; microseconds, depending on the computer model. 0009F8r 2 ;; 0009F8r 2 ;; M A medium-length pulse, whose cycle time typically ranges from 0009F8r 2 ;; 440 to 576 microseconds, depending on the computer model. 0009F8r 2 ;; 0009F8r 2 ;; L A long pulse, whose cycle time typically ranges from 600 to 744 0009F8r 2 ;; microseconds, depending on the computer model. 0009F8r 2 0009F8r 2 ;; [[According to the text in `Programming the PET/CBM' by Raeto West:]] 0009F8r 2 ;; A byte is stored as a byte marker (a long wave followed by a medium wave: L-M) 0009F8r 2 ;; followed by 9 bits: 8 data plus odd parity. 0009F8r 2 ;; A 0-bit is short followed by long (S-L) 0009F8r 2 ;; A 1-bit is long followed by short (L-S) 0009F8r 2 ;; [[but the diagram on page -236- agrees with the below:]] 0009F8r 2 0009F8r 2 ;; [[According to Keith Falkner in Compute! Issue #008, Jan 1981:]] 0009F8r 2 ;; A 0-bit is short followed by medium (S-M) 0009F8r 2 ;; A 1-bit is medium followed by short (M-S) 0009F8r 2 0009F8r 2 ;; [[According to the VICE source code, tape/tap.c:]] 0009F8r 2 ;; The tape preamble (leader) consists of at least 32 short pulses. 0009F8r 2 0009F8r 2 ;; The tape preamble (leader) ends with the data bytes 89, 88, 87, .. 81, 0009F8r 2 ;; or for the second copy 09, 08, 07, .. 01. 0009F8r 2 ;; 0009F8r 2 ;; A tape block is ended with L-S (instead of L-M for the next byte). 0009F8r 2 0009F8r 2 ; read tape bits, IRQ routine 0009F8r 2 0009F8r 2 ; read T2C which has been counting down from $FFFF. subtract this from $FFFF 0009F8r 2 0009F8r 2 TapeIrqRead: 0009F8r 2 ; IRQ4 0009F8r 2 ; read out the timer value making sure that we do not read 0009F8r 2 ; while a underflow occurs from the low byte to the high byte 0009F8r 2 0009F8r 2 AE 29 91 ldx TAPE_TIMER1_HI ; read in timer high byte 0009FBr 2 0009FBr 2 ; calculate $FF - timer low byte 0009FBr 2 A0 FF ldy #$FF 0009FDr 2 98 tya 0009FEr 2 ED 28 91 sbc TAPE_TIMER1_LO 000A01r 2 000A01r 2 EC 29 91 cpx TAPE_TIMER1_HI ; is the high byte still the same as above? 000A04r 2 000A04r 2 D0 F2 bne TapeIrqRead ; no -> we just had an underflow -> retry 000A06r 2 000A06r 2 86 rr stx zCMPO + 1 ; remember high byte of timer value 000A08r 2 000A08r 2 AA tax ; X := $FF - low byte of timer value as calculated above 000A09r 2 000A09r 2 ; restart timer with $FFFF (longest possible timer start address) 000A09r 2 000A09r 2 8C 28 91 sty TAPE_TIMER1_LO 000A0Cr 2 8C 29 91 sty TAPE_TIMER1_HI 000A0Fr 2 000A0Fr 2 .if CompileComputer >= C64_GENERAL 000A0Fr 2 000A0Fr 2 ; restart the timer in oneshot mode 000A0Fr 2 000A0Fr 2 lda #CIA_CRB_B_FORCE_LOAD | CIA_CRB_B_ONESHOT | CIA_CRB_B_START 000A0Fr 2 sta CIA1 + CIA_O_CRB 000A0Fr 2 000A0Fr 2 ; read the ICR (the read clears it) and store it in lTRDTMP 000A0Fr 2 000A0Fr 2 lda TAPE_REG_ICR 000A0Fr 2 sta lTRDTMP 000A0Fr 2 000A0Fr 2 .endif 000A0Fr 2 000A0Fr 2 98 tya ; now, calculate $FF - high byte of timer value 000A10r 2 E5 rr sbc zCMPO + 1 000A12r 2 86 rr stx zCMPO + 1 ; here, zCMPO+1 / A contains ($FFFF - timer value) 000A14r 2 000A14r 2 ; divide the timer value by 4 000A14r 2 000A14r 2 4A lsr a ; shift right, dividing by 2 (hi) 000A15r 2 66 rr ror zCMPO + 1 ; (lo) 000A17r 2 4A lsr a ; shift right, deviding by 2 another time (hi) 000A18r 2 66 rr ror zCMPO + 1 ; ==> time of pulse / 4 (lo) 000A1Ar 2 000A1Ar 2 A5 rr lda zCMPO ; get tape timing constant min byte 000A1Cr 2 18 clc 000A1Dr 2 69 3C adc #$3C 000A1Fr 2 000A1Fr 2 .if CompileComputer < C64_GENERAL 000A1Fr 2 2C 21 91 bit VIA2_PA 000A22r 2 .endif 000A22r 2 000A22r 2 C5 rr cmp zCMPO + 1 ; compare with time of pulse / 4 000A24r 2 ; compare with ($FFFF - TAPE_TIMER1) >> 2 000A24r 2 B0 4A bcs @LF9AC ; branch if min + $3C >= ($FFFF - T2C) >> 2 000A26r 2 ; or in other words, if the pulse is too short. 000A26r 2 A6 rr ldx ByteReceivedFlag ; or zDPSW 000A28r 2 F0 03 beq @LF969 ; no byte received yet 000A2Ar 2 4C rr rr jmp LFA60 ; byte received 000A2Dr 2 ; ------------------- 000A2Dr 2 000A2Dr 2 @LF969: 000A2Dr 2 A6 rr ldx zTSFCNT ; bit counter (8->0) 000A2Fr 2 30 1B bmi @LF988 ; -> @LFA10 000A31r 2 000A31r 2 ; ? Determine if the pulse is short, medium or long. 000A31r 2 000A31r 2 A2 00 ldx #$00 ; data bit may be 0 000A33r 2 69 30 adc #$30 000A35r 2 65 rr adc zCMPO ; add tape timing constant min byte 000A37r 2 C5 rr cmp zCMPO + 1 ; compare with time of pulse / 4 000A39r 2 B0 1C bcs @LF993 ; Is the pulse smaller? -> It is a SHORT pulse 000A3Br 2 E8 inx ; data bit may be 1 000A3Cr 2 69 26 adc #$26 000A3Er 2 65 rr adc zCMPO ; add tape timing constant min byte 000A40r 2 C5 rr cmp zCMPO + 1 ; compare with time of pulse / 4 000A42r 2 B0 17 bcs @LF997 ; Is the pulse still smaller? -> it is a MEDIUM pulse 000A44r 2 69 2C adc #$2C 000A46r 2 65 rr adc zCMPO ; add tape timing constant min byte 000A48r 2 C5 rr cmp zCMPO + 1 ; compare with time of pulse / 4 000A4Ar 2 90 03 bcc @LF98B ; pulse is too long 000A4Cr 2 @LF988: 000A4Cr 2 4C rr rr jmp @LFA10 ; Is the pulse smaller than the max long pulse? 000A4Fr 2 ; -> it is a LONG pulse 000A4Fr 2 ; ----------------- 000A4Fr 2 000A4Fr 2 @LF98B: ; pulse is too long 000A4Fr 2 A5 rr lda zBITTS ; ? get EOI flag byte 000A51r 2 F0 1D beq @LF9AC ; -> IrqEnd1 000A53r 2 85 rr sta ErrorFlagOnTapeRead ; or zBITC1 store non-zero 000A55r 2 D0 19 bne @LF9AC ; always 000A57r 2 000A57r 2 ; After a short pulse we need a medium one, 000A57r 2 ; or the other way around. That keeps the counter on 0. 000A57r 2 @LF993: ; pulse was SHORT 000A57r 2 E6 rr inc ReadBitSequenceErrors ; or zRINONE 000A59r 2 B0 02 bcs @LF999 ; always 000A5Br 2 @LF997: ; pulse was MEDIUM 000A5Br 2 C6 rr dec ReadBitSequenceErrors ; or zRINONE 000A5Dr 2 @LF999: 000A5Dr 2 38 sec ; ?? adjust some timing parameter 000A5Er 2 E9 13 sbc #$13 000A60r 2 E5 rr sbc zCMPO + 1 ; subtract time of pulse / 4 000A62r 2 65 rr adc zSVXT 000A64r 2 85 rr sta zSVXT 000A66r 2 000A66r 2 A5 rr lda zTBTCNT ; cycle counter (which half of the bit cycle is current) 000A68r 2 49 01 eor #$01 000A6Ar 2 85 rr sta zTBTCNT ; cycle counter 000A6Cr 2 F0 21 beq @LF9D5 ; wrong half of the bit cycle? i.e. 2nd pulse 000A6Er 2 000A6Er 2 86 rr stx zSCHAR ; distilled a bit (from ldx #$00 / inx above) 000A70r 2 ; takes the timing from the 1st pulse 000A70r 2 000A70r 2 @LF9AC: ; don't store a bit 000A70r 2 A5 rr lda zBITTS ; ? get EOI flag byte 000A72r 2 F0 18 beq @IrqEnd1 000A74r 2 .if CompileComputer >= C64_GENERAL 000A74r 2 lda lTRDTMP ; saved TAPE_REG_ICR 000A74r 2 and #$01 000A74r 2 bne @LF9BC ; timer had no interrupt 000A74r 2 lda lTD1IRQ 000A74r 2 bne @IrqEnd1 000A74r 2 .else 000A74r 2 2C 2D 91 bit VIA2_IFR 000A77r 2 50 13 bvc @IrqEnd1 ; timer 1 no interrupt 000A79r 2 .endif 000A79r 2 000A79r 2 @LF9BC: ; force restart for next bit 000A79r 2 A9 00 lda #$00 000A7Br 2 85 rr sta zTBTCNT ; cycle counter; there are 2 pulses per bit 000A7Dr 2 .if CompileComputer >= C64_GENERAL 000A7Dr 2 sta lTD1IRQ 000A7Dr 2 .endif 000A7Dr 2 A5 rr lda zTSFCNT ; bit counter (8->0) 000A7Fr 2 10 30 bpl @LF9F7 000A81r 2 30 C9 bmi @LF988 000A83r 2 000A83r 2 @LF9C9: 000A83r 2 A2 A6 ldx #$A6 000A85r 2 20 rr rr jsr TapeBitTimingAdjust 000A88r 2 A5 rr lda zPRTY ; parity 000A8Ar 2 D0 C3 bne @LF98B 000A8Cr 2 @IrqEnd1: 000A8Cr 2 4C rr rr jmp NMI_End 000A8Fr 2 ; ---------------------- 000A8Fr 2 000A8Fr 2 @LF9D5: 000A8Fr 2 A5 rr lda zSVXT 000A91r 2 F0 07 beq @LF9E0 000A93r 2 30 03 bmi @LF9DE 000A95r 2 C6 rr dec zCMPO 000A97r 2 2C .byte ASM_BIT3 000A98r 2 @LF9DE: 000A98r 2 E6 rr inc zCMPO 000A9Ar 2 @LF9E0: 000A9Ar 2 A9 00 lda #$00 000A9Cr 2 85 rr sta zSVXT 000A9Er 2 E4 rr cpx zSCHAR 000AA0r 2 D0 0F bne @LF9F7 000AA2r 2 8A txa 000AA3r 2 D0 AA bne @LF98B 000AA5r 2 A5 rr lda ReadBitSequenceErrors ; or zRINONE 000AA7r 2 30 C7 bmi @LF9AC 000AA9r 2 C9 10 cmp #$10 000AABr 2 90 C3 bcc @LF9AC 000AADr 2 85 rr sta zSYNO 000AAFr 2 B0 BF bcs @LF9AC 000AB1r 2 @LF9F7: 000AB1r 2 8A txa 000AB2r 2 45 rr eor zPRTY 000AB4r 2 85 rr sta zPRTY 000AB6r 2 A5 rr lda zBITTS 000AB8r 2 F0 D2 beq @IrqEnd1 000ABAr 2 C6 rr dec zTSFCNT ; bit counter (8->0) 000ABCr 2 30 C5 bmi @LF9C9 000ABEr 2 000ABEr 2 46 rr lsr zSCHAR ; shift a bit into the collected byte 000AC0r 2 66 rr ror SerialWordBuffer ; or zMYCH 000AC2r 2 A2 DA ldx #$DA 000AC4r 2 20 rr rr jsr TapeBitTimingAdjust 000AC7r 2 4C rr rr jmp NMI_End 000ACAr 2 ; ---------------------- 000ACAr 2 000ACAr 2 @LFA10: ; found a LONG pulse -or- no more bits 000ACAr 2 A5 rr lda zSYNO 000ACCr 2 F0 04 beq @LFA18 000ACEr 2 A5 rr lda zBITTS 000AD0r 2 F0 04 beq @LFA1F 000AD2r 2 000AD2r 2 @LFA18: 000AD2r 2 A5 rr lda zTSFCNT ; bit counter (8->0) 000AD4r 2 .if CompileComputer >= C64_GENERAL 000AD4r 2 bmi @LFA1F 000AD4r 2 jmp @LF997 000AD4r 2 .else 000AD4r 2 10 85 bpl @LF997 000AD6r 2 .endif 000AD6r 2 000AD6r 2 @LFA1F: 000AD6r 2 46 rr lsr zCMPO + 1 000AD8r 2 A9 93 lda #$93 000ADAr 2 38 sec 000ADBr 2 E5 rr sbc zCMPO + 1 000ADDr 2 65 rr adc zCMPO 000ADFr 2 0A asl a 000AE0r 2 AA tax 000AE1r 2 000AE1r 2 20 rr rr jsr TapeBitTimingAdjust 000AE4r 2 E6 rr inc ByteReceivedFlag ; or zDPSW 000AE6r 2 A5 rr lda zBITTS 000AE8r 2 D0 11 bne @LFA44 000AEAr 2 A5 rr lda zSYNO 000AECr 2 F0 26 beq @IrqEnd2 000AEEr 2 85 rr sta ErrorFlagOnTapeRead ; or zBITC1 000AF0r 2 A9 00 lda #$00 000AF2r 2 85 rr sta zSYNO 000AF4r 2 000AF4r 2 A9 C0 lda #TAPE_REG_ICR_B_SET_3 000AF6r 2 8D 2E 91 sta TAPE_REG_ICR 000AF9r 2 000AF9r 2 85 rr sta zBITTS 000AFBr 2 000AFBr 2 @LFA44: 000AFBr 2 A5 rr lda zSYNO 000AFDr 2 85 rr sta zNXTBIT ; ?? indicate whether we got a bit 000AFFr 2 F0 09 beq @LFA53 000B01r 2 A9 00 lda #$00 000B03r 2 85 rr sta zBITTS 000B05r 2 000B05r 2 A9 40 lda #TAPE_REG_ICR_B_UNSET_3 000B07r 2 8D 2E 91 sta TAPE_REG_ICR 000B0Ar 2 000B0Ar 2 @LFA53: 000B0Ar 2 A5 rr lda SerialWordBuffer ; or zMYCH 000B0Cr 2 85 rr sta ReadCharacterIn ; or zROPRTY 000B0Er 2 A5 rr lda ErrorFlagOnTapeRead ; or zBITC1 000B10r 2 05 rr ora ReadBitSequenceErrors ; or zRINONE 000B12r 2 85 rr sta ReadCharacterError ; or zRODATA 000B14r 2 @IrqEnd2: 000B14r 2 4C rr rr jmp NMI_End 000B17r 2 ; -------------------- 000B17r 2 000B17r 2 000B17r 2 ; store tape chars ; FA57 in PET 3032 000B17r 2 000B17r 2 LFA60: ; byte received 000B17r 2 20 rr rr jsr TapeInitInputOutputOfByte ; prepare input of a byte by initialising zTSFCNT, zTBTCNT, zBITC1, zPRTY and zRINONE; returns with A = 0 000B1Ar 2 85 rr sta ByteReceivedFlag ; zDPSW := 0 000B1Cr 2 000B1Cr 2 A2 DA ldx #$DA 000B1Er 2 20 rr rr jsr TapeBitTimingAdjust 000B21r 2 A5 rr lda zFSBLK ; number of blocks remaining to read 000B23r 2 F0 02 beq @LFA70 ; if pass 1 was error free, don't really 000B25r 2 85 rr sta NrBlocksRemaining ; bother with the second pass ; or zINBIT 000B27r 2 @LFA70: 000B27r 2 A9 0F lda #$0F 000B29r 2 24 rr bit zRIDATA ; 00=scan, $01-$0F=count, $40=load, $80=End of Tape marker 000B2Br 2 10 17 bpl @LFA8D 000B2Dr 2 ; ---- $80 = EOT 000B2Dr 2 A5 rr lda zNXTBIT ; ?? did we get a bit? 000B2Fr 2 D0 0C bne @LFA86 000B31r 2 000B31r 2 A6 rr ldx zFSBLK ; nr of copies remaining to read 000B33r 2 CA dex 000B34r 2 D0 0B bne @IrqEnd3 000B36r 2 A9 08 lda #STATUS_TAPE_LONG_BLOCK 000B38r 2 20 rr rr jsr SetStatus 000B3Br 2 D0 04 bne @IrqEnd3 000B3Dr 2 000B3Dr 2 @LFA86: 000B3Dr 2 A9 00 lda #$00 000B3Fr 2 85 rr sta zRIDATA ; switch to scan 000B41r 2 @IrqEnd3: 000B41r 2 4C rr rr jmp NMI_End 000B44r 2 ; ------------------ 000B44r 2 000B44r 2 @LFA8D: 000B44r 2 70 31 bvs @LFAC0 000B46r 2 D0 18 bne @LFAA9 000B48r 2 000B48r 2 A5 rr lda zNXTBIT ; ---- 00 = scan 000B4Ar 2 D0 F5 bne @IrqEnd3 ; ?? if we got a bit -> done 000B4Cr 2 000B4Cr 2 A5 rr lda ReadCharacterError ; or zRODATA 000B4Er 2 D0 F1 bne @IrqEnd3 ; error? -> done 000B50r 2 A5 rr lda NrBlocksRemaining ; or zINBIT 000B52r 2 4A lsr a 000B53r 2 A5 rr lda ReadCharacterIn ; or zROPRTY 000B55r 2 30 03 bmi @LFAA3 000B57r 2 90 18 bcc @LFABA ; ?? 0 or 2 blocks remaining ; switch to EOT 000B59r 2 18 clc 000B5Ar 2 @LFAA3: 000B5Ar 2 B0 15 bcs @LFABA ; switch to EOT 000B5Cr 2 29 0F and #$0F 000B5Er 2 85 rr sta zRIDATA ; switch to count 000B60r 2 000B60r 2 @LFAA9: ; ---- 01-0F = count 000B60r 2 C6 rr dec zRIDATA ; count down 1 000B62r 2 D0 DD bne @IrqEnd3 000B64r 2 A9 40 lda #$40 ; when we have reached 00, 000B66r 2 85 rr sta zRIDATA ; switch to load 000B68r 2 20 rr rr jsr Copy_zSTAL_to_zSAL 000B6Br 2 A9 00 lda #$00 000B6Dr 2 85 rr sta zRIPRTY 000B6Fr 2 F0 D0 beq @IrqEnd3 000B71r 2 ; ------------------------- 000B71r 2 000B71r 2 @LFABA: 000B71r 2 A9 80 lda #$80 ; switch to EOT 000B73r 2 85 rr sta zRIDATA 000B75r 2 D0 CA bne @IrqEnd3 000B77r 2 @LFAC0: ; ---- $40 = load 000B77r 2 A5 rr lda zNXTBIT 000B79r 2 F0 0A beq @LFACE ; ?? if we got a bit, go on 000B7Br 2 000B7Br 2 A9 04 lda #STATUS_TAPE_SHORT_BLOCK 000B7Dr 2 20 rr rr jsr SetStatus 000B80r 2 A9 00 lda #$00 000B82r 2 4C rr rr jmp @LFB4A ; switch to 00 scan 000B85r 2 000B85r 2 @LFACE: 000B85r 2 20 rr rr jsr HasEndAddressBeenReached 000B88r 2 90 03 bcc @LFAD6 ; no 000B8Ar 2 4C rr rr jmp @LFB48 ; yes 000B8Dr 2 ; ------------------------ 000B8Dr 2 000B8Dr 2 @LFAD6: ; end address has not been reached 000B8Dr 2 A6 rr ldx NrBlocksRemaining ; # blocks remaining, 1 or 2 ; or zINBIT 000B8Fr 2 CA dex 000B90r 2 000B90r 2 F0 2D beq @LFB08 ; go to second pass 000B92r 2 000B92r 2 A5 rr lda zVERCKK ; LOAD or VERIFY 000B94r 2 F0 0C beq @LFAEB 000B96r 2 000B96r 2 A0 00 ldy #$00 ; VERIFY 000B98r 2 A5 rr lda ReadCharacterIn ; or zROPRTY 000B9Ar 2 D1 rr cmp (zSAL),y ; check if byte matches 000B9Cr 2 F0 04 beq @LFAEB 000B9Er 2 000B9Er 2 A9 01 lda #$01 ; remember there was an error 000BA0r 2 85 rr sta ReadCharacterError ; or zRODATA 000BA2r 2 @LFAEB: ; LOAD 000BA2r 2 A5 rr lda ReadCharacterError ; or zRODATA 000BA4r 2 F0 4B beq @LFB3A ; just store this byte 000BA6r 2 000BA6r 2 A2 3D ldx #$3D ; max # of read errors we can store 000BA8r 2 E4 rr cpx Pass1ReadErrors ; or zPTR1 000BAAr 2 90 3E bcc @LFB33 ; too many -> LOAD or VERIFY error 000BACr 2 A6 rr ldx Pass1ReadErrors ; or zPTR1 000BAEr 2 A5 rr lda zSAL + 1 ; store high byte of error address 000BB0r 2 9D rr rr sta lSTACK + 1,x 000BB3r 2 A5 rr lda zSAL ; and low byte 000BB5r 2 9D rr rr sta lSTACK,x 000BB8r 2 E8 inx 000BB9r 2 E8 inx 000BBAr 2 86 rr stx Pass1ReadErrors ; or zPTR1 000BBCr 2 4C rr rr jmp @LFB3A ; store this byte anyway 000BBFr 2 ; ----------------- 000BBFr 2 000BBFr 2 000BBFr 2 @LFB08: ; this is done during the second read pass 000BBFr 2 A6 rr ldx Pass2ReadErrors ; pass 2 read errors or zPTR2 000BC1r 2 E4 rr cpx Pass1ReadErrors ; pass 1 read errors or zPTR1 000BC3r 2 F0 35 beq @GotAllReadErrors ; processed all 000BC5r 2 000BC5r 2 A5 rr lda zSAL ; current address LO 000BC7r 2 DD rr rr cmp lSTACK,x ; equal to address of next read error? 000BCAr 2 D0 2E bne @GotAllReadErrors 000BCCr 2 A5 rr lda zSAL + 1 ; also check current address HI 000BCEr 2 DD rr rr cmp lSTACK + 1,x 000BD1r 2 D0 27 bne @GotAllReadErrors 000BD3r 2 E6 rr inc Pass2ReadErrors ; move over to next address of a read error 000BD5r 2 E6 rr inc Pass2ReadErrors ; or zPTR2 000BD7r 2 A5 rr lda zVERCKK ; check if LOAD or VERIFY 000BD9r 2 F0 0B beq @LFB2F 000BDBr 2 000BDBr 2 A5 rr lda ReadCharacterIn ; do a VERIFY ; or zROPRTY 000BDDr 2 A0 00 ldy #0 000BDFr 2 D1 rr cmp (zSAL),y ; 2nd pass matches memory -> ok 000BE1r 2 F0 17 beq @GotAllReadErrors 000BE3r 2 C8 iny 000BE4r 2 84 rr sty ReadCharacterError ; read character error flag ; or zRODATA 000BE6r 2 @LFB2F: 000BE6r 2 A5 rr lda ReadCharacterError ; or zRODATA 000BE8r 2 F0 07 beq @LFB3A 000BEAr 2 @LFB33: ; unrecoverable read error, or, VERIFY error 000BEAr 2 A9 10 lda #STATUS_VERIFY 000BECr 2 20 rr rr jsr SetStatus 000BEFr 2 D0 09 bne @GotAllReadErrors 000BF1r 2 000BF1r 2 @LFB3A: ; just (maybe) store the byte that was read 000BF1r 2 A5 rr lda zVERCKK ; 1 = VERIFY 000BF3r 2 D0 05 bne @GotAllReadErrors 000BF5r 2 A8 tay 000BF6r 2 A5 rr lda ReadCharacterIn ; or zROPRTY 000BF8r 2 91 rr sta (zSAL),y ; store the byte as read from tape into memory 000BFAr 2 @GotAllReadErrors: 000BFAr 2 20 rr rr jsr Increment_zSAL_Address 000BFDr 2 D0 3A bne @IrqEnd4 000BFFr 2 @LFB48: 000BFFr 2 A9 80 lda #$80 ; switch to EOT 000C01r 2 @LFB4A: 000C01r 2 85 rr sta zRIDATA ; switch reading mode 000C03r 2 000C03r 2 .if CompileComputer >= C64_GENERAL 000C03r 2 sei 000C03r 2 ldx #TAPE_REG_ICR_B_UNSET_3 000C03r 2 stx TAPE_REG_ICR 000C03r 2 000C03r 2 ldx TAPE_REG_ICR 000C03r 2 .endif 000C03r 2 000C03r 2 A6 rr ldx zFSBLK ; nr of blocks to read (or write) 000C05r 2 CA dex 000C06r 2 30 02 bmi @LFB5C 000C08r 2 86 rr stx zFSBLK ; only decrement if not negative 000C0Ar 2 @LFB5C: 000C0Ar 2 C6 rr dec NrBlocksRemaining ; or zINBIT 000C0Cr 2 F0 08 beq @LFB68 ; finish up by calculating the parity 000C0Er 2 000C0Er 2 A5 rr lda Pass1ReadErrors ; or zPTR1 000C10r 2 D0 27 bne @IrqEnd4 ; more errors? keep going 000C12r 2 85 rr sta zFSBLK ; no errors? 0 blocks to read (or write) 000C14r 2 F0 23 beq @IrqEnd4 ; unconditional branch 000C16r 2 ; -------------- 000C16r 2 000C16r 2 ; Finish up the loading by checking the parity byte 000C16r 2 000C16r 2 @LFB68: 000C16r 2 20 rr rr jsr TapeStopMotor_and_InitTimer ; stop cass. motor, restore timer, restore IRQ vector 000C19r 2 000C19r 2 ; Calculate and check parity (just a XOR) 000C19r 2 20 rr rr jsr Copy_zSTAL_to_zSAL 000C1Cr 2 A0 00 ldy #$00 000C1Er 2 84 rr sty zRIPRTY ; clear to 00 000C20r 2 000C20r 2 @LFB72: 000C20r 2 B1 rr lda (zSAL),y 000C22r 2 45 rr eor zRIPRTY ; xor another byte into it 000C24r 2 85 rr sta zRIPRTY 000C26r 2 20 rr rr jsr Increment_zSAL_Address 000C29r 2 20 rr rr jsr HasEndAddressBeenReached 000C2Cr 2 90 F2 bcc @LFB72 ; and another byte 000C2Er 2 A5 rr lda zRIPRTY 000C30r 2 45 rr eor ReadCharacterIn ; mix in final parity byte ; or zROPRTY 000C32r 2 F0 05 beq @IrqEnd4 000C34r 2 000C34r 2 A9 20 lda #STATUS_TAPE_CHKSUM_ERR ; not equal -> error 000C36r 2 20 rr rr jsr SetStatus 000C39r 2 @IrqEnd4: 000C39r 2 4C rr rr jmp NMI_End 000C3Cr 2 ; -------------------- 000C3Cr 2 000C3Cr 2 Copy_zSTAL_to_zSAL: 000C3Cr 2 A5 rr lda zSTAL + 1 000C3Er 2 85 rr sta zSAL + 1 000C40r 2 A5 rr lda zSTAL 000C42r 2 85 rr sta zSAL 000C44r 2 60 rts 000C45r 2 ; ------------------------- 000C45r 2 000C45r 2 ; prepare input or output of a byte by initialising zTSFCNT, zTBTCNT, zBITC1, zPRTY and zRINONE 000C45r 2 ; 000C45r 2 ; Return: 000C45r 2 ; A = 0 000C45r 2 000C45r 2 TapeInitInputOutputOfByte: 000C45r 2 A9 08 lda #$08 ; set number of bits to be output to 8 000C47r 2 85 rr sta zTSFCNT 000C49r 2 000C49r 2 A9 00 lda #$00 000C4Br 2 85 rr sta zTBTCNT ; mark: the bit to output is the real bit, not the inverted one 000C4Dr 2 000C4Dr 2 85 rr sta zBITC1 ; clear bit-counter that determines if the start or the end of a pulse have been reached 000C4Fr 2 000C4Fr 2 85 rr sta zPRTY ; clear parity 000C51r 2 000C51r 2 85 rr sta zRINONE ; set: the start bit ("1") has not yet been written 000C53r 2 000C53r 2 60 rts 000C54r 2 ; -------------------- 000C54r 2 000C54r 2 TapeSetTimerAndWriteEdgeForBit: 000C54r 2 A5 rr lda zROPRTY ; get data byte to be output 000C56r 2 4A lsr a ; get lowest bit into C 000C57r 2 A9 60 lda #TAPE_TIMER_CONSTANT_BIT0 ; preset $60 as timer value in case the lowest bit is 0 000C59r 2 90 02 bcc TapeSetTimerLowAndWriteEdge ; C = 0 --> branch, use $60 constant 000C5Br 2 000C5Br 2 TapeSetTimerAndWriteEdgeFor1: 000C5Br 2 A9 B0 lda #TAPE_TIMER_CONSTANT_BIT1 ; set $B0 as timer value because the lowest bit is 1 000C5Dr 2 000C5Dr 2 TapeSetTimerLowAndWriteEdge: 000C5Dr 2 A2 00 ldx #$00 ; high byte of timer value 000C5Fr 2 000C5Fr 2 TapeSetTimerAndWriteEdge: 000C5Fr 2 8D 28 91 sta TAPE_TIMER1_LO ; set timer low 000C62r 2 8E 29 91 stx TAPE_TIMER1_HI ; and high 000C65r 2 000C65r 2 .if CompileComputer >= C64_GENERAL 000C65r 2 lda TAPE_REG_ICR ; clear ICR by reading it 000C65r 2 000C65r 2 lda #CIA_CRB_B_FORCE_LOAD | CIA_CRB_B_ONESHOT | CIA_CRB_B_START 000C65r 2 sta CIA1 + CIA_O_CRB ; program timer B as oneshot, starting it 000C65r 2 .endif 000C65r 2 000C65r 2 ; change the level of the CASS WRITE line 000C65r 2 000C65r 2 AD 20 91 lda TAPE_REG_WRITE 000C68r 2 49 08 eor #TAPE_B_WRITE 000C6Ar 2 8D 20 91 sta TAPE_REG_WRITE 000C6Dr 2 000C6Dr 2 29 08 and #TAPE_B_WRITE ; determine the new level 000C6Fr 2 60 rts 000C70r 2 ; ----------------------- 000C70r 2 000C70r 2 LFBC8: 000C70r 2 ; TODO 000C70r 2 38 sec 000C71r 2 .if CompileComputer >= C64_GENERAL 000C71r 2 ror zRODATA 000C71r 2 .else 000C71r 2 66 rr ror zSAL + 1 000C73r 2 .endif 000C73r 2 30 3C bmi TapeIrqEnd1 ; (uncond. branch) 000C75r 2 ; ------------------------ 000C75r 2 000C75r 2 TapeIrqWrite: 000C75r 2 ; IRQ2 000C75r 2 A5 rr lda zBITC1 000C77r 2 D0 12 bne @LFBE3 000C79r 2 000C79r 2 A9 10 lda #TAPE_TIMER_CONSTANT_WRITE 000C7Dr 2 20 rr rr jsr TapeSetTimerAndWriteEdge 000C80r 2 D0 2F bne TapeIrqEnd1 ; if the write bit is 1, the pulse has just started -> branch -> quit IRQ, we only proceed when the pulse has ended 000C82r 2 000C82r 2 E6 rr inc zBITC1 ; mark: we have already written the bit above 000C84r 2 000C84r 2 ; TODO ??? 000C84r 2 000C84r 2 .if CompileComputer >= C64_GENERAL 000C84r 2 lda zRODATA 000C84r 2 .else 000C84r 2 A5 rr lda zSAL + 1 000C86r 2 .endif 000C86r 2 10 29 bpl TapeIrqEnd1 000C88r 2 000C88r 2 4C rr rr jmp TapeBlockCompletelyWritten ; the complete block has been written 000C8Br 2 ; --------------------------- 000C8Br 2 000C8Br 2 @LFBE3: 000C8Br 2 ; write a "1" bit 000C8Br 2 000C8Br 2 A5 rr lda zRINONE ; have we already written the bit? 000C8Dr 2 D0 09 bne @LFBF0 ; yes -> branch, write data bit 000C8Fr 2 000C8Fr 2 20 rr rr jsr TapeSetTimerAndWriteEdgeFor1 ; set a pulse for a "1" bit 000C92r 2 D0 1D bne TapeIrqEnd1 ; if the write bit is 1, the pulse has just started -> branch -> quit IRQ, we only proceed when the pulse has ended 000C94r 2 000C94r 2 E6 rr inc zRINONE ; mark: The "1" bit has already been written 000C96r 2 D0 19 bne TapeIrqEnd1 ; (uncond. branch: If we are here, zRINONE was zero, thus, it cannot be there here after the inc) 000C98r 2 ; --------------------------- 000C98r 2 000C98r 2 @LFBF0: 000C98r 2 20 rr rr jsr TapeSetTimerAndWriteEdgeForBit ; set the timer for a "1" or "0" bit, depending upon if the bit to be output (zROPRTY.0) is 1 or 0. 000C9Br 2 D0 14 bne TapeIrqEnd1 ; if the write bit is 1, the pulse has just started -> branch -> quit IRQ, we only proceed when the pulse has ended 000C9Dr 2 000C9Dr 2 ; after outputting the "0" or "1" bit, the routine 000C9Dr 2 ; also outputs the inverse of it ("1" or "0", respectively) 000C9Dr 2 000C9Dr 2 ; Here, at this place, zTBTCNT is used to find out if the first, 000C9Dr 2 ; original bit has been sent (= $00), or if the inverted one has 000C9Dr 2 ; been sent (= $01) 000C9Dr 2 000C9Dr 2 A5 rr lda zTBTCNT 000C9Fr 2 49 01 eor #$01 000CA1r 2 85 rr sta zTBTCNT ; invert zTBTCNT.0 000CA3r 2 000CA3r 2 F0 0F beq TapeBitWritten ; if zTBTCNT == $00 here, then the second, inverted bit has been sent -> branch, the bit is completely written 000CA5r 2 000CA5r 2 ; invert data bit that was just output (zROPRTY.0) 000CA5r 2 ; Thus, the inverted bit is output the next time 000CA5r 2 000CA5r 2 A5 rr lda zROPRTY 000CA7r 2 49 01 eor #$01 000CA9r 2 85 rr sta zROPRTY 000CABr 2 000CABr 2 ; calculate the parity (with the inverted bit) 000CABr 2 29 01 and #$01 ; extract the (inverted) data bit 000CADr 2 45 rr eor zPRTY ; and eor it with parity (TODO?) 000CAFr 2 85 rr sta zPRTY 000CB1r 2 000CB1r 2 TapeIrqEnd1: 000CB1r 2 4C rr rr jmp NMI_End 000CB4r 2 ; ------------------- 000CB4r 2 000CB4r 2 TapeBitWritten: 000CB4r 2 ; the bit has been written (in non-inverted and inverted form) 000CB4r 2 000CB4r 2 46 rr lsr zROPRTY ; extract next bit to be output 000CB6r 2 000CB6r 2 C6 rr dec zTSFCNT ; decrement number of bits to be output 000CB8r 2 000CB8r 2 A5 rr lda zTSFCNT ; still bits to be output? 000CBAr 2 F0 3A beq TapeOutputParityBit ; no -> branch, output the parity bit 000CBCr 2 000CBCr 2 10 F3 bpl TapeIrqEnd1 ; no. of bits to be output > 0 --> still bits to be output, end IRQ here 000CBEr 2 000CBEr 2 LFC16: 000CBEr 2 ; when we reach here, all bits of the current byte have been output 000CBEr 2 ; thus, advance to the next byte 000CBEr 2 000CBEr 2 20 rr rr jsr TapeInitInputOutputOfByte ; prepare output of a byte by initialising zTSFCNT, zTBTCNT, zBITC1, zPRTY and zRINONE 000CC1r 2 000CC1r 2 58 cli ; TODO: timing is not that critical anymore (we have a start bit, thus, a delay is not fatal) 000CC2r 2 000CC2r 2 ; TODO ??? Have we reached end of current byte? 000CC2r 2 000CC2r 2 ; TODO follow logic of this code part 000CC2r 2 000CC2r 2 A5 rr lda zCNTDN ; countdown at end of preamble 000CC4r 2 F0 12 beq @LFC30 ; zero -> branch, proceed to next byte and check if end address has been reached 000CC6r 2 000CC6r 2 ; We're at the end of the preamble, write 89, 88, or 09, 08, ... etc 000CC6r 2 000CC6r 2 A2 00 ldx #0 000CC8r 2 86 rr stx zSCHAR ; clear check byte 000CCAr 2 000CCAr 2 C6 rr dec zCNTDN 000CCCr 2 000CCCr 2 A6 rr ldx zFSBLK ; is this the first copy of the tape file? 000CCEr 2 E0 02 cpx #$02 000CD0r 2 D0 02 bne @LFC2C ; no -> branch, output TODO ??? 000CD2r 2 000CD2r 2 09 80 ora #$80 ; or in 1st copy, 89, 88, 87... 000CD4r 2 000CD4r 2 @LFC2C: 000CD4r 2 85 rr sta zROPRTY ; byte to write 000CD6r 2 D0 D9 bne TapeIrqEnd1 ; (uncond. branch) 000CD8r 2 ; ------------------ 000CD8r 2 000CD8r 2 @LFC30: 000CD8r 2 20 rr rr jsr HasEndAddressBeenReached ; check if the last byte has been written (the end address has been reached) 000CDBr 2 90 0A bcc @ProcessNextByte ; no -> branch, process the next byte 000CDDr 2 000CDDr 2 D0 91 bne LFBC8 ; has the extra check byte been written -> branch -> TODO 000CDFr 2 000CDFr 2 E6 rr inc zSAL + 1 ; increment start address: this way, the "bne" above will branch the next time! 000CE1r 2 000CE1r 2 A5 rr lda zSCHAR ; get the check byte 000CE3r 2 85 rr sta zROPRTY ; and put it as output byte 000CE5r 2 000CE5r 2 B0 CA bcs TapeIrqEnd1 ; (uncond. branch) 000CE7r 2 ; ------------------------- 000CE7r 2 000CE7r 2 @ProcessNextByte: 000CE7r 2 A0 00 ldy #0 000CE9r 2 B1 rr lda (zSAL),y ; read next byte to process 000CEBr 2 85 rr sta zROPRTY ; and store it as new byte to output 000CEDr 2 000CEDr 2 45 rr eor zSCHAR ; XOR it with the check byte 000CEFr 2 85 rr sta zSCHAR ; and store it 000CF1r 2 000CF1r 2 20 rr rr jsr Increment_zSAL_Address ; increment pointer to next byte to write 000CF4r 2 000CF4r 2 D0 BB bne TapeIrqEnd1 ; if we do not want to write $FFFF, this is an uncond. branch 000CF6r 2 ; BUG: If we write the KERNAL onto tape, we will fall through! (TODO: Really) 000CF6r 2 ; --------------------------- 000CF6r 2 000CF6r 2 TapeOutputParityBit: 000CF6r 2 A5 rr lda zPRTY 000CF8r 2 49 01 eor #$01 000CFAr 2 85 rr sta zROPRTY 000CFCr 2 000CFCr 2 TapeIrqEnd2: 000CFCr 2 4C rr rr jmp NMI_End 000CFFr 2 ; ------------------------- 000CFFr 2 000CFFr 2 TapeBlockCompletelyWritten: 000CFFr 2 ; the block has been completely written to the tape 000CFFr 2 000CFFr 2 ; found out if we still have a copy to be written 000CFFr 2 000CFFr 2 C6 rr dec zFSBLK ; decrement number of copies still to write 000D01r 2 D0 03 bne :+ ; have we reached 0? --> skip next instruction --> do not switch off the tape motor 000D03r 2 000D03r 2 20 rr rr jsr TapeSwitchOffMotor ; switch off the tape motor 000D06r 2 000D06r 2 A9 50 : lda #$50 000D08r 2 85 rr sta zINBIT ; TODO: Write "shorter" preamble 000D0Ar 2 000D0Ar 2 ; set IRQ vector to: write preamble 000D0Ar 2 000D0Ar 2 A2 08 ldx #(VecTapeIrqWritePreamble - TapeIrqVectors) + 8 000D0Cr 2 78 sei 000D0Dr 2 20 rr rr jsr TapeSetIrqVector 000D10r 2 000D10r 2 D0 EA bne TapeIrqEnd2 ; (uncond. branch) 000D12r 2 ; ------------------------------------- 000D12r 2 000D12r 2 000D12r 2 ; This IRQ routine is called when the system wants to write a preamble to the tape 000D12r 2 000D12r 2 TapeIrqWritePreamble: 000D12r 2 A9 78 lda #TAPE_TIMER_CONSTANT_PREAMBLE 000D14r 2 20 rr rr jsr TapeSetTimerLowAndWriteEdge 000D17r 2 000D17r 2 D0 E3 bne TapeIrqEnd2 ; if the write bit is 1, the pulse has just started -> branch -> quit IRQ, we only proceed when the pulse has ended 000D19r 2 000D19r 2 ; if we reach here, the tape write bit is 0. 000D19r 2 ; We have just written a pulse of length TAPE_TIMER_CONSTANT_PREAMBLE 000D19r 2 000D19r 2 C6 rr dec zINBIT ; decrement number of bits to write 000D1Br 2 D0 DF bne TapeIrqEnd2 ; not yet 0 --> branch --> quit IRQ, we're done for now (write more bits) 000D1Dr 2 000D1Dr 2 20 rr rr jsr TapeInitInputOutputOfByte ; prepare output of a byte by initialising zTSFCNT, zTBTCNT, zBITC1, zPRTY and zRINONE 000D20r 2 000D20r 2 C6 rr dec zRIPRTY ; decrement number of "bytes" (of zINBIT bits each, that is, $100 bits each!) to write 000D22r 2 10 D8 bpl TapeIrqEnd2 ; not yet negative -> branch, we're done for now (write more bytes) 000D24r 2 000D24r 2 A2 0A ldx #(VecTapeIrqWrite - TapeIrqVectors) + 8 ; change the IRQ routine to the write routine itself 000D26r 2 20 rr rr jsr TapeSetIrqVector 000D29r 2 000D29r 2 58 cli 000D2Ar 2 000D2Ar 2 E6 rr inc zRIPRTY ; set number of bytes back to 0 000D2Cr 2 000D2Cr 2 A5 rr lda zFSBLK ; check number of copies still to write 000D2Er 2 F0 30 beq TapeAllCopiesWritten ; 0 copies to write --> branch, quit writing to tape 000D30r 2 000D30r 2 20 rr rr jsr Copy_zSTAL_to_zSAL ; TODO copy the tape start address to the start address 000D33r 2 000D33r 2 A2 09 ldx #$09 ; Leader (preamble) finishes with 89, 88, .. 81 000D35r 2 ; for 2nd copy: 09, 08, ... 01 000D35r 2 86 rr stx zCNTDN 000D37r 2 000D37r 2 .if CompileComputer >= C64_GENERAL 000D37r 2 stx zRODATA 000D37r 2 .endif 000D37r 2 D0 85 bne LFC16 ; always ; switch to writing bytes 000D39r 2 ; ----------------------- 000D39r 2 000D39r 2 .endif ; .if CompileComputer = C64_GS 000D39r 2 000D39r 2 ; stop cass. motor, restore timer, restore IRQ vector 000D39r 2 ; 000D39r 2 ; Remark: 000D39r 2 ; Flags stay unchanged! 000D39r 2 ; 000D39r 2 TapeStopMotor_and_InitTimer: 000D39r 2 08 php ; remember I status 000D3Ar 2 78 sei ; make sure we do not get interrupted by an IRQ 000D3Br 2 000D3Br 2 .if CompileComputer >= C64_GENERAL 000D3Br 2 ; enable display 000D3Br 2 lda VIC + VICII_O_ControlReg1 000D3Br 2 ora #VICII_B_ControlReg1_DEN 000D3Br 2 sta VIC + VICII_O_ControlReg1 000D3Br 2 .endif 000D3Br 2 000D3Br 2 20 rr rr jsr TapeSwitchOffMotor ; switch tape motor off 000D3Er 2 000D3Er 2 A9 7F lda #TAPE_REG_ICR_B_CLEARALL ; clear all interrupt sources 000D40r 2 8D 2E 91 sta TAPE_REG_ICR 000D43r 2 000D43r 2 .if CompileComputer < C64_GENERAL 000D43r 2 ; TODO document 000D43r 2 A9 F7 lda #$F7 000D45r 2 8D 20 91 sta VIA2_PB 000D48r 2 A9 40 lda #VIA_ACR_B_T1_CONTROL_FREERUN 000D4Ar 2 8D 2B 91 sta VIA2_ACR 000D4Dr 2 .endif 000D4Dr 2 000D4Dr 2 20 rr rr jsr iIOINIT_TIMER ; initialise timers (part of iIOINIT) 000D50r 2 000D50r 2 ; restore interrupt vector 000D50r 2 ; 000D50r 2 AD rr rr lda lIRQTMP + 1 ; get high address of stored IRQ vector 000D53r 2 F0 09 beq :+ ; = 0 --> no IRQ vector was stored -> branch, skip restoring 000D55r 2 8D rr rr sta lCINV + 1 ; restore IRQ vector high 000D58r 2 000D58r 2 AD rr rr lda lIRQTMP ; stored IRQ vector low 000D5Br 2 8D rr rr sta lCINV ; restore IRQ vector low 000D5Er 2 : 000D5Er 2 28 plp ; restore I status 000D5Fr 2 60 rts 000D60r 2 ; ----------------------- 000D60r 2 000D60r 2 TapeAllCopiesWritten: 000D60r 2 20 rr rr jsr TapeStopMotor_and_InitTimer ; stop cass. motor, restore timer, restore IRQ vector --> complete END the tape IRQ routines. 000D63r 2 F0 97 beq TapeIrqEnd2 ; (uncond. branch, as TapeStopMotor_and_InitTimer restores the flags, and we are only called via a BEQ) 000D65r 2 ; ------------------------- 000D65r 2 000D65r 2 ; set IRQ vector according to X 000D65r 2 ; X must be calculated rather "weird": It is done as ldx #(VecNAME - TapeIrqVectors) + 8 if VecNAME is to be set. 000D65r 2 TapeSetIrqVector: 000D65r 2 BD rr rr lda TapeIrqVectors - 8,x ; get low byte of vector 000D68r 2 8D rr rr sta lCINV ; and store it as IRQ vector low 000D6Br 2 BD rr rr lda TapeIrqVectors - 8 + 1,x ; get high byte of vector 000D6Er 2 8D rr rr sta lCINV + 1 ; and store it as IRQ vector high 000D71r 2 60 rts 000D72r 2 ; ------------------- 000D72r 2 000D72r 2 ; Switch off the tape motor 000D72r 2 ; 000D72r 2 TapeSwitchOffMotor: 000D72r 2 AD 1C 91 lda TAPE_REG_MOTOR 000D75r 2 09 0E ora #TAPE_B_MOTOR_ON_ALL 000D77r 2 8D 1C 91 sta TAPE_REG_MOTOR 000D7Ar 2 60 rts 000D7Br 2 000D7Br 2 ; Check if the end address has been reached 000D7Br 2 ; in writing 000D7Br 2 ; 000D7Br 2 ; Return: 000D7Br 2 ; C = 0: End address has not yet been reached 000D7Br 2 ; C = 1: End address has been reached 000D7Br 2 ; 000D7Br 2 ; This routine calculated zSAL/zSAL+1 - zEAL/zEAL+1. 000D7Br 2 ; If zSAL/zSAL+1 is smaller than zEAL/zEAL+1, we end with C=0, as there was a "borrow". 000D7Br 2 ; Otherwise (equal or bigger), C=1 as no borrow occurred. 000D7Br 2 ; 000D7Br 2 ; This routine is also used in fileio.a65 for IEC transfers 000D7Br 2 ; 000D7Br 2 HasEndAddressBeenReached: 000D7Br 2 38 sec 000D7Cr 2 A5 rr lda zSAL 000D7Er 2 E5 rr sbc zEAL 000D80r 2 A5 rr lda zSAL + 1 000D82r 2 E5 rr sbc zEAL + 1 000D84r 2 60 rts 000D85r 2 000D85r 2 ; Increment the zSAL/zSAL+1 address 000D85r 2 ; That is, this routine proceeds the pointer to the next character to be written/read. 000D85r 2 ; 000D85r 2 ; This routine is also used in fileio.a65 for IEC transfers 000D85r 2 ; 000D85r 2 Increment_zSAL_Address: 000D85r 2 E6 rr inc zSAL 000D87r 2 D0 02 bne @Rts 000D89r 2 E6 rr inc zSAL + 1 000D8Br 2 @Rts: 000D8Br 2 60 rts 000D8Cr 2 ; ------------------------ 000D8Cr 2 000D8Cr 2 000D8Cr 1 .include "../kernal/init.a65" 000D8Cr 2 ; This is the RESET routine that is called when a hardware RESET occurs. 000D8Cr 2 ; After determining if an expansion cartridge is available - in this case, 000D8Cr 2 ; this routine aborts and calls the RESET routine of the cartridge - 000D8Cr 2 ; it has to set up the I/O areas and all memory. Afterwards, it calls 000D8Cr 2 ; the BASIC through the BASIC cold start vector 000D8Cr 2 ; 000D8Cr 2 RESET: 000D8Cr 2 A2 FF ldx #<$01FF 000D8Er 2 78 sei ; no interrupts are allowed (we have not set it up yet) 000D8Fr 2 9A txs ; SP = $FF, so we have maximum stack space 000D90r 2 D8 cld ; make sure we are in binary mode, not in decimal mode 000D91r 2 20 rr rr jsr CheckCartridge ; check for an expansion cartridge 000D94r 2 D0 03 bne @NoCartridge ; no cartridge -> jump 000D96r 2 6C 00 A0 jmp (CART_RESET) ; we have a cartridge, exit and call the RESET routine of the cart 000D99r 2 000D99r 2 ; in case we have no cartridge, proceed with initialisation 000D99r 2 000D99r 2 @NoCartridge: 000D99r 2 .if CompileComputer >= C64_GENERAL 000D99r 2 stx VIC + VICII_O_ControlReg2 ; switch to 38 cols mode 000D99r 2 ; this seems to be cosmetic only. If the C64 already has a visible 000D99r 2 ; screen, one can clearly see that the RESET makes the left and 000D99r 2 ; right border smaller on a RESET and/or JSR $FCE2 (SYS 64738) 000D99r 2 jsr iIOINIT ; initialise the I/O area 000D99r 2 .endif 000D99r 2 000D99r 2 20 rr rr jsr iRAMTAS ; clear memory and determine RAM areas 000D9Cr 2 20 rr rr jsr iRESTOR ; restore the KERNEL jump vectors 000D9Fr 2 .if CompileComputer < C64_GENERAL 000D9Fr 2 20 rr rr jsr iIOINIT ; initialise the I/O area 000DA2r 2 .endif 000DA2r 2 000DA2r 2 ; Initialise the video 000DA2r 2 .if CompileComputer >= C64_02 000DA2r 2 jsr iCINT_WITH_PAL_NTSC ; initialise the video. Also make sure to determine PAL or NTSC, and adjust the timings accordingly 000DA2r 2 .else 000DA2r 2 20 rr rr jsr iCINT ; initialise the video. 000DA5r 2 .endif 000DA5r 2 58 cli 000DA6r 2 6C rr rr jmp (bRESTART) ; call BASIC 000DA9r 2 000DA9r 2 ; Check if a cartridge is available. 000DA9r 2 ; For this, it checks for the "cartridge magic" 000DA9r 2 ; If there is a cartridge, this routine returns with Z=1 000DA9r 2 ; else with Z=0 000DA9r 2 ; 000DA9r 2 CheckCartridge: 000DA9r 2 A2 05 ldx #END_Copy_CARTRIDGE_MAGIC - Copy_CARTRIDGE_MAGIC 000DABr 2 @CheckNext: 000DABr 2 BD rr rr lda Copy_CARTRIDGE_MAGIC - 1,x 000DAEr 2 DD 03 A0 cmp CART_MAGIC - 1,x 000DB1r 2 D0 03 bne @NoCart 000DB3r 2 CA dex 000DB4r 2 D0 F5 bne @CheckNext 000DB6r 2 @NoCart: 000DB6r 2 60 rts 000DB7r 2 000DB7r 2 ; Copy of the cartridge magic 000DB7r 2 ; CheckCartridge checks agains these characters 000DB7r 2 ; to find out if a cartridge is available. 000DB7r 2 ; 000DB7r 2 Copy_CARTRIDGE_MAGIC: 000DB7r 2 .if CompileComputer >= C64_GENERAL 000DB7r 2 asc80 "CBM" 000DB7r 2 .byte "80" 000DB7r 2 .else 000DB7r 2 41 30 .byte "A0" 000DB9r 2 C3 C2 CD asc80 "CBM" 000DBCr 2 .endif 000DBCr 2 END_Copy_CARTRIDGE_MAGIC: 000DBCr 2 000DBCr 2 ; 000DBCr 2 ; B-23. Function Name: RESTOR 000DBCr 2 ; 000DBCr 2 ; Purpose: Restore default system and interrupt vectors 000DBCr 2 ; Call address: $FF8A (hex) 65418 (decimal) 000DBCr 2 ; Preparatory routines: None 000DBCr 2 ; Error returns: None 000DBCr 2 ; Stack requirements: 2 000DBCr 2 ; Registers affected: A, X, Y 000DBCr 2 ; 000DBCr 2 ; Description: This routine restores the default values of all system 000DBCr 2 ; vectors used in KERNAL and BASIC routines and interrupts. (See the Memory 000DBCr 2 ; Map for the default vector contents). The KERNAL VECTOR routine is used 000DBCr 2 ; to read and alter individual system vectors. 000DBCr 2 ; 000DBCr 2 ; How to Use: 000DBCr 2 ; 1) Call this routine. 000DBCr 2 ; 000DBCr 2 ; EXAMPLE: 000DBCr 2 ; JSR RESTOR 000DBCr 2 ; 000DBCr 2 iRESTOR: 000DBCr 2 A2 rr ldx #Copy_of_lCINV 000DC0r 2 18 clc 000DC1r 2 000DC1r 2 ; B-39. Function Name: VECTOR 000DC1r 2 ; 000DC1r 2 ; Purpose: Manage RAM vectors 000DC1r 2 ; Call address: $FF8D (hex) 65421 (decimal) 000DC1r 2 ; Communication registers: X, Y 000DC1r 2 ; Preparatory routines: None 000DC1r 2 ; Error returns: None 000DC1r 2 ; Stack requirements: 2 000DC1r 2 ; Registers affected: A, X, Y 000DC1r 2 ; 000DC1r 2 ; 000DC1r 2 ; Description: This routine manages all system vector jump addresses 000DC1r 2 ; stored in RAM. Calling this routine with the the accumulator carry bit 000DC1r 2 ; set stores the current contents of the RAM vectors in a list pointed to 000DC1r 2 ; by the X and Y registers. When this routine is called with the carry 000DC1r 2 ; clear, the user list pointed to by the X and Y registers is transferred 000DC1r 2 ; to the system RAM vectors. The RAM vectors are listed in the memory map. 000DC1r 2 ; 000DC1r 2 ; +-----------------------------------------------------------------------+ 000DC1r 2 ; | NOTE: This routine requires caution in its use. The best way to use it| 000DC1r 2 ; | is to first read the entire vector contents into the user area, alter | 000DC1r 2 ; | the desired vectors, and then copy the contents back to the system | 000DC1r 2 ; | vectors. | 000DC1r 2 ; +-----------------------------------------------------------------------+ 000DC1r 2 ; 000DC1r 2 ; How to Use: 000DC1r 2 ; 000DC1r 2 ; READ THE SYSTEM RAM VECTORS 000DC1r 2 ; 000DC1r 2 ; 1) Set the carry. 000DC1r 2 ; 2) Set the X and y registers to the address to put the vectors. 000DC1r 2 ; 3) Call this routine. 000DC1r 2 ; 000DC1r 2 ; LOAD THE SYSTEM RAM VECTORS 000DC1r 2 ; 000DC1r 2 ; 1) Clear the carry bit. 000DC1r 2 ; 2) Set the X and Y registers to the address of the vector list in RAM 000DC1r 2 ; that must be loaded. 000DC1r 2 ; 3) Call this routine. 000DC1r 2 ; 000DC1r 2 ; 000DC1r 2 ; EXAMPLE: 000DC1r 2 ; ;CHANGE THE INPUT ROUTINES TO NEW SYSTEM 000DC1r 2 ; LDX #USER 000DC1r 2 ; SEC 000DC1r 2 ; JSR VECTOR ;READ OLD VECTORS 000DC1r 2 ; LDA #MYINP 000DC1r 2 ; STA USER+11 000DC1r 2 ; LDX #USER 000DC1r 2 ; CLC 000DC1r 2 ; JSR VECTOR ;ALTER SYSTEM 000DC1r 2 ; ... 000DC1r 2 ; USER *=*+26 000DC1r 2 000DC1r 2 iVECTOR: 000DC1r 2 ; remember the address where to load/store the vector list 000DC1r 2 86 rr stx zMEMUSS 000DC3r 2 84 rr sty zMEMUSS + 1 000DC5r 2 000DC5r 2 A0 1F ldy #END_Copy_of_lCINV - Copy_of_lCINV - 1 ; get number of bytes to copy 000DC7r 2 B9 rr rr @Loop: lda lCINV,y 000DCAr 2 B0 02 bcs @DoSet ; if C=0, write the buffer to the address at x/y 000DCCr 2 B1 rr lda (zMEMUSS),y ; if C=1, get the data from x/y and write it to the system buffers 000DCEr 2 91 rr @DoSet: sta (zMEMUSS),y 000DD0r 2 99 rr rr sta lCINV,y 000DD3r 2 88 dey 000DD4r 2 10 F1 bpl @Loop 000DD6r 2 60 rts 000DD7r 2 000DD7r 2 ; the system vectors as set by default 000DD7r 2 000DD7r 2 Copy_of_lCINV: 000DD7r 2 rr rr .addr KIRQ ; lCINV 000DD9r 2 rr rr .addr RUNSTOP_RESTORE ; lCNBINV 000DDBr 2 rr rr .addr KNMI ; lNMINV 000DDDr 2 rr rr .addr KOPEN ; lIOPEN 000DDFr 2 rr rr .addr KCLOSE ; lICLOSE 000DE1r 2 rr rr .addr KCHKIN ; lICHKIN 000DE3r 2 rr rr .addr KCHKOUT ; lICHKOUT 000DE5r 2 rr rr .addr KCLRCH ; lICLRCH 000DE7r 2 rr rr .addr KBASIN ; lIBASIN 000DE9r 2 rr rr .addr KBSOUT ; lIBSOUT 000DEBr 2 rr rr .addr KSTOP ; lISTOP 000DEDr 2 rr rr .addr KGETIN ; lIGETIN 000DEFr 2 rr rr .addr KCLALL ; lICLALL 000DF1r 2 rr rr .addr RUNSTOP_RESTORE ; lUSRCMD 000DF3r 2 rr rr .addr KLOAD ; lILOAD 000DF5r 2 rr rr .addr KSAVE ; lISAVE 000DF7r 2 END_Copy_of_lCINV: 000DF7r 2 000DF7r 2 ; B.20. Function Name: RAMTAS 000DF7r 2 ; 000DF7r 2 ; Purpose: Perform RAM test 000DF7r 2 ; Call address: $FF87 (hex) 65415 (decimal) 000DF7r 2 ; Communication registers: A, X, Y 000DF7r 2 ; Preparatory routines: None 000DF7r 2 ; Error returns: None 000DF7r 2 ; Stack requirements: 2 000DF7r 2 ; Registers affected: A, X, Y 000DF7r 2 ; 000DF7r 2 ; Description: This routine is used to test RAM and set the top and 000DF7r 2 ; bottom of memory pointers accordingly. It also clears locations $0000 to 000DF7r 2 ; $0101 and $0200 to $03FF. It also allocates the cassette buffer, and sets 000DF7r 2 ; the screen base to $0400. Normally, this routine is called as part of the 000DF7r 2 ; initialization process of a Commodore 64 program cartridge. 000DF7r 2 ; 000DF7r 2 ; EXAMPLE: 000DF7r 2 ; JSR RAMTAS 000DF7r 2 ; 000DF7r 2 iRAMTAS: 000DF7r 2 ; clear zero page and $200-$3ff 000DF7r 2 A9 00 lda #0 000DF9r 2 .if CompileComputer >= C64_GENERAL 000DF9r 2 tay 000DF9r 2 .else 000DF9r 2 AA tax 000DFAr 2 .endif 000DFAr 2 000DFAr 2 @MemClearLoop: 000DFAr 2 000DFAr 2 .if CompileComputer >= C64_GENERAL 000DFAr 2 sta 2,y ; on the C64, start with ZP address 2 so we do not overwrite $00/$01 (6510 on-chip I/O pins!) 000DFAr 2 sta $200,y 000DFAr 2 sta $300,y 000DFAr 2 iny 000DFAr 2 .else 000DFAr 2 95 00 sta 0,x 000DFCr 2 9D 00 02 sta $200,x 000DFFr 2 9D 00 03 sta $300,x 000E02r 2 E8 inx 000E03r 2 .endif 000E03r 2 D0 F5 bne @MemClearLoop 000E05r 2 000E05r 2 ; set the cassette (tape) buffer address 000E05r 2 A2 rr ldx #lTBUFFR 000E09r 2 86 rr stx zTAPE1 000E0Br 2 84 rr sty zTAPE1 + 1 000E0Dr 2 000E0Dr 2 ; Check memory for writability by writing 000E0Dr 2 ; a pattern to it ($55, then $AA). If the 000E0Dr 2 ; addresses contain exactly these values afterwards, 000E0Dr 2 ; we have working RAM. 000E0Dr 2 000E0Dr 2 .if CompileComputer >= C64_GENERAL 000E0Dr 2 tay ; y = 0 000E0Dr 2 lda #(>lVIDEORAM)-1 000E0Dr 2 sta zSTAL + 1 000E0Dr 2 @IncHi: inc zSTAL + 1 000E0Dr 2 @Loop: lda (zSTAL),y ; remember original value of the memory location 000E0Dr 2 tax ; in X 000E0Dr 2 000E0Dr 2 lda #$55 ; write $55 into memory location 000E0Dr 2 sta (zSTAL),y 000E0Dr 2 cmp (zSTAL),y ; still $55? 000E0Dr 2 bne @NotEqual ; no, quit loop 000E0Dr 2 000E0Dr 2 rol a ; test $AA pattern instead 000E0Dr 2 sta (zSTAL),y 000E0Dr 2 cmp (zSTAL),y ; still $AA? 000E0Dr 2 bne @NotEqual ; no, quit loop 000E0Dr 2 000E0Dr 2 ; 000E0Dr 2 ; the old value is only restored if the memory is determined as RAM. 000E0Dr 2 ; otherwise, either $55 or $AA remains at the last location. 000E0Dr 2 ; this is in contrast to the VIC 20 implementation, which leaves all 000E0Dr 2 ; bytes unchanged. 000E0Dr 2 ; Ironically, for the VIC20, there is no difference if this byte is 000E0Dr 2 ; restored or not. For the C64, however, there is a difference, as 000E0Dr 2 ; the RAM under the ROM at $A000 is overwritten with $55 after this 000E0Dr 2 ; function has been called if the BASIC ROM is switched on. 000E0Dr 2 ; 000E0Dr 2 txa ; restore old value 000E0Dr 2 sta (zSTAL),y 000E0Dr 2 000E0Dr 2 .if CompileComputer = C64_GS 000E0Dr 2 nop 000E0Dr 2 bne @IncHi 000E0Dr 2 .else 000E0Dr 2 iny ; proceed to next memory location 000E0Dr 2 bne @Loop ; and do it again 000E0Dr 2 .endif 000E0Dr 2 beq @IncHi ; try next page 000E0Dr 2 ; ------------------------------ 000E0Dr 2 000E0Dr 2 @NotEqual: 000E0Dr 2 tya ; low byte of failed addres 000E0Dr 2 tax ; into X 000E0Dr 2 ldy zSTAL + 1 ; high byte of failed address into y 000E0Dr 2 clc ; (unneccessary, as we call iMEMTOP_Set, not iMEMTOP in the next line) 000E0Dr 2 jsr iMEMTOP_Set ; set memory top to x/y 000E0Dr 2 000E0Dr 2 lda #>lBASICRAM ; set BASIC start to $0800 000E0Dr 2 sta lMEMSTR + 1 ; (low byte is already 0, as we just cleared the ZP) 000E0Dr 2 000E0Dr 2 lda #>lVIDEORAM ; set video RAM start to $0400 000E0Dr 2 sta lHIBASE 000E0Dr 2 rts 000E0Dr 2 000E0Dr 2 .else 000E0Dr 2 000E0Dr 2 85 rr sta zSTAL ; zSTAL low = 0 (unneccessary, as we already cleared ZP to 0) 000E0Fr 2 85 rr sta zTEMPX ; (unneccessary, as we already cleared ZP to 0) 000E11r 2 8D rr rr sta lMEMSTR ; BASIC start low = 0 (unneccessary, as we already cleared ZP to 0) 000E14r 2 A8 tay ; Y = 0 000E15r 2 000E15r 2 A9 04 lda #>$0400 ; start memory test at the location $0400. 000E17r 2 ; This is the first address where memory can be available on the VIC20, 000E17r 2 ; if a 3 KB RAM expansion is present. 000E17r 2 85 rr sta zSTAL + 1 000E19r 2 000E19r 2 @MemTestLoop: 000E19r 2 ; increment address to be tested. 000E19r 2 ; Note that the VIC20 will actually start the test at $0401 with this, thus, $0400 will not be tested at all. 000E19r 2 000E19r 2 E6 rr inc zSTAL ; increment low byte of address to be tested 000E1Br 2 D0 02 bne @SkipHighByte 000E1Dr 2 E6 rr inc zSTAL + 1 ; increment high byte, if necessary 000E1Fr 2 000E1Fr 2 @SkipHighByte: 000E1Fr 2 20 rr rr jsr CheckWritability ; check if byte is writeable RAM (C=1) or not (C=0) 000E22r 2 000E22r 2 A5 rr lda zTEMPX ; until we found (first) RAM, handle 000E24r 2 F0 22 beq @FindMemStart ; the test separately at @FindMemStart 000E26r 2 000E26r 2 ; if we reach here, we have already found the start of RAM somewhere between $0400-$10FF. 000E26r 2 ; Thus, we continue the loop until we found a non-RAM location 000E26r 2 000E26r 2 B0 F1 bcs @MemTestLoop ; if we still have RAM, test the next location 000E28r 2 000E28r 2 ; here, we found the end of RAM 000E28r 2 000E28r 2 A4 rr ldy zSTAL + 1 ; get end of RAM pointer into x/y 000E2Ar 2 A6 rr ldx zSTAL 000E2Cr 2 C0 20 cpy #>$2000 ; end of RAM below $2000? 000E2Er 2 90 25 bcc @Panic ; then panic, we have a severe problem, as we did not even find the RAM every VIC20 has! 000E30r 2 000E30r 2 C0 21 cpy #>$2100 ; end of RAM >= $2100? 000E32r 2 B0 08 bcs @MemConf2 ; yet, set "configuration type 2", expanded with more than 3 KB RAM 000E34r 2 000E34r 2 ; we have an unexpanded VIC20 (or expanded with not more than 3KB) 000E34r 2 A0 1E ldy #>$1E00 ; put screen memory at $1E00 (- $1FFF) 000E36r 2 8C rr rr sty lHIBASE 000E39r 2 ; put memory top at $1E00 000E39r 2 000E39r 2 @SetMemTop: 000E39r 2 4C rr rr jmp iMEMTOP_Set 000E3Cr 2 000E3Cr 2 @MemConf2: 000E3Cr 2 A9 12 lda #>$1200 ; set user basic start to $1200 000E3Er 2 8D rr rr sta lMEMSTR + 1 000E41r 2 A9 10 lda #>$1000 ; set screen memory to $1000 000E43r 2 8D rr rr sta lHIBASE 000E46r 2 D0 F1 bne @SetMemTop ; set memory top to what was determined (in x/y) 000E48r 2 ; ------------------ 000E48r 2 000E48r 2 @FindMemStart: 000E48r 2 ; if we reach here, we are not sure if there is memory at $0400-$0FFF (3 KB expansion) 000E48r 2 ; thus, we proceed when we have NOT yet found writeable RAM. 000E48r 2 000E48r 2 90 CF bcc @MemTestLoop ; no RAM --> jump 000E4Ar 2 000E4Ar 2 ; here, we have found the start of RAM 000E4Ar 2 A5 rr lda zSTAL + 1 ; remember the start of RAM 000E4Cr 2 8D rr rr sta lMEMSTR + 1 ; at (lMEMSTR) 000E4Fr 2 85 rr sta zTEMPX ; remember we already found start of RAM. 000E51r 2 ; with this, we will not jump to @FindMemStart anymore 000E51r 2 C9 11 cmp #>$1100 000E53r 2 90 C4 bcc @MemTestLoop ; if start of RAM is below $1100, continue 000E55r 2 000E55r 2 ; otherwise, we have a severe error, as RAM *must* start at $1000 in every VIC20. 000E55r 2 ; Thus, stop booting with a: 000E55r 2 000E55r 2 ; endless loop: stop boot 000E55r 2 @Panic: 000E55r 2 20 rr rr jsr SET_VIC_DEFAULTS 000E58r 2 4C rr rr jmp @Panic 000E5Br 2 .endif 000E5Br 2 000E5Br 2 000E5Br 2 ; TODO 000E5Br 2 000E5Br 2 TapeIrqVectors: 000E5Br 2 000E5Br 2 .if CompileComputer = C64_GS 000E5Br 2 .addr NMI_End 000E5Br 2 .addr NMI_End 000E5Br 2 .addr NMI_End 000E5Br 2 .addr NMI_End 000E5Br 2 .else 000E5Br 2 000E5Br 2 VecTapeIrqWritePreamble: 000E5Br 2 rr rr .addr TapeIrqWritePreamble 000E5Dr 2 VecTapeIrqWrite: 000E5Dr 2 rr rr .addr TapeIrqWrite 000E5Fr 2 VecKIRQ: 000E5Fr 2 rr rr .addr KIRQ 000E61r 2 VecTapeIrqRead: 000E61r 2 rr rr .addr TapeIrqRead 000E63r 2 000E63r 2 .endif 000E63r 2 000E63r 2 ; B-13. Function Name: IOINIT 000E63r 2 ; 000E63r 2 ; Purpose: Initialize I/O devices 000E63r 2 ; Call Address: $FF84 (hex) 65412 (decimal) 000E63r 2 ; Communication registers: None 000E63r 2 ; Preparatory routines: None 000E63r 2 ; Error returns: 000E63r 2 ; Stack requirements: None 000E63r 2 ; Registers affected: A, X, Y 000E63r 2 ; 000E63r 2 ; Description: This routine initializes all input/output devices and 000E63r 2 ; routines. It is normally called as part of the initialization procedure 000E63r 2 ; of a Commodore 64 program cartridge. 000E63r 2 ; 000E63r 2 ; EXAMPLE: 000E63r 2 ; JSR IOINIT 000E63r 2 ; 000E63r 2 000E63r 2 iIOINIT: 000E63r 2 .if CompileComputer >= C64_GENERAL 000E63r 2 000E63r 2 ; clear all bits in the interrupt control register. 000E63r 2 ; Thus, no CIA will generate any interrupts until 000E63r 2 ; reprogrammed 000E63r 2 lda #~CIA_ICR_BW_SET 000E63r 2 sta CIA1 + CIA_O_ICR 000E63r 2 sta CIA2 + CIA_O_ICR 000E63r 2 000E63r 2 ; (A = $7F) 000E63r 2 sta CIA1 + CIA_O_PA 000E63r 2 000E63r 2 ; stop all timers (TA, TB) on CIA1 and CIA2 000E63r 2 lda #CIA_CRA_B_ONESHOT ; is the same as CIA_CRB_B_ONESHOT! 000E63r 2 sta CIA1 + CIA_O_CRA 000E63r 2 sta CIA2 + CIA_O_CRA 000E63r 2 000E63r 2 sta CIA1 + CIA_O_CRB 000E63r 2 sta CIA2 + CIA_O_CRB 000E63r 2 000E63r 2 ; Port B (PB) of CIA1 and CIA2 are inputs 000E63r 2 ldx #$00 000E63r 2 stx CIA1 + CIA_O_DDRB ; keyboard column 000E63r 2 stx CIA2 + CIA_O_DDRB 000E63r 2 000E63r 2 stx SID + SID_O_FiltMode 000E63r 2 000E63r 2 ; Port A (PA) of CIA1 is output 000E63r 2 dex ; X = $FF 000E63r 2 stx CIA1 + CIA_O_DDRA ; keyboard row 000E63r 2 000E63r 2 ; VIC reaches bank 0 ($0000-$1FFF), RS232 TXD is active. IEC lines are all inactive. 000E63r 2 lda #CIA2_PA_B_VA14 | CIA2_PA_B_VA15 | CIA2_PA_B_RS232_TXD 000E63r 2 sta CIA2 + CIA_O_PA ; IEC_REG_DATA_CLK_OUT 000E63r 2 000E63r 2 lda #CIA2_PA_B_VA14 | CIA2_PA_B_VA15 | CIA2_PA_B_RS232_TXD | CIA2_PA_B_IEC_ATN_OUT | CIA2_PA_B_IEC_CLK_OUT | CIA2_PA_B_IEC_DATA_OUT ; not: CIA2_PA_B_IEC_CLK_IN and CIA2_PA_B_IEC_DATA_IN 000E63r 2 sta CIA2 + CIA_O_DDRA ; IEC_DDR 000E63r 2 000E63r 2 lda #P6510_B_LORAM | P6510_B_HIRAM | P6510_B_CHAREN | P6510_B_CASS_MOTOR | P6510_B_UNUSED 000E63r 2 sta zR6510 000E63r 2 lda #P6510_B_LORAM | P6510_B_HIRAM | P6510_B_CHAREN | P6510_B_CASS_WRITE | P6510_B_CASS_MOTOR 000E63r 2 000E63r 2 sta zD6510 000E63r 2 000E63r 2 iIOINIT_TIMER: 000E63r 2 .if CompileComputer >= C64_02 000E63r 2 lda lTVSFLG 000E63r 2 beq LFDEC 000E63r 2 lda #= C64_02 000E63r 2 lda #>DEFAULT_INIT_VALUE_CIA1_TA_PAL 000E63r 2 jmp LFDF3 000E63r 2 LFDEC: lda #DEFAULT_INIT_VALUE_CIA1_TA_NTSC 000E63r 2 LFDF3: sta CIA1 + CIA_O_TAHI 000E63r 2 .else 000E63r 2 lda #>DEFAULT_INIT_VALUE_CIA1_TA_1MHZ 000E63r 2 sta CIA1 + CIA_O_TAHI 000E63r 2 .endif 000E63r 2 000E63r 2 .macro IOINIT_PATCH 000E63r 2 lda #CIA_ICR_BW_SET |CIA_ICR_B_TA 000E63r 2 sta CIA1 + CIA_O_ICR 000E63r 2 lda CIA1 + CIA_O_CRA 000E63r 2 and #CIA_CRA_B_50HZ ; clear everything but 50/60 Hz flag 000E63r 2 ora #CIA_CRA_B_FORCE_LOAD | CIA_CRA_B_START ; start timer in continuous mode 000E63r 2 sta CIA1 + CIA_O_CRA 000E63r 2 jmp IecClkSet 000E63r 2 .endmacro 000E63r 2 000E63r 2 .if CompileComputer >= C64_02 000E63r 2 jmp Patch_IOINIT 000E63r 2 .else 000E63r 2 IOINIT_PATCH 000E63r 2 .endif 000E63r 2 000E63r 2 .else 000E63r 2 ; this is a VIC20 000E63r 2 000E63r 2 A9 7F lda #$7F 000E65r 2 8D 1E 91 sta VIA1_IEC 000E68r 2 8D 2E 91 sta VIA2_IEC 000E6Br 2 A9 40 lda #$40 000E6Dr 2 8D 2B 91 sta VIA2_ACR 000E70r 2 A9 40 lda #$40 000E72r 2 8D 1B 91 sta VIA1_ACR 000E75r 2 A9 FE lda #$FE 000E77r 2 8D 1C 91 sta VIA1_PCR 000E7Ar 2 A9 DE lda #$DE 000E7Cr 2 8D 2C 91 sta VIA2_PCR 000E7Fr 2 A2 00 ldx #$00 000E81r 2 8E 12 91 stx VIA1_DDRB 000E84r 2 A2 FF ldx #$FF 000E86r 2 8E 22 91 stx VIA2_DDRB 000E89r 2 A2 00 ldx #$00 000E8Br 2 8E 23 91 stx VIA2_DDRA 000E8Er 2 A2 80 ldx #$80 000E90r 2 8E 13 91 stx VIA1_DDRA 000E93r 2 A2 00 ldx #$00 000E95r 2 8E 1F 91 stx VIA1_PA_NO_HS 000E98r 2 20 rr rr jsr IecClkClear 000E9Br 2 A9 82 lda #$82 000E9Dr 2 8D 1E 91 sta VIA1_IEC 000EA0r 2 20 rr rr jsr IecClkSet 000EA3r 2 000EA3r 2 ;LFE39: 000EA3r 2 iIOINIT_TIMER: 000EA3r 2 A9 C0 lda #$C0 000EA5r 2 8D 2E 91 sta VIA2_IEC 000EA8r 2 A9 89 lda #DEFAULT_VIA2_T1 000EAFr 2 8D 25 91 sta VIA2_T1CH 000EB2r 2 60 rts 000EB3r 2 000EB3r 2 .endif 000EB3r 2 000EB3r 2 000EB3r 2 ; B-30. Function Name: SETNAM 000EB3r 2 ; 000EB3r 2 ; Purpose: Set file name 000EB3r 2 ; Call address: $FFBD (hex) 65469 (decimal) 000EB3r 2 ; Communication registers: A, X, Y 000EB3r 2 ; Preparatory routines: 000EB3r 2 ; Stack requirements: 2 000EB3r 2 ; Registers affected: 000EB3r 2 ; 000EB3r 2 ; Description: This routine is used to set up the file name for the OPEN, 000EB3r 2 ; SAVE, or LOAD routines. The accumulator must be loaded with the length of 000EB3r 2 ; the file name. The X and Y registers must be loaded with the address of 000EB3r 2 ; the file name, in standard 6502 low-byte/high-byte format. The address 000EB3r 2 ; can be any valid memory address in the system where a string of 000EB3r 2 ; characters for the file name is stored. If no file name is desired, the 000EB3r 2 ; accumulator must be set to 0, representing a zero file length. The X and 000EB3r 2 ; Y registers can be set to any memory address in that case. 000EB3r 2 ; 000EB3r 2 ; How to Use: 000EB3r 2 ; 000EB3r 2 ; 1) Load the accumulator with the length of the file name. 000EB3r 2 ; 2) Load the X index register with the low order address of the file 000EB3r 2 ; name. 000EB3r 2 ; 3) Load the Y index register with the high order address. 000EB3r 2 ; 4) Call this routine. 000EB3r 2 ; 000EB3r 2 ; EXAMPLE: 000EB3r 2 ; 000EB3r 2 ; LDA #NAME2-NAME ;LOAD LENGTH OF FILE NAME 000EB3r 2 ; LDX #NAME 000EB3r 2 ; JSR SETNAM 000EB3r 2 ; 000EB3r 2 iSETNAM: 000EB3r 2 85 rr sta zFNLEN ; store name of file name 000EB5r 2 86 rr stx zFNADR ; and pointer to it 000EB7r 2 84 rr sty zFNADR + 1 000EB9r 2 60 rts 000EBAr 2 000EBAr 2 ; B-28. Function Name: SETLFS 000EBAr 2 ; 000EBAr 2 ; Purpose: Set up a logical file 000EBAr 2 ; Call address: $FFBA (hex) 65466 (decimal) 000EBAr 2 ; Communication registers: A, X, Y 000EBAr 2 ; Preparatory routines: None 000EBAr 2 ; Error returns: None 000EBAr 2 ; Stack requirements: 2 000EBAr 2 ; Registers affected: None 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; Description: This routine sets the logical file number, device address, 000EBAr 2 ; and secondary address (command number) for other KERNAL routines. 000EBAr 2 ; The logical file number is used by the system as a key to the file 000EBAr 2 ; table created by the OPEN file routine. Device addresses can range from 0 000EBAr 2 ; to 31. The following codes are used by the Commodore 64 to stand for the 000EBAr 2 ; CBM devices listed below: 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; ADDRESS DEVICE 000EBAr 2 ; 000EBAr 2 ; 0 Keyboard 000EBAr 2 ; 1 Datassette(TM) 000EBAr 2 ; 2 RS-232C device 000EBAr 2 ; 3 CRT display 000EBAr 2 ; 4 Serial bus printer 000EBAr 2 ; 8 CBM serial bus disk drive 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; Device numbers 4 or greater automatically refer to devices on the 000EBAr 2 ; serial bus. 000EBAr 2 ; A command to the device is sent as a secondary address on the serial 000EBAr 2 ; bus after the device number is sent during the serial attention 000EBAr 2 ; handshaking sequence. If no secondary address is to be sent, the Y index 000EBAr 2 ; register should be set to 255. 000EBAr 2 ; 000EBAr 2 ; How to Use: 000EBAr 2 ; 000EBAr 2 ; 1) Load the accumulator with the logical file number. 000EBAr 2 ; 2) Load the X index register with the device number. 000EBAr 2 ; 3) Load the Y index register with the command. 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 ; EXAMPLE: 000EBAr 2 ; 000EBAr 2 ; FOR LOGICAL FILE 32, DEVICE #4, AND NO COMMAND: 000EBAr 2 ; LDA #32 000EBAr 2 ; LDX #4 000EBAr 2 ; LDY #255 000EBAr 2 ; JSR SETLFS 000EBAr 2 ; 000EBAr 2 ; 000EBAr 2 iSETLFS: 000EBAr 2 85 rr sta zLA ; store logical file number 000EBCr 2 86 rr stx zFA ; store device number (primary address) 000EBEr 2 84 rr sty zSA ; store secondary address 000EC0r 2 60 rts 000EC1r 2 000EC1r 2 ; B-22. Function Name: READST 000EC1r 2 ; 000EC1r 2 ; Purpose: Read status word 000EC1r 2 ; Call address: $FFB7 (hex) 65463 (decimal) 000EC1r 2 ; Communication registers: A 000EC1r 2 ; Preparatory routines: None 000EC1r 2 ; Error returns: None 000EC1r 2 ; Stack requirements: 2 000EC1r 2 ; Registers affected: A 000EC1r 2 ; 000EC1r 2 ; Description: This routine returns the current status of the I/O devices 000EC1r 2 ; in the accumulator. The routine is usually called after new communication 000EC1r 2 ; to an I/O device. The routine gives you information about device status, 000EC1r 2 ; or errors that have occurred during the I/O operation. 000EC1r 2 ; The bits returned in the accumulator contain the following information: 000EC1r 2 ; (see table below) 000EC1r 2 ; 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | ST Bit | ST Numeric | Cassette | Serial | Tape Verify | 000EC1r 2 ; | Position| Value | Read | Bus R/W | + Load | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 0 | 1 | | time out | | 000EC1r 2 ; | | | | write | | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 1 | 2 | | time out | | 000EC1r 2 ; | | | | read | | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 2 | 4 | short block | | short block | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 3 | 8 | long block | | long block | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 4 | 16 | unrecoverable | | any mismatch | 000EC1r 2 ; | | | read error | | | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 5 | 32 | checksum | | checksum | 000EC1r 2 ; | | | error | | error | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 6 | 64 | end of file | EOI line | | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; | 7 | -128 | end of tape | device not | end of tape | 000EC1r 2 ; | | | | present | | 000EC1r 2 ; +---------+------------+---------------+------------+-------------------+ 000EC1r 2 ; 000EC1r 2 ; 000EC1r 2 ; 000EC1r 2 ; How to Use: 000EC1r 2 ; 000EC1r 2 ; 1) Call this routine. 000EC1r 2 ; 2) Decode the information in the A register as it refers to your pro- 000EC1r 2 ; gram. 000EC1r 2 ; 000EC1r 2 ; EXAMPLE: 000EC1r 2 ; 000EC1r 2 ; ;CHECK FOR END OF FILE DURING READ 000EC1r 2 ; JSR READST 000EC1r 2 ; AND #64 ;CHECK EOF BIT (EOF=END OF FILE) 000EC1r 2 ; BNE EOF ;BRANCH ON EOF 000EC1r 2 ; 000EC1r 2 iREADST: 000EC1r 2 A5 rr lda zFA ; get device address 000EC3r 2 C9 02 cmp #FILE_RS232 ; is it a RS232 device? 000EC5r 2 D0 0B bne iREADST_Normal ; no, return regular status 000EC7r 2 000EC7r 2 ; here, we have a RS232 device. 000EC7r 2 ; return the special status of the RS232 device 000EC7r 2 ; (not documented in the KERNAL description above!) 000EC7r 2 000EC7r 2 AD rr rr lda lRSSTAT ; get RS232 status 000ECAr 2 .if CompileComputer >= C64_GENERAL 000ECAr 2 pha ; make sure to remember RS232 status 000ECAr 2 000ECAr 2 ; Leaving this out for the VIC 20 is obviously a severe bug, which 000ECAr 2 ; makes iREADST for RS232 completely useless on it 000ECAr 2 000ECAr 2 .endif 000ECAr 2 A9 00 lda #$00 ; clear RS232 status 000ECCr 2 8D rr rr sta lRSSTAT 000ECFr 2 .if CompileComputer >= C64_GENERAL 000ECFr 2 pla ; get the RS232 status back 000ECFr 2 000ECFr 2 ; Leaving this out for the VIC 20 is obviously a severe bug, which 000ECFr 2 ; makes iREADST for RS232 completely useless on it 000ECFr 2 000ECFr 2 .endif 000ECFr 2 60 rts 000ED0r 2 000ED0r 2 ; B-29. Function Name: SETMSG 000ED0r 2 ; 000ED0r 2 ; Purpose: Control system message output 000ED0r 2 ; Call address: $FF90 (hex) 65424 (decimal) 000ED0r 2 ; Communication registers: A 000ED0r 2 ; Preparatory routines: None 000ED0r 2 ; Error returns: None 000ED0r 2 ; Stack requirements: 2 000ED0r 2 ; Registers affected: A 000ED0r 2 ; 000ED0r 2 ; Description: This routine controls the printing of error and control 000ED0r 2 ; messages by the KERNAL. Either print error messages or print control mes- 000ED0r 2 ; sages can be selected by setting the accumulator when the routine is 000ED0r 2 ; called. FILE NOT FOUND is an example of an error message. PRESS PLAY ON 000ED0r 2 ; CASSETTE is an example of a control message. 000ED0r 2 ; Bits 6 and 7 of this value determine where the message will come from. 000ED0r 2 ; If bit 7 is 1, one of the error messages from the KERNAL is printed. If 000ED0r 2 ; bit 6 is set, control messages are printed. 000ED0r 2 ; 000ED0r 2 ; How to Use: 000ED0r 2 ; 000ED0r 2 ; 1) Set accumulator to desired value. 000ED0r 2 ; 2) Call this routine. 000ED0r 2 ; 000ED0r 2 ; EXAMPLE: 000ED0r 2 ; 000ED0r 2 ; LDA #$40 000ED0r 2 ; JSR SETMSG ;TURN ON CONTROL MESSAGES 000ED0r 2 ; LDA #$80 000ED0r 2 ; JSR SETMSG ;TURN ON ERROR MESSAGES 000ED0r 2 ; LDA #0 000ED0r 2 ; JSR SETMSG ;TURN OFF ALL KERNAL MESSAGES 000ED0r 2 ; 000ED0r 2 iSETMSG: 000ED0r 2 85 rr sta zNSGFLG 000ED2r 2 000ED2r 2 ; in fact, these three commands belong to iREADST! 000ED2r 2 ; read the status (LFE1A) or set one or more status bits (LFE1C) 000ED2r 2 iREADST_Normal: 000ED2r 2 A5 rr lda zSTATUS 000ED4r 2 SetStatus: 000ED4r 2 05 rr ora zSTATUS 000ED6r 2 85 rr sta zSTATUS 000ED8r 2 60 rts 000ED9r 2 000ED9r 2 ; B-32. Function Name: SETTMO 000ED9r 2 ; 000ED9r 2 ; Purpose: Set IEEE bus card timeout flag 000ED9r 2 ; Call address: $FFA2 (hex) 65442 (decimal) 000ED9r 2 ; Communication registers: A 000ED9r 2 ; Preparatory routines: None 000ED9r 2 ; Error returns: None 000ED9r 2 ; Stack requirements: 2 000ED9r 2 ; Registers affected: None 000ED9r 2 ; +-----------------------------------------------------------------------+ 000ED9r 2 ; | NOTE: This routine is used ONLY with an IEEE add-on card! | 000ED9r 2 ; +-----------------------------------------------------------------------+ 000ED9r 2 ; Description: This routine sets the timeout flag for the IEEE bus. When 000ED9r 2 ; the timeout flag is set, the Commodore 64 will wait for a device on the 000ED9r 2 ; IEEE port for 64 milliseconds. If the device does not respond to the 000ED9r 2 ; Commodore 64's Data Address Valid (DAV) signal within that time the 000ED9r 2 ; Commodore 64 will recognize an error condition and leave the handshake 000ED9r 2 ; sequence. When this routine is called when the accumulator contains a 0 000ED9r 2 ; in bit 7, timeouts are enabled. A 1 in bit 7 will disable the timeouts. 000ED9r 2 ; 000ED9r 2 ; +-----------------------------------------------------------------------+ 000ED9r 2 ; | NOTE: The Commodore 64 uses the timeout feature to communicate that a | 000ED9r 2 ; | disk file is not found on an attempt to OPEN a file only with an IEEE | 000ED9r 2 ; | card. | 000ED9r 2 ; +-----------------------------------------------------------------------+ 000ED9r 2 ; 000ED9r 2 ; How to Use: 000ED9r 2 ; 000ED9r 2 ; TO SET THE TIMEOUT FLAG 000ED9r 2 ; 1) Set bit 7 of the accumulator to 0. 000ED9r 2 ; 2) Call this routine. 000ED9r 2 ; 000ED9r 2 ; TO RESET THE TIMEOUT FLAG 000ED9r 2 ; 1) Set bit 7 of the accumulator to 1. 000ED9r 2 ; 2) Call this routine. 000ED9r 2 ; 000ED9r 2 ; EXAMPLE: 000ED9r 2 ; 000ED9r 2 ; ;DISABLE TIMEOUT 000ED9r 2 ; LDA #0 000ED9r 2 ; JSR SETTMO 000ED9r 2 ; 000ED9r 2 iSETTMO: 000ED9r 2 8D rr rr sta lTIMOUT 000EDCr 2 60 rts 000EDDr 2 000EDDr 2 000EDDr 2 ; B-17. Function Name: MEMTOP 000EDDr 2 ; 000EDDr 2 ; Purpose: Set the top of RAM 000EDDr 2 ; Call address: $FF99 (hex) 65433 (decimal) 000EDDr 2 ; Communication registers: X, Y 000EDDr 2 ; Preparatory routines: None 000EDDr 2 ; Error returns: None 000EDDr 2 ; Stack requirements: 2 000EDDr 2 ; Registers affected: X, Y 000EDDr 2 ; 000EDDr 2 ; Description: This routine is used to set the top of RAM. When this 000EDDr 2 ; routine is called with the carry bit of the accumulator set, the pointer 000EDDr 2 ; to the top of RAM will be loaded into the X and Y registers. When this 000EDDr 2 ; routine is called with the accumulator carry bit clear, the contents of 000EDDr 2 ; the X and Y registers are loaded in the top of memory pointer, changing 000EDDr 2 ; the top of memory. 000EDDr 2 ; 000EDDr 2 ; EXAMPLE: 000EDDr 2 ; ;DEALLOCATE THE RS-232 BUFFER 000EDDr 2 ; SEC 000EDDr 2 ; JSR MEMTOP ;READ TOP OF MEMORY 000EDDr 2 ; DEX 000EDDr 2 ; CLC 000EDDr 2 ; JSR MEMTOP ;SET NEW TOP OF MEMORY 000EDDr 2 ; 000EDDr 2 iMEMTOP: 000EDDr 2 90 06 bcc iMEMTOP_Set ; c = 0 --> set MEMTOP 000EDFr 2 iMEMTOP_Get: 000EDFr 2 AE rr rr ldx lMEMSIZ ; get MEMTOP to x/y 000EE2r 2 AC rr rr ldy lMEMSIZ + 1 000EE5r 2 iMEMTOP_Set: 000EE5r 2 8E rr rr stx lMEMSIZ ; set MEMTOP from x/y 000EE8r 2 8C rr rr sty lMEMSIZ + 1 000EEBr 2 60 rts 000EECr 2 000EECr 2 ; B-16. Function Name: MEMBOT 000EECr 2 ; 000EECr 2 ; Purpose: Set bottom of memory 000EECr 2 ; Call address: $FF9C (hex) 65436 (decimal) 000EECr 2 ; Communication registers: X, Y 000EECr 2 ; Preparatory routines: None 000EECr 2 ; Error returns: None 000EECr 2 ; Stack requirements: None 000EECr 2 ; Registers affected: X, Y 000EECr 2 ; 000EECr 2 ; Description: This routine is used to set the bottom of the memory. If 000EECr 2 ; the accumulator carry bit is set when this routine is called, a pointer 000EECr 2 ; to the lowest byte of RAM is returned in the X and Y registers. On the 000EECr 2 ; unexpanded Commodore 64 the initial value of this pointer is $0800 000EECr 2 ; (2048 in decimal). If the accumulator carry bit is clear (-O) when this 000EECr 2 ; routine is called, the values of the X and Y registers are transferred to 000EECr 2 ; the low and high bytes, respectively, of the pointer to the beginning of 000EECr 2 ; RAM. 000EECr 2 ; 000EECr 2 ; 000EECr 2 ; 000EECr 2 ; How to Use: 000EECr 2 ; TO READ THE BOTTOM OF RAM 000EECr 2 ; 1) Set the carry. 000EECr 2 ; 2) Call this routine. 000EECr 2 ; 000EECr 2 ; TO SET THE BOTTOM OF MEMORY 000EECr 2 ; 1) Clear the carry. 000EECr 2 ; 2) Call this routine. 000EECr 2 ; 000EECr 2 ; EXAMPLE: 000EECr 2 ; 000EECr 2 ; ;MOVE BOTTOM OF MEMORY UP 1 PAGE 000EECr 2 ; SEC ;READ MEMORY BOTTOM 000EECr 2 ; JSR MEMBOT 000EECr 2 ; INY 000EECr 2 ; CLC ;SET MEMORY BOTTOM TO NEW VALUE 000EECr 2 ; JSR MEMBOT 000EECr 2 ; 000EECr 2 iMEMBOT: 000EECr 2 90 06 bcc @Set ; c = 0 --> set MEMBOT 000EEEr 2 000EEEr 2 AE rr rr ldx lMEMSTR ; get MEMBOT to x/y 000EF1r 2 AC rr rr ldy lMEMSTR + 1 000EF4r 2 000EF4r 2 8E rr rr @Set: stx lMEMSTR ; set MEMBOT from x/y 000EF7r 2 8C rr rr sty lMEMSTR + 1 000EFAr 2 60 rts 000EFBr 2 000EFBr 2 000EFBr 2 .if CompileComputer < C64_GENERAL 000EFBr 2 ; 000EFBr 2 ; Test if the memory location pointed to by (zSTAL),y is writable RAM. 000EFBr 2 ; For this, we write $55, then $AA into the location. After each write, 000EFBr 2 ; we test if the memory is $55 and $AA, respectively. 000EFBr 2 ; The memory location is left unchanged (that is, the old value is written 000EFBr 2 ; back to it), regardless of the outcome of the test. 000EFBr 2 ; 000EFBr 2 ; If the area is determined as RAM, return with c=1, else c=0. 000EFBr 2 ; 000EFBr 2 CheckWritability: 000EFBr 2 B1 rr lda (zSTAL),y ; remember original value of the memory location 000EFDr 2 AA tax ; in X 000EFEr 2 000EFEr 2 A9 55 lda #$55 ; write $55 into memory location 000F00r 2 91 rr sta (zSTAL),y 000F02r 2 D1 rr cmp (zSTAL),y ; still $55? 000F04r 2 D0 08 bne @NotEqual ; no, quit loop 000F06r 2 000F06r 2 6A ror a ; test $AA pattern instead 000F07r 2 91 rr sta (zSTAL),y 000F09r 2 D1 rr cmp (zSTAL),y ; still $AA? 000F0Br 2 D0 01 bne @NotEqual ; no, quit loop 000F0Dr 2 000F0Dr 2 A9 .byte $A9 ; with next byte: "lda #$18". Make sure the CLC is not executed. 000F0Er 2 000F0Er 2 @NotEqual: 000F0Er 2 18 clc ; return: There was a difference 000F0Fr 2 000F0Fr 2 8A txa ; restore old value 000F10r 2 91 rr sta (zSTAL),y 000F12r 2 60 rts 000F13r 2 .endif 000F13r 2 000F13r 2 ; 6502 NMI routine 000F13r 2 ; This routine is called whenever an NMI occurs. 000F13r 2 ; 000F13r 2 78 NMI: sei ; block IRQ 000F14r 2 6C rr rr jmp (lNMINV) ; normally points to KNMI 000F17r 2 000F17r 2 48 KNMI: pha ; save A, X and Y onto the stack 000F18r 2 8A txa 000F19r 2 48 pha 000F1Ar 2 98 tya 000F1Br 2 48 pha 000F1Cr 2 000F1Cr 2 .if CompileComputer >= C64_GENERAL 000F1Cr 2 ; clear all bits in the interrupt control register to prevent further interrupts 000F1Cr 2 lda #~CIA_ICR_BW_SET 000F1Cr 2 sta CIA2 + CIA_O_ICR 000F1Cr 2 000F1Cr 2 ; check if CIA2 generated this NMI 000F1Cr 2 ldy CIA2 + CIA_O_ICR 000F1Cr 2 bmi NMI_FROM_IO ; CIA2 generated the NMI, process it 000F1Cr 2 .else 000F1Cr 2 ; check if VIA1 generated this NMI 000F1Cr 2 AD 1D 91 lda VIA1_IFR 000F1Fr 2 10 48 bpl LFEFF 000F21r 2 2D 1E 91 and VIA1_IEC 000F24r 2 AA tax 000F25r 2 29 02 and #$02 000F27r 2 F0 1F beq NMI_FROM_IO 000F29r 2 .endif 000F29r 2 000F29r 2 20 rr rr jsr CheckCartridge ; is there a cartridge (with magic) installed at $8000 (C64) / $A000 (VIC-20)? 000F2Cr 2 D0 03 bne @NoCartridge ; no, skip 000F2Er 2 6C 02 A0 jmp (CART_NMI) ; yes, let the cartridge process the NMI 000F31r 2 000F31r 2 @NoCartridge: 000F31r 2 .if CompileComputer >= C64_GENERAL 000F31r 2 jsr iUDTIM_CheckRunStop 000F31r 2 .else 000F31r 2 2C 11 91 bit VIA1_PA 000F34r 2 20 rr rr jsr iUDTIM 000F37r 2 .endif 000F37r 2 20 rr rr jsr kSTOP 000F3Ar 2 D0 2D bne LFEFF 000F3Cr 2 000F3Cr 2 RUNSTOP_RESTORE: 000F3Cr 2 20 rr rr jsr iRESTOR 000F3Fr 2 20 rr rr jsr iIOINIT 000F42r 2 20 rr rr jsr iCINT 000F45r 2 6C rr rr jmp (bRESTART + 2) 000F48r 2 000F48r 2 NMI_FROM_IO: 000F48r 2 000F48r 2 .if CompileComputer >= C64_GENERAL 000F48r 2 LFEFF: 000F48r 2 ; TODO combine more? 000F48r 2 000F48r 2 ; TODO follow logic (currently, there is no description *why* these tests are done!) 000F48r 2 000F48r 2 tya ; A := Y, which has contents of CIA2 + CIA_O_ICR here 000F48r 2 and lENABL ; only check bits that are set in lENABL 000F48r 2 tax 000F48r 2 000F48r 2 and #CIA_ICR_B_TA ; check if TA of CIA2 generated the interrupt 000F48r 2 beq @NoTimerAUnderflow ; no -> branch, next test 000F48r 2 000F48r 2 lda RS232_TXD_REG 000F48r 2 and #~CIA2_PA_B_RS232_TXD 000F48r 2 ora zNXTBIT 000F48r 2 sta RS232_TXD_REG 000F48r 2 000F48r 2 ; clear all interrupt sources of CIA2 that are currently set 000F48r 2 lda lENABL ; get enabled interrupt sources 000F48r 2 sta CIA2 + CIA_O_ICR 000F48r 2 000F48r 2 txa 000F48r 2 and #CIA_ICR_B_FLAG | CIA_ICR_B_TB ; check if timer B or FLAG generated the interrupt 000F48r 2 beq @Continue ; none -> branch 000F48r 2 000F48r 2 and #CIA_ICR_B_TB ; check if timer B generated the interrupt 000F48r 2 beq @IntFromFlag ; no -> branch 000F48r 2 000F48r 2 jsr LFED6 000F48r 2 jmp @Continue 000F48r 2 000F48r 2 @IntFromFlag: 000F48r 2 jsr LFF07 000F48r 2 000F48r 2 @Continue: 000F48r 2 jsr LEEBB 000F48r 2 jmp @ClearAllCIA2Interrupts 000F48r 2 000F48r 2 @NoTimerAUnderflow: 000F48r 2 txa 000F48r 2 and #CIA_ICR_B_TB ; check if TB of CIA2 generated the interrupt 000F48r 2 beq @NoTimerBUnderflow ; no -> branch, next test 000F48r 2 jsr LFED6 000F48r 2 jmp @ClearAllCIA2Interrupts 000F48r 2 000F48r 2 @NoTimerBUnderflow: 000F48r 2 txa 000F48r 2 and #CIA_ICR_B_FLAG ; check if FLAG of CIA2 generated the interrupt 000F48r 2 beq @ClearAllCIA2Interrupts ; no -> branch, next test 000F48r 2 jsr LFF07 000F48r 2 000F48r 2 @ClearAllCIA2Interrupts: 000F48r 2 ; clear all interrupt sources of CIA2 that are currently set 000F48r 2 lda lENABL ; get enabled interrupt sources 000F48r 2 sta CIA2 + CIA_O_ICR 000F48r 2 000F48r 2 .else 000F48r 2 000F48r 2 AD 1E 91 lda VIA1_IEC 000F4Br 2 09 80 ora #$80 000F4Dr 2 48 pha 000F4Er 2 A9 7F lda #$7F 000F50r 2 8D 1E 91 sta VIA1_IEC 000F53r 2 8A txa 000F54r 2 29 40 and #$40 000F56r 2 F0 14 beq LFF02 000F58r 2 A9 CE lda #$CE 000F5Ar 2 05 rr ora zNXTBIT 000F5Cr 2 8D 1C 91 sta VIA1_PCR 000F5Fr 2 AD 14 91 lda VIA1_T1CL 000F62r 2 68 pla 000F63r 2 8D 1E 91 sta VIA1_IEC 000F66r 2 20 rr rr jsr LEEBB 000F69r 2 LFEFF: 000F69r 2 4C rr rr jmp NMI_End 000F6Cr 2 ; ----------------------- 000F6Cr 2 000F6Cr 2 8A LFF02: txa 000F6Dr 2 29 20 and #$20 000F6Fr 2 F0 25 beq @LFF2C 000F71r 2 AD 10 91 lda VIA1_PB 000F74r 2 29 01 and #$01 000F76r 2 85 rr sta zINBIT 000F78r 2 AD 18 91 lda VIA1_T2CL 000F7Br 2 E9 16 sbc #$16 000F7Dr 2 6D rr rr adc lBAUDOF 000F80r 2 8D 18 91 sta VIA1_T2CL 000F83r 2 AD 19 91 lda VIA1_T2CH 000F86r 2 6D rr rr adc lBAUDOF + 1 000F89r 2 8D 19 91 sta VIA1_T2CH 000F8Cr 2 68 pla 000F8Dr 2 8D 1E 91 sta VIA1_IEC 000F90r 2 20 rr rr jsr LEF59 000F93r 2 4C rr rr jmp NMI_End 000F96r 2 8A @LFF2C: txa 000F97r 2 29 10 and #$10 000F99r 2 F0 25 beq NMI_End 000F9Br 2 AD rr rr lda lM51CTR 000F9Er 2 29 0F and #$0F 000FA0r 2 D0 00 bne @LFF38 000FA2r 2 0A @LFF38: asl a 000FA3r 2 AA tax 000FA4r 2 BD rr rr lda LFEC2 - 2,x 000FA7r 2 8D 18 91 sta VIA1_T2CL 000FAAr 2 BD rr rr lda LFEC2 - 1,x 000FADr 2 8D 19 91 sta VIA1_T2CH 000FB0r 2 AD 10 91 lda VIA1_PB 000FB3r 2 68 pla 000FB4r 2 09 20 ora #$20 000FB6r 2 29 EF and #$EF 000FB8r 2 8D 1E 91 sta VIA1_IEC 000FBBr 2 AE rr rr ldx lBITNUM 000FBEr 2 86 rr stx zBITC1 000FC0r 2 .endif 000FC0r 2 000FC0r 2 NMI_End: 000FC0r 2 68 pla 000FC1r 2 A8 tay 000FC2r 2 68 pla 000FC3r 2 AA tax 000FC4r 2 68 pla 000FC5r 2 40 rti 000FC6r 2 000FC6r 2 LFEC2: 000FC6r 2 000FC6r 2 .if CompileComputer >= C64_GENERAL 000FC6r 2 000FC6r 2 .if CompileComputer >= C64_02 000FC6r 2 .word $27C1 000FC6r 2 .word $1A3E 000FC6r 2 .word $11C5 000FC6r 2 .word $0E74 000FC6r 2 .word $0CED 000FC6r 2 .word $0645 000FC6r 2 .word $02F0 000FC6r 2 .word $0146 000FC6r 2 .word $00B8 000FC6r 2 .word $0071 000FC6r 2 .else 000FC6r 2 .word $26AC 000FC6r 2 .word $19A7 000FC6r 2 .word $115D 000FC6r 2 .word $0E1F 000FC6r 2 .word $0CA1 000FC6r 2 .word $061F 000FC6r 2 .word $02DD 000FC6r 2 .word $013D 000FC6r 2 .word $00B2 000FC6r 2 .word $006C 000FC6r 2 000FC6r 2 .endif 000FC6r 2 000FC6r 2 .else 000FC6r 2 000FC6r 2 .if CompileComputer >= VIC20_07 000FC6r 2 000FC6r 2 .word $2AE6 000FC6r 2 .word $1C78 000FC6r 2 .word $1349 000FC6r 2 .word $0FB1 000FC6r 2 .word $0E0A 000FC6r 2 .word $06D3 000FC6r 2 .word $0338 000FC6r 2 .word $016A 000FC6r 2 .word $00D0 000FC6r 2 .word $0083 000FC6r 2 .word $0036 000FC6r 2 000FC6r 2 .else 000FC6r 2 000FC6r 2 92 27 .word $2792 000FC8r 2 40 1A .word $1A40 000FCAr 2 C6 11 .word $11C6 000FCCr 2 74 0E .word $0E74 000FCEr 2 EE 0C .word $0CEE 000FD0r 2 45 06 .word $0645 000FD2r 2 F1 02 .word $02F1 000FD4r 2 46 01 .word $0146 000FD6r 2 B8 00 .word $00B8 000FD8r 2 71 00 .word $0071 000FDAr 2 2A 00 .word $002A 000FDCr 2 000FDCr 2 .endif 000FDCr 2 000FDCr 2 .endif 000FDCr 2 000FDCr 2 000FDCr 2 .if CompileComputer >= C64_GENERAL 000FDCr 2 LFED6: lda CIA2 + CIA_O_PB 000FDCr 2 and #$01 000FDCr 2 sta zINBIT 000FDCr 2 lda CIA2 + CIA_O_TBLO 000FDCr 2 sbc #$1C 000FDCr 2 adc lBAUDOF 000FDCr 2 sta CIA2 + CIA_O_TBLO 000FDCr 2 lda CIA2 + CIA_O_TBHI 000FDCr 2 adc lBAUDOF + 1 000FDCr 2 sta CIA2 + CIA_O_TBHI 000FDCr 2 lda #$11 000FDCr 2 sta CIA2 + CIA_O_CRB 000FDCr 2 000FDCr 2 ; clear all interrupt sources of CIA2 that are currently set 000FDCr 2 lda lENABL ; get enabled interrupt sources 000FDCr 2 sta CIA2 + CIA_O_ICR 000FDCr 2 000FDCr 2 lda #$FF 000FDCr 2 sta CIA2 + CIA_O_TBLO 000FDCr 2 sta CIA2 + CIA_O_TBHI 000FDCr 2 jmp LEF59 000FDCr 2 LFF07: 000FDCr 2 .if CompileComputer = C64_01 000FDCr 2 lda lM51CTR 000FDCr 2 and #$0F 000FDCr 2 bne LFF1A 000FDCr 2 .endif 000FDCr 2 lda lM51AJB 000FDCr 2 sta CIA2 + CIA_O_TBLO 000FDCr 2 lda lM51AJB + 1 000FDCr 2 .if CompileComputer = C64_01 000FDCr 2 jmp LFF25 000FDCr 2 LFF1A: asl a 000FDCr 2 tax 000FDCr 2 lda LFEC2 - 2,x 000FDCr 2 sta CIA2 + CIA_O_TBLO 000FDCr 2 lda LFEC2 - 1,x 000FDCr 2 LFF25: 000FDCr 2 .endif 000FDCr 2 sta CIA2 + CIA_O_TBHI 000FDCr 2 lda #$11 000FDCr 2 sta CIA2 + CIA_O_CRB 000FDCr 2 000FDCr 2 lda #CIA_ICR_B_FLAG | CIA_ICR_B_TB 000FDCr 2 eor lENABL 000FDCr 2 sta lENABL 000FDCr 2 000FDCr 2 lda #$FF 000FDCr 2 sta CIA2 + CIA_O_TBLO 000FDCr 2 sta CIA2 + CIA_O_TBHI 000FDCr 2 ldx lBITNUM 000FDCr 2 stx zBITC1 000FDCr 2 rts 000FDCr 2 000FDCr 2 .if CompileComputer >= C64_02 000FDCr 2 LFF2E: tax 000FDCr 2 lda lM51AJB + 1 000FDCr 2 rol a 000FDCr 2 tay 000FDCr 2 txa 000FDCr 2 adc #<200 000FDCr 2 sta lBAUDOF 000FDCr 2 tya 000FDCr 2 adc #>200 000FDCr 2 sta lBAUDOF + 1 000FDCr 2 rts 000FDCr 2 .endif 000FDCr 2 000FDCr 2 .segment "TapeFakeFiller" 000FDCr 2 nop 000FDCr 2 nop 000FDCr 2 000FDCr 2 ; FillUntil KERNAL_START + $1F43, $EA 000FDCr 2 .segment "TapeFakeIrq" 000FDCr 2 000FDCr 2 ; This is a faked IRQ entry point. It is used by the tape routine to execute the IRQ routine, 000FDCr 2 ; returning to a predefined address afterwards. 000FDCr 2 ; 000FDCr 2 ; When this address is called (JMPed to), the return address - 1 is already on the stack. 000FDCr 2 ; This routine has to set a flag register on the stack, making sure that the B bit is unset 000FDCr 2 ; forcing a processing of an IRQ (and not of a BRK instruction) 000FDCr 2 ; 000FDCr 2 FakeIRQ: 000FDCr 2 php ; push flag register onto stack 000FDCr 2 000FDCr 2 ; now, manipulate the flag register making sure B is unset 000FDCr 2 000FDCr 2 pla ; get it back into the Accu 000FDCr 2 and #~A6502_FLAGS_B ; make sure B is unset 000FDCr 2 pha ; store the flag register back onto the stack 000FDCr 2 000FDCr 2 000FDCr 2 .endif 000FDCr 2 000FDCr 2 ; 6502 IRQ routine 000FDCr 2 ; This routine is called whenever an IRQ occurs. 000FDCr 2 ; 000FDCr 2 48 IRQ: pha ; save A, X and Y onto stack 000FDDr 2 8A txa 000FDEr 2 48 pha 000FDFr 2 98 tya 000FE0r 2 48 pha 000FE1r 2 000FE1r 2 BA tsx ; SP -> X 000FE2r 2 BD rr rr lda lSTACK + 4,x ; Read status register from stack 000FE5r 2 29 10 and #A6502_FLAGS_B ; check BRK flag 000FE7r 2 F0 03 beq @isIRQ ; BRK flag is 0 --> it was an IRQ 000FE9r 2 000FE9r 2 6C rr rr jmp (lCNBINV) ; BRK flag was 1, process the BRK instruction 000FECr 2 000FECr 2 6C rr rr @isIRQ: jmp (lCINV) ; process the IRQ. Normally, this points to KIRQ 000FEFr 2 000FEFr 2 000FEFr 2 .if CompileComputer >= C64_GENERAL 000FEFr 2 .if CompileComputer >= C64_02 000FEFr 2 000FEFr 2 ; B-7. Function Name: CINT 000FEFr 2 ; 000FEFr 2 ; Purpose: Initialize screen editor & 6567 video chip 000FEFr 2 ; Call address: $FF81 (hex) 65409 (decimal) 000FEFr 2 ; Communication registers: None 000FEFr 2 ; Preparatory routines: None 000FEFr 2 ; Error returns: None 000FEFr 2 ; Stack requirements: 4 000FEFr 2 ; Registers affected: A, X, Y 000FEFr 2 ; 000FEFr 2 ; 000FEFr 2 ; Description: This routine sets up the 6567 video controller chip in the 000FEFr 2 ; Commodore 64 for normal operation. The KERNAL screen editor is also 000FEFr 2 ; initialized. This routine should be called by a Commodore 64 program 000FEFr 2 ; cartridge. 000FEFr 2 ; 000FEFr 2 ; How to Use: 000FEFr 2 ; 000FEFr 2 ; 1) Call this routine. 000FEFr 2 ; 000FEFr 2 ; EXAMPLE: 000FEFr 2 ; 000FEFr 2 ; JSR CINT 000FEFr 2 ; JMP RUN ;BEGIN EXECUTION 000FEFr 2 ; 000FEFr 2 ; NOTE: iCINT_WITH_PAL_NTSC is an *extended* version. 000FEFr 2 ; It determines if there is a 6567 (NTSC) or 6569 (PAL) VIC chip. 000FEFr 2 ; It stores the result in lTVSFLG (TV Standard FLaG), with 000FEFr 2 ; 0 = NTSC, 1 = PAL. 000FEFr 2 ; Then, it reprograms the CIA timer for PAL or NTSC. 000FEFr 2 ; 000FEFr 2 iCINT_WITH_PAL_NTSC: 000FEFr 2 jsr iCINT 000FEFr 2 000FEFr 2 @WaitForRaster: 000FEFr 2 lda VIC + VICII_O_Raster 000FEFr 2 bne @WaitForRaster 000FEFr 2 lda VIC + VICII_O_IRQFlags 000FEFr 2 and #$01 000FEFr 2 sta lTVSFLG 000FEFr 2 jmp iIOINIT_TIMER 000FEFr 2 000FEFr 2 ; Remainder of iIOINIT. As the code become too large because of the PAL/NTSC 000FEFr 2 ; implementation, this patch is here now. 000FEFr 2 ; 000FEFr 2 Patch_IOINIT: 000FEFr 2 IOINIT_PATCH 000FEFr 2 .endif 000FEFr 2 .endif 000FEFr 2 000FEFr 2 .if CompileComputer >= C64_GENERAL 000FEFr 2 000FEFr 2 ; FillUntil KERNAL_START + $1F80 000FEFr 2 .segment "KernalJumpTable" 000FEFr 2 000FEFr 2 .byte VERSION_FF80 ; a version number for the KERNAL 000FEFr 2 000FEFr 2 ; here, the KERNAL jump table begins 000FEFr 2 ; 000FEFr 2 000FEFr 2 000FEFr 2 ; the VIC-20 does not know CINT, IOINIT and RAMTAS, as these were added with the C64: 000FEFr 2 000FEFr 2 kCINT: 000FEFr 2 .if CompileComputer >= C64_02 000FEFr 2 ; on C64 >= -02 ROM, determine if this is a PAL or an NTSC machine, 000FEFr 2 ; and set the IRQ timings accordingly. 000FEFr 2 ; Afterwards, iCINT is called. 000FEFr 2 jmp iCINT_WITH_PAL_NTSC 000FEFr 2 .else 000FEFr 2 ; for C64 with -01 ROM, iCINT is called directly. 000FEFr 2 jmp iCINT 000FEFr 2 .endif 000FEFr 2 000FEFr 2 kIOINIT: jmp iIOINIT 000FEFr 2 kRAMTAS: jmp iRAMTAS 000FEFr 2 000FEFr 2 .else 000FEFr 2 000FEFr 2 ; FillUntil $FF8A,FILL_FFXX 000FEFr 2 000FEFr 2 .endif 000FEFr 2 000FEFr 2 .segment "KernalJumpTable2" 000000r 2 000000r 2 ; here, the KERNAL jump table common to VIC20 and C64 begins 000000r 2 000000r 2 4C rr rr kRESTOR: jmp iRESTOR 000003r 2 4C rr rr kVECTOR: jmp iVECTOR 000006r 2 4C rr rr kSETMSG: jmp iSETMSG 000009r 2 4C rr rr kSECOND: jmp iSECOND 00000Cr 2 4C rr rr kTKSA: jmp iTKSA 00000Fr 2 4C rr rr kMEMTOP: jmp iMEMTOP 000012r 2 4C rr rr kMEMBOT: jmp iMEMBOT 000015r 2 4C rr rr kSCNKEY: jmp iSCNKEY 000018r 2 4C rr rr kSETTMO: jmp iSETTMO 00001Br 2 kACPTR: 00001Br 2 .ifdef JIFFY 00001Br 2 jmp JDLFBAA 00001Br 2 .else 00001Br 2 4C rr rr jmp iACPTR 00001Er 2 .endif 00001Er 2 4C rr rr kCIOUT: jmp iCIOUT 000021r 2 4C rr rr kUNTLK: jmp iUNTLK 000024r 2 4C rr rr kUNLSN: jmp iUNLSN 000027r 2 4C rr rr kLISTEN: jmp iLISTEN 00002Ar 2 4C rr rr kTALK: jmp iTALK 00002Dr 2 4C rr rr kREADST: jmp iREADST 000030r 2 4C rr rr kSETLFS: jmp iSETLFS 000033r 2 4C rr rr kSETNAM: jmp iSETNAM 000036r 2 6C rr rr kOPEN: jmp (lIOPEN) 000039r 2 6C rr rr kCLOSE: jmp (lICLOSE) 00003Cr 2 6C rr rr kCHKIN: jmp (lICHKIN) 00003Fr 2 6C rr rr kCHKOUT: jmp (lICKOUT) 000042r 2 6C rr rr kCLRCHN: jmp (lICLRCH) 000045r 2 6C rr rr kCHRIN: jmp (lIBASIN) 000048r 2 6C rr rr kCHROUT: jmp (lIBSOUT) 00004Br 2 4C rr rr kLOAD: jmp iLOAD 00004Er 2 4C rr rr kSAVE: jmp iSAVE 000051r 2 4C rr rr kSETTIM: jmp iSETTIM 000054r 2 4C rr rr kRDTIM: jmp iRDTIM 000057r 2 6C rr rr kSTOP: jmp (lISTOP) 00005Ar 2 6C rr rr kGETIN: jmp (lIGETIN) 00005Dr 2 6C rr rr kCLALL: jmp (lICLALL) 000060r 2 4C rr rr kUDTIM: jmp iUDTIM 000063r 2 4C rr rr kSCREEN: jmp iSCREEN 000066r 2 4C rr rr kPLOT: jmp iPLOT 000069r 2 4C rr rr kIOBASE: jmp iIOBASE 00006Cr 2 00006Cr 2 .if (CompileComputer >= C64_GENERAL) .AND (.NOT .defined(C64JAPAN)) 00006Cr 2 .byte "RR" ; Robert Russell 00006Cr 2 .if CompileComputer = C64_4064 00006Cr 2 .byte 0,0 00006Cr 2 .else 00006Cr 2 .byte "BY" ; Bob Yannes 00006Cr 2 .endif 00006Cr 2 .endif 00006Cr 2 00006Cr 2 ; FillUntil $FFFA,FILL_FFXXa 00006Cr 2 .segment "Int6502" 000000r 2 000000r 2 rr rr .addr NMI ; 6502 NMI vector 000002r 2 rr rr .addr RESET ; 6502 RESET vector 000004r 2 rr rr .addr IRQ ; 6502 IRQ vector 000006r 2 000006r 1 000006r 1 .segment "BASICFILL" 000000r 1 AA AA AA AA FillCount $1e, $aa 000004r 1 AA AA AA AA 000008r 1 AA AA AA AA 00001Er 1 00001Er 1