diff --git a/compiler/examples/numbergame-c64.p8 b/compiler/examples/numbergame-c64.p8 index 2853b952d..8ce948e64 100644 --- a/compiler/examples/numbergame-c64.p8 +++ b/compiler/examples/numbergame-c64.p8 @@ -5,16 +5,17 @@ ~ main { sub start() { str name = "????????????????????????????????????????" - str guess = "??????????" + str guessstr = "??????????" + ubyte guess ubyte secretnumber = 0 ubyte attempts_left = 10 memory uword freadstr_arg = $22 ; argument for FREADSTR uword testword ; greeting - c64.VMCSB = %10111 ; switch lowercase chars + c64.VMCSB |= 2 ; switch lowercase chars c64.STROUT("Please introduce yourself: ") - Y = c64scr.input_chars(name) + c64scr.input_chars(name) c64.CHROUT('\n') c64.CHROUT('\n') c64.STROUT("Hello, ") @@ -28,7 +29,7 @@ c64.FADDH() ; add 0.5.. c64.FADDH() ; and again, so +1 total A, Y = c64flt.GETADRAY() - secretnumber = A + secretnumber = A ; secret number = rnd()*100+1 ask_guess: c64.STROUT("\nYou have ") @@ -37,17 +38,22 @@ ask_guess: if(attempts_left>0) c64.STROUT("es") c64.STROUT(" left.\nWhat is your next guess? ") - Y = c64scr.input_chars(guess) + c64scr.input_chars(guessstr) c64.CHROUT('\n') - freadstr_arg = guess - c64.FREADSTR(A) + freadstr_arg = guessstr + rsave() + c64.FREADSTR(Y) A, Y = c64flt.GETADRAY() - if(A==secretnumber) { + guess=A + rrestore() + c64.EXTCOL=guess ; @debug + c64.BGCOL0=secretnumber ;@debug + if(guess==secretnumber) { ; @todo equal_b doesn't work c64.STROUT("\nThat's my number, impressive!\n") goto goodbye } c64.STROUT("\nThat is too ") - if(A > secretnumber) + if(guess > secretnumber) ; @todo greater_ub doesn't work? c64.STROUT("low!\n") else c64.STROUT("high!\n") diff --git a/compiler/examples/numbergame-novm.p8 b/compiler/examples/numbergame-novm.p8 index 9fc26e9df..99e24b281 100644 --- a/compiler/examples/numbergame-novm.p8 +++ b/compiler/examples/numbergame-novm.p8 @@ -4,13 +4,13 @@ ~ main { sub start() { - str name = " " - str guess = "000000" + str name = "????????????????????????????????????????" + str guess = "??????????" ubyte secretnumber = rnd() % 100 - c64.VMCSB = %10111 ; switch lowercase chars + c64.VMCSB |= 2 ; switch lowercase chars c64scr.print_string("Please introduce yourself: ") - Y=c64scr.input_chars(name) + c64scr.input_chars(name) c64scr.print_string("\n\nHello, ") c64scr.print_string(name) c64scr.print_string(".\nLet's play a number guessing game.\nI am thinking of a number from 1 to 100!You'll have to guess it!\n") @@ -21,7 +21,7 @@ c64scr.print_string(" guess") if attempts_left>1 c64scr.print_string("es") c64scr.print_string(" left.\nWhat is your next guess? ") - Y=c64scr.input_chars(guess) + c64scr.input_chars(guess) ubyte guessednumber = str2ubyte(guess) if guessednumber==secretnumber { c64scr.print_string("\n\nYou guessed it, impressive!\n") diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index afd0479cd..a48daedd3 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -6,38 +6,227 @@ sub start() { - math.randseed($2ae4) + ubyte ub1 + ubyte ub2 + byte b1 + byte b2 + uword uw1 + uword uw2 + word w1 + word w2 + float f1 + float f2 - ubyte loop - c64scr.print_string("random bytes:\n") - for loop in 1 to 5 { - rsave() ; @todo automatic based on clobbers declaration - c64scr.print_byte_decimal(loop) - c64.CHROUT(':') - c64.CHROUT(' ') - ubyte ubr = rnd() - c64scr.print_byte_decimal(ubr) + + rsave() + ub1=100 + ub2=199 + c64.STROUT("ub1=100,ub2=199\n") + rrestore() + + if ub1==ub2 { + rsave() + c64.STROUT(" true: ub1==ub2\n") rrestore() - c64.CHROUT('\n') - } - c64scr.print_string("\nrandom words:\n") - for loop in 1 to 5 { - rsave() ; @todo automatic based on clobbers declaration - c64scr.print_byte_decimal(loop) - c64.CHROUT(':') - c64.CHROUT(' ') - uword uwr = rndw() - c64scr.print_word_decimal(uwr) + } else { + rsave() + c64.STROUT(" false: ub1==ub2\n") rrestore() - c64.CHROUT('\n') } - c64scr.print_string("\nrandom floats:\n") - for loop in 1 to 5 { - c64scr.print_byte_decimal(loop) - c64.CHROUT(':') - c64.CHROUT(' ') - float f = rndf() - c64flt.print_float_ln(f) + + if ub1!=ub2 { + rsave() + c64.STROUT(" true: ub1!=ub2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: ub1!=ub2\n") + rrestore() + } + + + rsave() + ub1=199 + ub2=199 + c64.STROUT("ub1=ub2=199\n") + rrestore() + + if ub1==ub2 { + rsave() + c64.STROUT(" true: ub1==ub2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: ub1==ub2\n") + rrestore() + } + + if ub1!=ub2 { + rsave() + c64.STROUT(" true: ub1!=ub2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: ub1!=ub2\n") + rrestore() + } + + rsave() + b1=50 + b2=111 + c64.STROUT("b1=50,b2=111\n") + rrestore() + + if b1==b2 { + rsave() + c64.STROUT(" true: b1==b2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: b1==b2\n") + rrestore() + } + + if b1!=b2 { + rsave() + c64.STROUT(" true: b1!=b2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: b1!=b2\n") + rrestore() + } + + + rsave() + b1=111 + b2=111 + c64.STROUT("b1=b2=111\n") + rrestore() + + if b1==b2 { + rsave() + c64.STROUT(" true: b1==b2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: b1==b2\n") + rrestore() + } + + if b1!=b2 { + rsave() + c64.STROUT(" true: b1!=b2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: b1!=b2\n") + rrestore() + } + + + rsave() + uw1=1234 + uw2=59999 + c64.STROUT("uw1=1234,uw2=59999\n") + rrestore() + + if uw1==uw2 { + rsave() + c64.STROUT(" true: uw1==uw2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: uw1==uw2\n") + rrestore() + } + + if uw1!=uw2 { + rsave() + c64.STROUT(" true: uw1!=uw2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: uw1!=uw2\n") + rrestore() + } + + rsave() + uw1=52999 + uw2=52999 + c64.STROUT("uw1=uw2=52999\n") + rrestore() + + if uw1==uw2 { + rsave() + c64.STROUT(" true: uw1==uw2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: uw1==uw2\n") + rrestore() + } + + if uw1!=uw2 { + rsave() + c64.STROUT(" true: uw1!=uw2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: uw1!=uw2\n") + rrestore() + } + + rsave() + w1=1234 + w2=-9999 + c64.STROUT("w1=1234, w2=-9999\n") + rrestore() + + if w1==w2 { + rsave() + c64.STROUT(" true: w1==w2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: w1==w2\n") + rrestore() + } + + if w1!=w2 { + rsave() + c64.STROUT(" true: w1!=w2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: w1!=w2\n") + rrestore() + } + + rsave() + w1=44 + w2=44 + c64.STROUT("w1=w2=44\n") + rrestore() + + if w1==w2 { + rsave() + c64.STROUT(" true: w1==w2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: w1==w2\n") + rrestore() + } + + if w1!=w2 { + rsave() + c64.STROUT(" true: w1!=w2\n") + rrestore() + } else { + rsave() + c64.STROUT(" false: w1!=w2\n") + rrestore() } } } diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 8554d3de4..65e976dde 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -156,10 +156,10 @@ fun main(args: Array) { if(startEmu) { println("\nStarting C64 emulator...") - val monitorfile = "$programname.mon_list" - val cmdline = listOf("x64", "-moncommands", monitorfile, + val cmdline = listOf("x64", "-moncommands", "$programname.vice-mon-list", "-autostartprgmode", "1", "-autostart-warp", "-autostart", programname+".prg") - ProcessBuilder(cmdline).inheritIO().start() + val process = ProcessBuilder(cmdline).inheritIO().start() + process.waitFor() } } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index d425ff3bb..c293fdcd1 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -2141,6 +2141,7 @@ internal fun unescape(str: String, position: Position): String { '\\' -> '\\' 'n' -> '\n' 'r' -> '\r' + '"' -> '"' 'u' -> { "${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}".toInt(16).toChar() } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 546bff02c..b3f8b5c31 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -297,6 +297,11 @@ class AstChecker(private val namespace: INameScope, if(subroutine.asmClobbers.intersect(regCounts.keys).isNotEmpty()) err("a return register is also in the clobber list") + } else { + // TODO: currently, non-asm subroutines can only take numeric arguments + if(!subroutine.parameters.all{it.type in NumericDatatypes}) { + err("non-asm subroutine can only take numerical parameters (no str/array types) for now") + } } return subroutine } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 0baed16b3..3b3dd2199 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -785,6 +785,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.EQUAL_BYTE -> " jsr prog8_lib.equal_b" Opcode.EQUAL_WORD -> " jsr prog8_lib.equal_w" Opcode.EQUAL_F -> " jsr prog8_lib.equal_f" + Opcode.NOTEQUAL_BYTE -> " jsr prog8_lib.notequal_b" + Opcode.NOTEQUAL_WORD -> " jsr prog8_lib.notequal_w" + Opcode.NOTEQUAL_F -> " jsr prog8_lib.notequal_f" Opcode.LESS_UB -> " jsr prog8_lib.less_ub" Opcode.LESS_B -> " jsr prog8_lib.less_b" @@ -1452,7 +1455,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // var = (u)wordarray[index_byte] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 " lda ${segment[1].callLabel}+$index | sta ${segment[2].callLabel} | lda ${segment[1].callLabel}+${index+1} | sta ${segment[2].callLabel}+1" }, // var = (u)wordarray[index var] @@ -1580,7 +1583,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // mem uword = (u)wordarray[indexvalue] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 """ lda ${segment[1].callLabel}+$index ldy ${segment[1].callLabel}+1+$index @@ -1675,7 +1678,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // ----------- assignment to UWORD ARRAY ---------------- // uwordarray[index] = (u)word value AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 + val index = intVal(segment[1])*2 val value = hexVal(segment[0]) """ lda #<$value @@ -1743,7 +1746,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // uwordarray[index] = ubytevar AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[2].arg!!.integerValue()*2 + val index = intVal(segment[2])*2 when(segment[0].callLabel) { "A" -> " sta ${segment[3].callLabel}+$index | lda #0 | sta ${segment[3].callLabel}+${index+1}" "X" -> " stx ${segment[3].callLabel}+$index | lda #0 | sta ${segment[3].callLabel}+${index+1}" @@ -1753,7 +1756,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // wordarray[index] = bytevar (extend sign) AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.B2WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[2].arg!!.integerValue()*2 + val index = intVal(segment[2])*2 when(segment[0].callLabel) { "A" -> """ @@ -1842,7 +1845,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // wordarray[index] = mem byte (extend sign) AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.B2WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[2].arg!!.integerValue()*2 + val index = intVal(segment[2])*2 """ lda ${hexVal(segment[0])} sta ${segment[3].callLabel}+$index @@ -1913,7 +1916,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // wordarray[index] = mem word AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 + val index = intVal(segment[1])*2 """ lda ${hexVal(segment[0])} sta ${segment[2].callLabel}+$index @@ -2019,7 +2022,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // uwordarray[index] = mem ubyte AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[2].arg!!.integerValue()*2 + val index = intVal(segment[2])*2 """ lda ${hexVal(segment[0])} sta ${segment[3].callLabel}+$index @@ -2029,17 +2032,17 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // uwordarray[index] = (u)wordvar AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 + val index = intVal(segment[1])*2 " lda ${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda ${segment[0].callLabel}+1 | sta ${segment[2].callLabel}+${index+1}" }, // uwordarray[index] = address-of var AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 + val index = intVal(segment[1])*2 " lda #<${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda #>${segment[0].callLabel} | sta ${segment[2].callLabel}+${index+1}" }, // uwordarray[index] = mem uword AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - val index = segment[1].arg!!.integerValue()*2 + val index = intVal(segment[1])*2 """ lda ${hexVal(segment[0])} ldy ${hexValPlusOne(segment[0])} @@ -2061,7 +2064,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // uwordarray2[index2] = (u)wordarray1[index1] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment-> val index1 = intVal(segment[0]) - val index2 = segment[2].arg!!.integerValue()*2 + val index2 = intVal(segment[2])*2 """ lda ${segment[1].callLabel}+$index1 ldy ${segment[1].callLabel}+${index1+1} @@ -2151,7 +2154,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // uwordarray2[indexvar] = uwordarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment-> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 val loadIndex2Y = when(segment[2].callLabel) { "A" -> " asl a | tay" "X" -> " txa | asl a | tay" @@ -2355,7 +2358,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // floatvar = wordarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.W2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 """ lda ${segment[1].callLabel}+$index ldy ${segment[1].callLabel}+${index+1} @@ -2368,7 +2371,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // floatvar = uwordarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.UW2FLOAT, Opcode.POP_VAR_FLOAT)) { segment-> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 """ lda ${segment[1].callLabel}+$index ldy ${segment[1].callLabel}+${index+1} @@ -2554,7 +2557,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // memfloat = wordarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.W2FLOAT, Opcode.POP_MEM_FLOAT)) { segment-> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 """ lda ${segment[1].callLabel}+$index ldy ${segment[1].callLabel}+${index+1} @@ -2567,7 +2570,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // memfloat = uwordarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.UW2FLOAT, Opcode.POP_MEM_FLOAT)) { segment-> - val index = segment[0].arg!!.integerValue()*2 + val index = intVal(segment[0])*2 """ lda ${segment[1].callLabel}+$index ldy ${segment[1].callLabel}+${index+1} @@ -2773,7 +2776,24 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGXY_WORD)) { segment -> TODO("$segment") + }, + + // push memory byte | bytevalue + AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE), + listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE)) { segment -> + " lda ${hexVal(segment[0])} | ora #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " + }, + // push memory byte & bytevalue + AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE), + listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE)) { segment -> + " lda ${hexVal(segment[0])} | and #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " + }, + // push memory byte ^ bytevalue + AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE), + listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment -> + " lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " } + ) } diff --git a/compiler/src/prog8/compiler/target/c64/Commodore64.kt b/compiler/src/prog8/compiler/target/c64/Commodore64.kt index 12ed53013..b024214f8 100644 --- a/compiler/src/prog8/compiler/target/c64/Commodore64.kt +++ b/compiler/src/prog8/compiler/target/c64/Commodore64.kt @@ -28,6 +28,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { companion object { const val SCRATCH_B1 = 0x02 const val SCRATCH_REG = 0x03 // temp storage for a register + const val SCRATCH_REG_X = 0x50 // temp storage for register X (the evaluation stack pointer) const val SCRATCH_W1 = 0xfb // $fb/$fc const val SCRATCH_W2 = 0xfd // $fd/$fe } @@ -36,6 +37,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { if(options.zeropage== ZeropageType.FULL) { free.addAll(0x04 .. 0xfa) free.add(0xff) + free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1+1, SCRATCH_W2, SCRATCH_W2+1)) free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ } else { if(options.zeropage== ZeropageType.KERNALSAFE) { @@ -43,18 +45,17 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { free.addAll(listOf(0x09, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x53, 0x6f, 0x70)) + 0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53, 0x6f, 0x70)) } - // add the Zp addresses not even used by BASIC + // add the other free Zp addresses // these are valid for the C-64 (when no RS232 I/O is performed): - // ($02, $03, $fb-$fc, $fd-$fe are reserved as scratch addresses for various routines) - // KNOWN WORKING FREE: 0x04, 0x05, 0x06, 0x2a, 0x52, 0xf7, 0xf8, 0xf9, 0xfa)) free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0d, 0x0e, - 0x12, 0x2a, 0x52, 0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa, + 0x51, 0x52, 0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa, 0xb5, 0xb6, 0xf7, 0xf8, 0xf9, 0xfa)) } assert(SCRATCH_B1 !in free) assert(SCRATCH_REG !in free) + assert(SCRATCH_REG_X !in free) assert(SCRATCH_W1 !in free) assert(SCRATCH_W2 !in free) diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index 376c0f3f5..d7c275340 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -536,7 +536,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position) else if(lv.type==DataType.BYTE && lv.bytevalue!!>=0) assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position) - else if(lv.type==DataType.WORD && lv.bytevalue!!>=0) + else if(lv.type==DataType.WORD && lv.wordvalue!!>=0) assignment.value = LiteralValue(DataType.UWORD, wordvalue = lv.asIntegerValue, position=lv.position) else if(lv.type==DataType.FLOAT) { val d = lv.floatvalue!! diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 480521384..14c6a22d5 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1126,14 +1126,14 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.EQUAL_BYTE -> { val (top, second) = evalstack.pop2() - checkDt(top, DataType.UBYTE) - checkDt(second, DataType.UBYTE) + checkDt(top, DataType.BYTE, DataType.UBYTE) + checkDt(second, DataType.BYTE, DataType.UBYTE) evalstack.push(Value(DataType.UBYTE, if (second == top) 1 else 0)) } Opcode.EQUAL_WORD -> { val (top, second) = evalstack.pop2() - checkDt(top, DataType.UWORD) - checkDt(second, DataType.UWORD) + checkDt(top, DataType.WORD, DataType.UWORD) + checkDt(second, DataType.WORD, DataType.UWORD) evalstack.push(Value(DataType.UBYTE, if (second == top) 1 else 0)) } Opcode.EQUAL_F -> { @@ -1144,14 +1144,14 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.NOTEQUAL_BYTE -> { val (top, second) = evalstack.pop2() - checkDt(top, DataType.UBYTE) - checkDt(second, DataType.UBYTE) + checkDt(top, DataType.BYTE, DataType.UBYTE) + checkDt(second, DataType.BYTE, DataType.UBYTE) evalstack.push(Value(DataType.UBYTE, if (second != top) 1 else 0)) } Opcode.NOTEQUAL_WORD -> { val (top, second) = evalstack.pop2() - checkDt(top, DataType.UWORD) - checkDt(second, DataType.UWORD) + checkDt(top, DataType.WORD, DataType.UWORD) + checkDt(second, DataType.UWORD, DataType.UWORD) evalstack.push(Value(DataType.UBYTE, if (second != top) 1 else 0)) } Opcode.NOTEQUAL_F -> { diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index fee285671..ab452c24e 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -154,17 +154,17 @@ class TestZeropage { @Test fun testFreeSpaces() { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(23, zp1.available()) + assertEquals(22, zp1.available()) val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true)) - assertEquals(71, zp2.available()) + assertEquals(70, zp2.available()) val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) - assertEquals(239, zp3.available()) + assertEquals(238, zp3.available()) } @Test fun testReservedSpace() { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) - assertEquals(239, zp1.available()) + assertEquals(238, zp1.available()) assertTrue(50 in zp1.free) assertTrue(100 in zp1.free) assertTrue(49 in zp1.free) @@ -187,7 +187,7 @@ class TestZeropage { @Test fun testBasicsafeAllocation() { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(23, zp.available()) + assertEquals(22, zp.available()) zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos)) assertFailsWith { @@ -211,17 +211,17 @@ class TestZeropage { @Test fun testFullAllocation() { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) - assertEquals(239, zp.available()) + assertEquals(238, zp.available()) val loc = zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos)) assertTrue(loc > 3) assertFalse(loc in zp.free) val num = zp.available() / 5 val rest = zp.available() % 5 - for(i in 0..num-4) { + for(i in 0..num-5) { zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos)) } - assertEquals(19,zp.available()) + assertEquals(23,zp.available()) assertFailsWith { // can't allocate because no more sequential bytes, only fragmented @@ -234,7 +234,9 @@ class TestZeropage { zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos)) zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos)) - assertEquals(1, zp.available()) + assertEquals(5, zp.available()) + zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos)) + zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos)) zp.allocate(VarDecl(VarDeclType.VAR, DataType.UBYTE, null, "", null, dummypos)) assertFailsWith { // no more space @@ -244,23 +246,18 @@ class TestZeropage { @Test fun testEfficientAllocation() { - // free = (0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0d, 0x0e, - // 0x12, 0x2a, 0x52, 0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa, - // 0xb5, 0xb6, 0xf7, 0xf8, 0xf9, 0xfa)) val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(23, zp.available()) + assertEquals(22, zp.available()) assertEquals(0x04, zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))) assertEquals(0x09, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UBYTE, null, "", null, dummypos))) - assertEquals(0x12, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UBYTE, null, "", null, dummypos))) assertEquals(0x0d, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) + assertEquals(0x51, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) assertEquals(0x94, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) - assertEquals(0x2a, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UBYTE, null, "", null, dummypos))) assertEquals(0xa7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) assertEquals(0xa9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) assertEquals(0xb5, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) assertEquals(0xf7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) assertEquals(0xf9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UWORD, null, "", null, dummypos))) - assertEquals(0x52, zp.allocate(VarDecl(VarDeclType.VAR, DataType.UBYTE, null, "", null, dummypos))) assertEquals(0, zp.available()) } } diff --git a/prog8lib/c64lib.p8 b/prog8lib/c64lib.p8 index 61177a8e8..393806f08 100644 --- a/prog8lib/c64lib.p8 +++ b/prog8lib/c64lib.p8 @@ -141,7 +141,7 @@ asmsub GIVAYF (lo: ubyte @ Y, hi: ubyte @ A) -> clobbers(A,X,Y) -> () = $b391 asmsub FREADUY (unsigned: ubyte @ Y) -> clobbers(A,X,Y) -> () = $b3a2 ; 8 bit unsigned Y -> float in fac1 asmsub FREADSA (signed: ubyte @ A) -> clobbers(A,X,Y) -> () = $bc3c ; 8 bit signed A -> float in fac1 asmsub FREADSTR (length: ubyte @ A) -> clobbers(A,X,Y) -> () = $b7b5 ; str -> fac1, $22/23 must point to string, A=string length -asmsub FPRINTLN () -> clobbers(A,X,Y) -> () = $aabc ; print string of fac1, on one line (= with newline) (consider FOUT + STROUT as well) +asmsub FPRINTLN () -> clobbers(A,X,Y) -> () = $aabc ; print string of fac1, on one line (= with newline) destroys fac1. (consider FOUT + STROUT as well) asmsub FOUT () -> clobbers(X) -> (uword @ AY) = $bddd ; fac1 -> string, address returned in AY ($0100) asmsub FADDH () -> clobbers(A,X,Y) -> () = $b849 ; fac1 += 0.5, for rounding- call this before INT diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index 03622f793..e2c8170b8 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -269,31 +269,72 @@ remainder_f .proc .warn "not implemented" .pend -equal_ub .proc - rts - .warn "not implemented" - .pend - + equal_b .proc + ; -- are the two bytes on the stack identical? + inx + lda ESTACK_LO,x + cmp ESTACK_LO+1,x + bne + + lda #1 + sta ESTACK_LO+1,x + rts ++ lda #0 + sta ESTACK_LO+1,x rts - .warn "not implemented" .pend equal_w .proc + ; -- are the two words on the stack identical? + inx + lda ESTACK_LO,x + cmp ESTACK_LO+1,x + bne + + lda ESTACK_HI,x + cmp ESTACK_HI+1,x + bne + + txa ; words are equal + sta ESTACK_LO+1,x rts - .warn "not implemented" - .pend - -equal_uw .proc ++ lda #0 ; words are not equal + sta ESTACK_LO+1,x rts - .warn "not implemented" .pend equal_f .proc rts .warn "not implemented" .pend + +notequal_b .proc + ; -- are the two bytes on the stack different? + inx + lda ESTACK_LO,x + eor ESTACK_LO+1,x + sta ESTACK_LO+1,x + rts + .pend + +notequal_w .proc + ; -- are the two words on the stack different? + inx + lda ESTACK_LO,x + eor ESTACK_LO+1,x + beq + + sta ESTACK_LO+1,x + rts ++ lda ESTACK_HI,x + eor ESTACK_HI+1,x + sta ESTACK_LO+1,x + rts + .pend +notequal_f .proc + rts + .warn "not implemented" + .pend + + less_ub .proc rts .warn "not implemented" @@ -345,8 +386,14 @@ lesseq_f .proc .pend greater_ub .proc + inx + lda ESTACK_LO,x + clc + sbc ESTACK_LO+1,x + lda #0 + adc #0 + sta ESTACK_LO+1,x rts - .warn "not implemented" .pend greater_b .proc