diff --git a/compiler/res/prog8lib/c64/floats.asm b/compiler/res/prog8lib/c64/floats.asm index 4b8ce24c5..81045ea06 100644 --- a/compiler/res/prog8lib/c64/floats.asm +++ b/compiler/res/prog8lib/c64/floats.asm @@ -573,6 +573,18 @@ func_ceil .proc + jmp push_fac1_as_result .pend +func_any_f_into_A .proc + jsr func_any_f +_popA inx + lda P8ESTACK_LO,x + rts + .pend + +func_all_f_into_A .proc + jsr func_all_f + jmp func_any_f_into_A._popA + .pend + func_any_f .proc inx lda P8ESTACK_LO,x ; array size diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index 29802bb58..3a0a0b0ac 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -702,6 +702,10 @@ func_read_flags .proc rts .pend +func_sqrt16_into_A .proc + jsr func_sqrt16 + jmp func_any_b_into_A._popA + .pend func_sqrt16 .proc ; TODO is this one faster? http://6502org.wikidot.com/software-math-sqrt @@ -754,6 +758,78 @@ _stab .byte $01,$02,$04,$08,$10,$20,$40,$80 .pend +func_sin8_into_A .proc + inx + ldy P8ESTACK_LO,x + lda func_sin8._sinecos8,y + rts + .pend + +func_sin8u_into_A .proc + inx + ldy P8ESTACK_LO,x + lda func_sin8u._sinecos8u,y + rts + .pend + +func_sin16_into_AY .proc + inx + ldy P8ESTACK_LO,x + lda func_sin16._sinecos8lo,y + pha + lda func_sin16._sinecos8hi,y + tay + pla + rts + .pend + +func_sin16u_into_AY .proc + inx + ldy P8ESTACK_LO,x + lda func_sin16u._sinecos8ulo,y + pha + lda func_sin16u._sinecos8uhi,y + tay + pla + rts + .pend + +func_cos8_into_A .proc + inx + ldy P8ESTACK_LO,x + lda func_sin8._sinecos8+64,y + rts + .pend + +func_cos8u_into_A .proc + inx + ldy P8ESTACK_LO,x + lda func_sin8u._sinecos8u+64,y + rts + .pend + +func_cos16_into_AY .proc + inx + ldy P8ESTACK_LO,x + lda func_sin16._sinecos8lo+64,y + pha + lda func_sin16._sinecos8hi+64,y + tay + pla + rts + .pend + +func_cos16u_into_AY .proc + inx + ldy P8ESTACK_LO,x + lda func_sin16u._sinecos8ulo+64,y + pha + lda func_sin16u._sinecos8uhi+64,y + tay + pla + rts + .pend + func_sin8 .proc ldy P8ESTACK_LO+1,x lda _sinecos8,y @@ -838,6 +914,29 @@ peek_address .proc rts .pend +func_any_b_into_A .proc + jsr func_any_b +_popA inx + lda P8ESTACK_LO,x + rts + .pend + +func_all_b_into_A .proc + jsr func_all_b + jmp func_any_b_into_A._popA + .pend + +func_any_w_into_A .proc + jsr func_any_w + jmp func_any_b_into_A._popA + .pend + +func_all_w_into_A .proc + jsr func_all_w + jmp func_any_b_into_A._popA + .pend + + func_any_b .proc inx lda P8ESTACK_LO,x ; array size @@ -1103,6 +1202,72 @@ pop_array_and_lengthmin1Y .proc rts .pend +func_min_ub_into_A .proc + jsr func_min_ub +_popA inx + lda P8ESTACK_LO,x + rts + .pend + +func_min_b_into_A .proc + jsr func_min_b + jmp func_min_ub_into_A._popA + .pend + +func_max_ub_into_A .proc + jsr func_max_ub + jmp func_min_ub_into_A._popA + .pend + +func_max_b_into_A .proc + jsr func_max_b + jmp func_min_ub_into_A._popA + .pend + +func_sum_ub_into_AY .proc + jsr func_sum_ub +_popAY inx + lda P8ESTACK_LO,x + ldy P8ESTACK_HI,x + rts + .pend + +func_sum_b_into_AY .proc + jsr func_sum_b + jmp func_sum_ub_into_AY._popAY + .pend + +func_min_uw_into_AY .proc + jsr func_min_uw + jmp func_sum_ub_into_AY._popAY + .pend + +func_min_w_into_AY .proc + jsr func_min_w + jmp func_sum_ub_into_AY._popAY + .pend + +func_max_uw_into_AY .proc + jsr func_max_uw + jmp func_sum_ub_into_AY._popAY + .pend + +func_max_w_into_AY .proc + jsr func_max_w + jmp func_sum_ub_into_AY._popAY + .pend + +func_sum_uw_into_AY .proc + jsr func_sum_uw + jmp func_sum_ub_into_AY._popAY + .pend + +func_sum_w_into_AY .proc + jsr func_sum_w + jmp func_sum_ub_into_AY._popAY + .pend + + func_min_ub .proc jsr pop_array_and_lengthmin1Y lda #255 @@ -2165,5 +2330,6 @@ func_strcmp .proc lda P8ESTACK_LO+1,x jsr strcmp_mem sta P8ESTACK_LO+1,x + ; make sure A contains the result value as well rts .pend diff --git a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt index 52e1eba04..b1f99f336 100644 --- a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt +++ b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt @@ -263,7 +263,6 @@ private class AsmSubroutineParameter(name: String, type: DataType, val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?, - // TODO implement: val stack: Boolean, position: Position) : SubroutineParameter(name, type, position) private class AsmSubroutineReturn(val type: DataType, diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 16562df77..9b46299bb 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -44,7 +44,7 @@ class BuiltinFunctionStatementPlaceholder(val name: String, override val positio } } -data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?, val stack: Boolean) +data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?, val stack: Boolean) // TODO get rid of stack? class Block(override val name: String, val address: Int?, diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 9c3749939..bad1fc1f4 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -550,23 +550,20 @@ internal class AsmGen(private val program: Program, private fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names - internal fun saveRegister(register: CpuRegister, dontUseStack: Boolean, scope: Subroutine?) { + internal fun saveRegister(register: CpuRegister, dontUseStack: Boolean, scope: Subroutine) { if(dontUseStack) { when (register) { CpuRegister.A -> { out(" sta _prog8_regsaveA") - if (scope != null) - scope.asmGenInfo.usedRegsaveA = true + scope.asmGenInfo.usedRegsaveA = true } CpuRegister.X -> { out(" stx _prog8_regsaveX") - if (scope != null) - scope.asmGenInfo.usedRegsaveX = true + scope.asmGenInfo.usedRegsaveX = true } CpuRegister.Y -> { out(" sty _prog8_regsaveY") - if (scope != null) - scope.asmGenInfo.usedRegsaveY = true + scope.asmGenInfo.usedRegsaveY = true } } @@ -577,16 +574,14 @@ internal class AsmGen(private val program: Program, if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx") else { out(" stx _prog8_regsaveX") - if (scope != null) - scope.asmGenInfo.usedRegsaveX = true + scope.asmGenInfo.usedRegsaveX = true } } CpuRegister.Y -> { if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy") else { out(" sty _prog8_regsaveY") - if (scope != null) - scope.asmGenInfo.usedRegsaveY = true + scope.asmGenInfo.usedRegsaveY = true } } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 103fb1225..5c53d8b3d 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -36,18 +36,21 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val when (functionName) { "msb" -> funcMsb(fcall, resultToStack) "lsb" -> funcLsb(fcall, resultToStack) - // TODO THE OTHERS -// "mkword" -> funcMkword(fcall, func) // TODO resultToStack + "mkword" -> funcMkword(fcall, resultToStack) "abs" -> funcAbs(fcall, func, resultToStack) "swap" -> funcSwap(fcall) -// "strlen" -> funcStrlen(fcall) // TODO resultToStack -// "min", "max", "sum" -> funcMinMaxSum(fcall, functionName) // TODO resultToStack -// "any", "all" -> funcAnyAll(fcall, functionName) // TODO resultToStack + "min", "max" -> funcMinMax(fcall, functionName, resultToStack) + "sum" -> funcSum(fcall, resultToStack) + "any", "all" -> funcAnyAll(fcall, functionName, resultToStack) + "sin8", "sin8u", "sin16", "sin16u", + "cos8", "cos8u", "cos16", "cos16u" -> funcSinCosInt(fcall, func, functionName, resultToStack) "sgn" -> funcSgn(fcall, func, resultToStack) "sin", "cos", "tan", "atan", "ln", "log2", "sqrt", "rad", "deg", "round", "floor", "ceil", -// "rdnf" -> funcVariousFloatFuncs(fcall, func, functionName) // TODO resultToStack + "rdnf" -> funcVariousFloatFuncs(fcall, func, functionName, resultToStack) + "rnd", "rndw" -> funcRnd(functionName, resultToStack) + "sqrt16" -> funcSqrt16(fcall, func, resultToStack) "rol" -> funcRol(fcall) "rol2" -> funcRol2(fcall) "ror" -> funcRor(fcall) @@ -63,22 +66,55 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val // restore all registers and cpu status flag asmgen.out(" pla | tay | pla | tax | pla | plp") } + "read_flags" -> { + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_read_flags") + else + asmgen.out(" php | pla") + } "clear_carry" -> asmgen.out(" clc") "set_carry" -> asmgen.out(" sec") "clear_irqd" -> asmgen.out(" cli") "set_irqd" -> asmgen.out(" sei") - else -> { + "strlen" -> funcStrlen(fcall, resultToStack) + "strcmp" -> funcStrcmp(fcall, func, resultToStack) + "substr", "leftstr", "rightstr", + "memcopy", "memset", "memsetw" -> { translateArguments(fcall.args, func) - if(resultToStack) { - asmgen.out(" jsr prog8_lib.func_$functionName") - } else { - TODO("builtin function $fcall") - // TODO call function that puts result in registers, not on stack - } + asmgen.out(" jsr prog8_lib.func_$functionName") } + "exit" -> asmgen.out(" jmp prog8_lib.func_exit") + else -> TODO("missing asmgen for builtin func $functionName") } } + private fun funcStrcmp(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean) { + translateArguments(fcall.args, func) + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_strcmp") + else + asmgen.out(" jsr prog8_lib.func_strcmp | inx") // result is also in register A + } + + private fun funcSqrt16(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean) { + translateArguments(fcall.args, func) + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_sqrt16") + else + asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") + } + + private fun funcSinCosInt(fcall: IFunctionCall, func: FSignature, functionName: String, resultToStack: Boolean) { + translateArguments(fcall.args, func) + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_$functionName") + else + when(functionName) { + "sin8", "sin8u", "cos8", "cos8u" -> asmgen.out(" jsr prog8_lib.func_${functionName}_into_A") + "sin16", "sin16u", "cos16", "cos16u" -> asmgen.out(" jsr prog8_lib.func_${functionName}_into_AY") + } + } + private fun funcReverse(fcall: IFunctionCall) { val variable = fcall.args.single() if (variable is IdentifierReference) { @@ -351,9 +387,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } - private fun funcVariousFloatFuncs(fcall: IFunctionCall, func: FSignature, functionName: String) { + private fun funcVariousFloatFuncs(fcall: IFunctionCall, func: FSignature, functionName: String, resultToStack: Boolean) { translateArguments(fcall.args, func) - asmgen.out(" jsr floats.func_$functionName") + if(resultToStack) { + asmgen.out(" jsr floats.func_$functionName") + } else { + TODO("float func result via registers $functionName") + } } private fun funcSgn(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean) { @@ -380,46 +420,88 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } - private fun funcAnyAll(fcall: IFunctionCall, functionName: String) { + private fun funcAnyAll(fcall: IFunctionCall, functionName: String, resultToStack: Boolean) { outputPushAddressAndLenghtOfArray(fcall.args[0]) val dt = fcall.args.single().inferType(program) - when (dt.typeOrElse(DataType.STRUCT)) { - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_b") - DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${functionName}_f") - else -> throw AssemblyError("weird type $dt") + if(resultToStack) { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_b") + DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${functionName}_f") + else -> throw AssemblyError("weird type $dt") + } + } else { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_b_into_A") + DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w_into_A") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${functionName}_f_into_A") + else -> throw AssemblyError("weird type $dt") + } } } - private fun funcMinMaxSum(fcall: IFunctionCall, functionName: String) { + private fun funcMinMax(fcall: IFunctionCall, functionName: String, resultToStack: Boolean) { outputPushAddressAndLenghtOfArray(fcall.args[0]) val dt = fcall.args.single().inferType(program) - when (dt.typeOrElse(DataType.STRUCT)) { - DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_ub") - DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${functionName}_b") - DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${functionName}_uw") - DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${functionName}_f") - else -> throw AssemblyError("weird type $dt") + if(resultToStack) { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_ub") + DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${functionName}_b") + DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${functionName}_uw") + DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${functionName}_f") + else -> throw AssemblyError("weird type $dt") + } + } else { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${functionName}_ub_into_A") + DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${functionName}_b_into_A") + DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${functionName}_uw_into_AY") + DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${functionName}_w_into_AY") + DataType.ARRAY_F -> TODO("min/max of floats result in float via registers") + else -> throw AssemblyError("weird type $dt") + } } } - private fun funcStrlen(fcall: IFunctionCall) { + private fun funcSum(fcall: IFunctionCall, resultToStack: Boolean) { + outputPushAddressAndLenghtOfArray(fcall.args[0]) + val dt = fcall.args.single().inferType(program) + if(resultToStack) { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_sum_ub") + DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_sum_b") + DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_sum_uw") + DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_sum_w") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_sum_f") + else -> throw AssemblyError("weird type $dt") + } + } else { + when (dt.typeOrElse(DataType.STRUCT)) { + DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_sum_ub_into_AY") + DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_sum_b_into_AY") + DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_sum_uw_into_AY") + DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_sum_w_into_AY") + DataType.ARRAY_F -> TODO("sum of floats result in float via registers") + else -> throw AssemblyError("weird type $dt") + } + } + } + + private fun funcStrlen(fcall: IFunctionCall, resultToStack: Boolean) { val name = asmgen.asmVariableName(fcall.args[0] as IdentifierReference) val type = fcall.args[0].inferType(program) when { - type.istype(DataType.STR) -> asmgen.out(""" - lda #<$name - ldy #>$name - jsr prog8_lib.strlen - sta P8ESTACK_LO,x - dex""") - type.istype(DataType.UWORD) -> asmgen.out(""" - lda $name - ldy $name+1 - jsr prog8_lib.strlen - sta P8ESTACK_LO,x - dex""") + type.istype(DataType.STR) -> { + asmgen.out(" lda #<$name | ldy #>$name | jsr prog8_lib.strlen") + if(resultToStack) + asmgen.out(" sta P8ESTACK_LO,x | dex") + } + type.istype(DataType.UWORD) -> { + asmgen.out(" lda $name | ldy $name+1 | jsr prog8_lib.strlen") + if(resultToStack) + asmgen.out(" sta P8ESTACK_LO,x | dex") + } else -> throw AssemblyError("strlen requires str or uword arg") } } @@ -795,11 +877,37 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } - private fun funcMkword(fcall: IFunctionCall, func: FSignature) { - // trick: push the args in reverse order (msb first, lsb second) this saves some instructions - asmgen.translateExpression(fcall.args[1]) - asmgen.translateExpression(fcall.args[0]) - asmgen.out(" inx | lda P8ESTACK_LO,x | sta P8ESTACK_HI+1,x") + private fun funcRnd(functionName: String, resultToStack: Boolean) { + when(functionName) { + "rnd" -> { + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_rnd") + else + asmgen.out(" jsr math.randbyte") + } + "rndw" -> { + if(resultToStack) + asmgen.out(" jsr prog8_lib.func_rndw") + else + asmgen.out(" jsr math.randword") + } + else -> throw AssemblyError("wrong func") + } + } + + private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean) { + if(resultToStack) { + // trick: push the args in reverse order (lsb first, msb second) this saves some instructions + asmgen.translateExpression(fcall.args[1]) + asmgen.translateExpression(fcall.args[0]) + asmgen.out(" inx | lda P8ESTACK_LO,x | sta P8ESTACK_HI+1,x") + } else { + // TODO some args without stack usage... + // trick: push the args in reverse order (lsb first, msb second) this saves some instructions + asmgen.translateExpression(fcall.args[1]) + asmgen.translateExpression(fcall.args[0]) + asmgen.out(" inx | ldy P8ESTACK_LO,x | inx | lda P8ESTACK_LO,x") + } } private fun funcMsb(fcall: IFunctionCall, resultToStack: Boolean) { @@ -814,9 +922,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val if(resultToStack) asmgen.out(" sta P8ESTACK_LO,x | dex") } else { - TODO("msb from non-identifier expression $arg") -// asmgen.translateExpression(arg) -// asmgen.out(" lda P8ESTACK_HI+1,x | sta P8ESTACK_LO+1,x") + asmgen.translateExpression(arg) // TODO this evalutes onto stack, use registers instead + if(resultToStack) + asmgen.out(" lda P8ESTACK_HI+1,x | sta P8ESTACK_LO+1,x") + else + asmgen.out(" inx | lda P8ESTACK_HI,x") } } @@ -832,9 +942,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val if(resultToStack) asmgen.out(" sta P8ESTACK_LO,x | dex") } else { - TODO("lsb from non-identifier expression $arg") -// asmgen.translateExpression(arg) - // just ignore any high-byte + // TODO this evalutes onto stack, use registers instead + asmgen.translateExpression(arg) + if(resultToStack) { + // simply ignore the high-byte of what's on the stack now + } else { + asmgen.out(" inx | lda P8ESTACK_LO,x") + } } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 5897eaa4a..a1663e5c6 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -1687,7 +1687,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } private fun translateCompareStrings(operator: String) { - asmgen.out(" jsr prog8_lib.func_strcmp | lda P8ESTACK_LO+1,x") // result of compare in A + asmgen.out(" jsr prog8_lib.func_strcmp") // result of compare is on stack but also in A when(operator) { "==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO+1,x") "!=" -> asmgen.out(" and #1 | sta P8ESTACK_LO+1,x") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 1abb3699b..8ae4d56c3 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -37,7 +37,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam() if(saveX) - asmgen.saveRegister(CpuRegister.X, preserveStatusRegisterAfterCall, (stmt as Node).definingSubroutine()) + asmgen.saveRegister(CpuRegister.X, preserveStatusRegisterAfterCall, (stmt as Node).definingSubroutine()!!) val subName = asmgen.asmSymbolName(stmt.target) if(stmt.args.isNotEmpty()) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt index b3142c227..4ed1f6258 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt @@ -97,7 +97,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg else { asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.A) - asmgen.saveRegister(CpuRegister.X, false, scope) + asmgen.saveRegister(CpuRegister.X, false, scope!!) asmgen.out(" tax") when(elementDt) { in ByteDatatypes -> { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index 9e69f1026..c3595f58a 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -130,14 +130,18 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen is Subroutine -> { val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any { it.statusflag != null } asmgen.translateFunctionCall(value, preserveStatusRegisterAfterCall) - when ((sub.asmReturnvaluesRegisters.single { it.registerOrPair != null }).registerOrPair) { - RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A) - RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X) - RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y) - RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX) - RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) - RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY) - else -> throw AssemblyError("should be just one register byte result value") + if(sub.returntypes.single()==DataType.STR) { + TODO("assignment of string => copy string ${assign.position}") + } else { + when ((sub.asmReturnvaluesRegisters.single { it.registerOrPair != null }).registerOrPair) { + RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A) + RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X) + RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y) + RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX) + RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) + RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY) + else -> throw AssemblyError("should be just one register byte result value") + } } if (preserveStatusRegisterAfterCall) asmgen.out(" plp\t; restore status flags from call") @@ -151,6 +155,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen when(returntype.typeOrElse(DataType.STRUCT)) { in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY + DataType.STR -> TODO("assign string => copy string") DataType.FLOAT -> TODO("assign float result from ${sub.name}") else -> throw AssemblyError("weird result type") } @@ -775,10 +780,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } private fun assignRegisterpairWord(target: AsmAssignTarget, regs: RegisterOrPair) { - require(target.datatype in NumericDatatypes) + require(target.datatype in NumericDatatypes) { + "zzz" + } if(target.datatype==DataType.FLOAT) { if (regs == RegisterOrPair.AY) { - asmgen.out(" brk ; TODO FLOAT RETURN VALUE") // TODO + asmgen.out(" brk ; TODO FLOAT RETURN VALUE") // TODO float value via registers return } else throw AssemblyError("float reaturn value should be via AY return pointer") @@ -793,7 +800,20 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } TargetStorageKind.ARRAY -> { - TODO("store register pair $regs into word-array ${target.array}") + // TODO can be a bit more optimized if the array indexer is a number + when(regs) { + RegisterOrPair.AX -> asmgen.out(" pha | txa | pha") + RegisterOrPair.AY -> asmgen.out(" pha | tya | pha") + RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha") + else -> throw AssemblyError("expected reg pair") + } + asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true) + asmgen.out(""" + pla + sta ${target.asmVarname},y + dey + pla + sta ${target.asmVarname},y""") } TargetStorageKind.REGISTER -> { when(regs) { @@ -1190,7 +1210,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.storeByteIntoPointer(addressExpr, null) } else -> { - asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()) + asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!) asmgen.translateExpression(addressExpr) asmgen.restoreRegister(CpuRegister.A, false) asmgen.out(""" diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 76fa36af9..aac13bc65 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -136,13 +136,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } DataType.FLOAT -> { when { - valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble(), target.scope) - ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident, target.scope) + valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble(), target.scope!!) + ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident, target.scope!!) value is TypecastExpression -> { if (tryRemoveRedundantCast(value, target, operator)) return - inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope) + inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope!!) } - else -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope) + else -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope!!) } } else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") @@ -1295,7 +1295,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.out(" inx") } - private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine?) { + private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) { // this should be the last resort for code generation for this, // because the value is evaluated onto the eval stack (=slow). if(asmgen.options.slowCodegenWarnings) @@ -1350,7 +1350,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.restoreRegister(CpuRegister.X, false) } - private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine?) { + private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine) { val valueDt = ident.targetVarDecl(program.namespace)!!.datatype if(valueDt != DataType.FLOAT) throw AssemblyError("float variable expected") @@ -1419,7 +1419,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.restoreRegister(CpuRegister.X, false) } - private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine?) { + private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine) { val constValueName = asmgen.getFloatAsmConst(value) asmgen.saveRegister(CpuRegister.X, false, scope) when (operator) { diff --git a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt index fae0af264..6572150e0 100644 --- a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt @@ -617,8 +617,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() if (amount >= 16) { return NumericLiteralValue(targetDt, 0, expr.position) } else if (amount >= 8) { - // TODO is this correct??? - val lsb = TypecastExpression(expr.left, DataType.UBYTE, true, expr.position) + val lsb = FunctionCall(IdentifierReference(listOf("lsb"), expr.position), mutableListOf(expr.left), expr.position) if (amount == 8) { return FunctionCall(IdentifierReference(listOf("mkword"), expr.position), mutableListOf(lsb, NumericLiteralValue.optimalInteger(0, expr.position)), expr.position) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 9eb01103a..a4b7defdb 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -6,7 +6,7 @@ TODO - make memset(w) and memcopy able to work with >256 bytes - make memset and memcopy use the ROM routines on the CX16 - calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines) -- get rid of @stack in asmsub altogether (because all subroutines are no longer using this calling convention anymore) +- get rid of @stack in asmsub (syntax, ast) altogether (because all subroutines are no longer using this calling convention anymore) - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - see if we can group some errors together for instance the (now single) errors about unidentified symbols diff --git a/examples/plasma.p8 b/examples/plasma.p8 index 81d9dc0ed..2e8547679 100644 --- a/examples/plasma.p8 +++ b/examples/plasma.p8 @@ -9,6 +9,8 @@ ; Converted to prog8 by Irmen de Jong. +; TODO why is the output of this larger with the register-eval stuff than before with the stack eval stuff? + main { const uword SCREEN1 = $E000 const uword SCREEN2 = $E400 diff --git a/examples/test.p8 b/examples/test.p8 index d49f9129a..aaa1e464a 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -11,50 +11,37 @@ main { sub start() { - byte bb - word ww - bb = 0 - bb = sgn(bb) - txt.print_b(bb) - txt.chrout('\n') - bb = 127 - bb = sgn(bb) - txt.print_b(bb) - txt.chrout('\n') - bb = -1 - bb = sgn(bb) - txt.print_b(bb) - txt.chrout('\n') - bb = -127 - bb = sgn(bb) - txt.print_b(bb) - txt.chrout('\n') - bb = -128 - bb = sgn(bb) - txt.print_b(bb) - txt.chrout('\n') + uword ss + + ss = %1000000110101010 + ss <<= 8 + txt.print_uwbin(ss, 1) txt.chrout('\n') - ww = 0 - ww = sgn(ww) - txt.print_w(ww) + ss = %1000000110101111 + ss <<= 9 + txt.print_uwbin(ss, 1) txt.chrout('\n') - ww = 32767 - ww = sgn(ww) - txt.print_w(ww) + + ss = %1000000110101111 + ss <<= 14 + txt.print_uwbin(ss, 1) txt.chrout('\n') - ww = -1 - ww = sgn(ww) - txt.print_w(ww) + + ss = %1000000110101111 + ss <<= 15 + txt.print_uwbin(ss, 1) txt.chrout('\n') - ww = -32767 - ww = sgn(ww) - txt.print_w(ww) + + ss = %1000000110101111 + ss <<= 16 + txt.print_uwbin(ss, 1) txt.chrout('\n') - ww = -32768 - ww = sgn(ww) - txt.print_w(ww) + + ss = %1000000110101010 + ss <<= 17 + txt.print_uwbin(ss, 1) txt.chrout('\n') main22.testX() @@ -87,7 +74,7 @@ main22 { txt.chrout('\n') void getstr() - ssss = getstr() + ; TODO string assign ssss = getstr() txt.print_uwhex(ssss, true) txt.chrout('\n')