diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index c046cac34..f23fd5510 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -790,7 +790,7 @@ data class AssignTarget(val register: Register?, fun shortString(withTypePrefix: Boolean=false): String { if(register!=null) - return (if(withTypePrefix) "0register::" else "") + register.toString() + return (if(withTypePrefix) "0register::" else "") + register.name if(identifier!=null) return (if(withTypePrefix) "3identifier::" else "") + identifier.nameInSource.last() if(arrayindexed!=null) diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 0ddffaec9..3feb1b770 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -1137,9 +1137,9 @@ private class AstChecker(private val namespace: INameScope, checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position)) } else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes) - checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)) + checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.name.toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)) else - checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position)) + checkResult.add(ExpressionError("cannot assign ${sourceDatatype.name.toLowerCase()} to ${targetDatatype.name.toLowerCase()}", position)) return false } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 9c35ec270..37237ef6b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -615,7 +615,7 @@ internal class Compiler(private val rootModule: Module, private fun translate(expr: IExpression) { when(expr) { is RegisterExpr -> { - prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = expr.register.toString()) + prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = expr.register.name) } is PrefixExpression -> { translate(expr.expression) @@ -645,7 +645,7 @@ internal class Compiler(private val rootModule: Module, if(target is BuiltinFunctionStatementPlaceholder) { // call to a builtin function (some will just be an opcode!) val funcname = expr.target.nameInSource[0] - translateFunctionCall(funcname, expr.arglist) + translateBuiltinFunctionCall(funcname, expr.arglist) } else { when(target) { is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.position) @@ -761,7 +761,7 @@ internal class Compiler(private val rootModule: Module, val targetStmt = stmt.target.targetStatement(namespace)!! if(targetStmt is BuiltinFunctionStatementPlaceholder) { val funcname = stmt.target.nameInSource[0] - translateFunctionCall(funcname, stmt.arglist) + translateBuiltinFunctionCall(funcname, stmt.arglist) return } @@ -771,20 +771,18 @@ internal class Compiler(private val rootModule: Module, is Subroutine -> { translateSubroutineCall(targetStmt, stmt.arglist, stmt.position) // make sure we clean up the unused result values from the stack - // only if they're non-register return values! - if(targetStmt.asmReturnvaluesRegisters.isEmpty()) - for(rv in targetStmt.returntypes) { - val opcode=opcodeDiscard(rv) - prog.instr(opcode) - } + for(rv in targetStmt.returntypes) { + val opcode=opcodeDiscard(rv) + prog.instr(opcode) + } } else -> throw AstException("invalid call target node type: ${targetStmt::class}") } } - private fun translateFunctionCall(funcname: String, args: List) { - // some functions are implemented as vm opcodes + private fun translateBuiltinFunctionCall(funcname: String, args: List) { + // some builtin functions are implemented directly as vm opcodes if(funcname == "swap") { translateSwap(args) @@ -1000,157 +998,7 @@ internal class Compiler(private val rootModule: Module, // We don't bother about saving A and Y. They're considered expendable. if(subroutine.isAsmSubroutine) { - if(subroutine.parameters.size!=subroutine.asmParameterRegisters.size) - throw CompilerException("no support for mix of register and non-register subroutine arguments") - - // only register arguments (or status-flag bits) - var carryParam: Boolean? = null - for(arg in arguments.zip(subroutine.asmParameterRegisters)) { - if(arg.second.statusflag!=null) { - if(arg.second.statusflag==Statusflag.Pc) - carryParam = arg.first.constValue(namespace, heap)!!.asBooleanValue - else - throw CompilerException("no support for status flag parameter: ${arg.second.statusflag}") - } else { - when (arg.second.registerOrPair!!) { - A -> { - val assign = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, arg.first, callPosition) - assign.linkParents(arguments[0].parent) - translate(assign) - } - X -> { - if(!restoreX) { - prog.instr(Opcode.RSAVEX) - restoreX = true - } - val assign = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, arg.first, callPosition) - assign.linkParents(arguments[0].parent) - translate(assign) - } - Y -> { - val assign = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, arg.first, callPosition) - assign.linkParents(arguments[0].parent) - translate(assign) - } - AX -> { - if(!restoreX) { - prog.instr(Opcode.RSAVEX) - restoreX = true - } - val valueA: IExpression - val valueX: IExpression - val paramDt = arg.first.resultingDatatype(namespace, heap) - when (paramDt) { - DataType.UBYTE -> { - valueA=arg.first - valueX=LiteralValue.optimalInteger(0, callPosition) - val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition) - val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition) - assignA.linkParents(arguments[0].parent) - assignX.linkParents(arguments[0].parent) - translate(assignA) - translate(assignX) - } - DataType.UWORD -> { - translate(arg.first) - prog.instr(Opcode.POP_REGAX_WORD) - } - DataType.STR, DataType.STR_S -> { - 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") - } - } - AY -> { - val valueA: IExpression - val valueY: IExpression - val paramDt = arg.first.resultingDatatype(namespace, heap) - when (paramDt) { - DataType.UBYTE -> { - valueA=arg.first - valueY=LiteralValue.optimalInteger(0, callPosition) - val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition) - val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition) - assignA.linkParents(arguments[0].parent) - assignY.linkParents(arguments[0].parent) - translate(assignA) - translate(assignY) - } - DataType.UWORD, DataType.WORD -> { - translate(arg.first) - prog.instr(Opcode.POP_REGAY_WORD) - } - DataType.STR, DataType.STR_S -> { - 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") - } - } - XY -> { - if(!restoreX) { - prog.instr(Opcode.RSAVEX) - restoreX = true - } - val valueX: IExpression - val valueY: IExpression - val paramDt = arg.first.resultingDatatype(namespace, heap) - when (paramDt) { - DataType.UBYTE -> { - valueX=arg.first - valueY=LiteralValue.optimalInteger(0, callPosition) - val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition) - val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition) - assignX.linkParents(arguments[0].parent) - assignY.linkParents(arguments[0].parent) - translate(assignX) - translate(assignY) - } - DataType.UWORD -> { - translate(arg.first) - prog.instr(Opcode.POP_REGXY_WORD) - } - DataType.STR, DataType.STR_S -> { - 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") - } - } - } - } - } - - // carry is set last, to avoid clobbering it when loading the other parameters - when(carryParam) { - true -> prog.instr(Opcode.SEC) - false -> prog.instr(Opcode.CLC) - } + restoreX = translateAsmSubCallArguments(subroutine, arguments, callPosition, restoreX) } else { // only regular (non-register) arguments // "assign" the arguments to the locally scoped parameter variables for this subroutine @@ -1165,6 +1013,176 @@ internal class Compiler(private val rootModule: Module, prog.instr(Opcode.CALL, callLabel = subroutine.scopedname) if(restoreX) prog.instr(Opcode.RRESTOREX) + + if(subroutine.isAsmSubroutine && subroutine.asmReturnvaluesRegisters.isNotEmpty()) { + // the result values of the asm-subroutine that are returned in registers, have to be pushed on the stack + // (in reversed order) otherwise the asm-subroutine can't be used in expressions. + for(rv in subroutine.asmReturnvaluesRegisters.reversed()) { + if(rv.statusflag!=null) + TODO("not yet supported: return values in cpu status flag $rv $subroutine") + when(rv.registerOrPair) { + A,X,Y -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = rv.registerOrPair.name) + AX, AY, XY -> prog.instr(Opcode.PUSH_VAR_WORD, callLabel = rv.registerOrPair.name) + null -> {} + } + } + } + } + + private fun translateAsmSubCallArguments(subroutine: Subroutine, arguments: List, callPosition: Position, restoreXinitial: Boolean): Boolean { + var restoreX = restoreXinitial + if (subroutine.parameters.size != subroutine.asmParameterRegisters.size) + TODO("no support yet for mix of register and non-register subroutine arguments") + + // only register arguments (or status-flag bits) + var carryParam: Boolean? = null + for (arg in arguments.zip(subroutine.asmParameterRegisters)) { + if (arg.second.statusflag != null) { + if (arg.second.statusflag == Statusflag.Pc) + carryParam = arg.first.constValue(namespace, heap)!!.asBooleanValue + else + throw CompilerException("no support for status flag parameter: ${arg.second.statusflag}") + } else { + when (arg.second.registerOrPair!!) { + A -> { + val assign = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, arg.first, callPosition) + assign.linkParents(arguments[0].parent) + translate(assign) + } + X -> { + if (!restoreX) { + prog.instr(Opcode.RSAVEX) + restoreX = true + } + val assign = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, arg.first, callPosition) + assign.linkParents(arguments[0].parent) + translate(assign) + } + Y -> { + val assign = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, arg.first, callPosition) + assign.linkParents(arguments[0].parent) + translate(assign) + } + AX -> { + if (!restoreX) { + prog.instr(Opcode.RSAVEX) + restoreX = true + } + val valueA: IExpression + val valueX: IExpression + val paramDt = arg.first.resultingDatatype(namespace, heap) + when (paramDt) { + DataType.UBYTE -> { + valueA = arg.first + valueX = LiteralValue.optimalInteger(0, callPosition) + val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition) + val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition) + assignA.linkParents(arguments[0].parent) + assignX.linkParents(arguments[0].parent) + translate(assignA) + translate(assignX) + } + DataType.UWORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGAX_WORD) + } + DataType.STR, DataType.STR_S -> { + 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") + } + } + AY -> { + val valueA: IExpression + val valueY: IExpression + val paramDt = arg.first.resultingDatatype(namespace, heap) + when (paramDt) { + DataType.UBYTE -> { + valueA = arg.first + valueY = LiteralValue.optimalInteger(0, callPosition) + val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, null, callPosition)), null, valueA, callPosition) + val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition) + assignA.linkParents(arguments[0].parent) + assignY.linkParents(arguments[0].parent) + translate(assignA) + translate(assignY) + } + DataType.UWORD, DataType.WORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGAY_WORD) + } + DataType.STR, DataType.STR_S -> { + 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") + } + } + XY -> { + if (!restoreX) { + prog.instr(Opcode.RSAVEX) + restoreX = true + } + val valueX: IExpression + val valueY: IExpression + val paramDt = arg.first.resultingDatatype(namespace, heap) + when (paramDt) { + DataType.UBYTE -> { + valueX = arg.first + valueY = LiteralValue.optimalInteger(0, callPosition) + val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, null, callPosition)), null, valueX, callPosition) + val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, null, callPosition)), null, valueY, callPosition) + assignX.linkParents(arguments[0].parent) + assignY.linkParents(arguments[0].parent) + translate(assignX) + translate(assignY) + } + DataType.UWORD -> { + translate(arg.first) + prog.instr(Opcode.POP_REGXY_WORD) + } + DataType.STR, DataType.STR_S -> { + 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") + } + } + } + } + } + + // carry is set last, to avoid clobbering it when loading the other parameters + when (carryParam) { + true -> prog.instr(Opcode.SEC) + false -> prog.instr(Opcode.CLC) + } + return restoreX } private fun translateBinaryOperator(operator: String, dt: DataType) { @@ -1442,8 +1460,8 @@ internal class Compiler(private val rootModule: Module, prog.line(stmt.position) when { stmt.target.register != null -> when(stmt.operator) { - "++" -> prog.instr(Opcode.INC_VAR_UB, callLabel = stmt.target.register.toString()) - "--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register.toString()) + "++" -> prog.instr(Opcode.INC_VAR_UB, callLabel = stmt.target.register!!.name) + "--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register!!.name) } stmt.target.identifier != null -> { val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl @@ -1541,15 +1559,6 @@ internal class Compiler(private val rootModule: Module, if(stmt.aug_op!=null) throw CompilerException("augmented assignment should have been converted to regular assignment already") - if(stmt.value is FunctionCall) { - val sub = (stmt.value as FunctionCall).target.targetStatement(namespace) - if(sub is Subroutine && sub.asmReturnvaluesRegisters.isNotEmpty()) { - // the subroutine call returns its values in registers - storeRegisterIntoTarget(sub.asmReturnvaluesRegisters.single(), assignTarget, stmt) - return - } - } - // pop the result value back into the assignment target val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!! popValueIntoTarget(assignTarget, datatype) @@ -1581,6 +1590,7 @@ internal class Compiler(private val rootModule: Module, private fun translateMultiReturnAssignment(stmt: Assignment) { val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace) if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) { + // TODO check correctness of multi-return values (they should be on the stack rather than directly assigned!) // we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values // for now, we only support multiple return values as long as they're returned in registers as well. if(targetStmt.asmReturnvaluesRegisters.isEmpty()) @@ -1667,7 +1677,7 @@ internal class Compiler(private val rootModule: Module, } } else throw CompilerException("invalid assignment target type ${target::class}") } - assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.toString()) + assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.name) assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it assignTarget.memoryAddress != null -> { val address = assignTarget.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue @@ -1703,7 +1713,7 @@ internal class Compiler(private val rootModule: Module, if(loop.loopRegister!=null) { val reg = loop.loopRegister - loopVarName = reg.toString() + loopVarName = reg.name loopVarDt = DataType.UBYTE } else { val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl) @@ -2036,7 +2046,7 @@ internal class Compiler(private val rootModule: Module, postIncr.linkParents(body) translate(postIncr) if(lvTarget.register!=null) - prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString()) + prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.name) else { val opcode = opcodePushvar(targetStatement!!.datatype) prog.instr(opcode, callLabel = targetStatement.scopedname) diff --git a/compiler/src/prog8/compiler/intermediate/Instruction.kt b/compiler/src/prog8/compiler/intermediate/Instruction.kt index a39648c47..79c9487ee 100644 --- a/compiler/src/prog8/compiler/intermediate/Instruction.kt +++ b/compiler/src/prog8/compiler/intermediate/Instruction.kt @@ -23,10 +23,10 @@ open class Instruction(val opcode: Opcode, } opcode in opcodesWithVarArgument -> { // opcodes that manipulate a variable - "${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd() + "${opcode.name.toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd() } - callLabel==null -> "${opcode.toString().toLowerCase()} $argStr" - else -> "${opcode.toString().toLowerCase()} $callLabel $argStr" + callLabel==null -> "${opcode.name.toLowerCase()} $argStr" + else -> "${opcode.name.toLowerCase()} $callLabel $argStr" } .trimEnd() diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 225319830..593d0c785 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -462,11 +462,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap heap.allEntries().forEach { when { it.value.str!=null -> - out.println("${it.key} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"") + out.println("${it.key} ${it.value.type.name.toLowerCase()} \"${escape(it.value.str!!)}\"") it.value.array!=null -> - out.println("${it.key} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}") + out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.array!!.toList()}") it.value.doubleArray!=null -> - out.println("${it.key} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}") + out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.doubleArray!!.toList()}") else -> throw CompilerException("invalid heap entry $it") } } @@ -477,12 +477,12 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap out.println("%variables") for(variable in blk.variables) { val valuestr = variable.value.toString() - out.println("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr") + out.println("${variable.key} ${variable.value.type.name.toLowerCase()} $valuestr") } out.println("%end_variables") out.println("%memorypointers") for(iconst in blk.memoryPointers) { - out.println("${iconst.key} ${iconst.value.second.toString().toLowerCase()} uw:${iconst.value.first.toString(16)}") + out.println("${iconst.key} ${iconst.value.second.name.toLowerCase()} uw:${iconst.value.first.toString(16)}") } out.println("%end_memorypointers") out.println("%instructions") diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 9f95e006e..308f6c0e3 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -514,8 +514,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Syscall.FUNC_MAX_F, Syscall.FUNC_MIN_F, Syscall.FUNC_AVG_F, - Syscall.FUNC_SUM_F -> " jsr c64flt.${call.toString().toLowerCase()}" - else -> " jsr prog8_lib.${call.toString().toLowerCase()}" + Syscall.FUNC_SUM_F -> " jsr c64flt.${call.name.toLowerCase()}" + null -> "" + else -> " jsr prog8_lib.${call.name.toLowerCase()}" } } Opcode.BREAKPOINT -> { diff --git a/examples/tehtriz.p8 b/examples/tehtriz.p8 index 599f464f6..eea1066c7 100644 --- a/examples/tehtriz.p8 +++ b/examples/tehtriz.p8 @@ -357,7 +357,6 @@ waitkey: ubyte yp2 = ypos+2 ubyte yp3 = ypos+3 - ; @todo the boolean expression below currently doesn't work because the result of an asmsub call (getchr) is not put on the stack right now if(currentBlock[0] and c64scr.getchr(x, ypos)!=32) return false if(currentBlock[4] and c64scr.getchr(x, yp1)!=32) @@ -414,7 +413,6 @@ waitkey: ubyte yp2 = ypos+2 ubyte yp3 = ypos+3 - ; @todo the boolean expression below currently doesn't work because the result of an asmsub call (getchr) is not put on the stack right now if(currentBlock[3] and c64scr.getchr(x, ypos)!=32) return false if(currentBlock[7] and c64scr.getchr(x, yp1)!=32) diff --git a/examples/test.p8 b/examples/test.p8 index 8baca0171..b041cc220 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,16 +7,46 @@ ; @todo see looplabelproblem.p8 - - ;ubyte x = rnd82() % 6 ; @todo fix compiler crash + always 0??? - - ; if(X and c64scr.getcc(1,1)!=32) ... @todo the result value of the asmsub getcc is not put on the eval stack when used in an expression - sub start() { + ubyte xx + + c64scr.print_ub(X) + c64.CHROUT('\n') + + A=c64scr.getchr(20,1) + c64scr.print_ub(A) + c64.CHROUT('\n') + xx=c64scr.getchr(20,1) + c64scr.print_ub(xx) + c64.CHROUT('\n') + c64scr.print_ub(X) + c64.CHROUT('\n') + + A=1+c64scr.getchr(20,1) + c64scr.print_ub(A) + c64.CHROUT('\n') + xx=1+c64scr.getchr(20,1) + c64scr.print_ub(xx) + c64.CHROUT('\n') + c64scr.print_ub(X) + c64.CHROUT('\n') + + A=c64scr.getchr(20,1)+1 + c64scr.print_ub(A) + c64.CHROUT('\n') + xx=c64scr.getchr(20,1)+1 + c64scr.print_ub(xx) + c64.CHROUT('\n') + c64scr.print_ub(X) + c64.CHROUT('\n') } + asmsub asm_routine(ubyte arg1 @ A, ubyte arg2 @ Y) -> clobbers() -> (ubyte @ A) { + return A+Y + } + sub drawNext(ubyte x) { A=x }