From f3c9be4e0617c9c817bd84cfaa47f6b021c15471 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 12 Jan 2019 14:55:57 +0100 Subject: [PATCH] float ++/-- and missing asm code handlers added --- compiler/res/prog8lib/c64flt.p8 | 37 +++++++++ compiler/src/prog8/compiler/Compiler.kt | 27 ++++--- .../src/prog8/compiler/intermediate/Opcode.kt | 2 - .../src/prog8/compiler/target/c64/AsmGen.kt | 74 +++++++----------- compiler/src/prog8/stackvm/StackVm.kt | 11 --- examples/test.p8 | 78 +++++++++---------- 6 files changed, 116 insertions(+), 113 deletions(-) diff --git a/compiler/res/prog8lib/c64flt.p8 b/compiler/res/prog8lib/c64flt.p8 index 0f9e9666f..dd9533dd8 100644 --- a/compiler/res/prog8lib/c64flt.p8 +++ b/compiler/res/prog8lib/c64flt.p8 @@ -490,6 +490,43 @@ dec_var_f .proc ldx c64.SCRATCH_ZPREGX rts .pend + +inc_indexed_var_f .proc + ; -- add 1 to float in array pointed to by A/Y, at index X + pha + txa + sta c64.SCRATCH_ZPB1 + asl a + asl a + clc + adc c64.SCRATCH_ZPB1 + sta c64.SCRATCH_ZPB1 + pla + clc + adc c64.SCRATCH_ZPB1 + bcc + + iny ++ jmp inc_var_f + .pend + +dec_indexed_var_f .proc + ; -- subtract 1 to float in array pointed to by A/Y, at index X + pha + txa + sta c64.SCRATCH_ZPB1 + asl a + asl a + clc + adc c64.SCRATCH_ZPB1 + sta c64.SCRATCH_ZPB1 + pla + clc + adc c64.SCRATCH_ZPB1 + bcc + + iny ++ jmp dec_var_f + .pend + pop_2_floats_f2_in_fac1 .proc ; -- pop 2 floats from stack, load the second one in FAC1 as well diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 15543ce93..473a47bd3 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -975,13 +975,17 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.POP_REGAX_WORD) } DataType.STR, DataType.STR_S -> { - pushStringAddress(arg.first, false) // TODO with or without remove last opcode?? + pushStringAddress(arg.first, false) prog.instr(Opcode.POP_REGAX_WORD) } DataType.FLOAT -> { pushFloatAddress(arg.first) prog.instr(Opcode.POP_REGAX_WORD) } + in ArrayDatatypes -> { + pushStringAddress(arg.first, false) + prog.instr(Opcode.POP_REGAX_WORD) + } else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition") } } @@ -1005,13 +1009,17 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.POP_REGAY_WORD) } DataType.STR, DataType.STR_S -> { - pushStringAddress(arg.first, false) // TODO with or without remove last opcode?? + pushStringAddress(arg.first, false) prog.instr(Opcode.POP_REGAY_WORD) } DataType.FLOAT -> { pushFloatAddress(arg.first) prog.instr(Opcode.POP_REGAY_WORD) } + in ArrayDatatypes -> { + pushStringAddress(arg.first, false) + prog.instr(Opcode.POP_REGAY_WORD) + } else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition") } } @@ -1039,13 +1047,17 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.POP_REGXY_WORD) } DataType.STR, DataType.STR_S -> { - pushStringAddress(arg.first, false) // TODO with or without remove last opcode?? + pushStringAddress(arg.first, false) prog.instr(Opcode.POP_REGXY_WORD) } DataType.FLOAT -> { pushFloatAddress(arg.first) prog.instr(Opcode.POP_REGXY_WORD) } + in ArrayDatatypes -> { + pushStringAddress(arg.first, false) + prog.instr(Opcode.POP_REGXY_WORD) + } else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition") } } @@ -1491,10 +1503,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun pushStringAddress(value: IExpression, removeLastOpcode: Boolean) { when (value) { - is LiteralValue -> { - if(removeLastOpcode) prog.removeLastInstruction() - prog.instr(Opcode.PUSH_ADDR_STR, Value(value.type, value.heapId!!)) - } + is LiteralValue -> throw CompilerException("can only push address of string that is a variable on the heap") is IdentifierReference -> { val vardecl = value.targetStatement(namespace) as VarDecl if(removeLastOpcode) prog.removeLastInstruction() @@ -1506,9 +1515,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun pushFloatAddress(value: IExpression) { when (value) { - is LiteralValue -> { - prog.instr(Opcode.PUSH_ADDR_FLOAT, Value(value.type, value.floatvalue!!)) - } + is LiteralValue -> throw CompilerException("can only push address of float that is a variable on the heap") is IdentifierReference -> { val vardecl = value.targetStatement(namespace) as VarDecl prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname) diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index a87443a62..ea6d1270c 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -18,8 +18,6 @@ enum class Opcode { PUSH_REGAX_WORD, // push registers A/X as a 16-bit word PUSH_REGAY_WORD, // push registers A/Y as a 16-bit word PUSH_REGXY_WORD, // push registers X/Y as a 16-bit word - PUSH_ADDR_STR, // push the address of the string value (literal) - PUSH_ADDR_FLOAT, // push the address of the float value (literal) PUSH_ADDR_HEAPVAR, // push the address of the variable that's on the heap (string or array) // popping values off the (evaluation) stack, possibly storing them in another location diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 06b2ed42e..dfe4a90b2 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -580,10 +580,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.PUSH_ADDR_HEAPVAR -> { " lda #<${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda #>${ins.callLabel} | sta ${ESTACK_HI.toHex()},x | dex" } - Opcode.PUSH_ADDR_FLOAT -> { - val varname = getFloatConst(ins.arg!!) - " lda #<$varname | sta ${ESTACK_LO.toHex()},x | lda #>$varname | sta ${ESTACK_HI.toHex()},x | dex" - } Opcode.POP_REGAX_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself") Opcode.POP_REGXY_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself") Opcode.POP_REGAY_WORD -> { @@ -1047,25 +1043,34 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8) Opcode.SHR_UBYTE -> AsmFragment(" lsr $variable+$index", 8) Opcode.SHR_SBYTE -> AsmFragment(" lda $variable+$index | asl a | ror $variable+$index") - Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+$index*2", 8) - Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+$index*2", 8) - Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index*2+1} | asl a | ror $variable+${index*2+1} | ror $variable+$index*2", 8) + Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+${index*2}", 8) + Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+${index*2}", 8) + Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index*2+1} | asl a | ror $variable+${index*2+1} | ror $variable+${index*2}", 8) Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8) Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8) - Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index*2+1} | rol $variable+$index*2", 8) - Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index*2+1} | ror $variable+$index*2", 8) + Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index*2+1} | rol $variable+${index*2}", 8) + Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index*2+1} | ror $variable+${index*2}", 8) Opcode.ROL2_BYTE -> AsmFragment(" lda $variable+$index | cmp #\$80 | rol $variable+$index", 8) Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10) - Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+$index*2 | bcc + | inc $variable+$index*2+1 |+",20) - Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+$index*2 | bcc + | lda $variable+${index*2+1} | ora #\$80 | sta $variable+${index*2+1} |+", 30) + Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index*2+1} | rol $variable+${index*2} | bcc + | inc $variable+${index*2+1} |+",20) + Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index*2+1} | ror $variable+${index*2} | bcc + | lda $variable+${index*2+1} | ora #\$80 | sta $variable+${index*2+1} |+", 30) Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" inc $variable+$index", 2) Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" dec $variable+$index", 5) - Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w") - Opcode.INC_INDEXED_VAR_UW -> TODO("inc array_uw") - Opcode.INC_INDEXED_VAR_FLOAT -> TODO("inc array_f") - Opcode.DEC_INDEXED_VAR_W -> TODO("dec array_w") - Opcode.DEC_INDEXED_VAR_UW -> TODO("dec array_uw") - Opcode.DEC_INDEXED_VAR_FLOAT -> TODO("dec array_f") + Opcode.INC_INDEXED_VAR_W, Opcode.INC_INDEXED_VAR_UW -> AsmFragment(" inc $variable+${index*2} | bne + | inc $variable+${index*2+1} |+") + Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_UW -> AsmFragment(" lda $variable+${index*2} | bne + | dec $variable+${index*2+1} |+ | dec $variable+${index*2}") + Opcode.INC_INDEXED_VAR_FLOAT -> AsmFragment( + """ + lda #<($variable+${index*Mflpt5.MemorySize}) + ldy #>($variable+${index*Mflpt5.MemorySize}) + jsr c64flt.inc_var_f + """) + Opcode.DEC_INDEXED_VAR_FLOAT -> AsmFragment( + """ + lda #<($variable+${index*Mflpt5.MemorySize}) + ldy #>($variable+${index*Mflpt5.MemorySize}) + jsr c64flt.dec_var_f + """) + else -> null } } @@ -1114,12 +1119,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.ROR2_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x | bcc + | lda $variable+1,x | ora #\$80 | sta $variable+1,x |+ $restoreX", 30) Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX inc $variable,x | tax", 10) Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" txa | $loadX dec $variable,x | tax", 10) - Opcode.INC_INDEXED_VAR_W -> TODO("inc array_w") - Opcode.INC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord inc $variable,x | bne + | inc $variable+1,x |+ $restoreX", 10) - Opcode.INC_INDEXED_VAR_FLOAT -> TODO("inc array_f") - Opcode.DEC_INDEXED_VAR_W -> TODO("dec array_w") - Opcode.DEC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord lda $variable,x | bne + | dec $variable+1,x |+ | dec $variable,x $restoreX", 10) - Opcode.DEC_INDEXED_VAR_FLOAT -> TODO("dec array_f") + Opcode.INC_INDEXED_VAR_W, Opcode.INC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord inc $variable,x | bne + | inc $variable+1,x |+ $restoreX", 10) + Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_UW -> AsmFragment("$saveX $loadXWord lda $variable,x | bne + | dec $variable+1,x |+ | dec $variable,x $restoreX", 10) + Opcode.INC_INDEXED_VAR_FLOAT -> AsmFragment(" lda #<$variable | ldy #>$variable | $saveX $loadX jsr c64flt.inc_indexed_var_f $restoreX") + Opcode.DEC_INDEXED_VAR_FLOAT -> AsmFragment(" lda #<$variable | ldy #>$variable | $saveX $loadX jsr c64flt.dec_indexed_var_f $restoreX") else -> null } @@ -2995,29 +2998,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_REGXY_WORD)) { segment -> " ldx #<${segment[0].callLabel} | ldy #>${segment[0].callLabel} " }, - // set a register pair to a certain memory address (of a floating point value) - AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGAX_WORD)) { segment -> - val varname=getFloatConst(segment[0].arg!!) - " lda #<$varname | ldx #>$varname " - }, - AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGAY_WORD)) { segment -> - val varname=getFloatConst(segment[0].arg!!) - " lda #<$varname | ldy #>$varname " - }, - AsmPattern(listOf(Opcode.PUSH_ADDR_FLOAT, Opcode.POP_REGXY_WORD)) { segment -> - val varname=getFloatConst(segment[0].arg!!) - " ldx #<$varname | ldy #>$varname " - }, - // set a register pair to a certain memory address (of a literal string value) - AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGAX_WORD)) { segment -> - TODO("$segment") - }, - AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGAY_WORD)) { segment -> - TODO("$segment") - }, - 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), @@ -3183,7 +3163,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ }, - // more efficient versions of x+1 and x-1 to avoid pushing the 1 on the stack @todo what about 1+x? reorder? + // more efficient versions of x+1 and x-1 to avoid pushing the 1 on the stack AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.ADD_B), listOf(Opcode.PUSH_BYTE, Opcode.ADD_UB)) { segment -> val amount = segment[0].arg!!.integerValue() if(amount in 1..2) { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index dc231ac91..4f26e2db4 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1497,17 +1497,6 @@ class StackVm(private var traceOutputFile: String?) { throw VmExecutionException("expected variable on heap") evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable (this is taken care of properly in the assembly code generator) } - Opcode.PUSH_ADDR_STR -> { - val heapId = ins.arg!!.heapId - if(heapId<0) - throw VmExecutionException("expected string to be on heap") - evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string (this is taken care of properly in the assembly code generator) - } - Opcode.PUSH_ADDR_FLOAT -> { - val floatvalue = ins.arg!! - checkDt(floatvalue, DataType.FLOAT) - evalstack.push(Value(DataType.UWORD, floatvalue.numericValue().toInt() and 65535)) // push the "address" of the floating point value (this is taken care of properly in the assembly code generator) - } Opcode.CAST_UB_TO_B -> typecast(DataType.UBYTE, DataType.BYTE) Opcode.CAST_W_TO_B -> typecast(DataType.WORD, DataType.BYTE) Opcode.CAST_UW_TO_B -> typecast(DataType.UWORD, DataType.BYTE) diff --git a/examples/test.p8 b/examples/test.p8 index 245b4b2f5..f2ab5f2ec 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,56 +1,48 @@ %import c64utils +%import c64flt ~ main { sub start() { - byte b - ubyte ub - memory ubyte mb = $c000 - memory uword muw = $c000 - word w - uword uw - uword[4] uwa + uword[4] uwa = 5 + ubyte[4] uba = 5 + word[4] wa = 5 + byte[4] ba = 5 + float[4] fa = 5.123 + str naam = "irmen" + float ff = 3.4444 - ub=%10001011 - for ubyte i in 0 to 10 { - c64scr.print_ubbin(1, ub) - rol2(ub) - c64.CHROUT('\n') - } - c64.CHROUT('\n') + uword addr - uw=%1000101100001110 - for ubyte i in 0 to 10 { - c64scr.print_uwbin(1, uw) - rol2(uw) - c64.CHROUT('\n') - } - c64.CHROUT('\n') + addr = naam + addr = uwa + addr = fa - muw=%1000101100001110 - for ubyte i in 0 to 10 { - c64scr.print_uwbin(1, muw) - rol2(muw) - c64.CHROUT('\n') - } - c64.CHROUT('\n') + pairAX(naam) + pairAX("hello") + pairAX("hello2") + pairAX("hello2") + pairAX("hello2") + pairAY("hello2") + pairAY("hello2") + pairXY("hello2") + pairXY("hello2") + pairAX(uwa) + pairAX(fa) + pairAY(naam) + pairAY(uwa) + pairAY(fa) + pairXY(naam) + pairXY(uwa) + pairXY(fa) - ubyte x=2 - uwa[x]=%1000101100001110 - for ubyte i in 0 to 10 { - c64scr.print_uwbin(1, uwa[x]) - rol2(uwa[x]) - c64.CHROUT('\n') - } - c64.CHROUT('\n') + } - uwa[2]=%1000101100001110 - for ubyte i in 0 to 10 { - c64scr.print_uwbin(1, uwa[2]) - rol2(uwa[2]) ; @todo wrong - c64.CHROUT('\n') - } - c64.CHROUT('\n') + asmsub pairAX(uword address @ AX) -> clobbers() -> () { + } + asmsub pairAY(uword address @ AY) -> clobbers() -> () { + } + asmsub pairXY(uword address @ XY) -> clobbers() -> () { } }