diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt index 141bdbdc7..86ed2ae76 100644 --- a/codeCore/src/prog8/code/SymbolTableMaker.kt +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -26,8 +26,6 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY), PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY), PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY), - PtMemMapped("P8ESTACK_LO", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_LO, 128u, Position.DUMMY), - PtMemMapped("P8ESTACK_HI", DataType.ARRAY_UB, options.compTarget.machine.ESTACK_HI, 128u, Position.DUMMY) ).forEach { it.parent = program st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it)) diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index f305bedc4..a1d54844b 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -126,7 +126,6 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni else "->" } - else -> throw InternalCompilerException("unrecognised ast node $node") } } diff --git a/codeCore/src/prog8/code/core/BuiltinFunctions.kt b/codeCore/src/prog8/code/core/BuiltinFunctions.kt index e1fef8abd..5a69b8024 100644 --- a/codeCore/src/prog8/code/core/BuiltinFunctions.kt +++ b/codeCore/src/prog8/code/core/BuiltinFunctions.kt @@ -124,9 +124,7 @@ val BuiltinFunctions: Map = mapOf( "push" to FSignature(false, listOf(FParam("value", ByteDatatypes)), null), "pushw" to FSignature(false, listOf(FParam("value", WordDatatypes)), null), "rsave" to FSignature(false, emptyList(), null), - "rsavex" to FSignature(false, emptyList(), null), "rrestore" to FSignature(false, emptyList(), null), - "rrestorex" to FSignature(false, emptyList(), null), "memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD), "callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD), ) diff --git a/codeCore/src/prog8/code/core/CompilationOptions.kt b/codeCore/src/prog8/code/core/CompilationOptions.kt index 3837dd839..7d1719922 100644 --- a/codeCore/src/prog8/code/core/CompilationOptions.kt +++ b/codeCore/src/prog8/code/core/CompilationOptions.kt @@ -13,15 +13,12 @@ class CompilationOptions(val output: OutputType, val compTarget: ICompilationTarget, // these are set later, based on command line arguments or options in the source code: var loadAddress: UInt, - var slowCodegenWarnings: Boolean = false, var optimize: Boolean = false, - var optimizeFloatExpressions: Boolean = false, var asmQuiet: Boolean = false, var asmListfile: Boolean = false, var experimentalCodegen: Boolean = false, var varsHighBank: Int? = null, var splitWordArrays: Boolean = false, - var evalStackBaseAddress: UInt? = null, var outputDir: Path = Path(""), var symbolDefs: Map = emptyMap() ) { diff --git a/codeCore/src/prog8/code/core/IMachineDefinition.kt b/codeCore/src/prog8/code/core/IMachineDefinition.kt index ed973afb1..a835f1907 100644 --- a/codeCore/src/prog8/code/core/IMachineDefinition.kt +++ b/codeCore/src/prog8/code/core/IMachineDefinition.kt @@ -13,8 +13,6 @@ interface IMachineDefinition { val FLOAT_MAX_NEGATIVE: Double val FLOAT_MAX_POSITIVE: Double val FLOAT_MEM_SIZE: Int - var ESTACK_LO: UInt - var ESTACK_HI: UInt val PROGRAM_LOAD_ADDRESS : UInt val BSSHIGHRAM_START: UInt val BSSHIGHRAM_END: UInt @@ -29,11 +27,4 @@ interface IMachineDefinition { fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) fun isIOAddress(address: UInt): Boolean - fun overrideEvalStack(evalStackBaseAddress: UInt) { - require(evalStackBaseAddress and 255u == 0u) - ESTACK_LO = evalStackBaseAddress - ESTACK_HI = evalStackBaseAddress + 256u - require(ESTACK_LO !in golden.region && ESTACK_HI !in golden.region) { "user-set ESTACK can't be in GOLDEN ram" } - } - } diff --git a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt b/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt index 99903c8ad..9332b2643 100644 --- a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt @@ -13,10 +13,6 @@ class AtariMachineDefinition: IMachineDefinition { override val FLOAT_MEM_SIZE = 6 override val PROGRAM_LOAD_ADDRESS = 0x2000u - // the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations) - override var ESTACK_LO = 0x1b00u // $1b00-$1b7f inclusive // TODO - override var ESTACK_HI = 0x1b80u // $1b80-$1bff inclusive // TODO - override val BSSHIGHRAM_START = 0u // TODO override val BSSHIGHRAM_END = 0u // TODO diff --git a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt b/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt index 18d632140..29d2e4066 100644 --- a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt @@ -15,10 +15,6 @@ class C128MachineDefinition: IMachineDefinition { override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val PROGRAM_LOAD_ADDRESS = 0x1c01u - // the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations) - override var ESTACK_LO = 0x1b00u // $1b00-$1b7f inclusive - override var ESTACK_HI = 0x1b80u // $1b80-$1bff inclusive - override val BSSHIGHRAM_START = 0u // TODO override val BSSHIGHRAM_END = 0u // TODO diff --git a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt b/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt index d29f582f0..ace08c556 100644 --- a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt @@ -16,12 +16,8 @@ class C64MachineDefinition: IMachineDefinition { override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val PROGRAM_LOAD_ADDRESS = 0x0801u - // the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations) - override var ESTACK_LO = 0xcf00u // $cf00-$cf7f inclusive - override var ESTACK_HI = 0xcf80u // $cf80-$cfff inclusive - override val BSSHIGHRAM_START = 0xc000u - override val BSSHIGHRAM_END = ESTACK_LO + override val BSSHIGHRAM_END = 0xd000u override lateinit var zeropage: Zeropage override lateinit var golden: GoldenRam @@ -62,7 +58,7 @@ class C64MachineDefinition: IMachineDefinition { override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = C64Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, 0xc000u until ESTACK_LO) + golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u) } } diff --git a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt b/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt index 34b63c252..33acf4480 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt @@ -15,10 +15,6 @@ class CX16MachineDefinition: IMachineDefinition { override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val PROGRAM_LOAD_ADDRESS = 0x0801u - // the 2*128 byte evaluation stack (1 page, on which bytes, words, and even floats are stored during calculations) - override var ESTACK_LO = 0x0700u // $0700-$077f inclusive - override var ESTACK_HI = 0x0780u // $0780-$07ff inclusive - override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active override val BSSHIGHRAM_END = 0xc000u // rom starts here. @@ -64,7 +60,7 @@ class CX16MachineDefinition: IMachineDefinition { override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = CX16Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, 0x0400u until ESTACK_LO) + golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u) } } diff --git a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt index e5ac52167..da07f14de 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt @@ -40,7 +40,6 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { ZeropageType.DONTUSE -> { free.clear() // don't use zeropage at all } - else -> throw InternalCompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}") } val distinctFree = free.distinct() diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt index 2c555f76d..dbe4ed1ba 100644 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt @@ -15,8 +15,6 @@ class VirtualMachineDefinition: IMachineDefinition { override val FLOAT_MEM_SIZE = 4 // 32-bits floating point override val PROGRAM_LOAD_ADDRESS = 0u // not actually used - override var ESTACK_LO = 0u // not actually used - override var ESTACK_HI = 0u // not actually used override val BSSHIGHRAM_START = 0u // not actually used override val BSSHIGHRAM_END = 0u // not actually used override lateinit var zeropage: Zeropage // not actually used diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 06970d1ee..dd1188d33 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -207,8 +207,8 @@ class AsmGen6502Internal ( private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this) private val functioncallAsmGen = FunctionCallAsmGen(program, this) private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage) - private val assignmentAsmGen = AssignmentAsmGen(program, symbolTable, this, allocator) - private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator) + private val anyExprGen = AnyExprAsmGen(this) + private val assignmentAsmGen = AssignmentAsmGen(program, this, anyExprGen, allocator) private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen) fun compileToAssembly(): IAssemblyProgram? { @@ -394,32 +394,6 @@ class AsmGen6502Internal ( return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly } - internal fun saveRegisterLocal(register: CpuRegister, scope: IPtSubroutine) { - if (isTargetCpu(CpuType.CPU65c02)) { - // just use the cpu's stack for all registers, shorter code - when (register) { - CpuRegister.A -> out(" pha") - CpuRegister.X -> out(" phx") - CpuRegister.Y -> out(" phy") - } - } else { - when (register) { - CpuRegister.A -> { - // just use the stack, only for A - out(" pha") - } - CpuRegister.X -> { - out(" stx prog8_regsaveX") - subroutineExtra(scope).usedRegsaveX = true - } - CpuRegister.Y -> { - out(" sty prog8_regsaveY") - subroutineExtra(scope).usedRegsaveY = true - } - } - } - } - internal fun saveRegisterStack(register: CpuRegister, keepA: Boolean) { when (register) { CpuRegister.A -> out(" pha") @@ -444,24 +418,6 @@ class AsmGen6502Internal ( } } - internal fun restoreRegisterLocal(register: CpuRegister) { - if (isTargetCpu(CpuType.CPU65c02)) { - when (register) { - // this just used the stack, for all registers. Shorter code. - CpuRegister.A -> out(" pla") - CpuRegister.X -> out(" plx") - CpuRegister.Y -> out(" ply") - } - - } else { - when (register) { - CpuRegister.A -> out(" pla") // this just used the stack but only for A - CpuRegister.X -> out(" ldx prog8_regsaveX") - CpuRegister.Y -> out(" ldy prog8_regsaveY") - } - } - } - internal fun restoreRegisterStack(register: CpuRegister, keepA: Boolean) { when (register) { CpuRegister.A -> { @@ -581,22 +537,12 @@ class AsmGen6502Internal ( } } - @Deprecated("avoid calling this as it generates slow evalstack based code") - internal fun translateExpression(expression: PtExpression) = - expressionsAsmGen.translateExpression(expression) - - internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? = - builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister) + internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? = + builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultRegister) internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) = functioncallAsmGen.translateFunctionCall(functionCallExpr) - internal fun saveXbeforeCall(functionCall: PtFunctionCall) = - functioncallAsmGen.saveXbeforeCall(functionCall) - - internal fun restoreXafterCall(functionCall: PtFunctionCall) = - functioncallAsmGen.restoreXafterCall(functionCall) - internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) = assignmentAsmGen.translateNormalAssignment(assign, scope) @@ -625,7 +571,6 @@ class AsmGen6502Internal ( } internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) { - // don't use translateExpression() to avoid evalstack when (target.datatype) { in ByteDatatypes -> { assignExpressionToRegister(value, RegisterOrPair.A) @@ -1086,20 +1031,6 @@ $repeatLabel""") } } - internal fun signExtendStackLsb(valueDt: DataType) { - // sign extend signed byte on stack to signed word on stack - when(valueDt) { - DataType.UBYTE -> { - if(isTargetCpu(CpuType.CPU65c02)) - out(" stz P8ESTACK_HI+1,x") - else - out(" lda #0 | sta P8ESTACK_HI+1,x") - } - DataType.BYTE -> out(" jsr prog8_lib.sign_extend_stack_byte") - else -> throw AssemblyError("need byte type") - } - } - internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) { // sign extend signed byte in a var to a full word in that variable when(valueDt) { @@ -1728,7 +1659,7 @@ $repeatLabel""") } else if (left is PtMemoryByte) { return if(rightConstVal.number.toInt()!=0) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) code("#${rightConstVal.number.toInt()}") } else @@ -1875,7 +1806,7 @@ $repeatLabel""") out(" beq $jumpIfFalseLabel") } else if (left is PtMemoryByte) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else @@ -2036,7 +1967,7 @@ $repeatLabel""") out(" bne $jumpIfFalseLabel") } else if (left is PtMemoryByte) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else @@ -2200,7 +2131,7 @@ $repeatLabel""") } else if (left is PtMemoryByte) { if(rightConstVal.number.toInt()!=0) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) code("#${rightConstVal.number.toInt()}") } return @@ -2363,7 +2294,7 @@ $repeatLabel""") out(" bne $jumpIfFalseLabel") } else if (left is PtMemoryByte) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else @@ -2409,7 +2340,7 @@ $repeatLabel""") out(" beq $jumpIfFalseLabel") } else if (left is PtMemoryByte) { - translateDirectMemReadExpressionToRegAorStack(left, false) + translateDirectMemReadExpressionToRegA(left) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else @@ -2865,22 +2796,14 @@ $repeatLabel""") +""") } - internal fun translateDirectMemReadExpressionToRegAorStack(expr: PtMemoryByte, pushResultOnEstack: Boolean) { + internal fun translateDirectMemReadExpressionToRegA(expr: PtMemoryByte) { fun assignViaExprEval() { assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD) if (isTargetCpu(CpuType.CPU65c02)) { - if (pushResultOnEstack) { - out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x") - } else { - out(" lda (P8ZP_SCRATCH_W2)") - } + out(" lda (P8ZP_SCRATCH_W2)") } else { - if (pushResultOnEstack) { - out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y | dex | sta P8ESTACK_LO+1,x") - } else { - out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") - } + out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") } } @@ -2888,21 +2811,14 @@ $repeatLabel""") is PtNumber -> { val address = (expr.address as PtNumber).number.toInt() out(" lda ${address.toHex()}") - if(pushResultOnEstack) - out(" sta P8ESTACK_LO,x | dex") } is PtIdentifier -> { // the identifier is a pointer variable, so read the value from the address in it loadByteFromPointerIntoA(expr.address as PtIdentifier) - if(pushResultOnEstack) - out(" sta P8ESTACK_LO,x | dex") } is PtBinaryExpression -> { val addrExpr = expr.address as PtBinaryExpression - if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { - if(pushResultOnEstack) - out(" sta P8ESTACK_LO,x | dex") - } else { + if(!tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { assignViaExprEval() } } @@ -3098,6 +3014,14 @@ $repeatLabel""") } } + internal fun pushFAC1() { + out(" jsr floats.pushFAC1") + } + + internal fun popFAC1() { + out(" jsr floats.popFAC1") + } + internal fun needAsaveForExpr(arg: PtExpression): Boolean = arg !is PtNumber && arg !is PtIdentifier && (arg !is PtMemoryByte || !arg.isSimple()) @@ -3130,9 +3054,6 @@ $repeatLabel""") * it's more consistent to only define these attributes on a Subroutine node. */ internal class SubroutineExtraAsmInfo { - var usedRegsaveA = false - var usedRegsaveX = false - var usedRegsaveY = false var usedFloatEvalResultVar1 = false var usedFloatEvalResultVar2 = false diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt index 5180b8583..5e14d1945 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt @@ -15,21 +15,7 @@ internal fun optimizeAssembly(lines: MutableList, machine: IMachineDefin var linesByFour = getLinesBy(lines, 4) - var mods = optimizeUselessStackByteWrites(linesByFour) - if(mods.isNotEmpty()) { - apply(mods, lines) - linesByFour = getLinesBy(lines, 4) - numberOfOptimizations++ - } - - mods = optimizeIncDec(linesByFour) - if(mods.isNotEmpty()) { - apply(mods, lines) - linesByFour = getLinesBy(lines, 4) - numberOfOptimizations++ - } - - mods = optimizeCmpSequence(linesByFour) + var mods = optimizeIncDec(linesByFour) if(mods.isNotEmpty()) { apply(mods, lines) linesByFour = getLinesBy(lines, 4) @@ -97,44 +83,6 @@ private fun getLinesBy(lines: MutableList, windowSize: Int) = // all lines (that aren't empty or comments) in sliding windows of certain size lines.withIndex().filter { it.value.isNotBlank() && !it.value.trimStart().startsWith(';') }.windowed(windowSize, partialWindows = false) -private fun optimizeCmpSequence(linesByFour: List>>): List { - // when statement (on bytes) generates a sequence of: - // lda $ce01,x - // cmp #$20 - // beq check_prog8_s72choice_32 - // lda $ce01,x - // cmp #$21 - // beq check_prog8_s73choice_33 - // the repeated lda can be removed - val mods = mutableListOf() - for(lines in linesByFour) { - if(lines[0].value.trim()=="lda P8ESTACK_LO+1,x" && - lines[1].value.trim().startsWith("cmp ") && - lines[2].value.trim().startsWith("beq ") && - lines[3].value.trim()=="lda P8ESTACK_LO+1,x") { - mods.add(Modification(lines[3].index, true, null)) // remove the second lda - } - } - return mods -} - -private fun optimizeUselessStackByteWrites(linesByFour: List>>): List { - // sta on stack, dex, inx, lda from stack -> eliminate this useless stack byte write - // this is a lot harder for word values because the instruction sequence varies. - val mods = mutableListOf() - for(lines in linesByFour) { - if(lines[0].value.trim()=="sta P8ESTACK_LO,x" && - lines[1].value.trim()=="dex" && - lines[2].value.trim()=="inx" && - lines[3].value.trim()=="lda P8ESTACK_LO,x") { - mods.add(Modification(lines[1].index, true, null)) - mods.add(Modification(lines[2].index, true, null)) - mods.add(Modification(lines[3].index, true, null)) - } - } - return mods -} - private fun optimizeSameAssignments( linesByFourteen: List>>, machine: IMachineDefinition, diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 4084419f3..3d248e3ed 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -10,34 +10,31 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal, private val assignAsmGen: AssignmentAsmGen) { - internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? { - return translateFunctioncall(fcall, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) + internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? { + return translateFunctioncall(fcall, discardResult = false, resultRegister = resultRegister) } internal fun translateFunctioncallStatement(fcall: PtBuiltinFunctionCall) { - translateFunctioncall(fcall, discardResult = true, resultToStack = false, resultRegister = null) + translateFunctioncall(fcall, discardResult = true, resultRegister = null) } - private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? { + private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): DataType? { if (discardResult && fcall.hasNoSideEffects) return null // can just ignore the whole function call altogether - if(discardResult && resultToStack) - throw AssemblyError("cannot both discard the result AND put it onto stack") - val sscope = fcall.definingISub() when (fcall.name) { - "msb" -> funcMsb(fcall, resultToStack, resultRegister) - "lsb" -> funcLsb(fcall, resultToStack, resultRegister) - "mkword" -> funcMkword(fcall, resultToStack, resultRegister) - "clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultToStack, resultRegister) - "min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultToStack, resultRegister) - "max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultToStack, resultRegister) - "abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultToStack, resultRegister, sscope) - "any", "all" -> funcAnyAll(fcall, resultToStack, resultRegister, sscope) - "sgn" -> funcSgn(fcall, resultToStack, resultRegister, sscope) - "sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(fcall, resultToStack, resultRegister, sscope) + "msb" -> funcMsb(fcall, resultRegister) + "lsb" -> funcLsb(fcall, resultRegister) + "mkword" -> funcMkword(fcall, resultRegister) + "clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultRegister) + "min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultRegister) + "max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultRegister) + "abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultRegister, sscope) + "any", "all" -> funcAnyAll(fcall, resultRegister, sscope) + "sgn" -> funcSgn(fcall, resultRegister, sscope) + "sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(fcall, resultRegister, sscope) "divmod__ubyte" -> funcDivmod(fcall) "divmod__uword" -> funcDivmodW(fcall) "rol" -> funcRol(fcall) @@ -46,8 +43,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, "ror2" -> funcRor2(fcall) "sort" -> funcSort(fcall) "reverse" -> funcReverse(fcall) - "memory" -> funcMemory(fcall, discardResult, resultToStack, resultRegister) - "peekw" -> funcPeekW(fcall, resultToStack, resultRegister) + "memory" -> funcMemory(fcall, discardResult, resultRegister) + "peekw" -> funcPeekW(fcall, resultRegister) "peek" -> throw AssemblyError("peek() should have been replaced by @()") "pokew" -> funcPokeW(fcall) "pokemon" -> { /* meme function */ } @@ -71,12 +68,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub()) } "rsave" -> funcRsave() - "rsavex" -> funcRsaveX() "rrestore" -> funcRrestore() - "rrestorex" -> funcRrestoreX() "cmp" -> funcCmp(fcall) "callfar" -> funcCallFar(fcall) - "prog8_lib_stringcompare" -> funcStringCompare(fcall, resultToStack) + "prog8_lib_stringcompare" -> funcStringCompare(fcall) else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}") } @@ -115,11 +110,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, sty $remainderVar+1""") } - private fun funcStringCompare(fcall: PtBuiltinFunctionCall, resultToStack: Boolean) { + private fun funcStringCompare(fcall: PtBuiltinFunctionCall) { asmgen.assignWordOperandsToAYAndVar(fcall.args[0], fcall.args[1], "P8ZP_SCRATCH_W2") asmgen.out(" jsr prog8_lib.strcmp_mem") - if(resultToStack) - asmgen.out(" sta P8ESTACK_LO,x | dex") } private fun funcRsave() { @@ -142,13 +135,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, lda P8ZP_SCRATCH_REG""") } - private fun funcRsaveX() { - if (asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" phx") - else - asmgen.out(" txa | pha") - } - private fun funcRrestore() { if (asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(""" @@ -166,13 +152,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, plp""") } - private fun funcRrestoreX() { - if (asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" plx") - else - asmgen.out(" sta P8ZP_SCRATCH_B1 | pla | tax | lda P8ZP_SCRATCH_B1") - } - private fun funcCallFar(fcall: PtBuiltinFunctionCall) { if(asmgen.options.compTarget.name != "cx16") throw AssemblyError("callfar only works on cx16 target at this time") @@ -253,7 +232,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } } - private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?) { if(discardResult) throw AssemblyError("should not discard result of memory allocation at $fcall") val name = (fcall.args[0] as PtString).value @@ -263,41 +242,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, addressOf.add(slabname) addressOf.parent = fcall val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf) - val target = - if(resultToStack) - AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, null, fcall.position) - else - AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen) + val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen) val assign = AsmAssignment(src, target, program.memsizer, fcall.position) asmgen.translateNormalAssignment(assign, fcall.definingISub()) } - private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) when(fcall.args[0].type) { DataType.UBYTE -> { - if(resultToStack) - asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_stack") - else { - asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) - } + asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A") + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) } DataType.UWORD -> { - if(resultToStack) - asmgen.out(" jsr prog8_lib.func_sqrt16_stack") - else { - asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) - } + asmgen.out(" jsr prog8_lib.func_sqrt16_into_A") + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false) } DataType.FLOAT -> { asmgen.out(" jsr floats.func_sqrt_into_FAC1") - if(resultToStack) - assignAsmGen.assignFAC1float(AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.FLOAT, scope, fcall.position)) - else { - assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) - } + assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) } else -> throw AssemblyError("weird dt") } @@ -466,16 +429,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) - asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A) + asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) - asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.restoreRegisterStack(CpuRegister.X, false) asmgen.out(""" - sta (+) + 1 - sty (+) + 2 + ror ${'$'}ffff,x ; modified""") - asmgen.restoreRegisterLocal(CpuRegister.X) } else { asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" @@ -571,16 +531,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) - asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A) + asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) - asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.restoreRegisterStack(CpuRegister.X, false) asmgen.out(""" - sta (+) + 1 - sty (+) + 2 + rol ${'$'}ffff,x ; modified""") - asmgen.restoreRegisterLocal(CpuRegister.X) } else { asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" @@ -633,88 +590,56 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE) } - private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) val dt = fcall.args.single().type - if(resultToStack) { - when (dt) { - DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_stack") - DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_stack") - DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_stack") - DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_stack") - DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_stack") - else -> throw AssemblyError("weird type $dt") - } - } else { - when (dt) { - DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") - DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") - DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") - DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A") - DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A") - else -> throw AssemblyError("weird type $dt") - } - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true) + when (dt) { + DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") + DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") + DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") + DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A") + DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A") + else -> throw AssemblyError("weird type $dt") } + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true) } - private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { outputAddressAndLenghtOfArray(fcall.args[0]) val dt = fcall.args.single().type - if(resultToStack) { - when (dt) { - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_stack") - DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_stack") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_stack") - in SplitWordArrayTypes -> TODO("split word any/all") - else -> throw AssemblyError("weird type $dt") - } - } else { - when (dt) { - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_into_A | ldy #0") - DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_into_A | ldy #0") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_into_A | ldy #0") - in SplitWordArrayTypes -> TODO("split word any/all") - else -> throw AssemblyError("weird type $dt") - } - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, dt in SignedDatatypes) + when (dt) { + DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_into_A | ldy #0") + DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_into_A | ldy #0") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_into_A | ldy #0") + in SplitWordArrayTypes -> TODO("split word any/all") + else -> throw AssemblyError("weird type $dt") } + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, dt in SignedDatatypes) } - private fun funcAbs(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { + private fun funcAbs(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { translateArguments(fcall, scope) val dt = fcall.args.single().type - if(resultToStack) { - when (dt) { - DataType.BYTE -> asmgen.out(" jsr prog8_lib.abs_b_stack") - DataType.WORD -> asmgen.out(" jsr prog8_lib.abs_w_stack") - else -> { - asmgen.out(" jsr floats.func_abs_f_into_FAC1") - assignAsmGen.assignFAC1float(AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.FLOAT, scope, fcall.position)) - } + when (dt) { + DataType.BYTE -> { + asmgen.out(" jsr prog8_lib.abs_b_into_A") + assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false) } - } else { - when (dt) { - DataType.BYTE -> { - asmgen.out(" jsr prog8_lib.abs_b_into_A") - assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false) - } - DataType.WORD -> { - asmgen.out(" jsr prog8_lib.abs_w_into_AY") - assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY) - } - DataType.FLOAT -> { - asmgen.out(" jsr floats.func_abs_f_into_FAC1") - assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) - } - DataType.UBYTE -> { - asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen)) - } - DataType.UWORD -> { - asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen)) - } - else -> throw AssemblyError("weird type") + DataType.WORD -> { + asmgen.out(" jsr prog8_lib.abs_w_into_AY") + assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY) } + DataType.FLOAT -> { + asmgen.out(" jsr floats.func_abs_f_into_FAC1") + assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen)) + } + DataType.UBYTE -> { + asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen)) + } + DataType.UWORD -> { + asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen)) + } + else -> throw AssemblyError("weird type") } } @@ -730,7 +655,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val varname = asmgen.asmVariableName(addrExpr) if(asmgen.isZpVar(addrExpr)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) if (asmgen.isTargetCpu(CpuType.CPU65c02)) { asmgen.out(""" @@ -746,7 +670,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, iny sta ($varname),y""") } - asmgen.restoreRegisterLocal(CpuRegister.X) return } } @@ -756,18 +679,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { // can do ZP,Y indexing val varname = asmgen.asmVariableName(pointer) - val scope = fcall.definingISub()!! - asmgen.saveRegisterLocal(CpuRegister.X, scope) asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y) - asmgen.saveRegisterLocal(CpuRegister.Y, scope) + asmgen.saveRegisterStack(CpuRegister.Y, false) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) - asmgen.restoreRegisterLocal(CpuRegister.Y) + asmgen.restoreRegisterStack(CpuRegister.Y, true) asmgen.out(""" sta ($varname),y txa iny sta ($varname),y""") - asmgen.restoreRegisterLocal(CpuRegister.X) return } } @@ -779,7 +699,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(" jsr prog8_lib.func_pokew") } - private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { fun fallback() { asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) asmgen.out(" jsr prog8_lib.func_peekw") @@ -830,23 +750,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, else -> fallback() } - if(resultToStack){ - asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") - } else { - when(resultRegister ?: RegisterOrPair.AY) { - RegisterOrPair.AY -> {} - RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") - RegisterOrPair.XY -> asmgen.out(" tax") - in Cx16VirtualRegisters -> asmgen.out( - " sta cx16.${ - resultRegister.toString().lowercase() - } | sty cx16.${resultRegister.toString().lowercase()}+1") - else -> throw AssemblyError("invalid reg") - } + when(resultRegister ?: RegisterOrPair.AY) { + RegisterOrPair.AY -> {} + RegisterOrPair.AX -> asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") + RegisterOrPair.XY -> asmgen.out(" tax") + in Cx16VirtualRegisters -> asmgen.out( + " sta cx16.${ + resultRegister.toString().lowercase() + } | sty cx16.${resultRegister.toString().lowercase()}+1") + else -> throw AssemblyError("invalid reg") } } - private fun funcClamp(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcClamp(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val signed = fcall.type in SignedDatatypes when(fcall.type) { in ByteDatatypes -> { @@ -854,30 +770,22 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}") - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) - assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) + assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed) } in WordDatatypes -> { assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}") - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) - assignAsmGen.assignRegisterpairWord(targetReg, RegisterOrPair.AY) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) + assignAsmGen.assignRegisterpairWord(targetReg, RegisterOrPair.AY) } else -> throw AssemblyError("invalid dt") } } - private fun funcMin(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMin(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val signed = fcall.type in SignedDatatypes if(fcall.type in ByteDatatypes) { asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_B1", fcall.type) // right @@ -887,12 +795,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(""" lda P8ZP_SCRATCH_B1 +""") - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) - asmgen.assignRegister(RegisterOrPair.A, targetReg) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) + asmgen.assignRegister(RegisterOrPair.A, targetReg) } else if(fcall.type in WordDatatypes) { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right @@ -928,18 +832,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, ldy P8ZP_SCRATCH_W1+1 +""") } - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) - asmgen.assignRegister(RegisterOrPair.AY, targetReg) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) + asmgen.assignRegister(RegisterOrPair.AY, targetReg) } else { throw AssemblyError("min float not supported") } } - private fun funcMax(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMax(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val signed = fcall.type in SignedDatatypes if(fcall.type in ByteDatatypes) { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_B1", fcall.type) // left @@ -949,12 +849,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.out(""" lda P8ZP_SCRATCH_B1 +""") - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) - asmgen.assignRegister(RegisterOrPair.A, targetReg) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen) + asmgen.assignRegister(RegisterOrPair.A, targetReg) } else if(fcall.type in WordDatatypes) { asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right @@ -990,72 +886,61 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, ldy P8ZP_SCRATCH_W2+1 +""") } - if(resultToStack) { - asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex") - } else { - val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) - asmgen.assignRegister(RegisterOrPair.AY, targetReg) - } + val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, signed, fcall.position, fcall.definingISub(), asmgen) + asmgen.assignRegister(RegisterOrPair.AY, targetReg) } else { throw AssemblyError("max float not supported") } } - private fun funcMkword(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { - if(resultToStack) { - asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - asmgen.out(" sta P8ESTACK_LO,x | pla | sta P8ESTACK_HI,x | dex") - } else { - val reg = resultRegister ?: RegisterOrPair.AY - var needAsave = asmgen.needAsaveForExpr(fcall.args[0]) - if(!needAsave) { - val mr0 = fcall.args[0] as? PtMemoryByte - val mr1 = fcall.args[1] as? PtMemoryByte - if (mr0 != null) - needAsave = mr0.address !is PtNumber - if (mr1 != null) - needAsave = needAsave or (mr1.address !is PtNumber) + private fun funcMkword(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { + val reg = resultRegister ?: RegisterOrPair.AY + var needAsave = asmgen.needAsaveForExpr(fcall.args[0]) + if(!needAsave) { + val mr0 = fcall.args[0] as? PtMemoryByte + val mr1 = fcall.args[1] as? PtMemoryByte + if (mr0 != null) + needAsave = mr0.address !is PtNumber + if (mr1 != null) + needAsave = needAsave or (mr1.address !is PtNumber) + } + when(reg) { + RegisterOrPair.AX -> { + asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb + if(needAsave) + asmgen.out(" pha") + asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.X) // msb + if(needAsave) + asmgen.out(" pla") } - when(reg) { - RegisterOrPair.AX -> { - asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - if(needAsave) - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.X) // msb - if(needAsave) - asmgen.out(" pla") - } - RegisterOrPair.AY -> { - asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - if(needAsave) - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb - if(needAsave) - asmgen.out(" pla") - } - RegisterOrPair.XY -> { - asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - if(needAsave) - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb - if(needAsave) - asmgen.out(" pla") - asmgen.out(" tax") - } - in Cx16VirtualRegisters -> { - asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb - asmgen.out(" sta cx16.${reg.toString().lowercase()}") - asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb - asmgen.out(" sta cx16.${reg.toString().lowercase()}+1") - } - else -> throw AssemblyError("invalid mkword target reg") + RegisterOrPair.AY -> { + asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb + if(needAsave) + asmgen.out(" pha") + asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb + if(needAsave) + asmgen.out(" pla") } + RegisterOrPair.XY -> { + asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb + if(needAsave) + asmgen.out(" pha") + asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb + if(needAsave) + asmgen.out(" pla") + asmgen.out(" tax") + } + in Cx16VirtualRegisters -> { + asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb + asmgen.out(" sta cx16.${reg.toString().lowercase()}") + asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // msb + asmgen.out(" sta cx16.${reg.toString().lowercase()}+1") + } + else -> throw AssemblyError("invalid mkword target reg") } } - private fun funcMsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() if (arg.type !in WordDatatypes) throw AssemblyError("msb required word argument") @@ -1063,53 +948,44 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, throw AssemblyError("msb(const) should have been const-folded away") if (arg is PtIdentifier) { val sourceName = asmgen.asmVariableName(arg) - if(resultToStack) { - asmgen.out(" lda $sourceName+1 | sta P8ESTACK_LO,x | dex") - } else { - when(resultRegister) { - null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+1") - RegisterOrPair.X -> asmgen.out(" ldx $sourceName+1") - RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+1") - RegisterOrPair.AX -> asmgen.out(" lda $sourceName+1 | ldx #0") - RegisterOrPair.AY -> asmgen.out(" lda $sourceName+1 | ldy #0") - RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+1 | ldy #0") - in Cx16VirtualRegisters -> { - val regname = resultRegister.name.lowercase() - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" lda $sourceName+1 | sta cx16.$regname | stz cx16.$regname+1") - else - asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1") - } - else -> throw AssemblyError("invalid reg") + when(resultRegister) { + null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+1") + RegisterOrPair.X -> asmgen.out(" ldx $sourceName+1") + RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+1") + RegisterOrPair.AX -> asmgen.out(" lda $sourceName+1 | ldx #0") + RegisterOrPair.AY -> asmgen.out(" lda $sourceName+1 | ldy #0") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+1 | ldy #0") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" lda $sourceName+1 | sta cx16.$regname | stz cx16.$regname+1") + else + asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1") } + else -> throw AssemblyError("invalid reg") } } else { - if(resultToStack) { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - asmgen.out(" tya | sta P8ESTACK_LO,x | dex") - } else { - when(resultRegister) { - null, RegisterOrPair.A -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - asmgen.out(" tya") - } - RegisterOrPair.X -> { - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX) - asmgen.out(" pla") - } - RegisterOrPair.Y -> { - asmgen.out(" pha") - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - asmgen.out(" pla") - } - else -> throw AssemblyError("invalid reg") + when(resultRegister) { + null, RegisterOrPair.A -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) + asmgen.out(" tya") } + RegisterOrPair.X -> { + asmgen.out(" pha") + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX) + asmgen.out(" pla") + } + RegisterOrPair.Y -> { + asmgen.out(" pha") + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) + asmgen.out(" pla") + } + else -> throw AssemblyError("invalid reg") } } } - private fun funcLsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() if (arg.type !in WordDatatypes) throw AssemblyError("lsb required word argument") @@ -1118,72 +994,60 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, if (arg is PtIdentifier) { val sourceName = asmgen.asmVariableName(arg) - if(resultToStack) { - asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x | dex") - } else { - when(resultRegister) { - null, RegisterOrPair.A -> asmgen.out(" lda $sourceName") - RegisterOrPair.X -> asmgen.out(" ldx $sourceName") - RegisterOrPair.Y -> asmgen.out(" ldy $sourceName") - RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0") - RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0") - RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0") - in Cx16VirtualRegisters -> { - val regname = resultRegister.name.lowercase() - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1") - else - asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1") - } - else -> throw AssemblyError("invalid reg") + when(resultRegister) { + null, RegisterOrPair.A -> asmgen.out(" lda $sourceName") + RegisterOrPair.X -> asmgen.out(" ldx $sourceName") + RegisterOrPair.Y -> asmgen.out(" ldy $sourceName") + RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0") + RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1") + else + asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1") } + else -> throw AssemblyError("invalid reg") } } else { - if(resultToStack) { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - // NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction. - // this is required because the compiler assumes the status bits are set according to what A is (lsb) - // and will not generate another cmp when lsb() is directly used inside a comparison expression. - asmgen.out(" sta P8ESTACK_LO,x | dex") - } else { - when(resultRegister) { - null, RegisterOrPair.A -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - // NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction. - // this is required because the compiler assumes the status bits are set according to what A is (lsb) - // and will not generate another cmp when lsb() is directly used inside a comparison expression. - } - RegisterOrPair.X -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY) - // NOTE: we rely on the fact that the above assignment to XY, assigns the Lsb to X as the last instruction. - // this is required because the compiler assumes the status bits are set according to what X is (lsb) - // and will not generate another cmp when lsb() is directly used inside a comparison expression. - } - RegisterOrPair.Y -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - asmgen.out(" tay | cpy #0") - } - RegisterOrPair.AY -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) - asmgen.out(" ldy #0 | cmp #0") - } - RegisterOrPair.AX -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX) - asmgen.out(" ldx #0 | cmp #0") - } - RegisterOrPair.XY -> { - asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY) - asmgen.out(" ldy #0 | cpx #0") - } - in Cx16VirtualRegisters -> { - asmgen.assignExpressionToRegister(fcall.args.single(), resultRegister) - val zero = PtNumber(DataType.UBYTE, 0.0, Position.DUMMY) - zero.parent=fcall - assignAsmGen.assignExpressionToVariable(zero, "cx16.${resultRegister.toString().lowercase()}H", DataType.UBYTE) - asmgen.out(" lda cx16.r0L") - } - else -> throw AssemblyError("invalid reg") + when(resultRegister) { + null, RegisterOrPair.A -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) + // NOTE: we rely on the fact that the above assignment to AY, assigns the Lsb to A as the last instruction. + // this is required because the compiler assumes the status bits are set according to what A is (lsb) + // and will not generate another cmp when lsb() is directly used inside a comparison expression. } + RegisterOrPair.X -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY) + // NOTE: we rely on the fact that the above assignment to XY, assigns the Lsb to X as the last instruction. + // this is required because the compiler assumes the status bits are set according to what X is (lsb) + // and will not generate another cmp when lsb() is directly used inside a comparison expression. + } + RegisterOrPair.Y -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) + asmgen.out(" tay | cpy #0") + } + RegisterOrPair.AY -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY) + asmgen.out(" ldy #0 | cmp #0") + } + RegisterOrPair.AX -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AX) + asmgen.out(" ldx #0 | cmp #0") + } + RegisterOrPair.XY -> { + asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.XY) + asmgen.out(" ldy #0 | cpx #0") + } + in Cx16VirtualRegisters -> { + asmgen.assignExpressionToRegister(fcall.args.single(), resultRegister) + val zero = PtNumber(DataType.UBYTE, 0.0, Position.DUMMY) + zero.parent=fcall + assignAsmGen.assignExpressionToVariable(zero, "cx16.${resultRegister.toString().lowercase()}H", DataType.UBYTE) + asmgen.out(" lda cx16.r0L") + } + else -> throw AssemblyError("invalid reg") } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt deleted file mode 100644 index 3386ccace..000000000 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ /dev/null @@ -1,933 +0,0 @@ -package prog8.codegen.cpu6502 - -import prog8.code.ast.* -import prog8.code.core.* -import kotlin.math.absoluteValue - -internal class ExpressionsAsmGen(private val program: PtProgram, - private val asmgen: AsmGen6502Internal, - private val allocator: VariableAllocator) { - - @Deprecated("avoid calling this as it generates slow evalstack based code") - internal fun translateExpression(expression: PtExpression) { - if (this.asmgen.options.slowCodegenWarnings) { - asmgen.errors.warn("slow stack evaluation used for expression", expression.position) - } - translateExpressionInternal(expression) - } - - - // the rest of the methods are all PRIVATE - - - private fun translateExpressionInternal(expression: PtExpression) { - - when(expression) { - is PtPrefix -> translateExpression(expression) - is PtBinaryExpression -> translateExpression(expression) - is PtArrayIndexer -> translateExpression(expression) - is PtTypeCast -> translateExpression(expression) - is PtAddressOf -> translateExpression(expression) - is PtMemoryByte -> asmgen.translateDirectMemReadExpressionToRegAorStack(expression, true) - is PtNumber -> translateExpression(expression) - is PtIdentifier -> translateExpression(expression) - is PtFunctionCall -> translateFunctionCallResultOntoStack(expression) - is PtBuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null) - is PtContainmentCheck -> translateContainmentCheck(expression) - is PtArray, is PtString -> throw AssemblyError("string/array literal value assignment should have been replaced by a variable") - is PtRange -> throw AssemblyError("range expression should have been changed into array values") - is PtMachineRegister -> throw AssemblyError("machine register ast node should not occur in 6502 codegen it is for IR code") - else -> TODO("missing expression asmgen for $expression") - } - } - - private fun translateContainmentCheck(check: PtContainmentCheck) { - asmgen.assignExpressionToRegister(check, RegisterOrPair.A) - asmgen.out(" sta P8ESTACK_LO,x | dex") - } - - private fun translateFunctionCallResultOntoStack(call: PtFunctionCall) { - // only for use in nested expression evaluation - - val symbol = asmgen.symbolTable.lookup(call.name) - val sub = symbol!!.astNode as IPtSubroutine - asmgen.saveXbeforeCall(call) - asmgen.translateFunctionCall(call) - if(sub.regXasResult()) { - // store the return value in X somewhere that we can access again below - asmgen.out(" stx P8ZP_SCRATCH_REG") - } - asmgen.restoreXafterCall(call) - - val returns: List> = sub.returnsWhatWhere() - for ((reg, _) in returns) { - // result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree) - if (reg.registerOrPair != null) { - when (reg.registerOrPair!!) { - RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex") - RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex") - RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") - RegisterOrPair.X -> asmgen.out(" lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex") - RegisterOrPair.AX -> asmgen.out(" sta P8ESTACK_LO,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_HI,x | dex") - RegisterOrPair.XY -> asmgen.out(" tya | sta P8ESTACK_HI,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex") - RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.push_fac1") - RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.push_fac2") - RegisterOrPair.R0, - RegisterOrPair.R1, - RegisterOrPair.R2, - RegisterOrPair.R3, - RegisterOrPair.R4, - RegisterOrPair.R5, - RegisterOrPair.R6, - RegisterOrPair.R7, - RegisterOrPair.R8, - RegisterOrPair.R9, - RegisterOrPair.R10, - RegisterOrPair.R11, - RegisterOrPair.R12, - RegisterOrPair.R13, - RegisterOrPair.R14, - RegisterOrPair.R15 -> { - asmgen.out( - """ - lda cx16.${reg.registerOrPair.toString().lowercase()} - sta P8ESTACK_LO,x - lda cx16.${reg.registerOrPair.toString().lowercase()}+1 - sta P8ESTACK_HI,x - dex - """) - } - } - } else when(reg.statusflag) { - Statusflag.Pc -> { - asmgen.out(""" - lda #0 - rol a - sta P8ESTACK_LO,x - dex""") - } - Statusflag.Pz -> { - asmgen.out(""" - beq + - lda #0 - beq ++ -+ lda #1 -+ sta P8ESTACK_LO,x - dex""") - } - Statusflag.Pv -> { - asmgen.out(""" - bvs + - lda #0 - beq ++ -+ lda #1 -+ sta P8ESTACK_LO,x - dex""") - } - Statusflag.Pn -> { - asmgen.out(""" - bmi + - lda #0 - beq ++ -+ lda #1 -+ sta P8ESTACK_LO,x - dex""") - } - null -> {} - } - } - } - - private fun translateExpression(typecast: PtTypeCast) { - translateExpressionInternal(typecast.value) - when(typecast.value.type) { - DataType.UBYTE, DataType.BOOL -> { - when(typecast.type) { - DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> { - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_HI+1,x") - else - asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") - } - DataType.FLOAT -> asmgen.out(" jsr floats.stack_ub2float") - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") - else -> throw AssemblyError("weird type") - } - } - DataType.BYTE -> { - when(typecast.type) { - DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.signExtendStackLsb(DataType.BYTE) - DataType.FLOAT -> asmgen.out(" jsr floats.stack_b2float") - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") - else -> throw AssemblyError("weird type") - } - } - DataType.UWORD -> { - when(typecast.type) { - DataType.BYTE, DataType.UBYTE -> {} - DataType.WORD, DataType.UWORD -> {} - DataType.FLOAT -> asmgen.out(" jsr floats.stack_uw2float") - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") - else -> throw AssemblyError("weird type") - } - } - DataType.WORD -> { - when(typecast.type) { - DataType.BYTE, DataType.UBYTE -> {} - DataType.WORD, DataType.UWORD -> {} - DataType.FLOAT -> asmgen.out(" jsr floats.stack_w2float") - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") - else -> throw AssemblyError("weird type") - } - } - DataType.FLOAT -> { - when(typecast.type) { - DataType.UBYTE -> asmgen.out(" jsr floats.stack_float2uw") - DataType.BYTE -> asmgen.out(" jsr floats.stack_float2w") - DataType.UWORD -> asmgen.out(" jsr floats.stack_float2uw") - DataType.WORD -> asmgen.out(" jsr floats.stack_float2w") - DataType.FLOAT -> {} - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") - else -> throw AssemblyError("weird type") - } - } - DataType.STR -> { - if (typecast.type != DataType.UWORD && typecast.type == DataType.STR) - throw AssemblyError("cannot typecast a string into another incompatitble type") - } - in PassByReferenceDatatypes -> throw AssemblyError("cannot cast pass-by-reference value into another type") - else -> throw AssemblyError("weird type") - } - } - - private fun translateExpression(expr: PtAddressOf) { - val name = asmgen.asmVariableName(expr.identifier) - asmgen.out(" lda #<$name | sta P8ESTACK_LO,x | lda #>$name | sta P8ESTACK_HI,x | dex") - } - - private fun translateExpression(expr: PtNumber) { - when(expr.type) { - DataType.UBYTE, DataType.BYTE -> asmgen.out(" lda #${expr.number.toHex()} | sta P8ESTACK_LO,x | dex") - DataType.UWORD, DataType.WORD -> asmgen.out(""" - lda #<${expr.number.toHex()} - sta P8ESTACK_LO,x - lda #>${expr.number.toHex()} - sta P8ESTACK_HI,x - dex - """) - DataType.FLOAT -> { - val floatConst = allocator.getFloatAsmConst(expr.number) - asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") - } - else -> throw AssemblyError("weird type") - } - } - - private fun translateExpression(expr: PtIdentifier) { - val varname = asmgen.asmVariableName(expr) - when(expr.type) { - DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" lda $varname | sta P8ESTACK_LO,x | dex") - } - DataType.UWORD, DataType.WORD -> { - asmgen.out(" lda $varname | sta P8ESTACK_LO,x | lda $varname+1 | sta P8ESTACK_HI,x | dex") - } - DataType.FLOAT -> { - asmgen.out(" lda #<$varname | ldy #>$varname| jsr floats.push_float") - } - in SplitWordArrayTypes -> { - throw AssemblyError("can't push address of split-word array ${expr.position}") - } - in IterableDatatypes -> { - asmgen.out(" lda #<$varname | sta P8ESTACK_LO,x | lda #>$varname | sta P8ESTACK_HI,x | dex") - } - else -> throw AssemblyError("stack push weird variable type $expr") - } - } - - private fun translateExpression(expr: PtBinaryExpression) { - // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! - if(translateSomewhatOptimized(expr.left, expr.operator, expr.right)) - return - - val leftDt = expr.left.type - val rightDt = expr.right.type - - // compare with zero - if(expr.operator in ComparisonOperators) { - if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { - val rightVal = expr.right.asConstInteger() - if(rightVal==0) - return translateComparisonWithZero(expr.left, leftDt, expr.operator) - } - } - - if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators) - return translateCompareStrings(expr.left, expr.operator, expr.right) - - if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes) - || (leftDt in WordDatatypes && rightDt !in WordDatatypes)) - throw AssemblyError("binary operator ${expr.operator} left/right dt not identical") - - // the general, non-optimized cases - // TODO optimize more cases.... (or one day just don't use the evalstack at all anymore) - translateExpressionInternal(expr.left) - translateExpressionInternal(expr.right) - when (leftDt) { - in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt) - in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt) - DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator) - else -> throw AssemblyError("non-numerical datatype") - } - } - - private fun translateSomewhatOptimized(left: PtExpression, operator: String, right: PtExpression): Boolean { - val leftDt = left.type - val rightDt = right.type - when(operator) { - "+" -> { - if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVal = left.asConstInteger() - val rightVal = right.asConstInteger() - if (leftVal!=null && leftVal in -4..4) { - translateExpressionInternal(right) - if(rightDt in ByteDatatypes) { - val incdec = if(leftVal<0) "dec" else "inc" - repeat(leftVal.absoluteValue) { - asmgen.out(" $incdec P8ESTACK_LO+1,x") - } - } else { - // word - if(leftVal<0) { - repeat(leftVal.absoluteValue) { - asmgen.out(""" - lda P8ESTACK_LO+1,x - bne + - dec P8ESTACK_HI+1,x -+ dec P8ESTACK_LO+1,x""") - } - } else { - repeat(leftVal) { - asmgen.out(""" - inc P8ESTACK_LO+1,x - bne + - inc P8ESTACK_HI+1,x -+""") - } - } - } - return true - } - else if (rightVal!=null && rightVal in -4..4) - { - translateExpressionInternal(left) - if(leftDt in ByteDatatypes) { - val incdec = if(rightVal<0) "dec" else "inc" - repeat(rightVal.absoluteValue) { - asmgen.out(" $incdec P8ESTACK_LO+1,x") - } - } else { - // word - if(rightVal<0) { - repeat(rightVal.absoluteValue) { - asmgen.out(""" - lda P8ESTACK_LO+1,x - bne + - dec P8ESTACK_HI+1,x -+ dec P8ESTACK_LO+1,x""") - } - } else { - repeat(rightVal) { - asmgen.out(""" - inc P8ESTACK_LO+1,x - bne + - inc P8ESTACK_HI+1,x -+""") - } - } - } - return true - } - } - } - "-" -> { - if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = right.asConstInteger() - if (rightVal!=null && rightVal in -4..4) - { - translateExpressionInternal(left) - if(leftDt in ByteDatatypes) { - val incdec = if(rightVal<0) "inc" else "dec" - repeat(rightVal.absoluteValue) { - asmgen.out(" $incdec P8ESTACK_LO+1,x") - } - } else { - // word - if(rightVal>0) { - repeat(rightVal.absoluteValue) { - asmgen.out(""" - lda P8ESTACK_LO+1,x - bne + - dec P8ESTACK_HI+1,x -+ dec P8ESTACK_LO+1,x""") - } - } else { - repeat(rightVal) { - asmgen.out(""" - inc P8ESTACK_LO+1,x - bne + - inc P8ESTACK_HI+1,x -+""") - } - } - } - return true - } - } - } - ">>" -> { - val amount = right.asConstInteger() - if(amount!=null) { - translateExpressionInternal(left) - when (leftDt) { - DataType.UBYTE -> { - if (amount <= 2) - repeat(amount) { asmgen.out(" lsr P8ESTACK_LO+1,x") } - else { - asmgen.out(" lda P8ESTACK_LO+1,x") - repeat(amount) { asmgen.out(" lsr a") } - asmgen.out(" sta P8ESTACK_LO+1,x") - } - } - DataType.BYTE -> { - if (amount <= 2) - repeat(amount) { asmgen.out(" lda P8ESTACK_LO+1,x | asl a | ror P8ESTACK_LO+1,x") } - else { - asmgen.out(" lda P8ESTACK_LO+1,x | sta P8ZP_SCRATCH_B1") - repeat(amount) { asmgen.out(" asl a | ror P8ZP_SCRATCH_B1 | lda P8ZP_SCRATCH_B1") } - asmgen.out(" sta P8ESTACK_LO+1,x") - } - } - DataType.UWORD -> { - if(amount>=16) { - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_LO+1,x | stz P8ESTACK_HI+1,x") - else - asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x") - return true - } - var amountLeft = amount - while (amountLeft >= 7) { - asmgen.out(" jsr math.shift_right_uw_7") - amountLeft -= 7 - } - if (amountLeft in 0..2) - repeat(amountLeft) { asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") } - else - asmgen.out(" jsr math.shift_right_uw_$amountLeft") - } - DataType.WORD -> { - if(amount>=16) { - asmgen.out(""" - lda P8ESTACK_HI+1,x - bmi + - lda #0 - sta P8ESTACK_LO+1,x - sta P8ESTACK_HI+1,x - beq ++ -+ lda #255 - sta P8ESTACK_LO+1,x - sta P8ESTACK_HI+1,x -+""") - return true - } - var amountLeft = amount - while (amountLeft >= 7) { - asmgen.out(" jsr math.shift_right_w_7") - amountLeft -= 7 - } - if (amountLeft in 0..2) - repeat(amountLeft) { asmgen.out(" lda P8ESTACK_HI+1,x | asl a | ror P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") } - else - asmgen.out(" jsr math.shift_right_w_$amountLeft") - } - else -> throw AssemblyError("weird type") - } - return true - } - } - "<<" -> { - val amount = right.asConstInteger() - if(amount!=null) { - translateExpressionInternal(left) - if (leftDt in ByteDatatypes) { - if (amount <= 2) - repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") } - else { - asmgen.out(" lda P8ESTACK_LO+1,x") - repeat(amount) { asmgen.out(" asl a") } - asmgen.out(" sta P8ESTACK_LO+1,x") - } - } else { - var amountLeft = amount - while (amountLeft >= 7) { - asmgen.out(" jsr math.shift_left_w_7") - amountLeft -= 7 - } - if (amountLeft in 0..2) - repeat(amountLeft) { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") } - else - asmgen.out(" jsr math.shift_left_w_$amountLeft") - } - return true - } - } - "*" -> { - if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVar = left as? PtIdentifier - val rightVar = right as? PtIdentifier - if(leftVar!=null && rightVar!=null && leftVar==rightVar) { - translateSquared(leftVar, leftDt) - return true - } - } - - val value = right as? PtNumber - if(value!=null) { - if(rightDt in IntegerDatatypes) { - val amount = value.number.toInt() - if(amount==2) { - // optimize x*2 common case - translateExpressionInternal(left) - if(leftDt in ByteDatatypes) { - asmgen.out(" asl P8ESTACK_LO+1,x") - } else { - asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") - } - return true - } - when(rightDt) { - DataType.UBYTE -> { - if(amount in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr math.stack_mul_byte_$amount") - return true - } - } - DataType.BYTE -> { - if(amount in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr math.stack_mul_byte_$amount") - return true - } - if(amount.absoluteValue in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}") - return true - } - } - DataType.UWORD -> { - if(amount in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr math.stack_mul_word_$amount") - return true - } - } - DataType.WORD -> { - if(amount in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr math.stack_mul_word_$amount") - return true - } - if(amount.absoluteValue in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(left) - asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}") - return true - } - } - else -> {} - } - } - } - } - "/" -> { - if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = right.asConstInteger() - if(rightVal!=null && rightVal==2) { - translateExpressionInternal(left) - when (leftDt) { - DataType.UBYTE -> { - asmgen.out(" lsr P8ESTACK_LO+1,x") - } - DataType.UWORD -> { - asmgen.out(" lsr P8ESTACK_HI+1,x | ror P8ESTACK_LO+1,x") - } - DataType.BYTE -> { - // signed divide using shift needs adjusting of negative value to get correct rounding towards zero - asmgen.out(""" - lda P8ESTACK_LO+1,x - bpl + - inc P8ESTACK_LO+1,x - lda P8ESTACK_LO+1,x -+ asl a - ror P8ESTACK_LO+1,x""") - } - DataType.WORD -> { - // signed divide using shift needs adjusting of negative value to get correct rounding towards zero - asmgen.out(""" - lda P8ESTACK_HI+1,x - bpl ++ - inc P8ESTACK_LO+1,x - bne + - inc P8ESTACK_HI+1,x -+ lda P8ESTACK_HI+1,x -+ asl a - ror P8ESTACK_HI+1,x - ror P8ESTACK_LO+1,x""") - } - else -> throw AssemblyError("weird dt") - } - return true - } - } - } - } - - return false - } - - private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) { - if(expr.isSimple()) { - if(operator=="!=") { - when (dt) { - in ByteDatatypes -> { - asmgen.assignExpressionToRegister(expr, RegisterOrPair.A, dt == DataType.BYTE) - asmgen.out(""" - beq + - lda #1 -+ sta P8ESTACK_LO,x - dex""") - return - } - in WordDatatypes -> { - asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, dt == DataType.WORD) - asmgen.out(""" - sty P8ZP_SCRATCH_B1 - ora P8ZP_SCRATCH_B1 - beq + - lda #1 -+ sta P8ESTACK_LO,x - dex""") - return - } - DataType.FLOAT -> { - asmgen.assignExpressionToRegister(expr, RegisterOrPair.FAC1, true) - asmgen.out(""" - jsr floats.SIGN - sta P8ESTACK_LO,x - dex""") - return - } - else -> {} - } - } - /* operator == is not worth it to special case, the code is mostly larger */ - } - translateExpressionInternal(expr) - when(operator) { - "==" -> { - when(dt) { - DataType.UBYTE, DataType.BYTE -> asmgen.out(" jsr prog8_lib.equalzero_b") - DataType.UWORD, DataType.WORD -> asmgen.out(" jsr prog8_lib.equalzero_w") - DataType.FLOAT -> asmgen.out(" jsr floats.equal_zero") - else -> throw AssemblyError("wrong dt") - } - } - "!=" -> { - when(dt) { - DataType.UBYTE, DataType.BYTE -> asmgen.out(" jsr prog8_lib.notequalzero_b") - DataType.UWORD, DataType.WORD -> asmgen.out(" jsr prog8_lib.notequalzero_w") - DataType.FLOAT -> asmgen.out(" jsr floats.notequal_zero") - else -> throw AssemblyError("wrong dt") - } - } - "<" -> { - if(dt==DataType.UBYTE || dt==DataType.UWORD) - return translateExpressionInternal(PtNumber.fromBoolean(false, expr.position)) - when(dt) { - DataType.BYTE -> asmgen.out(" jsr prog8_lib.lesszero_b") - DataType.WORD -> asmgen.out(" jsr prog8_lib.lesszero_w") - DataType.FLOAT -> asmgen.out(" jsr floats.less_zero") - else -> throw AssemblyError("wrong dt") - } - } - ">" -> { - when(dt) { - DataType.UBYTE -> asmgen.out(" jsr prog8_lib.greaterzero_ub") - DataType.BYTE -> asmgen.out(" jsr prog8_lib.greaterzero_sb") - DataType.UWORD -> asmgen.out(" jsr prog8_lib.greaterzero_uw") - DataType.WORD -> asmgen.out(" jsr prog8_lib.greaterzero_sw") - DataType.FLOAT -> asmgen.out(" jsr floats.greater_zero") - else -> throw AssemblyError("wrong dt") - } - } - "<=" -> { - when(dt) { - DataType.UBYTE -> asmgen.out(" jsr prog8_lib.equalzero_b") - DataType.BYTE -> asmgen.out(" jsr prog8_lib.lessequalzero_sb") - DataType.UWORD -> asmgen.out(" jsr prog8_lib.equalzero_w") - DataType.WORD -> asmgen.out(" jsr prog8_lib.lessequalzero_sw") - DataType.FLOAT -> asmgen.out(" jsr floats.lessequal_zero") - else -> throw AssemblyError("wrong dt") - } - } - ">=" -> { - if(dt==DataType.UBYTE || dt==DataType.UWORD) - return translateExpressionInternal(PtNumber.fromBoolean(true, expr.position)) - when(dt) { - DataType.BYTE -> asmgen.out(" jsr prog8_lib.greaterequalzero_sb") - DataType.WORD -> asmgen.out(" jsr prog8_lib.greaterequalzero_sw") - DataType.FLOAT -> asmgen.out(" jsr floats.greaterequal_zero") - else -> throw AssemblyError("wrong dt") - } - } - else -> throw AssemblyError("invalid comparison operator") - } - } - - private fun translateSquared(variable: PtIdentifier, dt: DataType) { - val asmVar = asmgen.asmVariableName(variable) - when(dt) { - DataType.BYTE, DataType.UBYTE -> { - asmgen.out(" lda $asmVar") - asmgen.signExtendAYlsb(dt) - asmgen.out(" jsr math.square") - } - DataType.UWORD, DataType.WORD -> { - asmgen.out(" lda $asmVar | ldy $asmVar+1 | jsr math.square") - } - else -> throw AssemblyError("require integer dt for square") - } - asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") - } - - private fun translateExpression(expr: PtPrefix) { - translateExpressionInternal(expr.value) - when(expr.operator) { - "+" -> {} - "-" -> { - when(expr.type) { - in ByteDatatypes -> asmgen.out(" jsr prog8_lib.neg_b") - in WordDatatypes -> asmgen.out(" jsr prog8_lib.neg_w") - DataType.FLOAT -> asmgen.out(" jsr floats.neg_f") - else -> throw AssemblyError("weird type") - } - } - "~" -> { - when(expr.type) { - in ByteDatatypes -> - asmgen.out(""" - lda P8ESTACK_LO+1,x - eor #255 - sta P8ESTACK_LO+1,x - """) - in WordDatatypes -> asmgen.out(" jsr prog8_lib.inv_word") - else -> throw AssemblyError("weird type") - } - } - else -> throw AssemblyError("invalid prefix operator ${expr.operator}") - } - } - - private fun translateExpression(arrayExpr: PtArrayIndexer) { - val elementDt = arrayExpr.type - val arrayVarName = asmgen.asmVariableName(arrayExpr.variable) - - if(arrayExpr.variable.type==DataType.UWORD) { - // indexing a pointer var instead of a real array or string - if(elementDt !in ByteDatatypes) - throw AssemblyError("non-array var indexing requires bytes dt") - if(arrayExpr.index.type != DataType.UBYTE) - throw AssemblyError("non-array var indexing requires bytes index") - asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y) - if(asmgen.isZpVar(arrayExpr.variable)) { - asmgen.out(" lda ($arrayVarName),y") - } else { - asmgen.out(" lda $arrayVarName | sta P8ZP_SCRATCH_W1 | lda $arrayVarName+1 | sta P8ZP_SCRATCH_W1+1") - asmgen.out(" lda (P8ZP_SCRATCH_W1),y") - } - asmgen.out(" sta P8ESTACK_LO,x | dex") - return - } - - if(arrayExpr.splitWords) - TODO("split words expression ${arrayExpr.position}") - - val constIndexNum = arrayExpr.index.asConstInteger() - if(constIndexNum!=null) { - val indexValue = constIndexNum * program.memsizer.memorySize(elementDt) - when(elementDt) { - in ByteDatatypes -> { - asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | dex") - } - in WordDatatypes -> { - asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | lda $arrayVarName+$indexValue+1 | sta P8ESTACK_HI,x | dex") - } - DataType.FLOAT -> { - asmgen.out(" lda #<($arrayVarName+$indexValue) | ldy #>($arrayVarName+$indexValue) | jsr floats.push_float") - } - else -> throw AssemblyError("weird element type") - } - } else { - when(elementDt) { - in ByteDatatypes -> { - asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y) - asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | dex") - } - in WordDatatypes -> { - asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y) - asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | lda $arrayVarName+1,y | sta P8ESTACK_HI,x | dex") - } - DataType.FLOAT -> { - asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.A) - asmgen.out(""" - ldy #>$arrayVarName - clc - adc #<$arrayVarName - bcc + - iny -+ jsr floats.push_float""") - } - else -> throw AssemblyError("weird dt") - } - - } - } - - private fun translateBinaryOperatorBytes(operator: String, types: DataType) { - when(operator) { - "*" -> asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier - "/" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") - "%" -> { - if(types==DataType.BYTE) - throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") - asmgen.out(" jsr prog8_lib.remainder_ub") - } - "+" -> asmgen.out(""" - lda P8ESTACK_LO+2,x - clc - adc P8ESTACK_LO+1,x - inx - sta P8ESTACK_LO+1,x - """) - "-" -> asmgen.out(""" - lda P8ESTACK_LO+2,x - sec - sbc P8ESTACK_LO+1,x - inx - sta P8ESTACK_LO+1,x - """) - "<<" -> asmgen.out(" jsr prog8_lib.shiftleft_b") - ">>" -> asmgen.out(" jsr prog8_lib.shiftright_b") - "<" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.less_ub" else " jsr prog8_lib.less_b") - ">" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.greater_ub" else " jsr prog8_lib.greater_b") - "<=" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.lesseq_ub" else " jsr prog8_lib.lesseq_b") - ">=" -> asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.greatereq_ub" else " jsr prog8_lib.greatereq_b") - "==" -> asmgen.out(" jsr prog8_lib.equal_b") - "!=" -> asmgen.out(" jsr prog8_lib.notequal_b") - "&" -> asmgen.out(" jsr prog8_lib.bitand_b") - "^" -> asmgen.out(" jsr prog8_lib.bitxor_b") - "|" -> asmgen.out(" jsr prog8_lib.bitor_b") - else -> throw AssemblyError("invalid operator $operator") - } - } - - private fun translateBinaryOperatorWords(operator: String, dt: DataType) { - when(operator) { - "*" -> asmgen.out(" jsr prog8_lib.mul_word") - "/" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.idiv_uw" else " jsr prog8_lib.idiv_w") - "%" -> { - if(dt==DataType.WORD) - throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") - asmgen.out(" jsr prog8_lib.remainder_uw") - } - "+" -> asmgen.out(" jsr prog8_lib.add_w") - "-" -> asmgen.out(" jsr prog8_lib.sub_w") - "<<" -> asmgen.out(" jsr math.shift_left_w") - ">>" -> { - if(dt==DataType.UWORD) - asmgen.out(" jsr math.shift_right_uw") - else - asmgen.out(" jsr math.shift_right_w") - } - "<" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.less_uw" else " jsr prog8_lib.less_w") - ">" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.greater_uw" else " jsr prog8_lib.greater_w") - "<=" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.lesseq_uw" else " jsr prog8_lib.lesseq_w") - ">=" -> asmgen.out(if(dt==DataType.UWORD) " jsr prog8_lib.greatereq_uw" else " jsr prog8_lib.greatereq_w") - "==" -> asmgen.out(" jsr prog8_lib.equal_w") - "!=" -> asmgen.out(" jsr prog8_lib.notequal_w") - "&" -> asmgen.out(" jsr prog8_lib.bitand_w") - "^" -> asmgen.out(" jsr prog8_lib.bitxor_w") - "|" -> asmgen.out(" jsr prog8_lib.bitor_w") - else -> throw AssemblyError("invalid operator $operator") - } - } - - private fun translateBinaryOperatorFloats(operator: String) { - when(operator) { - "*" -> asmgen.out(" jsr floats.mul_f") - "/" -> asmgen.out(" jsr floats.div_f") - "+" -> asmgen.out(" jsr floats.add_f") - "-" -> asmgen.out(" jsr floats.sub_f") - "<" -> asmgen.out(" jsr floats.less_f") - ">" -> asmgen.out(" jsr floats.greater_f") - "<=" -> asmgen.out(" jsr floats.lesseq_f") - ">=" -> asmgen.out(" jsr floats.greatereq_f") - "==" -> asmgen.out(" jsr floats.equal_f") - "!=" -> asmgen.out(" jsr floats.notequal_f") - "%", "<<", ">>", "&", "^", "|" -> throw AssemblyError("requires integer datatype") - else -> throw AssemblyError("invalid operator $operator") - } - } - - private fun translateCompareStrings(s1: PtExpression, operator: String, s2: PtExpression) { - asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD) - asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD) - asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A - compareStringsProcessResultInA(operator) - } - - private fun compareStringsProcessResultInA(operator: String) { - when(operator) { - "==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x") - "!=" -> asmgen.out(" and #1 | sta P8ESTACK_LO,x") - "<=" -> asmgen.out(""" - bpl + - lda #1 - bne ++ -+ lda #0 -+ sta P8ESTACK_LO,x""") - ">=" -> asmgen.out(""" - bmi + - lda #1 - bne ++ -+ lda #0 -+ sta P8ESTACK_LO,x""") - "<" -> asmgen.out(""" - bmi + - lda #0 - beq ++ -+ lda #1 -+ sta P8ESTACK_LO,x""") - ">" -> asmgen.out(""" - bpl + - lda #0 - beq ++ -+ lda #1 -+ sta P8ESTACK_LO,x""") - } - asmgen.out(" dex") - } -} diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index b1e7628ba..7f56fcbed 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -6,15 +6,6 @@ import prog8.code.ast.PtSub import prog8.code.core.* -internal fun IPtSubroutine.regXasResult(): Boolean = - (this is PtAsmSub) && this.returns.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - -internal fun IPtSubroutine.shouldSaveX(): Boolean = - this.regXasResult() || (this is PtAsmSub && (CpuRegister.X in this.clobbers || regXasParam())) - -internal fun PtAsmSub.regXasParam(): Boolean = - parameters.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) internal fun PtAsmSub.shouldKeepA(): KeepAresult { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 1051b6497..d9d06f376 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -11,42 +11,10 @@ import prog8.codegen.cpu6502.assignment.TargetStorageKind internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) { internal fun translateFunctionCallStatement(stmt: PtFunctionCall) { - saveXbeforeCall(stmt) translateFunctionCall(stmt) - restoreXafterCall(stmt) // just ignore any result values from the function call. } - internal fun saveXbeforeCall(stmt: PtFunctionCall) { - val symbol = asmgen.symbolTable.lookup(stmt.name) - val sub = symbol!!.astNode as IPtSubroutine - if(sub.shouldSaveX()) { - if(sub is PtAsmSub) { - val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if (regSaveOnStack) - asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry) - else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) - } else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) - } - } - - internal fun restoreXafterCall(stmt: PtFunctionCall) { - val symbol = asmgen.symbolTable.lookup(stmt.name) - val sub = symbol!!.astNode as IPtSubroutine - if(sub.shouldSaveX()) { - if(sub is PtAsmSub) { - val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if (regSaveOnStack) - asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn) - else - asmgen.restoreRegisterLocal(CpuRegister.X) - } else - asmgen.restoreRegisterLocal(CpuRegister.X) - } - } - internal fun optimizeIntArgsViaRegisters(sub: PtSub) = (sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes) || (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt index c92b706ca..327cada54 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt @@ -13,7 +13,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as val targetIdent = stmt.target.identifier val targetMemory = stmt.target.memory val targetArrayIdx = stmt.target.array - val scope = stmt.definingISub() when { targetIdent!=null -> { val what = asmgen.asmVariableName(targetIdent) @@ -76,7 +75,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as dec ${asmArrayvarname}_msb+$constIndex + dec ${asmArrayvarname}_lsb+$constIndex""") } else { - asmgen.saveRegisterLocal(CpuRegister.X, scope!!) asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X) if(incr) asmgen.out(" inc ${asmArrayvarname}_lsb,x | bne + | inc ${asmArrayvarname}_msb,x |+") @@ -86,7 +84,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as bne + dec ${asmArrayvarname}_msb,x + dec ${asmArrayvarname}_lsb,x""") - asmgen.restoreRegisterLocal(CpuRegister.X) } return } @@ -113,7 +110,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as } else { - asmgen.saveRegisterLocal(CpuRegister.X, scope!!) asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X) when(elementDt) { in ByteDatatypes -> { @@ -141,7 +137,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as } else -> throw AssemblyError("weird array elt dt") } - asmgen.restoreRegisterLocal(CpuRegister.X) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index aa9d38028..53b7fd29a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -75,8 +75,6 @@ internal class ProgramAndVarsGen( asmgen.out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word") asmgen.out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word") asmgen.out(".weak") // hack to allow user to override the following two with command line redefinition (however, just use '-esa' command line option instead!) - asmgen.out("P8ESTACK_LO = ${compTarget.machine.ESTACK_LO.toHex()}") - asmgen.out("P8ESTACK_HI = ${compTarget.machine.ESTACK_HI.toHex()}") asmgen.out(".endweak") if(options.symbolDefs.isNotEmpty()) { @@ -371,12 +369,6 @@ internal class ProgramAndVarsGen( else -> throw AssemblyError("weird dt for extravar $dt") } } - if(asmGenInfo.usedRegsaveA) // will probably never occur - asmgen.out("prog8_regsaveA .byte ?") - if(asmGenInfo.usedRegsaveX) - asmgen.out("prog8_regsaveX .byte ?") - if(asmGenInfo.usedRegsaveY) - asmgen.out("prog8_regsaveY .byte ?") if(asmGenInfo.usedFloatEvalResultVar1) asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") if(asmGenInfo.usedFloatEvalResultVar2) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt new file mode 100644 index 000000000..5bdbc606e --- /dev/null +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt @@ -0,0 +1,265 @@ +package prog8.codegen.cpu6502.assignment + +import prog8.code.ast.PtBinaryExpression +import prog8.code.core.* +import prog8.codegen.cpu6502.AsmGen6502Internal + +// +// This contains codegen for stack-based evaluation of binary expressions. +// It uses the CPU stack so depth is limited. +// It is called "as a last resort" if the optimized codegen path is unable +// to come up with a special case of the expression. +// +internal class AnyExprAsmGen( + private val asmgen: AsmGen6502Internal +) { + fun assignAnyExpressionUsingStack(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { + when(expr.type) { + in ByteDatatypes -> { + if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) + return assignByteBinExpr(expr, assign) + if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + require(expr.operator in ComparisonOperators) + TODO("words operands comparison -> byte") + } + if (expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { + require(expr.operator in ComparisonOperators) + return assignFloatBinExpr(expr, assign) + } + TODO("weird expr operand types") + } + in WordDatatypes -> { + require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + "both operands must be words" + } + return assignWordBinExpr(expr) + } + DataType.FLOAT -> { + require(expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { + "both operands must be floats" + } + return assignFloatBinExpr(expr, assign) + } + else -> throw AssemblyError("weird expression type in assignment") + } + } + + private fun assignWordBinExpr(expr: PtBinaryExpression): Boolean { + when(expr.operator) { + "+" -> { + TODO("word + at ${expr.position}") + } + "-" -> { + TODO("word - at ${expr.position}") + } + "*" -> { + TODO("word * at ${expr.position}") + } + "/" -> { + TODO("word / at ${expr.position}") + } + "<<" -> { + TODO("word << at ${expr.position}") + } + ">>" -> { + TODO("word >> at ${expr.position}") + } + "%" -> { + TODO("word % at ${expr.position}") + } + "&", "and" -> { + TODO("word and at ${expr.position}") + } + "|", "or" -> { + TODO("word or at ${expr.position}") + } + "^", "xor" -> { + TODO("word xor at ${expr.position}") + } + "==" -> { + TODO("word == at ${expr.position}") + } + "!=" -> { + TODO("word != at ${expr.position}") + } + "<" -> { + TODO("word < at ${expr.position}") + } + "<=" -> { + TODO("word <= at ${expr.position}") + } + ">" -> { + TODO("word > at ${expr.position}") + } + ">=" -> { + TODO("word >= at ${expr.position}") + } + else -> return false + } + } + + private fun assignByteBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { + when(expr.operator) { + "+" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.out(" pla | clc | adc P8ZP_SCRATCH_B1") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "-" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.out(" pla | sec | sbc P8ZP_SCRATCH_B1") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "*" -> { + TODO("byte * at ${expr.position}") + } + "/" -> { + TODO("byte / at ${expr.position}") + } + "<<" -> { + TODO("byte << at ${expr.position}") + } + ">>" -> { + TODO("byte >> at ${expr.position}") + } + "%" -> { + TODO("byte % at ${expr.position}") + } + "&", "and" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.out(" pla | and P8ZP_SCRATCH_B1") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "|", "or" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.out(" pla | ora P8ZP_SCRATCH_B1") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "^", "xor" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.out(" pla | eor P8ZP_SCRATCH_B1") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "==" -> { + TODO("byte == at ${expr.position}") + } + "!=" -> { + TODO("byte != at ${expr.position}") + } + "<" -> { + TODO("byte < at ${expr.position}") + } + "<=" -> { + TODO("byte <= at ${expr.position}") + } + ">" -> { + TODO("byte > at ${expr.position}") + } + ">=" -> { + TODO("byte >= at ${expr.position}") + } + else -> return false + } + } + + private fun assignFloatBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { + when(expr.operator) { + "+" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) + if(!expr.right.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true) + if(!expr.right.isSimple()) asmgen.popFAC1() + asmgen.out(" jsr floats.FADDT") + asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) + return true + } + "-" -> { + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true) + if(!expr.left.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true) + if(!expr.left.isSimple()) asmgen.popFAC1() + asmgen.out(" jsr floats.FSUBT") + asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) + return true + } + "*" -> { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) + if(!expr.right.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC2, true) + if(!expr.right.isSimple()) asmgen.popFAC1() + asmgen.out(" jsr floats.FMULTT") + asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) + return true + } + "/" -> { + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.FAC1, true) + if(!expr.left.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC2, true) + if(!expr.left.isSimple()) asmgen.popFAC1() + asmgen.out(" jsr floats.FDIVT") + asmgen.assignRegister(RegisterOrPair.FAC1, assign.target) + return true + } + "==" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_equal_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "!=" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_notequal_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "<" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_less_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + ">" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_greater_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + "<=" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_lesseq_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + ">=" -> { + setupFloatComparisonFAC1vsVarAY(expr) + asmgen.out(" jsr floats.var_fac1_greatereq_f") + asmgen.assignRegister(RegisterOrPair.A, assign.target) + return true + } + else -> TODO("float expression operator ${expr.operator}") + } + } + + private fun setupFloatComparisonFAC1vsVarAY(expr: PtBinaryExpression) { + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true) + if(!expr.right.isSimple()) asmgen.pushFAC1() + asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.FLOAT) + if(!expr.right.isSimple()) asmgen.popFAC1() + asmgen.out(" lda #floats.floats_temp_var") + } +} \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 19e581d46..0731e91fc 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -10,8 +10,7 @@ internal enum class TargetStorageKind { VARIABLE, ARRAY, MEMORY, - REGISTER, - STACK + REGISTER } internal enum class SourceStorageKind { @@ -20,7 +19,6 @@ internal enum class SourceStorageKind { ARRAY, MEMORY, REGISTER, - STACK, // value is already present on stack EXPRESSION, // expression in ast-form, still to be evaluated } @@ -120,7 +118,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, TargetStorageKind.MEMORY -> { left isSameAs memory!! } - TargetStorageKind.REGISTER, TargetStorageKind.STACK -> { + TargetStorageKind.REGISTER -> { false } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 0da196e58..175037976 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -1,6 +1,5 @@ package prog8.codegen.cpu6502.assignment -import prog8.code.SymbolTable import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen6502Internal @@ -9,8 +8,8 @@ import prog8.codegen.cpu6502.returnsWhatWhere internal class AssignmentAsmGen(private val program: PtProgram, - private val symbolTable: SymbolTable, private val asmgen: AsmGen6502Internal, + private val anyExprGen: AnyExprAsmGen, private val allocator: VariableAllocator) { private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator) @@ -174,10 +173,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, SourceStorageKind.REGISTER -> { asmgen.assignRegister(assign.source.register!!, assign.target) } - SourceStorageKind.STACK -> { - if(assign.target.kind!=TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype) - assignStackValue(assign.target) - } } } @@ -195,12 +190,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, is PtFunctionCall -> { val symbol = asmgen.symbolTable.lookup(value.name) val sub = symbol!!.astNode as IPtSubroutine - asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value) val returnValue = sub.returnsWhatWhere().singleOrNull { it.first.registerOrPair!=null } ?: sub.returnsWhatWhere().single { it.first.statusflag!=null } when (returnValue.second) { DataType.STR -> { - asmgen.restoreXafterCall(value) when(assign.target.datatype) { DataType.UWORD -> { // assign the address of the string result value @@ -214,7 +207,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } DataType.FLOAT -> { // float result from function sits in FAC1 - asmgen.restoreXafterCall(value) assignFAC1float(assign.target) } else -> { @@ -250,13 +242,11 @@ internal class AssignmentAsmGen(private val program: PtProgram, throw AssemblyError("should be just one register byte result value") } } - // we've processed the result value in the X register by now, so it's now finally safe to restore it - asmgen.restoreXafterCall(value) } } } is PtBuiltinFunctionCall -> { - val returnDt = asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register) + val returnDt = asmgen.translateBuiltinFunctionCallExpression(value, assign.target.register) if(assign.target.register==null) { // still need to assign the result to the target variable/etc. when(returnDt) { @@ -379,10 +369,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, } is PtBinaryExpression -> { if(!attemptAssignOptimizedBinexpr(value, assign)) { - // All remaining binary expressions just evaluate via the stack for now. - // (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here, - // because the code here is the implementation of exactly that...) - fallbackToStackEval(assign) + // TOO BAD: the expression was too complex to translate into assembly. + throw AssemblyError("Expression is too complex to translate into assembly. Split it up into several separate statements, introduce a temporary variable, or otherwise rewrite it. Location: ${assign.position}") } } else -> throw AssemblyError("weird assignment value type $value") @@ -465,90 +453,472 @@ internal class AssignmentAsmGen(private val program: PtProgram, } if(expr.type !in IntegerDatatypes) - return false + return anyExprGen.assignAnyExpressionUsingStack(expr, assign) - if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { - if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { - if (expr.right.isSimple()) { - if (expr.right is PtNumber || expr.right is PtIdentifier) { - assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right) - return true - } - else if (expr.left is PtNumber || expr.left is PtIdentifier) { - assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left) - return true - } - } + if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) + return optimizedLogicalOrBitwiseExpr(expr, assign.target) + if(expr.operator == "==" || expr.operator == "!=") + return optimizedEqualityExpr(expr, assign.target) + if(expr.operator=="+" || expr.operator=="-") + return optimizedPlusMinExpr(expr, assign.target) + if(expr.operator=="<<" || expr.operator==">>") + return optimizedBitshiftExpr(expr, assign.target) + if(expr.operator=="*") + return optimizedMultiplyExpr(expr, assign.target) + if(expr.operator=="/") + return optimizedDivideExpr(expr, assign.target) + if(expr.operator=="%") + return optimizedRemainderExpr(expr, assign.target) + return anyExprGen.assignAnyExpressionUsingStack(expr, assign) + } + + private fun optimizedRemainderExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + when(expr.type) { + DataType.UBYTE -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) - asmgen.restoreRegisterStack(CpuRegister.A, false) - when (expr.operator) { - "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") - "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") - "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1") - else -> throw AssemblyError("invalid operator") - } - assignRegisterByte(assign.target, CpuRegister.A, false) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) + asmgen.out(" pla | jsr math.divmod_ub_asm") + if(target.register==RegisterOrPair.A) + asmgen.out(" cmp #0") // fix the status register + else + assignRegisterByte(target, CpuRegister.A, false) return true } - else if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { - if (expr.right.isSimple()) { - if (expr.right is PtNumber || expr.right is PtIdentifier) { - assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right) - return true - } - else if (expr.left is PtNumber || expr.left is PtIdentifier) { - assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left) - return true - } - } - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - when (expr.operator) { - "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_W1 | pha | tya | and P8ZP_SCRATCH_W1+1 | tay | pla") - "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_W1 | pha | tya | ora P8ZP_SCRATCH_W1+1 | tay | pla") - "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_W1 | pha | tya | eor P8ZP_SCRATCH_W1+1 | tay | pla") - else -> throw AssemblyError("invalid operator") - } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) + DataType.UWORD -> { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(" jsr math.divmod_uw_asm") + assignVariableWord(target, "P8ZP_SCRATCH_W2", DataType.UWORD) return true } - return false + else -> return false } + } - if(expr.operator == "==" || expr.operator == "!=") { - // expression datatype is BOOL (ubyte) but operands can be anything - if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes && - expr.left.isSimple() && expr.right.isSimple()) { + private fun optimizedDivideExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + when(expr.type) { + DataType.UBYTE -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) - asmgen.restoreRegisterStack(CpuRegister.A, false) - if(expr.operator=="==") { + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) + asmgen.out(" pla | jsr math.divmod_ub_asm") + assignRegisterByte(target, CpuRegister.Y, false) + return true + } + DataType.BYTE -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, true) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, true) + asmgen.out(" pla | jsr math.divmod_b_asm") + assignRegisterByte(target, CpuRegister.Y, true) + return true + } + DataType.UWORD -> { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(" jsr math.divmod_uw_asm") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + DataType.WORD -> { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(" jsr math.divmod_w_asm") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + else -> return false + } + } + + private fun optimizedMultiplyExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + val value = expr.right.asConstInteger() + if(value==null) { + when(expr.type) { + in ByteDatatypes -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes) + asmgen.out(" pla | jsr math.multiply_bytes") + assignRegisterByte(target, CpuRegister.A, false) + return true + } + in WordDatatypes -> { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(" jsr math.multiply_words") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + else -> return false + } + } else { + when (expr.type) { + in ByteDatatypes -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + if (value in asmgen.optimizedByteMultiplications) + asmgen.out(" jsr math.mul_byte_${value}") + else + asmgen.out(" ldy #$value | jsr math.multiply_bytes") + assignRegisterByte(target, CpuRegister.A, false) + return true + } + in WordDatatypes -> { + if (value in asmgen.optimizedWordMultiplications) { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type in SignedDatatypes) + asmgen.out(" jsr math.mul_word_${value}") + } + else { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(" jsr math.multiply_words") + } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + else -> return false + } + } + } + + private fun optimizedBitshiftExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + val signed = expr.left.type in SignedDatatypes + val shifts = expr.right.asConstInteger() + val dt = expr.left.type + if(shifts==null) { + // bit shifts with variable shifts + when(expr.right.type) { + in ByteDatatypes -> { + assignExpressionToRegister(expr.right, RegisterOrPair.A, false) + } + in WordDatatypes -> { + assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) asmgen.out(""" + cpy #0 + beq + + lda #127 ++""") + } + else -> throw AssemblyError("weird shift value type") + } + asmgen.out(" pha") + if(dt in ByteDatatypes) { + assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) + asmgen.out(" ply") + if(expr.operator==">>") + if(signed) + asmgen.out(" jsr math.lsr_byte_A") + else + asmgen.out(" jsr math.lsr_ubyte_A") + else + asmgen.out(" jsr math.asl_byte_A") + assignRegisterByte(target, CpuRegister.A, signed) + return true + } else { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) + asmgen.out(" plx") + if(expr.operator==">>") + if(signed) + asmgen.out(" jsr math.lsr_word_AY") + else + asmgen.out(" jsr math.lsr_uword_AY") + else + asmgen.out(" jsr math.asl_word_AY") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + } + else { + // bit shift with constant value + if(dt in ByteDatatypes) { + assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) + when (shifts) { + in 0..7 -> { + if (expr.operator == "<<") { + repeat(shifts) { + asmgen.out(" asl a") + } + } else { + if (signed && shifts > 0) { + asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A") + } else { + repeat(shifts) { + asmgen.out(" lsr a") + } + } + } + assignRegisterByte(target, CpuRegister.A, signed) + return true + } + else -> { + if(signed && expr.operator==">>") { + asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A") + } else { + asmgen.out(" lda #0") + } + assignRegisterByte(target, CpuRegister.A, signed) + return true + } + } + } else if(dt in WordDatatypes) { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) + when (shifts) { + in 0..7 -> { + if(expr.operator=="<<") { + if(shifts>0) { + asmgen.out(" sty P8ZP_SCRATCH_B1") + repeat(shifts) { + asmgen.out(" asl a | rol P8ZP_SCRATCH_B1") + } + asmgen.out(" ldy P8ZP_SCRATCH_B1") + } + } else { + if(signed && shifts>0) { + asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY") + } else { + if(shifts>0) { + asmgen.out(" sty P8ZP_SCRATCH_B1") + repeat(shifts) { + asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a") + } + asmgen.out(" ldy P8ZP_SCRATCH_B1") + } + } + } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + in 8..15 -> { + if(expr.operator == "<<") { + // msb = lsb << (shifts-8), lsb = 0 + repeat(shifts-8) { + asmgen.out(" asl a") + } + asmgen.out(" tay | lda #0") + } else { + asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY") + } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + else -> { + if(signed && expr.operator==">>") { + asmgen.out(" ldx #$shifts | jsr math.lsr_word_AY") + } else { + asmgen.out(" lda #0 | ldy #0") + } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + } + } + } + return false + } + + private fun optimizedPlusMinExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + val dt = expr.type + val left = expr.left + val right = expr.right + if(dt in ByteDatatypes) { + when (right) { + is PtIdentifier -> { + assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + val symname = asmgen.asmVariableName(right) + if(expr.operator=="+") + asmgen.out(" clc | adc $symname") + else + asmgen.out(" sec | sbc $symname") + assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes) + return true + } + is PtNumber -> { + assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) + if(expr.operator=="+") + asmgen.out(" clc | adc #${right.number.toHex()}") + else + asmgen.out(" sec | sbc #${right.number.toHex()}") + assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes) + return true + } + else -> { + assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) + asmgen.out(" pha") + assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type) + asmgen.out(" pla") + if(expr.operator=="+") + asmgen.out(" clc | adc P8ZP_SCRATCH_B1") + else + asmgen.out(" sec | sbc P8ZP_SCRATCH_B1") + assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes) + return true + } + } + } else if(dt in WordDatatypes) { + + fun doAddOrSubWordExpr() { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + if(expr.operator=="+") + asmgen.out(""" + clc + adc P8ZP_SCRATCH_W1 + pha + tya + adc P8ZP_SCRATCH_W1+1 + tay + pla""") + else + asmgen.out(""" + sec + sbc P8ZP_SCRATCH_W1 + pha + tya + sbc P8ZP_SCRATCH_W1+1 + tay + pla""") + assignRegisterpairWord(target, RegisterOrPair.AY) + } + + when (right) { + is PtAddressOf -> { + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + val symbol = asmgen.asmVariableName(right.identifier) + if(expr.operator=="+") + asmgen.out(""" + clc + adc #<$symbol + pha + tya + adc #>$symbol + tay + pla""") + else + asmgen.out(""" + sec + sbc #<$symbol + pha + tya + sbc #>$symbol + tay + pla""") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + is PtIdentifier -> { + val symname = asmgen.asmVariableName(right) + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + if(expr.operator=="+") + asmgen.out(""" + clc + adc $symname + pha + tya + adc $symname+1 + tay + pla""") + else + asmgen.out(""" + sec + sbc $symname + pha + tya + sbc $symname+1 + tay + pla""") + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + is PtNumber -> { + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + if(expr.operator=="+") { + asmgen.out(""" + clc + adc #<${right.number.toHex()} + pha + tya + adc #>${right.number.toHex()} + tay + pla""") + } else if(expr.operator=="-") { + asmgen.out(""" + sec + sbc #<${right.number.toHex()} + pha + tya + sbc #>${right.number.toHex()} + tay + pla""") + } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + is PtTypeCast -> { + val castedValue = right.value + if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) { + val castedSymname = asmgen.asmVariableName(castedValue) + assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD) + if (expr.operator == "+") + asmgen.out( + """ + clc + adc $castedSymname + bcc + + iny ++""" + ) + else + asmgen.out( + """ + sec + sbc $castedSymname + bcs + + dey ++""" + ) + assignRegisterpairWord(target, RegisterOrPair.AY) + return true + } + doAddOrSubWordExpr() + return true + } + else -> { + doAddOrSubWordExpr() + return true + } + } + } + return false + } + + private fun optimizedEqualityExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + // expression datatype is BOOL (ubyte) but operands can be anything + if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes && + expr.left.isSimple() && expr.right.isSimple()) { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.restoreRegisterStack(CpuRegister.A, false) + if(expr.operator=="==") { + asmgen.out(""" cmp P8ZP_SCRATCH_B1 bne + lda #1 bne ++ + lda #0 +""") - } else { - asmgen.out(""" + } else { + asmgen.out(""" cmp P8ZP_SCRATCH_B1 beq + lda #1 bne ++ + lda #0 +""") - } - assignRegisterByte(assign.target, CpuRegister.A, false) - return true - } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes && - expr.left.isSimple() && expr.right.isSimple()) { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - if(expr.operator=="==") { - asmgen.out(""" + } + assignRegisterByte(target, CpuRegister.A, false) + return true + } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes && + expr.left.isSimple() && expr.right.isSimple()) { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + if(expr.operator=="==") { + asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + cpy P8ZP_SCRATCH_W1+1 @@ -557,8 +927,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") - } else { - asmgen.out(""" + } else { + asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + cpy P8ZP_SCRATCH_W1+1 @@ -567,339 +937,60 @@ internal class AssignmentAsmGen(private val program: PtProgram, beq ++ + lda #1 +""") - } - assignRegisterByte(assign.target, CpuRegister.A, false) - return true } - return false + assignRegisterByte(target, CpuRegister.A, false) + return true } - else if(expr.operator=="+" || expr.operator=="-") { - val dt = expr.type - val left = expr.left - val right = expr.right - if(dt in ByteDatatypes) { - when (right) { - is PtIdentifier -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) - val symname = asmgen.asmVariableName(right) - if(expr.operator=="+") - asmgen.out(" clc | adc $symname") - else - asmgen.out(" sec | sbc $symname") - assignRegisterByte(assign.target, CpuRegister.A, dt in SignedDatatypes) - return true - } - is PtNumber -> { - assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) - if(expr.operator=="+") - asmgen.out(" clc | adc #${right.number.toHex()}") - else - asmgen.out(" sec | sbc #${right.number.toHex()}") - assignRegisterByte(assign.target, CpuRegister.A, dt in SignedDatatypes) - return true - } - else -> { - assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) - asmgen.out(" pha") - assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type) - asmgen.out(" pla") - if(expr.operator=="+") - asmgen.out(" clc | adc P8ZP_SCRATCH_B1") - else - asmgen.out(" sec | sbc P8ZP_SCRATCH_B1") - assignRegisterByte(assign.target, CpuRegister.A, dt in SignedDatatypes) - return true - } - } - } else if(dt in WordDatatypes) { + return false + } - fun doAddOrSubWordExpr() { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - if(expr.operator=="+") - asmgen.out(""" - clc - adc P8ZP_SCRATCH_W1 - pha - tya - adc P8ZP_SCRATCH_W1+1 - tay - pla""") - else - asmgen.out(""" - sec - sbc P8ZP_SCRATCH_W1 - pha - tya - sbc P8ZP_SCRATCH_W1+1 - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) + private fun optimizedLogicalOrBitwiseExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { + if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { + if (expr.right.isSimple()) { + if (expr.right is PtNumber || expr.right is PtIdentifier) { + assignLogicalWithSimpleRightOperandByte(target, expr.left, expr.operator, expr.right) + return true } + else if (expr.left is PtNumber || expr.left is PtIdentifier) { + assignLogicalWithSimpleRightOperandByte(target, expr.right, expr.operator, expr.left) + return true + } + } - when (right) { - is PtAddressOf -> { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - val symbol = asmgen.asmVariableName(right.identifier) - if(expr.operator=="+") - asmgen.out(""" - clc - adc #<$symbol - pha - tya - adc #>$symbol - tay - pla""") - else - asmgen.out(""" - sec - sbc #<$symbol - pha - tya - sbc #>$symbol - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - is PtIdentifier -> { - val symname = asmgen.asmVariableName(right) - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") - asmgen.out(""" - clc - adc $symname - pha - tya - adc $symname+1 - tay - pla""") - else - asmgen.out(""" - sec - sbc $symname - pha - tya - sbc $symname+1 - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - is PtNumber -> { - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") { - asmgen.out(""" - clc - adc #<${right.number.toHex()} - pha - tya - adc #>${right.number.toHex()} - tay - pla""") - } else if(expr.operator=="-") { - asmgen.out(""" - sec - sbc #<${right.number.toHex()} - pha - tya - sbc #>${right.number.toHex()} - tay - pla""") - } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - is PtTypeCast -> { - val castedValue = right.value - if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) { - val castedSymname = asmgen.asmVariableName(castedValue) - assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD) - if (expr.operator == "+") - asmgen.out( - """ - clc - adc $castedSymname - bcc + - iny -+""" - ) - else - asmgen.out( - """ - sec - sbc $castedSymname - bcs + - dey -+""" - ) - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - doAddOrSubWordExpr() - return true - } - else -> { - doAddOrSubWordExpr() - return true - } - } + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.restoreRegisterStack(CpuRegister.A, false) + when (expr.operator) { + "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") + "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") + "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1") + else -> throw AssemblyError("invalid operator") } + assignRegisterByte(target, CpuRegister.A, false) + return true } - else if(expr.operator=="<<" || expr.operator==">>") { - val shifts = expr.right.asConstInteger() - if(shifts!=null) { - val dt = expr.left.type - if(dt in ByteDatatypes && shifts in 0..7) { - val signed = dt == DataType.BYTE - assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) - if(expr.operator=="<<") { - repeat(shifts) { - asmgen.out(" asl a") - } - } else { - if(signed && shifts>0) { - asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A") - } else { - repeat(shifts) { - asmgen.out(" lsr a") - } - } - } - assignRegisterByte(assign.target, CpuRegister.A, signed) + else if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if (expr.right.isSimple()) { + if (expr.right is PtNumber || expr.right is PtIdentifier) { + assignLogicalWithSimpleRightOperandWord(target, expr.left, expr.operator, expr.right) return true - } else if(dt in WordDatatypes && shifts in 0..7) { - val signed = dt == DataType.WORD - assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) - if(expr.operator=="<<") { - if(shifts>0) { - asmgen.out(" sty P8ZP_SCRATCH_B1") - repeat(shifts) { - asmgen.out(" asl a | rol P8ZP_SCRATCH_B1") - } - asmgen.out(" ldy P8ZP_SCRATCH_B1") - } - } else { - if(signed) { - // TODO("shift AY >> $shifts signed") - return false - } else { - if(shifts>0) { - asmgen.out(" sty P8ZP_SCRATCH_B1") - repeat(shifts) { - asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a") - } - asmgen.out(" ldy P8ZP_SCRATCH_B1") - } - } - } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) + } + else if (expr.left is PtNumber || expr.left is PtIdentifier) { + assignLogicalWithSimpleRightOperandWord(target, expr.right, expr.operator, expr.left) return true } } - } - else if(expr.operator=="*") { - val value = expr.right.asConstInteger() - if(value==null) { - when(expr.type) { - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) - asmgen.out(" pha") - assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes) - asmgen.out(" pla | jsr math.multiply_bytes") - assignRegisterByte(assign.target, CpuRegister.A, false) - return true - } - in WordDatatypes -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(" jsr math.multiply_words") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - else -> return false - } - } else { - when (expr.type) { - in ByteDatatypes -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) - if (value in asmgen.optimizedByteMultiplications) - asmgen.out(" jsr math.mul_byte_${value}") - else - asmgen.out(" ldy #$value | jsr math.multiply_bytes") - assignRegisterByte(assign.target, CpuRegister.A, false) - return true - } - in WordDatatypes -> { - if (value in asmgen.optimizedWordMultiplications) { - assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type in SignedDatatypes) - asmgen.out(" jsr math.mul_word_${value}") - } - else { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(" jsr math.multiply_words") - } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - else -> return false - } + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + when (expr.operator) { + "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_W1 | pha | tya | and P8ZP_SCRATCH_W1+1 | tay | pla") + "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_W1 | pha | tya | ora P8ZP_SCRATCH_W1+1 | tay | pla") + "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_W1 | pha | tya | eor P8ZP_SCRATCH_W1+1 | tay | pla") + else -> throw AssemblyError("invalid operator") } + assignRegisterpairWord(target, RegisterOrPair.AY) + return true } - else if(expr.operator=="/") { - when(expr.type) { - DataType.UBYTE -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - asmgen.out(" pha") - assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) - asmgen.out(" pla | jsr math.divmod_ub_asm") - assignRegisterByte(assign.target, CpuRegister.Y, false) - return true - } - DataType.BYTE -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, true) - asmgen.out(" pha") - assignExpressionToRegister(expr.right, RegisterOrPair.Y, true) - asmgen.out(" pla | jsr math.divmod_b_asm") - assignRegisterByte(assign.target, CpuRegister.Y, true) - return true - } - DataType.UWORD -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(" jsr math.divmod_uw_asm") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - DataType.WORD -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(" jsr math.divmod_w_asm") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } - else -> return false - } - } - else if(expr.operator=="%") { - when(expr.type) { - DataType.UBYTE -> { - assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - asmgen.out(" pha") - assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) - asmgen.out(" pla | jsr math.divmod_ub_asm") - if(assign.target.register==RegisterOrPair.A) - asmgen.out(" cmp #0") // fix the status register - else - assignRegisterByte(assign.target, CpuRegister.A, false) - return true - } - DataType.UWORD -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(" jsr math.divmod_uw_asm") - assignVariableWord(assign.target, "P8ZP_SCRATCH_W2", DataType.UWORD) - return true - } - else -> return false - } - } - return false } @@ -1281,15 +1372,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } - private fun fallbackToStackEval(assign: AsmAssignment) { - // this routine is called for assigning a binaryexpression value that has no optimized code path. - asmgen.translateExpression(assign.source.expression!!) - if (assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes) - asmgen.signExtendStackLsb(assign.source.datatype) - if (assign.target.kind != TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype) - assignStackValue(assign.target) - } - private fun containmentCheckIntoA(containment: PtContainmentCheck) { val elementDt = containment.element.type val symbol = asmgen.symbolTable.lookup(containment.iterable.name) @@ -1304,9 +1386,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, DataType.STR -> { // use subroutine assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + asmgen.saveRegisterStack(CpuRegister.A, true) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) + asmgen.restoreRegisterStack(CpuRegister.A, false) val stringVal = (variable as PtVariable).value as PtString asmgen.out(" ldy #${stringVal.value.length}") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -1317,9 +1399,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, } DataType.ARRAY_B, DataType.ARRAY_UB -> { assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + asmgen.saveRegisterStack(CpuRegister.A, true) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) + asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") return @@ -1533,50 +1615,35 @@ internal class AssignmentAsmGen(private val program: PtProgram, assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD) return } - TargetStorageKind.STACK -> { - // byte to word, just assign to registers first, then push onto stack - assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD) - asmgen.out(""" - sta P8ESTACK_LO,x - tya - sta P8ESTACK_HI,x - dex""") - return - } else -> throw AssemblyError("weird target") } } if(targetDt==DataType.FLOAT && (target.register==RegisterOrPair.FAC1 || target.register==RegisterOrPair.FAC2)) { + if(target.register==RegisterOrPair.FAC2) + asmgen.pushFAC1() when(valueDt) { DataType.UBYTE -> { assignExpressionToRegister(value, RegisterOrPair.Y, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADUY") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.BYTE -> { assignExpressionToRegister(value, RegisterOrPair.A, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADSA") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.UWORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVUAYFAY") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.WORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVAYFAY") - asmgen.restoreRegisterLocal(CpuRegister.X) } else -> throw AssemblyError("invalid dt") } if(target.register==RegisterOrPair.FAC2) { - asmgen.out(" jsr floats.MOVEF") + asmgen.out(" jsr floats.MOVEF") + asmgen.popFAC1() } return } @@ -1868,170 +1935,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } - - private fun assignStackValue(target: AsmAssignTarget) { - when(target.kind) { - TargetStorageKind.VARIABLE -> { - when (target.datatype) { - DataType.UBYTE, DataType.BYTE -> { - asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname}") - } - DataType.UWORD, DataType.WORD -> { - asmgen.out(""" - inx - lda P8ESTACK_LO,x - sta ${target.asmVarname} - lda P8ESTACK_HI,x - sta ${target.asmVarname}+1 - """) - } - DataType.FLOAT -> { - asmgen.out(""" - lda #<${target.asmVarname} - ldy #>${target.asmVarname} - jsr floats.pop_float - """) - } - DataType.STR -> { - asmgen.out(""" - lda #<${target.asmVarname} - ldy #>${target.asmVarname} - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - inx - lda P8ESTACK_HI,x - tay - lda P8ESTACK_LO,x - jsr prog8_lib.strcpy""") - } - else -> throw AssemblyError("weird target variable type ${target.datatype}") - } - } - TargetStorageKind.MEMORY -> { - asmgen.out(" inx | lda P8ESTACK_LO,x") - storeRegisterAInMemoryAddress(target.memory!!) - } - TargetStorageKind.ARRAY -> { - if(target.constArrayIndexValue!=null) { - val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt() - when(target.datatype) { - in ByteDatatypes -> { - asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname}+$scaledIdx") - } - in WordDatatypes -> { - if(target.array!!.splitWords) - asmgen.out(""" - inx - lda P8ESTACK_LO,x - sta ${target.asmVarname}_lsb+$scaledIdx - lda P8ESTACK_HI,x - sta ${target.asmVarname}_msb+$scaledIdx""") - else - asmgen.out(""" - inx - lda P8ESTACK_LO,x - sta ${target.asmVarname}+$scaledIdx - lda P8ESTACK_HI,x - sta ${target.asmVarname}+$scaledIdx+1""") - } - DataType.FLOAT -> { - asmgen.out(""" - lda #<(${target.asmVarname}+$scaledIdx) - ldy #>(${target.asmVarname}+$scaledIdx) - jsr floats.pop_float""") - } - else -> throw AssemblyError("weird target variable type ${target.datatype}") - } - } - else - { - target.array!! - when(target.datatype) { - DataType.UBYTE, DataType.BYTE -> { - asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y) - asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname},y") - } - DataType.UWORD, DataType.WORD -> { - if(target.array.splitWords) - TODO("assign into split words ${target.position}") - asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y) - asmgen.out(""" - inx - lda P8ESTACK_LO,x - sta ${target.asmVarname},y - lda P8ESTACK_HI,x - sta ${target.asmVarname}+1,y - """) - } - DataType.FLOAT -> { - asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.A) - asmgen.out(""" - ldy #>${target.asmVarname} - clc - adc #<${target.asmVarname} - bcc + - iny -+ jsr floats.pop_float""") - } - else -> throw AssemblyError("weird dt") - } - } - } - TargetStorageKind.REGISTER -> { - when (target.datatype) { - DataType.UBYTE, DataType.BYTE -> { - when(target.register!!) { - RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x") - RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.position}") - RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x") - RegisterOrPair.AX -> asmgen.out(" inx | txy | ldx #0 | lda P8ESTACK_LO,y") - RegisterOrPair.AY -> asmgen.out(" inx | ldy #0 | lda P8ESTACK_LO,x") - in Cx16VirtualRegisters -> { - asmgen.out( - """ - inx - lda P8ESTACK_LO,x - sta cx16.${target.register.toString().lowercase()} - lda #0 - sta cx16.${target.register.toString().lowercase()}+1 - """) - } - else -> throw AssemblyError("can't assign byte from stack to register pair XY") - } - } - DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> { - when(target.register!!) { - RegisterOrPair.AX -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.position}") - RegisterOrPair.AY-> asmgen.out(" inx | ldy P8ESTACK_HI,x | lda P8ESTACK_LO,x") - RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.position}") - in Cx16VirtualRegisters -> { - asmgen.out( - """ - inx - lda P8ESTACK_LO,x - sta cx16.${target.register.toString().lowercase()} - lda P8ESTACK_HI,x - sta cx16.${target.register.toString().lowercase()}+1 - """) - } - else -> throw AssemblyError("can't assign word to single byte register") - } - } - DataType.FLOAT -> { - when(target.register!!) { - RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.pop_float_fac1") - RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.pop_float_fac2") - else -> throw AssemblyError("can only assign float to Fac1 or 2") - } - } - - else -> throw AssemblyError("weird dt") - } - } - TargetStorageKind.STACK -> {} - } - } - private fun assignAddressOf(target: AsmAssignTarget, sourceName: String) { when(target.kind) { TargetStorageKind.VARIABLE -> { @@ -2066,14 +1969,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("can't load address in a single 8-bit register") } } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda #<$sourceName - sta P8ESTACK_LO,x - lda #>$sourceName - sta P8ESTACK_HI,x - dex""") - } } } @@ -2102,15 +1997,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("assign string to incompatible variable type") } } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda #<$sourceName - ldy #>$sourceName+1 - sta P8ESTACK_LO,x - tya - sta P8ESTACK_HI,x - dex""") - } else -> throw AssemblyError("string-assign to weird target") } } @@ -2245,39 +2131,22 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } - TargetStorageKind.STACK -> { - if(sourceDt==DataType.UBYTE) { - asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x") - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_HI,x") - else - asmgen.out(" lda #0 | sta P8ESTACK_HI,x") - } - else - asmgen.out(""" - lda $sourceName - sta P8ESTACK_LO,x - lda $sourceName+1 - sta P8ESTACK_HI,x - dex""") - } } } internal fun assignFAC2float(target: AsmAssignTarget) { - asmgen.out(" jsr floats.MOVFA") // fac2 -> fac1 - assignFAC1float(target) + asmgen.out(" jsr floats.MOVFA") + if(target.register != RegisterOrPair.FAC1) + assignFAC1float(target) } internal fun assignFAC1float(target: AsmAssignTarget) { when(target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(""" - stx P8ZP_SCRATCH_REG ldx #<${target.asmVarname} ldy #>${target.asmVarname} jsr floats.MOVMF - ldx P8ZP_SCRATCH_REG """) } TargetStorageKind.ARRAY -> { @@ -2297,10 +2166,11 @@ internal class AssignmentAsmGen(private val program: PtProgram, } TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to mem byte") TargetStorageKind.REGISTER -> { - if (target.register!! != RegisterOrPair.FAC1) + if(target.register==RegisterOrPair.FAC2) + asmgen.out(" jsr floats.MOVAF") + else if (target.register!! != RegisterOrPair.FAC1) throw AssemblyError("can't assign Fac1 float to another register") } - TargetStorageKind.STACK -> asmgen.out(" jsr floats.push_fac1") } } @@ -2339,7 +2209,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("can only assign float to Fac1 or 2") } } - TargetStorageKind.STACK -> asmgen.out(" jsr floats.push_float") } } @@ -2382,7 +2251,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("can only assign float to Fac1 or 2") } } - TargetStorageKind.STACK -> asmgen.out(" lda #<$sourceName | ldy #>$sourceName | jsr floats.push_float") } } @@ -2447,12 +2315,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird register") } } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda $sourceName - sta P8ESTACK_LO,x - dex""") - } } } @@ -2479,12 +2341,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1") } else { - asmgen.saveRegisterLocal(CpuRegister.X, wordtarget.scope!!) asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, wordtarget.datatype, CpuRegister.X) asmgen.out(" lda $sourceName") asmgen.signExtendAYlsb(DataType.BYTE) asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x") - asmgen.restoreRegisterLocal(CpuRegister.X) } } TargetStorageKind.REGISTER -> { @@ -2525,16 +2385,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("only reg pairs allowed as word target ${wordtarget.register}") } } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda $sourceName - sta P8ESTACK_LO,x - ora #$7f - bmi + - lda #0 -+ sta P8ESTACK_HI,x - dex""") - } else -> throw AssemblyError("target type isn't word") } } @@ -2602,13 +2452,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("only reg pairs allowed as word target") } } - TargetStorageKind.STACK -> { - asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x") - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_HI,x | dex") - else - asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex") - } else -> throw AssemblyError("target type isn't word") } } @@ -2644,21 +2487,67 @@ internal class AssignmentAsmGen(private val program: PtProgram, TargetStorageKind.ARRAY -> { if(assignAsWord) TODO("assign register as word into Array not yet supported") - if (target.constArrayIndexValue!=null) { - when (register) { - CpuRegister.A -> asmgen.out(" sta ${target.asmVarname}+${target.constArrayIndexValue}") - CpuRegister.X -> asmgen.out(" stx ${target.asmVarname}+${target.constArrayIndexValue}") - CpuRegister.Y -> asmgen.out(" sty ${target.asmVarname}+${target.constArrayIndexValue}") + if(target.array!!.splitWords) + TODO("assign register into split words ${target.position}") + if(target.origAstTarget?.array?.variable?.type==DataType.UWORD) { + // assigning an indexed pointer var + if (target.constArrayIndexValue!=null) { + when (register) { + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") + } + if(asmgen.isZpVar(target.origAstTarget!!.array!!.variable)) { + asmgen.out(" ldy #${target.constArrayIndexValue} | sta (${target.asmVarname}),y") + } else { + asmgen.out(""" + ldy ${target.asmVarname} + sty P8ZP_SCRATCH_W1 + ldy ${target.asmVarname}+1 + sty P8ZP_SCRATCH_W1+1 + ldy #${target.constArrayIndexValue} + sta (P8ZP_SCRATCH_W1),y""") + } } - } - else { - when (register) { - CpuRegister.A -> {} - CpuRegister.X -> asmgen.out(" txa") - CpuRegister.Y -> asmgen.out(" tya") + else { + when (register) { + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") + } + val indexVar = target.array!!.index as PtIdentifier + if(asmgen.isZpVar(target.origAstTarget!!.array!!.variable)) { + asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta (${target.asmVarname}),y") + } else { + asmgen.out(""" + ldy ${target.asmVarname} + sty P8ZP_SCRATCH_W1 + ldy ${target.asmVarname}+1 + sty P8ZP_SCRATCH_W1+1 + ldy ${asmgen.asmVariableName(indexVar)} + sta (P8ZP_SCRATCH_W1),y""") + } + } + return + } else { + // assign regular array indexing + if (target.constArrayIndexValue!=null) { + when (register) { + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") + } + asmgen.out(" sta ${target.asmVarname}+${target.constArrayIndexValue}") + } + else { + when (register) { + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") + } + val indexVar = target.array!!.index as PtIdentifier + asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y") } - val indexVar = target.array!!.index as PtIdentifier - asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y") } } TargetStorageKind.REGISTER -> { @@ -2804,15 +2693,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } - TargetStorageKind.STACK -> { - if(assignAsWord) - TODO("assign register as word onto Stack not yet supported") - when(register) { - CpuRegister.A -> asmgen.out(" sta P8ESTACK_LO,x | dex") - CpuRegister.X -> throw AssemblyError("can't use X here") - CpuRegister.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex") - } - } } } @@ -2992,22 +2872,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } } - TargetStorageKind.STACK -> { - when(regs) { - RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") - RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't use X here") - in Cx16VirtualRegisters -> { - val srcReg = asmgen.asmSymbolName(regs) - asmgen.out(""" - lda $srcReg - sta P8ESTACK_LO,x - lda $srcReg+1 - sta P8ESTACK_HI,x - dex""") - } - else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") - } - } TargetStorageKind.MEMORY -> throw AssemblyError("can't store word into memory byte") } } @@ -3049,9 +2913,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid register for word value") } } - TargetStorageKind.STACK -> { - asmgen.out(" stz P8ESTACK_LO,x | stz P8ESTACK_HI,x | dex") - } } return @@ -3111,14 +2972,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid register for word value") } } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda #<${word.toHex()} - sta P8ESTACK_LO,x - lda #>${word.toHex()} - sta P8ESTACK_HI,x - dex""") - } } } @@ -3174,9 +3027,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird register") } - TargetStorageKind.STACK -> { - asmgen.out(" stz P8ESTACK_LO,x | dex") - } } return @@ -3242,12 +3092,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird register") } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda #${byte.toHex()} - sta P8ESTACK_LO,x - dex""") - } } } @@ -3316,10 +3160,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("can only assign float to Fac1 or 2") } } - TargetStorageKind.STACK -> { - val floatConst = allocator.getFloatAsmConst(float) - asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") - } } } else { // non-zero value @@ -3373,10 +3213,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("can only assign float to Fac1 or 2") } } - TargetStorageKind.STACK -> { - val floatConst = allocator.getFloatAsmConst(float) - asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") - } } } } @@ -3417,12 +3253,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird register") } - TargetStorageKind.STACK -> { - asmgen.out(""" - lda ${address.toHex()} - sta P8ESTACK_LO,x - dex""") - } } } else if (identifier != null) { when(target.kind) { @@ -3459,10 +3289,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("weird register") } } - TargetStorageKind.STACK -> { - asmgen.loadByteFromPointerIntoA(identifier) - asmgen.out(" sta P8ESTACK_LO,x | dex") - } } } } @@ -3494,13 +3320,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else -> throw AssemblyError("word regs can only be pair") } - TargetStorageKind.STACK -> { - asmgen.out(" lda ${address.toHex()} | sta P8ESTACK_LO,x") - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_HI,x | dex") - else - asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex") - } else -> throw AssemblyError("other types aren't word") } } else if (identifier != null) { @@ -3534,14 +3353,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("word regs can only be pair") } } - TargetStorageKind.STACK -> { - asmgen.loadByteFromPointerIntoA(identifier) - asmgen.out(" sta P8ESTACK_LO,x") - if(asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" stz P8ESTACK_HI,x | dex") - else - asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex") - } else -> throw AssemblyError("other types aren't word") } } @@ -3651,9 +3462,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid reg dt for byte invert") } } - TargetStorageKind.STACK -> TODO("no asm gen for byte stack invert") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign), scope) - else -> throw AssemblyError("weird target") } } DataType.UWORD -> { @@ -3676,7 +3485,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid reg dt for word invert") } } - TargetStorageKind.STACK -> TODO("no asm gen for word stack invert") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("~", assign), scope) else -> throw AssemblyError("weird target") } @@ -3725,9 +3533,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that") - TargetStorageKind.STACK -> TODO("no asm gen for byte stack negate") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope) - else -> throw AssemblyError("weird target") } } DataType.WORD -> { @@ -3785,9 +3591,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } TargetStorageKind.MEMORY -> throw AssemblyError("memory is ubyte, can't negate that") - TargetStorageKind.STACK -> TODO("no asm gen for word stack negate") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope) - else -> throw AssemblyError("weird target") } } DataType.FLOAT -> { @@ -3807,7 +3611,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, sta ${target.asmVarname}+1 """) } - TargetStorageKind.STACK -> TODO("no asm gen for float stack negate") TargetStorageKind.ARRAY -> assignPrefixedExpressionToArrayElt(makePrefixedExprFromArrayExprAssign("-", assign), scope) else -> throw AssemblyError("weird target for in-place float negation") } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index 36a0882fa..8a6bde589 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -81,7 +81,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } in WordDatatypes -> { @@ -100,25 +99,47 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } DataType.FLOAT -> { when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + target.asmVarname, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + target.asmVarname, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + target.asmVarname, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.expression!! + ) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") @@ -143,7 +164,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } is PtIdentifier -> { @@ -162,13 +182,13 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_pointer(pointer, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } else -> { - // TODO use some other evaluation here; don't use the estack to transfer the address to read/write from - asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingISub(), target.position)) - asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") + asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UWORD, memory.definingISub(), target.position, register = RegisterOrPair.AY)) + asmgen.saveRegisterStack(CpuRegister.A, true) + asmgen.saveRegisterStack(CpuRegister.Y, false) + asmgen.out(" jsr prog8_lib.read_byte_from_address_in_AY | sta P8ZP_SCRATCH_B1") when(value.kind) { SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.asmVarname) @@ -182,9 +202,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } - asmgen.out(" lda P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_to_address_on_stack | inx") + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + asmgen.out(" ldx P8ZP_SCRATCH_B1 | jsr prog8_lib.write_byte_X_to_address_in_AY") } } } @@ -213,7 +234,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } in WordDatatypes -> { @@ -231,25 +251,47 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } DataType.FLOAT -> { when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(targetVarName, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(targetVarName, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(targetVarName, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + targetVarName, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + targetVarName, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + targetVarName, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float array") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(targetVarName, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(targetVarName, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(targetVarName, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.expression!! + ) } } - else -> throw AssemblyError("weird source type ${value.kind}") } } else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") @@ -264,7 +306,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, return asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y) asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1") - asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!) + asmgen.saveRegisterStack(CpuRegister.Y, false) when(value.kind) { SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.asmVarname) @@ -278,9 +320,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } - asmgen.restoreRegisterLocal(CpuRegister.Y) + asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y") } in WordDatatypes -> { @@ -310,7 +351,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, inplaceModification_word_value_to_variable("P8ZP_SCRATCH_W1", target.datatype, operator, value.expression!!) } } - else -> throw AssemblyError("weird source type ${value.kind}") } asmgen.restoreRegisterStack(CpuRegister.Y, false) if(target.array.splitWords) { @@ -336,21 +376,44 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$tempvar jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(tempvar, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(tempvar, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(tempvar, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + tempvar, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + tempvar, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + tempvar, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(tempvar, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + tempvar, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(tempvar, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + tempvar, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(tempvar, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + tempvar, + operator, + value.expression!! + ) } } - else -> throw AssemblyError("weird source type ${value.kind}") } asmgen.out(""" lda P8ZP_SCRATCH_W1 @@ -372,7 +435,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } TargetStorageKind.REGISTER -> throw AssemblyError("no asm gen for reg in-place modification") - TargetStorageKind.STACK -> throw AssemblyError("no asm gen for stack in-place modification") } } @@ -592,8 +654,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) { - // this should be the last resort for code generation for this, - // because the value is evaluated onto the eval stack (=slow). when (operator) { "+" -> { asmgen.assignExpressionToRegister(value, RegisterOrPair.A) @@ -1071,14 +1131,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) { when (operator) { "+" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(""" clc adc $name sta $name""") } "-" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG" asmgen.out(""" sta $tmpByte @@ -1088,15 +1148,15 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, sta $name""") } "|" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" ora $name | sta $name") } "&" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" and $name | sta $name") } "^" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" eor $name | sta $name") } else -> { @@ -1108,7 +1168,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) { when (operator) { "+" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(""" clc adc $name @@ -1118,7 +1178,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, +""") } "-" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) val tmpByte = if(name!="P8ZP_SCRATCH_B1") "P8ZP_SCRATCH_B1" else "P8ZP_SCRATCH_REG" asmgen.out(""" sta $tmpByte @@ -1131,11 +1191,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, +""") } "|" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" ora $name | sta $name") } "&" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" and $name | sta $name") if(dt in WordDatatypes) { if(asmgen.isTargetCpu(CpuType.CPU65c02)) @@ -1145,7 +1205,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } "^" -> { - asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) + asmgen.translateDirectMemReadExpressionToRegA(memread) asmgen.out(" eor $name | sta $name") } else -> { @@ -1998,8 +2058,6 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) { - // this should be the last resort for code generation for this, - // because the value is evaluated onto the eval stack (=slow). fun multiplyVarByWordInAY() { asmgen.out(""" sta P8ZP_SCRATCH_W1 @@ -2286,9 +2344,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } - private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: IPtSubroutine) { + private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression) { asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1) - asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { "+" -> { asmgen.out(""" @@ -2330,11 +2387,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String, scope: IPtSubroutine) { - asmgen.saveRegisterLocal(CpuRegister.X, scope) + private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String) { when (operator) { "+" -> { asmgen.out(""" @@ -2446,12 +2501,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: IPtSubroutine) { + private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) { val constValueName = allocator.getFloatAsmConst(value) - asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { "+" -> { if (value == 0.0) @@ -2569,6 +2622,5 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 51a144eb1..d9fc18a21 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -96,8 +96,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks { - if (codeGen.options.slowCodegenWarnings) - codeGen.errors.warn("indirect code for in-place assignment", origAssign.position) val value: PtExpression if(origAssign.operator in PrefixOperators) { value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 0f1760fe3..efd9cee58 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -24,10 +24,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "popw" -> funcPopw(call) "push" -> funcPush(call) "pushw" -> funcPushw(call) - "rsave", - "rsavex", - "rrestore", - "rrestorex" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore + "rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore "callfar" -> funcCallfar(call) "msb" -> funcMsb(call) "lsb" -> funcLsb(call) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index bad29de77..11c620ff7 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -29,9 +29,6 @@ class IRCodeGen( irSymbolTable = IRSymbolTable(symbolTable) val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding) - if(options.evalStackBaseAddress!=null) - throw AssemblyError("IR doesn't use eval-stack") - // collect global variables initializers program.allBlocks().forEach { val result = mutableListOf() diff --git a/codeOptimizers/src/prog8/optimizer/BinExprSplitter.kt b/codeOptimizers/src/prog8/optimizer/BinExprSplitter.kt deleted file mode 100644 index de5f0dae2..000000000 --- a/codeOptimizers/src/prog8/optimizer/BinExprSplitter.kt +++ /dev/null @@ -1,71 +0,0 @@ -package prog8.optimizer - -import prog8.ast.IStatementContainer -import prog8.ast.Node -import prog8.ast.Program -import prog8.ast.expressions.BinaryExpression -import prog8.ast.statements.AssignTarget -import prog8.ast.statements.Assignment -import prog8.ast.statements.AssignmentOrigin -import prog8.ast.walk.AstWalker -import prog8.ast.walk.IAstModification -import prog8.code.core.AugmentAssignmentOperators -import prog8.code.core.CompilationOptions -import prog8.code.core.DataType -import prog8.code.target.VMTarget - - -class BinExprSplitter(private val program: Program, private val options: CompilationOptions) : AstWalker() { - - override fun after(assignment: Assignment, parent: Node): Iterable { - - if(options.compTarget.name == VMTarget.NAME) - return noModifications // don't split expressions when targeting the vm codegen, it handles nested expressions well - - if(assignment.value.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions) - return noModifications - - val binExpr = assignment.value as? BinaryExpression - if (binExpr != null) { - - if(binExpr.operator in AugmentAssignmentOperators && isSimpleTarget(assignment.target)) { - if(assignment.target isSameAs binExpr.right) - return noModifications - if(assignment.target isSameAs binExpr.left) { - if(binExpr.right.isSimple) - return noModifications - val leftBx = binExpr.left as? BinaryExpression - if(leftBx!=null && (!leftBx.left.isSimple || !leftBx.right.isSimple)) - return noModifications - val rightBx = binExpr.right as? BinaryExpression - if(rightBx!=null && (!rightBx.left.isSimple || !rightBx.right.isSimple)) - return noModifications - } - - if(binExpr.right.isSimple) { - val firstAssign = Assignment(assignment.target.copy(), binExpr.left, AssignmentOrigin.OPTIMIZER, binExpr.left.position) - val targetExpr = assignment.target.toExpression() - val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position) - return listOf( - IAstModification.ReplaceNode(binExpr, augExpr, assignment), - IAstModification.InsertBefore(assignment, firstAssign, assignment.parent as IStatementContainer) - ) - } - } - - // Further unraveling of binary expressions is really complicated here and - // often results in much bigger code, thereby defeating the purpose a bit. - // All in all this should probably be fixed in a better code generation backend - // that doesn't require this at all. - } - - return noModifications - } - - private fun isSimpleTarget(target: AssignTarget) = - if (target.identifier!=null || target.memoryAddress!=null) - !target.isIOAddress(options.compTarget.machine) - else - false - -} diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 033e5065b..b4a36aa8c 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -235,6 +235,47 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { } } + if(rightconst!=null && (expr.operator=="<<" || expr.operator==">>")) { + val dt = expr.left.inferType(program) + if(dt.isBytes && rightconst.number>=8) { + if(dt.istype(DataType.UBYTE)) { + val zeroUB = NumericLiteral(DataType.UBYTE, 0.0, expr.position) + modifications.add(IAstModification.ReplaceNode(expr, zeroUB, parent)) + } else { + if(leftconst!=null) { + val zeroB = NumericLiteral(DataType.BYTE, 0.0, expr.position) + val minusoneB = NumericLiteral(DataType.BYTE, -1.0, expr.position) + if(leftconst.number<0.0) { + if(expr.operator=="<<") + modifications.add(IAstModification.ReplaceNode(expr, zeroB, parent)) + else + modifications.add(IAstModification.ReplaceNode(expr, minusoneB, parent)) + } else { + modifications.add(IAstModification.ReplaceNode(expr, zeroB, parent)) + } + } + } + } + else if(dt.isWords && rightconst.number>=16) { + if(dt.istype(DataType.UWORD)) { + val zeroUW = NumericLiteral(DataType.UWORD, 0.0, expr.position) + modifications.add(IAstModification.ReplaceNode(expr, zeroUW, parent)) + } else { + if(leftconst!=null) { + val zeroW = NumericLiteral(DataType.WORD, 0.0, expr.position) + val minusoneW = NumericLiteral(DataType.WORD, -1.0, expr.position) + if(leftconst.number<0.0) { + if(expr.operator=="<<") + modifications.add(IAstModification.ReplaceNode(expr, zeroW, parent)) + else + modifications.add(IAstModification.ReplaceNode(expr, minusoneW, parent)) + } else { + modifications.add(IAstModification.ReplaceNode(expr, zeroW, parent)) + } + } + } + } + } return modifications } diff --git a/codeOptimizers/src/prog8/optimizer/Extensions.kt b/codeOptimizers/src/prog8/optimizer/Extensions.kt index 66c8ac89f..e5542b627 100644 --- a/codeOptimizers/src/prog8/optimizer/Extensions.kt +++ b/codeOptimizers/src/prog8/optimizer/Extensions.kt @@ -65,9 +65,3 @@ fun Program.simplifyExpressions(errors: IErrorReporter, target: ICompilationTarg opti.visit(this) return opti.applyModifications() } - -fun Program.splitBinaryExpressions(options: CompilationOptions) : Int { - val opti = BinExprSplitter(this, options) - opti.visit(this) - return opti.applyModifications() -} diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 78416482a..6ca42b7a4 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -111,8 +111,6 @@ class StatementOptimizer(private val program: Program, // remove obvious dangling elses (else after a return) if(ifElse.elsepart.isNotEmpty() && ifElse.truepart.statements.singleOrNull() is Return) { val elsePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position) - if(options.slowCodegenWarnings) - errors.warn("else can be omitted", ifElse.elsepart.position) return listOf( IAstModification.ReplaceNode(ifElse.elsepart, AnonymousScope(mutableListOf(), ifElse.elsepart.position), ifElse), IAstModification.InsertAfter(ifElse, elsePart, parent as IStatementContainer) diff --git a/compiler/res/prog8lib/atari/textio.p8 b/compiler/res/prog8lib/atari/textio.p8 index 0a1e56d63..bae6c50bf 100644 --- a/compiler/res/prog8lib/atari/textio.p8 +++ b/compiler/res/prog8lib/atari/textio.p8 @@ -153,10 +153,9 @@ asmsub print (str text @ AY) clobbers(A,Y) { }} } -asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal pha tya @@ -164,16 +163,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { pla jsr chrout txa - jsr chrout - ldx P8ZP_SCRATCH_REG - rts + jmp chrout }} } -asmsub print_ub (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal _print_byte_digits pha @@ -189,16 +185,13 @@ _print_byte_digits beq _ones jsr chrout _ones txa - jsr chrout - ldx P8ZP_SCRATCH_REG - rts + jmp chrout }} } -asmsub print_b (byte value @ A) clobbers(A,Y) { +asmsub print_b (byte value @ A) clobbers(A,X,Y) { ; ---- print the byte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG pha cmp #0 bpl + @@ -210,10 +203,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) { }} } -asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG bcc + pha lda #'$' @@ -222,16 +214,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr conv.ubyte2hex jsr chrout tya - jsr chrout - ldx P8ZP_SCRATCH_REG - rts + jmp chrout }} } -asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_B1 bcc + lda #'%' @@ -244,12 +233,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr chrout dey bne - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ pha @@ -261,7 +249,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in hexadecimal form (4 digits) ; (if Carry is set, a radix prefix '$' is printed as well) %asm {{ @@ -274,10 +262,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { +asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal ldy #0 - lda conv.uword2decimal.decTenThousands,y @@ -285,17 +272,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { jsr chrout iny bne - -+ ldx P8ZP_SCRATCH_REG - rts ++ rts }} } -asmsub print_uw (uword value @ AY) clobbers(A,Y) { +asmsub print_uw (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal - ldx P8ZP_SCRATCH_REG ldy #0 - lda conv.uword2decimal.decTenThousands,y beq _allzero @@ -316,7 +300,7 @@ _allzero }} } -asmsub print_w (word value @ AY) clobbers(A,Y) { +asmsub print_w (word value @ AY) clobbers(A,X,Y) { ; ---- print the (signed) word in A/Y in decimal form, without left padding 0's %asm {{ cpy #0 @@ -388,7 +372,7 @@ sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) { }} } -asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { +asmsub plot (ubyte col @ Y, ubyte row @ A) { ; ---- set cursor at specific position ; TODO %asm {{ diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index b4d27563a..28a5822ed 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -104,34 +104,26 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr ; ---- utilities ----- -asmsub STOP2() -> ubyte @A { +asmsub STOP2() clobbers(X) -> ubyte @A { ; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag. %asm {{ - txa - pha jsr cbm.STOP beq + - pla - tax lda #0 rts -+ pla - tax - lda #1 ++ lda #1 rts }} } -asmsub RDTIM16() -> uword @AY { +asmsub RDTIM16() clobbers(X) -> uword @AY { ; -- like RDTIM() but only returning the lower 16 bits in AY for convenience %asm {{ - stx P8ZP_SCRATCH_REG jsr cbm.RDTIM pha txa tay pla - ldx P8ZP_SCRATCH_REG rts }} } @@ -446,10 +438,6 @@ _irq_handler_init sta IRQ_SCRATCH_ZPWORD2 lda P8ZP_SCRATCH_W2+1 sta IRQ_SCRATCH_ZPWORD2+1 - ; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it. - ; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler. - ; We assume IRQ handlers don't contain complex expressions taking up more than that. - ldx #32 cld rts @@ -774,111 +762,108 @@ cx16 { ; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage ; they are simulated on the C128 as well but their location in memory is different ; (because there's no room for them in the zeropage) - ; $1300-$1bff is unused RAM on C128. We'll use $1a00-$1bff as the lo/hi evalstack. - ; the virtual registers are allocated at the bottom of the eval-stack (should be ample space unless - ; you're doing insane nesting of expressions...) - ; NOTE: the memory location of these registers can change based on the "-esa" compiler option - &uword r0 = $1b00 - &uword r1 = $1b02 - &uword r2 = $1b04 - &uword r3 = $1b06 - &uword r4 = $1b08 - &uword r5 = $1b0a - &uword r6 = $1b0c - &uword r7 = $1b0e - &uword r8 = $1b10 - &uword r9 = $1b12 - &uword r10 = $1b14 - &uword r11 = $1b16 - &uword r12 = $1b18 - &uword r13 = $1b1a - &uword r14 = $1b1c - &uword r15 = $1b1e + ; $1300-$1bff is unused RAM on C128. + &uword r0 = $1be0 + &uword r1 = $1be2 + &uword r2 = $1be4 + &uword r3 = $1be6 + &uword r4 = $1be8 + &uword r5 = $1bea + &uword r6 = $1bec + &uword r7 = $1bee + &uword r8 = $1bf0 + &uword r9 = $1bf2 + &uword r10 = $1bf4 + &uword r11 = $1bf6 + &uword r12 = $1bf8 + &uword r13 = $1bfa + &uword r14 = $1bfc + &uword r15 = $1bfe - &word r0s = $1b00 - &word r1s = $1b02 - &word r2s = $1b04 - &word r3s = $1b06 - &word r4s = $1b08 - &word r5s = $1b0a - &word r6s = $1b0c - &word r7s = $1b0e - &word r8s = $1b10 - &word r9s = $1b12 - &word r10s = $1b14 - &word r11s = $1b16 - &word r12s = $1b18 - &word r13s = $1b1a - &word r14s = $1b1c - &word r15s = $1b1e + &word r0s = $1be0 + &word r1s = $1be2 + &word r2s = $1be4 + &word r3s = $1be6 + &word r4s = $1be8 + &word r5s = $1bea + &word r6s = $1bec + &word r7s = $1bee + &word r8s = $1bf0 + &word r9s = $1bf2 + &word r10s = $1bf4 + &word r11s = $1bf6 + &word r12s = $1bf8 + &word r13s = $1bfa + &word r14s = $1bfc + &word r15s = $1bfe - &ubyte r0L = $1b00 - &ubyte r1L = $1b02 - &ubyte r2L = $1b04 - &ubyte r3L = $1b06 - &ubyte r4L = $1b08 - &ubyte r5L = $1b0a - &ubyte r6L = $1b0c - &ubyte r7L = $1b0e - &ubyte r8L = $1b10 - &ubyte r9L = $1b12 - &ubyte r10L = $1b14 - &ubyte r11L = $1b16 - &ubyte r12L = $1b18 - &ubyte r13L = $1b1a - &ubyte r14L = $1b1c - &ubyte r15L = $1b1e + &ubyte r0L = $1be0 + &ubyte r1L = $1be2 + &ubyte r2L = $1be4 + &ubyte r3L = $1be6 + &ubyte r4L = $1be8 + &ubyte r5L = $1bea + &ubyte r6L = $1bec + &ubyte r7L = $1bee + &ubyte r8L = $1bf0 + &ubyte r9L = $1bf2 + &ubyte r10L = $1bf4 + &ubyte r11L = $1bf6 + &ubyte r12L = $1bf8 + &ubyte r13L = $1bfa + &ubyte r14L = $1bfc + &ubyte r15L = $1bfe - &ubyte r0H = $1b01 - &ubyte r1H = $1b03 - &ubyte r2H = $1b05 - &ubyte r3H = $1b07 - &ubyte r4H = $1b09 - &ubyte r5H = $1b0b - &ubyte r6H = $1b0d - &ubyte r7H = $1b0f - &ubyte r8H = $1b11 - &ubyte r9H = $1b13 - &ubyte r10H = $1b15 - &ubyte r11H = $1b17 - &ubyte r12H = $1b19 - &ubyte r13H = $1b1b - &ubyte r14H = $1b1d - &ubyte r15H = $1b1f + &ubyte r0H = $1be1 + &ubyte r1H = $1be3 + &ubyte r2H = $1be5 + &ubyte r3H = $1be7 + &ubyte r4H = $1be9 + &ubyte r5H = $1beb + &ubyte r6H = $1bed + &ubyte r7H = $1bef + &ubyte r8H = $1bf1 + &ubyte r9H = $1bf3 + &ubyte r10H = $1bf5 + &ubyte r11H = $1bf7 + &ubyte r12H = $1bf9 + &ubyte r13H = $1bfb + &ubyte r14H = $1bfd + &ubyte r15H = $1bff - &byte r0sL = $1b00 - &byte r1sL = $1b02 - &byte r2sL = $1b04 - &byte r3sL = $1b06 - &byte r4sL = $1b08 - &byte r5sL = $1b0a - &byte r6sL = $1b0c - &byte r7sL = $1b0e - &byte r8sL = $1b10 - &byte r9sL = $1b12 - &byte r10sL = $1b14 - &byte r11sL = $1b16 - &byte r12sL = $1b18 - &byte r13sL = $1b1a - &byte r14sL = $1b1c - &byte r15sL = $1b1e + &byte r0sL = $1be0 + &byte r1sL = $1be2 + &byte r2sL = $1be4 + &byte r3sL = $1be6 + &byte r4sL = $1be8 + &byte r5sL = $1bea + &byte r6sL = $1bec + &byte r7sL = $1bee + &byte r8sL = $1bf0 + &byte r9sL = $1bf2 + &byte r10sL = $1bf4 + &byte r11sL = $1bf6 + &byte r12sL = $1bf8 + &byte r13sL = $1bfa + &byte r14sL = $1bfc + &byte r15sL = $1bfe - &byte r0sH = $1b01 - &byte r1sH = $1b03 - &byte r2sH = $1b05 - &byte r3sH = $1b07 - &byte r4sH = $1b09 - &byte r5sH = $1b0b - &byte r6sH = $1b0d - &byte r7sH = $1b0f - &byte r8sH = $1b11 - &byte r9sH = $1b13 - &byte r10sH = $1b15 - &byte r11sH = $1b17 - &byte r12sH = $1b19 - &byte r13sH = $1b1b - &byte r14sH = $1b1d - &byte r15sH = $1b1f + &byte r0sH = $1be1 + &byte r1sH = $1be3 + &byte r2sH = $1be5 + &byte r3sH = $1be7 + &byte r4sH = $1be9 + &byte r5sH = $1beb + &byte r6sH = $1bed + &byte r7sH = $1bef + &byte r8sH = $1bf1 + &byte r9sH = $1bf3 + &byte r10sH = $1bf5 + &byte r11sH = $1bf7 + &byte r12sH = $1bf9 + &byte r13sH = $1bfb + &byte r14sH = $1bfd + &byte r15sH = $1bff asmsub save_virtual_registers() clobbers(A,Y) { %asm {{ diff --git a/compiler/res/prog8lib/c128/textio.p8 b/compiler/res/prog8lib/c128/textio.p8 index 5552f6e3e..c8cc8585c 100644 --- a/compiler/res/prog8lib/c128/textio.p8 +++ b/compiler/res/prog8lib/c128/textio.p8 @@ -97,13 +97,12 @@ sub uppercase() { c128.VM1 &= ~2 } -asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, Y) { +asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, X, Y) { ; ---- scroll the whole screen 1 character to the left ; contents of the rightmost column are unchanged, you should clear/refill this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -133,17 +132,15 @@ _scroll_screen ; scroll only the screen memory dey bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_right (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_right (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character to the right ; contents of the leftmost column are unchanged, you should clear/refill this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -169,17 +166,15 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_up (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character up ; contents of the bottom row are unchanged, you should refill/clear this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -205,17 +200,15 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_down (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_down (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character down ; contents of the top row are unchanged, you should refill/clear this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -241,7 +234,6 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } @@ -266,10 +258,9 @@ asmsub print (str text @ AY) clobbers(A,Y) { }} } -asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal pha tya @@ -277,16 +268,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { pla jsr cbm.CHROUT txa - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_ub (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal _print_byte_digits pha @@ -302,16 +290,13 @@ _print_byte_digits beq _ones jsr cbm.CHROUT _ones txa - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_b (byte value @ A) clobbers(A,Y) { +asmsub print_b (byte value @ A) clobbers(A,X,Y) { ; ---- print the byte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG pha cmp #0 bpl + @@ -323,10 +308,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) { }} } -asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG bcc + pha lda #'$' @@ -335,16 +319,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr conv.ubyte2hex jsr cbm.CHROUT tya - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_B1 bcc + lda #'%' @@ -357,12 +338,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr cbm.CHROUT dey bne - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ pha @@ -374,7 +354,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in hexadecimal form (4 digits) ; (if Carry is set, a radix prefix '$' is printed as well) %asm {{ @@ -387,10 +367,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { +asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal ldy #0 - lda conv.uword2decimal.decTenThousands,y @@ -398,17 +377,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { jsr cbm.CHROUT iny bne - -+ ldx P8ZP_SCRATCH_REG - rts ++ rts }} } -asmsub print_uw (uword value @ AY) clobbers(A,Y) { +asmsub print_uw (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal - ldx P8ZP_SCRATCH_REG ldy #0 - lda conv.uword2decimal.decTenThousands,y beq _allzero @@ -429,7 +405,7 @@ _allzero }} } -asmsub print_w (word value @ AY) clobbers(A,Y) { +asmsub print_w (word value @ AY) clobbers(A,X,Y) { ; ---- print the (signed) word in A/Y in decimal form, without left padding 0's %asm {{ cpy #0 @@ -583,15 +559,10 @@ _colormod sta $ffff ; modified }} } -asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { - ; ---- safe wrapper around PLOT kernal routine, to save the X register. +asmsub plot (ubyte col @ Y, ubyte row @ X) { %asm {{ - stx P8ZP_SCRATCH_REG - tax clc - jsr cbm.PLOT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.PLOT }} } diff --git a/compiler/res/prog8lib/c64/floats.asm b/compiler/res/prog8lib/c64/floats.asm index 2770cfb96..e118a0824 100644 --- a/compiler/res/prog8lib/c64/floats.asm +++ b/compiler/res/prog8lib/c64/floats.asm @@ -5,13 +5,11 @@ FL_ZERO_const .byte 0,0,0,0,0 ; 0.0 FL_LOG2_const .byte $80, $31, $72, $17, $f8 ; log(2) -floats_store_reg .byte 0 ; temp storage floats_temp_var .byte 0,0,0,0,0 ; temporary storage for a float ub2float .proc ; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y - ; clobbers A, Y - stx P8ZP_SCRATCH_REG + ; clobbers A, X, Y sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 ldy P8ZP_SCRATCH_B1 @@ -19,15 +17,12 @@ ub2float .proc jsr GIVAYF _fac_to_mem ldx P8ZP_SCRATCH_W2 ldy P8ZP_SCRATCH_W2+1 - jsr MOVMF - ldx P8ZP_SCRATCH_REG - rts + jmp MOVMF .pend b2float .proc ; -- convert byte in SCRATCH_ZPB1 to float at address A/Y - ; clobbers A, Y - stx P8ZP_SCRATCH_REG + ; clobbers A, X, Y sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 lda P8ZP_SCRATCH_B1 @@ -37,7 +32,7 @@ b2float .proc uw2float .proc ; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y - stx P8ZP_SCRATCH_REG + ; clobbers X sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 lda P8ZP_SCRATCH_W1 @@ -48,7 +43,7 @@ uw2float .proc w2float .proc ; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y - stx P8ZP_SCRATCH_REG + ; clobbers X sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 ldy P8ZP_SCRATCH_W1 @@ -60,7 +55,7 @@ w2float .proc cast_from_uw .proc ; -- uword in A/Y into float var at (P8ZP_SCRATCH_W2) - stx P8ZP_SCRATCH_REG + ; clobbers X jsr GIVUAYFAY jmp ub2float._fac_to_mem .pend @@ -68,7 +63,7 @@ cast_from_uw .proc cast_from_w .proc ; -- word in A/Y into float var at (P8ZP_SCRATCH_W2) - stx P8ZP_SCRATCH_REG + ; clobbers X jsr GIVAYFAY jmp ub2float._fac_to_mem .pend @@ -76,7 +71,7 @@ cast_from_w .proc cast_from_ub .proc ; -- ubyte in Y into float var at (P8ZP_SCRATCH_W2) - stx P8ZP_SCRATCH_REG + ; clobbers X jsr FREADUY jmp ub2float._fac_to_mem .pend @@ -84,169 +79,41 @@ cast_from_ub .proc cast_from_b .proc ; -- byte in A into float var at (P8ZP_SCRATCH_W2) - stx P8ZP_SCRATCH_REG + ; clobbers X jsr FREADSA jmp ub2float._fac_to_mem .pend cast_as_uw_into_ya .proc ; also used for float 2 ub ; -- cast float at A/Y to uword into Y/A + ; clobbers X jsr MOVFM jmp cast_FAC1_as_uw_into_ya .pend cast_as_w_into_ay .proc ; also used for float 2 b ; -- cast float at A/Y to word into A/Y + ; clobbers X jsr MOVFM jmp cast_FAC1_as_w_into_ay .pend cast_FAC1_as_uw_into_ya .proc ; also used for float 2 ub ; -- cast fac1 to uword into Y/A - stx P8ZP_SCRATCH_REG - jsr GETADR ; into Y/A - ldx P8ZP_SCRATCH_REG - rts + ; clobbers X + jmp GETADR ; into Y/A .pend cast_FAC1_as_w_into_ay .proc ; also used for float 2 b ; -- cast fac1 to word into A/Y - stx P8ZP_SCRATCH_REG + ; clobbers X jsr AYINT ldy floats.AYINT_facmo lda floats.AYINT_facmo+1 - ldx P8ZP_SCRATCH_REG rts .pend -stack_b2float .proc - ; -- b2float operating on the stack - inx - lda P8ESTACK_LO,x - stx P8ZP_SCRATCH_REG - jsr FREADSA - jmp push_fac1._internal - .pend - -stack_w2float .proc - ; -- w2float operating on the stack - inx - ldy P8ESTACK_LO,x - lda P8ESTACK_HI,x - stx P8ZP_SCRATCH_REG - jsr GIVAYF - jmp push_fac1._internal - .pend - -stack_ub2float .proc - ; -- ub2float operating on the stack - inx - lda P8ESTACK_LO,x - stx P8ZP_SCRATCH_REG - tay - lda #0 - jsr GIVAYF - jmp push_fac1._internal - .pend - -stack_uw2float .proc - ; -- uw2float operating on the stack - inx - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - stx P8ZP_SCRATCH_REG - jsr GIVUAYFAY - jmp push_fac1._internal - .pend - -stack_float2w .proc ; also used for float2b - jsr pop_float_fac1 - stx P8ZP_SCRATCH_REG - jsr AYINT - ldx P8ZP_SCRATCH_REG - lda floats.AYINT_facmo - sta P8ESTACK_HI,x - lda floats.AYINT_facmo+1 - sta P8ESTACK_LO,x - dex - rts - .pend - -stack_float2uw .proc ; also used for float2ub - jsr pop_float_fac1 - stx P8ZP_SCRATCH_REG - jsr GETADR - ldx P8ZP_SCRATCH_REG - sta P8ESTACK_HI,x - tya - sta P8ESTACK_LO,x - dex - rts - .pend - -push_float .proc - ; ---- push mflpt5 in A/Y onto stack - ; (taking 3 stack positions = 6 bytes of which 1 is padding) - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - ldy #0 - lda (P8ZP_SCRATCH_W1),y - sta P8ESTACK_LO,x - iny - lda (P8ZP_SCRATCH_W1),y - sta P8ESTACK_HI,x - dex - iny - lda (P8ZP_SCRATCH_W1),y - sta P8ESTACK_LO,x - iny - lda (P8ZP_SCRATCH_W1),y - sta P8ESTACK_HI,x - dex - iny - lda (P8ZP_SCRATCH_W1),y - sta P8ESTACK_LO,x - dex - rts - .pend - -pop_float .proc - ; ---- pops mflpt5 from stack to memory A/Y - ; (frees 3 stack positions = 6 bytes of which 1 is padding) - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - ldy #4 - inx - lda P8ESTACK_LO,x - sta (P8ZP_SCRATCH_W1),y - dey - inx - lda P8ESTACK_HI,x - sta (P8ZP_SCRATCH_W1),y - dey - lda P8ESTACK_LO,x - sta (P8ZP_SCRATCH_W1),y - dey - inx - lda P8ESTACK_HI,x - sta (P8ZP_SCRATCH_W1),y - dey - lda P8ESTACK_LO,x - sta (P8ZP_SCRATCH_W1),y - rts - .pend - -pop_float_fac1 .proc - ; -- pops float from stack into FAC1 - lda #fmath_float1 - jsr pop_float - lda #fmath_float1 - jmp MOVFM - .pend - copy_float .proc ; -- copies the 5 bytes of the mflt value pointed to by P8ZP_SCRATCH_W1, ; into the 5 bytes pointed to by A/Y. Clobbers A,Y. @@ -272,25 +139,23 @@ copy_float .proc inc_var_f .proc ; -- add 1 to float pointed to by A/Y + ; clobbers X sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - stx P8ZP_SCRATCH_REG jsr MOVFM lda #FL_ONE_const jsr FADD ldx P8ZP_SCRATCH_W1 ldy P8ZP_SCRATCH_W1+1 - jsr MOVMF - ldx P8ZP_SCRATCH_REG - rts + jmp MOVMF .pend dec_var_f .proc ; -- subtract 1 from float pointed to by A/Y + ; clobbers X sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - stx P8ZP_SCRATCH_REG lda #FL_ONE_const jsr MOVFM @@ -299,23 +164,7 @@ dec_var_f .proc jsr FSUB ldx P8ZP_SCRATCH_W1 ldy P8ZP_SCRATCH_W1+1 - jsr MOVMF - ldx P8ZP_SCRATCH_REG - rts - .pend - - -pop_2_floats_f2_in_fac1 .proc - ; -- pop 2 floats from stack, load the second one in FAC1 as well - lda #fmath_float2 - jsr pop_float - lda #fmath_float1 - jsr pop_float - lda #fmath_float2 - jmp MOVFM + jmp MOVMF .pend @@ -323,71 +172,9 @@ fmath_float1 .byte 0,0,0,0,0 ; storage for a mflpt5 value fmath_float2 .byte 0,0,0,0,0 ; storage for a mflpt5 value -push_fac1 .proc - ; -- push the float in FAC1 onto the stack - stx P8ZP_SCRATCH_REG -_internal ldx #fmath_float1 - jsr MOVMF - lda #fmath_float1 - ldx P8ZP_SCRATCH_REG - jmp push_float - .pend - -div_f .proc - ; -- push f1/f2 on stack - jsr pop_2_floats_f2_in_fac1 - stx P8ZP_SCRATCH_REG - lda #fmath_float1 - jsr FDIV - jmp push_fac1._internal - .pend - -add_f .proc - ; -- push f1+f2 on stack - jsr pop_2_floats_f2_in_fac1 - stx P8ZP_SCRATCH_REG - lda #fmath_float1 - jsr FADD - jmp push_fac1._internal - .pend - -sub_f .proc - ; -- push f1-f2 on stack - jsr pop_2_floats_f2_in_fac1 - stx P8ZP_SCRATCH_REG - lda #fmath_float1 - jsr FSUB - jmp push_fac1._internal - .pend - -mul_f .proc - ; -- push f1*f2 on stack - jsr pop_2_floats_f2_in_fac1 - stx P8ZP_SCRATCH_REG - lda #fmath_float1 - jsr FMULT - jmp push_fac1._internal - .pend - -neg_f .proc - ; -- toggle the sign bit on the stack - lda P8ESTACK_HI+3,x - eor #$80 - sta P8ESTACK_HI+3,x - rts - .pend - var_fac1_less_f .proc - ; -- is the float in FAC1 < the variable AY? - stx P8ZP_SCRATCH_REG + ; -- is the float in FAC1 < the variable AY? Result in A. Clobbers X. jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #255 beq + lda #0 @@ -397,10 +184,8 @@ var_fac1_less_f .proc .pend var_fac1_lesseq_f .proc - ; -- is the float in FAC1 <= the variable AY? - stx P8ZP_SCRATCH_REG + ; -- is the float in FAC1 <= the variable AY? Result in A. Clobbers X. jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #0 beq + cmp #255 @@ -412,10 +197,8 @@ var_fac1_lesseq_f .proc .pend var_fac1_greater_f .proc - ; -- is the float in FAC1 > the variable AY? - stx P8ZP_SCRATCH_REG + ; -- is the float in FAC1 > the variable AY? Result in A. Clobbers X. jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #1 beq + lda #0 @@ -425,10 +208,8 @@ var_fac1_greater_f .proc .pend var_fac1_greatereq_f .proc - ; -- is the float in FAC1 >= the variable AY? - stx P8ZP_SCRATCH_REG + ; -- is the float in FAC1 >= the variable AY? Result in A. Clobbers X. jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #0 beq + cmp #1 @@ -439,17 +220,23 @@ var_fac1_greatereq_f .proc rts .pend -var_fac1_notequal_f .proc - ; -- are the floats numbers in FAC1 and the variable AY *not* identical? - stx P8ZP_SCRATCH_REG +var_fac1_equal_f .proc + ; -- are the floats numbers in FAC1 and the variable AY *not* identical? Result in A. Clobbers X. + jsr FCOMP + and #1 + eor #1 + rts + .pend + +var_fac1_notequal_f .proc + ; -- are the floats numbers in FAC1 and the variable AY *not* identical? Result in A. Clobbers X. jsr FCOMP - ldx P8ZP_SCRATCH_REG and #1 rts .pend vars_equal_f .proc - ; -- are the mflpt5 numbers in P8ZP_SCRATCH_W1 and AY identical? + ; -- are the mflpt5 numbers in P8ZP_SCRATCH_W1 and AY identical? Result in A sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 ldy #0 @@ -478,51 +265,13 @@ _false lda #0 rts .pend -equal_f .proc - ; -- are the two mflpt5 numbers on the stack identical? - inx - inx - inx - inx - lda P8ESTACK_LO-3,x - cmp P8ESTACK_LO,x - bne _equals_false - lda P8ESTACK_LO-2,x - cmp P8ESTACK_LO+1,x - bne _equals_false - lda P8ESTACK_LO-1,x - cmp P8ESTACK_LO+2,x - bne _equals_false - lda P8ESTACK_HI-2,x - cmp P8ESTACK_HI+1,x - bne _equals_false - lda P8ESTACK_HI-1,x - cmp P8ESTACK_HI+2,x - bne _equals_false -_equals_true lda #1 -_equals_store inx - sta P8ESTACK_LO+1,x - rts -_equals_false lda #0 - beq _equals_store - .pend - -notequal_f .proc - ; -- are the two mflpt5 numbers on the stack different? - jsr equal_f - eor #1 ; invert the result - sta P8ESTACK_LO+1,x - rts - .pend vars_less_f .proc - ; -- is float in AY < float in P8ZP_SCRATCH_W2 ? + ; -- is float in AY < float in P8ZP_SCRATCH_W2 ? Result in A. Clobbers X. jsr MOVFM lda P8ZP_SCRATCH_W2 ldy P8ZP_SCRATCH_W2+1 - stx P8ZP_SCRATCH_REG jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #255 bne + lda #1 @@ -532,13 +281,11 @@ vars_less_f .proc .pend vars_lesseq_f .proc - ; -- is float in AY <= float in P8ZP_SCRATCH_W2 ? + ; -- is float in AY <= float in P8ZP_SCRATCH_W2 ? Result in A. Clobbers X. jsr MOVFM lda P8ZP_SCRATCH_W2 ldy P8ZP_SCRATCH_W2+1 - stx P8ZP_SCRATCH_REG jsr FCOMP - ldx P8ZP_SCRATCH_REG cmp #255 bne + - lda #1 @@ -550,7 +297,7 @@ vars_lesseq_f .proc .pend less_f .proc - ; -- is f1 < f2? + ; -- is f1 < f2? Result in A. Clobbers X. jsr compare_floats cmp #255 beq compare_floats._return_true @@ -559,7 +306,7 @@ less_f .proc lesseq_f .proc - ; -- is f1 <= f2? + ; -- is f1 <= f2? Result in A. Clobbers X. jsr compare_floats cmp #255 beq compare_floats._return_true @@ -569,7 +316,7 @@ lesseq_f .proc .pend greater_f .proc - ; -- is f1 > f2? + ; -- is f1 > f2? Result in A. Clobbers X. jsr compare_floats cmp #1 beq compare_floats._return_true @@ -577,7 +324,7 @@ greater_f .proc .pend greatereq_f .proc - ; -- is f1 >= f2? + ; -- is f1 >= f2? Result in A. Clobbers X. jsr compare_floats cmp #1 beq compare_floats._return_true @@ -586,32 +333,9 @@ greatereq_f .proc bne compare_floats._return_false .pend -compare_floats .proc - lda #fmath_float2 - jsr pop_float - lda #fmath_float1 - jsr pop_float - lda #fmath_float1 - jsr MOVFM ; fac1 = flt1 - lda #fmath_float2 - stx P8ZP_SCRATCH_REG - jsr FCOMP ; A = flt1 compared with flt2 (0=equal, 1=flt1>flt2, 255=flt1floats.floats_temp_var + jsr floats.MOVMF + lda floats.floats_temp_var + pha + lda floats.floats_temp_var+1 + pha + lda floats.floats_temp_var+2 + pha + lda floats.floats_temp_var+3 + pha + lda floats.floats_temp_var+4 + pha + ; re-push return address + lda P8ZP_SCRATCH_W2+1 + pha + lda P8ZP_SCRATCH_W2 + pha + rts + .pend -notequal_zero .proc - jsr floats.pop_float_fac1 - jsr floats.SIGN - bne equal_zero._true - beq equal_zero._false - .pend +popFAC1 .proc + ; -- pop floating point value from cpu stack into FAC1 + ; save return address + pla + sta P8ZP_SCRATCH_W2 + pla + sta P8ZP_SCRATCH_W2+1 + pla + sta floats.floats_temp_var+4 + pla + sta floats.floats_temp_var+3 + pla + sta floats.floats_temp_var+2 + pla + sta floats.floats_temp_var+1 + pla + sta floats.floats_temp_var + lda #floats.floats_temp_var + jsr floats.MOVFM + ; re-push return address + lda P8ZP_SCRATCH_W2+1 + pha + lda P8ZP_SCRATCH_W2 + pha + rts + .pend -greater_zero .proc - jsr floats.pop_float_fac1 - jsr floats.SIGN - beq equal_zero._false - bpl equal_zero._true - jmp equal_zero._false - .pend - -less_zero .proc - jsr floats.pop_float_fac1 - jsr floats.SIGN - bmi equal_zero._true - jmp equal_zero._false - .pend - -greaterequal_zero .proc - jsr floats.pop_float_fac1 - jsr floats.SIGN - bpl equal_zero._true - jmp equal_zero._false - .pend - -lessequal_zero .proc - jsr floats.pop_float_fac1 - jsr floats.SIGN - beq equal_zero._true - bmi equal_zero._true - jmp equal_zero._false - .pend diff --git a/compiler/res/prog8lib/c64/floats.p8 b/compiler/res/prog8lib/c64/floats.p8 index cd50b3381..2a544754a 100644 --- a/compiler/res/prog8lib/c64/floats.p8 +++ b/compiler/res/prog8lib/c64/floats.p8 @@ -159,12 +159,9 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY { sub rndf() -> float { %asm {{ - stx P8ZP_SCRATCH_REG lda #1 jsr FREADSA - jsr RND ; rng into fac1 - ldx P8ZP_SCRATCH_REG - rts + jmp RND ; rng into fac1 }} } diff --git a/compiler/res/prog8lib/c64/floats_funcs.asm b/compiler/res/prog8lib/c64/floats_funcs.asm index 79e560331..a06747e77 100644 --- a/compiler/res/prog8lib/c64/floats_funcs.asm +++ b/compiler/res/prog8lib/c64/floats_funcs.asm @@ -1,13 +1,6 @@ ; --- floating point builtin functions -func_sign_f_stack .proc - jsr func_sign_f_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_sign_f_into_A .proc jsr MOVFM jmp SIGN @@ -146,17 +139,11 @@ func_all_f_stack .proc .pend func_abs_f_into_FAC1 .proc - stx P8ZP_SCRATCH_REG jsr MOVFM - jsr ABS - ldx P8ZP_SCRATCH_REG - rts + jmp ABS .pend func_sqrt_into_FAC1 .proc - stx P8ZP_SCRATCH_REG jsr MOVFM - jsr SQR - ldx P8ZP_SCRATCH_REG - rts + jmp SQR .pend diff --git a/compiler/res/prog8lib/c64/graphics.p8 b/compiler/res/prog8lib/c64/graphics.p8 index 504bd6b77..e9684c491 100644 --- a/compiler/res/prog8lib/c64/graphics.p8 +++ b/compiler/res/prog8lib/c64/graphics.p8 @@ -185,7 +185,6 @@ graphics { lda length and #7 sta separate_pixels - stx P8ZP_SCRATCH_REG lsr length+1 ror length lsr length+1 @@ -210,8 +209,7 @@ _modified stx $ffff ; modified inc _modified+2 + dey bne _modified -_zero ldx P8ZP_SCRATCH_REG - +_zero ldy separate_pixels beq hline_zero2 lda _modified+1 diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index f15b34824..33dfafeb8 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -104,34 +104,26 @@ romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use txt.plot for a 'safe' wrapper that preserves X. romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices -asmsub STOP2() -> ubyte @A { +asmsub STOP2() clobbers(X) -> ubyte @A { ; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag. %asm {{ - txa - pha jsr cbm.STOP beq + - pla - tax lda #0 rts -+ pla - tax - lda #1 ++ lda #1 rts }} } -asmsub RDTIM16() -> uword @AY { +asmsub RDTIM16() clobbers(X) -> uword @AY { ; -- like RDTIM() but only returning the lower 16 bits in AY for convenience %asm {{ - stx P8ZP_SCRATCH_REG jsr cbm.RDTIM pha txa tay pla - ldx P8ZP_SCRATCH_REG rts }} } @@ -413,10 +405,6 @@ _irq_handler_init sta IRQ_SCRATCH_ZPWORD2 lda P8ZP_SCRATCH_W2+1 sta IRQ_SCRATCH_ZPWORD2+1 - ; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it. - ; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler. - ; We assume IRQ handlers don't contain complex expressions taking up more than that. - ldx #32 cld rts @@ -742,111 +730,110 @@ cx16 { ; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage ; they are simulated on the C64 as well but their location in memory is different - ; (because there's no room for them in the zeropage) - ; they are allocated at the bottom of the eval-stack (should be ample space unless - ; you're doing insane nesting of expressions...) - ; NOTE: the memory location of these registers can change based on the "-esa" compiler option - &uword r0 = $cf00 - &uword r1 = $cf02 - &uword r2 = $cf04 - &uword r3 = $cf06 - &uword r4 = $cf08 - &uword r5 = $cf0a - &uword r6 = $cf0c - &uword r7 = $cf0e - &uword r8 = $cf10 - &uword r9 = $cf12 - &uword r10 = $cf14 - &uword r11 = $cf16 - &uword r12 = $cf18 - &uword r13 = $cf1a - &uword r14 = $cf1c - &uword r15 = $cf1e + ; (because there's no room for them in the zeropage in the default configuration) + ; Note that when using ZP options that free up more of the zeropage (such as %zeropage kernalsafe) + ; there might be enough space to put them there after all, and the compiler will change these addresses! + &uword r0 = $cfe0 + &uword r1 = $cfe2 + &uword r2 = $cfe4 + &uword r3 = $cfe6 + &uword r4 = $cfe8 + &uword r5 = $cfea + &uword r6 = $cfec + &uword r7 = $cfee + &uword r8 = $cff0 + &uword r9 = $cff2 + &uword r10 = $cff4 + &uword r11 = $cff6 + &uword r12 = $cff8 + &uword r13 = $cffa + &uword r14 = $cffc + &uword r15 = $cffe - &word r0s = $cf00 - &word r1s = $cf02 - &word r2s = $cf04 - &word r3s = $cf06 - &word r4s = $cf08 - &word r5s = $cf0a - &word r6s = $cf0c - &word r7s = $cf0e - &word r8s = $cf10 - &word r9s = $cf12 - &word r10s = $cf14 - &word r11s = $cf16 - &word r12s = $cf18 - &word r13s = $cf1a - &word r14s = $cf1c - &word r15s = $cf1e + &word r0s = $cfe0 + &word r1s = $cfe2 + &word r2s = $cfe4 + &word r3s = $cfe6 + &word r4s = $cfe8 + &word r5s = $cfea + &word r6s = $cfec + &word r7s = $cfee + &word r8s = $cff0 + &word r9s = $cff2 + &word r10s = $cff4 + &word r11s = $cff6 + &word r12s = $cff8 + &word r13s = $cffa + &word r14s = $cffc + &word r15s = $cffe - &ubyte r0L = $cf00 - &ubyte r1L = $cf02 - &ubyte r2L = $cf04 - &ubyte r3L = $cf06 - &ubyte r4L = $cf08 - &ubyte r5L = $cf0a - &ubyte r6L = $cf0c - &ubyte r7L = $cf0e - &ubyte r8L = $cf10 - &ubyte r9L = $cf12 - &ubyte r10L = $cf14 - &ubyte r11L = $cf16 - &ubyte r12L = $cf18 - &ubyte r13L = $cf1a - &ubyte r14L = $cf1c - &ubyte r15L = $cf1e + &ubyte r0L = $cfe0 + &ubyte r1L = $cfe2 + &ubyte r2L = $cfe4 + &ubyte r3L = $cfe6 + &ubyte r4L = $cfe8 + &ubyte r5L = $cfea + &ubyte r6L = $cfec + &ubyte r7L = $cfee + &ubyte r8L = $cff0 + &ubyte r9L = $cff2 + &ubyte r10L = $cff4 + &ubyte r11L = $cff6 + &ubyte r12L = $cff8 + &ubyte r13L = $cffa + &ubyte r14L = $cffc + &ubyte r15L = $cffe - &ubyte r0H = $cf01 - &ubyte r1H = $cf03 - &ubyte r2H = $cf05 - &ubyte r3H = $cf07 - &ubyte r4H = $cf09 - &ubyte r5H = $cf0b - &ubyte r6H = $cf0d - &ubyte r7H = $cf0f - &ubyte r8H = $cf11 - &ubyte r9H = $cf13 - &ubyte r10H = $cf15 - &ubyte r11H = $cf17 - &ubyte r12H = $cf19 - &ubyte r13H = $cf1b - &ubyte r14H = $cf1d - &ubyte r15H = $cf1f + &ubyte r0H = $cfe1 + &ubyte r1H = $cfe3 + &ubyte r2H = $cfe5 + &ubyte r3H = $cfe7 + &ubyte r4H = $cfe9 + &ubyte r5H = $cfeb + &ubyte r6H = $cfed + &ubyte r7H = $cfef + &ubyte r8H = $cff1 + &ubyte r9H = $cff3 + &ubyte r10H = $cff5 + &ubyte r11H = $cff7 + &ubyte r12H = $cff9 + &ubyte r13H = $cffb + &ubyte r14H = $cffd + &ubyte r15H = $cfff - &byte r0sL = $cf00 - &byte r1sL = $cf02 - &byte r2sL = $cf04 - &byte r3sL = $cf06 - &byte r4sL = $cf08 - &byte r5sL = $cf0a - &byte r6sL = $cf0c - &byte r7sL = $cf0e - &byte r8sL = $cf10 - &byte r9sL = $cf12 - &byte r10sL = $cf14 - &byte r11sL = $cf16 - &byte r12sL = $cf18 - &byte r13sL = $cf1a - &byte r14sL = $cf1c - &byte r15sL = $cf1e + &byte r0sL = $cfe0 + &byte r1sL = $cfe2 + &byte r2sL = $cfe4 + &byte r3sL = $cfe6 + &byte r4sL = $cfe8 + &byte r5sL = $cfea + &byte r6sL = $cfec + &byte r7sL = $cfee + &byte r8sL = $cff0 + &byte r9sL = $cff2 + &byte r10sL = $cff4 + &byte r11sL = $cff6 + &byte r12sL = $cff8 + &byte r13sL = $cffa + &byte r14sL = $cffc + &byte r15sL = $cffe - &byte r0sH = $cf01 - &byte r1sH = $cf03 - &byte r2sH = $cf05 - &byte r3sH = $cf07 - &byte r4sH = $cf09 - &byte r5sH = $cf0b - &byte r6sH = $cf0d - &byte r7sH = $cf0f - &byte r8sH = $cf11 - &byte r9sH = $cf13 - &byte r10sH = $cf15 - &byte r11sH = $cf17 - &byte r12sH = $cf19 - &byte r13sH = $cf1b - &byte r14sH = $cf1d - &byte r15sH = $cf1f + &byte r0sH = $cfe1 + &byte r1sH = $cfe3 + &byte r2sH = $cfe5 + &byte r3sH = $cfe7 + &byte r4sH = $cfe9 + &byte r5sH = $cfeb + &byte r6sH = $cfed + &byte r7sH = $cfef + &byte r8sH = $cff1 + &byte r9sH = $cff3 + &byte r10sH = $cff5 + &byte r11sH = $cff7 + &byte r12sH = $cff9 + &byte r13sH = $cffb + &byte r14sH = $cffd + &byte r15sH = $cfff asmsub save_virtual_registers() clobbers(A,Y) { %asm {{ diff --git a/compiler/res/prog8lib/c64/textio.p8 b/compiler/res/prog8lib/c64/textio.p8 index 0cc5544ce..cd62921e7 100644 --- a/compiler/res/prog8lib/c64/textio.p8 +++ b/compiler/res/prog8lib/c64/textio.p8 @@ -96,13 +96,12 @@ sub uppercase() { c64.VMCSB &= ~2 } -asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, Y) { +asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, X, Y) { ; ---- scroll the whole screen 1 character to the left ; contents of the rightmost column are unchanged, you should clear/refill this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -132,17 +131,15 @@ _scroll_screen ; scroll only the screen memory dey bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_right (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_right (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character to the right ; contents of the leftmost column are unchanged, you should clear/refill this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -168,17 +165,15 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_up (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character up ; contents of the bottom row are unchanged, you should refill/clear this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -204,17 +199,15 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub scroll_down (bool alsocolors @ Pc) clobbers(A) { +asmsub scroll_down (bool alsocolors @ Pc) clobbers(A,X) { ; ---- scroll the whole screen 1 character down ; contents of the top row are unchanged, you should refill/clear this yourself ; Carry flag determines if screen color data must be scrolled too %asm {{ - stx P8ZP_SCRATCH_REG bcc _scroll_screen + ; scroll the screen and the color memory @@ -240,7 +233,6 @@ _scroll_screen ; scroll only the screen memory dex bpl - - ldx P8ZP_SCRATCH_REG rts }} } @@ -265,10 +257,9 @@ asmsub print (str text @ AY) clobbers(A,Y) { }} } -asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal pha tya @@ -276,16 +267,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { pla jsr cbm.CHROUT txa - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_ub (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal _print_byte_digits pha @@ -301,16 +289,13 @@ _print_byte_digits beq _ones jsr cbm.CHROUT _ones txa - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_b (byte value @ A) clobbers(A,Y) { +asmsub print_b (byte value @ A) clobbers(A,X,Y) { ; ---- print the byte in A in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG pha cmp #0 bpl + @@ -322,10 +307,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) { }} } -asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG bcc + pha lda #'$' @@ -334,16 +318,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr conv.ubyte2hex jsr cbm.CHROUT tya - jsr cbm.CHROUT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.CHROUT }} } -asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ - stx P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_B1 bcc + lda #'%' @@ -356,12 +337,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr cbm.CHROUT dey bne - - ldx P8ZP_SCRATCH_REG rts }} } -asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ pha @@ -373,7 +353,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in hexadecimal form (4 digits) ; (if Carry is set, a radix prefix '$' is printed as well) %asm {{ @@ -386,10 +366,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { +asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal ldy #0 - lda conv.uword2decimal.decTenThousands,y @@ -397,17 +376,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { jsr cbm.CHROUT iny bne - -+ ldx P8ZP_SCRATCH_REG - rts ++ rts }} } -asmsub print_uw (uword value @ AY) clobbers(A,Y) { +asmsub print_uw (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal - ldx P8ZP_SCRATCH_REG ldy #0 - lda conv.uword2decimal.decTenThousands,y beq _allzero @@ -428,7 +404,7 @@ _allzero }} } -asmsub print_w (word value @ AY) clobbers(A,Y) { +asmsub print_w (word value @ AY) clobbers(A,X,Y) { ; ---- print the (signed) word in A/Y in decimal form, without left padding 0's %asm {{ cpy #0 @@ -582,15 +558,10 @@ _colormod sta $ffff ; modified }} } -asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { - ; ---- safe wrapper around PLOT kernal routine, to save the X register. +asmsub plot (ubyte col @ Y, ubyte row @ X) { %asm {{ - stx P8ZP_SCRATCH_REG - tax clc - jsr cbm.PLOT - ldx P8ZP_SCRATCH_REG - rts + jmp cbm.PLOT }} } diff --git a/compiler/res/prog8lib/conv.p8 b/compiler/res/prog8lib/conv.p8 index 63f937b67..065e64702 100644 --- a/compiler/res/prog8lib/conv.p8 +++ b/compiler/res/prog8lib/conv.p8 @@ -8,25 +8,22 @@ conv { str @shared string_out = "????????????????" ; result buffer for the string conversion routines -asmsub str_ub0 (ubyte value @ A) clobbers(A,Y) { +asmsub str_ub0 (ubyte value @ A) clobbers(A,X,Y) { ; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.ubyte2decimal sty string_out sta string_out+1 stx string_out+2 lda #0 sta string_out+3 - ldx P8ZP_SCRATCH_REG rts }} } -asmsub str_ub (ubyte value @ A) clobbers(A,Y) { +asmsub str_ub (ubyte value @ A) clobbers(A,X,Y) { ; ---- convert the ubyte in A in decimal string form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG ldy #0 sty P8ZP_SCRATCH_B1 jsr conv.ubyte2decimal @@ -52,15 +49,13 @@ _output_byte_digits iny lda #0 sta string_out,y - ldx P8ZP_SCRATCH_REG rts }} } -asmsub str_b (byte value @ A) clobbers(A,Y) { +asmsub str_b (byte value @ A) clobbers(A,X,Y) { ; ---- convert the byte in A in decimal string form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG ldy #0 sty P8ZP_SCRATCH_B1 cmp #0 @@ -75,7 +70,7 @@ asmsub str_b (byte value @ A) clobbers(A,Y) { }} } -asmsub str_ubhex (ubyte value @ A) clobbers(A,Y) { +asmsub str_ubhex (ubyte value @ A) clobbers(A,X,Y) { ; ---- convert the ubyte in A in hex string form %asm {{ jsr conv.ubyte2hex @@ -87,7 +82,7 @@ asmsub str_ubhex (ubyte value @ A) clobbers(A,Y) { }} } -asmsub str_ubbin (ubyte value @ A) clobbers(A,Y) { +asmsub str_ubbin (ubyte value @ A) clobbers(A,X,Y) { ; ---- convert the ubyte in A in binary string form %asm {{ sta P8ZP_SCRATCH_B1 @@ -106,7 +101,7 @@ _digit sta string_out,y }} } -asmsub str_uwbin (uword value @ AY) clobbers(A,Y) { +asmsub str_uwbin (uword value @ AY) clobbers(A,X,Y) { ; ---- convert the uword in A/Y in binary string form %asm {{ sta P8ZP_SCRATCH_REG @@ -145,10 +140,9 @@ asmsub str_uwhex (uword value @ AY) clobbers(A,Y) { }} } -asmsub str_uw0 (uword value @ AY) clobbers(A,Y) { +asmsub str_uw0 (uword value @ AY) clobbers(A,X,Y) { ; ---- convert the uword in A/Y in decimal string form, with left padding 0s (5 positions total) %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal ldy #0 - lda conv.uword2decimal.decTenThousands,y @@ -156,15 +150,13 @@ asmsub str_uw0 (uword value @ AY) clobbers(A,Y) { beq + iny bne - -+ ldx P8ZP_SCRATCH_REG - rts ++ rts }} } -asmsub str_uw (uword value @ AY) clobbers(A,Y) { +asmsub str_uw (uword value @ AY) clobbers(A,X,Y) { ; ---- convert the uword in A/Y in decimal string form, without left padding 0s %asm {{ - stx P8ZP_SCRATCH_REG jsr conv.uword2decimal ldx #0 _output_digits @@ -182,7 +174,6 @@ _gotdigit sta string_out,x bne _gotdigit _end lda #0 sta string_out,x - ldx P8ZP_SCRATCH_REG rts _allzero lda #'0' @@ -192,12 +183,11 @@ _allzero lda #'0' }} } -asmsub str_w (word value @ AY) clobbers(A,Y) { +asmsub str_w (word value @ AY) clobbers(A,X,Y) { ; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's %asm {{ cpy #0 bpl str_uw - stx P8ZP_SCRATCH_REG pha lda #'-' sta string_out @@ -700,10 +690,9 @@ asmsub byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X { }} } -asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y { +asmsub ubyte2hex (ubyte value @A) clobbers(X) -> ubyte @A, ubyte @Y { ; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y) %asm {{ - stx P8ZP_SCRATCH_REG pha and #$0f tax @@ -715,7 +704,6 @@ asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y { lsr a tax lda _hex_digits,x - ldx P8ZP_SCRATCH_REG rts _hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well diff --git a/compiler/res/prog8lib/cx16/diskio.p8 b/compiler/res/prog8lib/cx16/diskio.p8 index 74fca8009..7a3c3175a 100644 --- a/compiler/res/prog8lib/cx16/diskio.p8 +++ b/compiler/res/prog8lib/cx16/diskio.p8 @@ -490,7 +490,6 @@ io_error: sta P8ZP_SCRATCH_W1 lda address+1 sta P8ZP_SCRATCH_W1+1 - stx P8ZP_SCRATCH_REG ldx end_address ldy end_address+1 lda headerless @@ -501,7 +500,6 @@ io_error: + lda # ubyte @A { + asmsub vload(str name @R0, ubyte bank @A, uword address @R1) clobbers(X, Y) -> ubyte @A { ; -- like the basic command VLOAD "filename",drivenumber,bank,address ; loads a file into Vera's video memory in the given bank:address, returns success in A ; the file has to have the usual 2 byte header (which will be skipped) %asm {{ clc internal_vload: - phx pha ldx drivenumber bcc + @@ -644,13 +640,12 @@ internal_vload: + jsr cbm.CLRCHN lda #1 jsr cbm.CLOSE - plx lda P8ZP_SCRATCH_B1 rts }} } - asmsub vload_raw(str name @R0, ubyte bank @A, uword address @R1) -> ubyte @A { + asmsub vload_raw(str name @R0, ubyte bank @A, uword address @R1) clobbers(X, Y) -> ubyte @A { ; -- like the basic command BVLOAD "filename",drivenumber,bank,address ; loads a file into Vera's video memory in the given bank:address, returns success in A ; the file is read fully including the first two bytes. diff --git a/compiler/res/prog8lib/cx16/floats.p8 b/compiler/res/prog8lib/cx16/floats.p8 index dfc5b5d1c..b1ef77556 100644 --- a/compiler/res/prog8lib/cx16/floats.p8 +++ b/compiler/res/prog8lib/cx16/floats.p8 @@ -99,14 +99,11 @@ asmsub FREADSA (byte value @A) clobbers(A,X,Y) { asmsub GIVUAYFAY (uword value @ AY) clobbers(A,X,Y) { ; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1 %asm {{ - phx sty $c4 ; facmo ($64 on c128) sta $c5 ; facmo+1 ($65 on c128) ldx #$90 sec - jsr FLOATC - plx - rts + jmp FLOATC }} } @@ -144,11 +141,8 @@ asmsub FREADUY (ubyte value @Y) { sub rndf() -> float { %asm {{ - phx lda #1 - jsr RND_0 - plx - rts + jmp RND_0 }} } diff --git a/compiler/res/prog8lib/cx16/gfx2.p8 b/compiler/res/prog8lib/cx16/gfx2.p8 index 7361f4806..e10a6021f 100644 --- a/compiler/res/prog8lib/cx16/gfx2.p8 +++ b/compiler/res/prog8lib/cx16/gfx2.p8 @@ -20,8 +20,6 @@ ; mode 6 = bitmap 640 x 480 x 4c ; higher color dephts in highres are not supported due to lack of VRAM -; TODO remove the phx/plx pairs in non-stack compiler version - gfx2 { %option no_symbol_prefixing @@ -223,7 +221,6 @@ _done position(x, y) %asm {{ lda color - phx ldx length+1 beq + ldy #0 @@ -237,7 +234,7 @@ _done - sta cx16.VERA_DATA0 dey bne - -+ plx ++ }} } 6 -> { @@ -262,7 +259,6 @@ _done sta cx16.VERA_ADDR_L lda cx16.r0+1 sta cx16.VERA_ADDR_M - phx ldx x }} @@ -285,10 +281,6 @@ _done + inx ; next pixel }} } - - %asm {{ - plx - }} } } } @@ -923,13 +915,12 @@ skip: }} } - asmsub next_pixels(uword pixels @AY, uword amount @R0) clobbers(A, Y) { + asmsub next_pixels(uword pixels @AY, uword amount @R0) clobbers(A, X, Y) { ; -- sets the next bunch of pixels from a prepared array of bytes. ; for 8 bpp screens this will plot 1 pixel per byte. ; for 1 bpp screens it will plot 8 pixels at once (colors are the bit patterns per byte). ; for 2 bpp screens it will plot 4 pixels at once (colors are the bit patterns per byte). %asm {{ - phx sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 ldx cx16.r0+1 @@ -951,14 +942,13 @@ skip: iny dex bne - -+ plx ++ rts }} } - asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) { + asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) clobbers(X) { ; this is only useful in 256 color mode where one pixel equals one byte value. %asm {{ - phx ldx #8 - asl cx16.r0 bcc + @@ -967,7 +957,6 @@ skip: + sty cx16.VERA_DATA0 + dex bne - - plx rts }} } @@ -999,7 +988,6 @@ skip: cx16.vaddr_autoincr(charset_bank, chardataptr, 0, 1) %asm {{ ; pre-shift the bits - phx ; TODO remove in non-stack version lda text.x and #7 sta P8ZP_SCRATCH_B1 @@ -1019,7 +1007,6 @@ skip: iny cpy #8 bne -- - plx ; TODO remove in non-stack version }} ; left part of shifted char position2(x, y, true) @@ -1086,7 +1073,6 @@ skip: position(x,y) y++ %asm {{ - phx ; TODO remove in non-stack version ldx color lda cx16.VERA_DATA1 sta P8ZP_SCRATCH_B1 @@ -1098,7 +1084,6 @@ skip: + lda cx16.VERA_DATA0 ; don't write a pixel, but do advance to the next address + dey bne - - plx ; TODO remove in non-stack version }} } x+=8 diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 998894c3b..bd2821a62 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -53,25 +53,21 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr ; ---- utility -asmsub STOP2() -> ubyte @A { +asmsub STOP2() clobbers(X) -> ubyte @A { ; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag. %asm {{ - phx jsr cbm.STOP beq + - plx lda #0 rts -+ plx - lda #1 ++ lda #1 rts }} } -asmsub RDTIM16() -> uword @AY { +asmsub RDTIM16() clobbers(X) -> uword @AY { ; -- like RDTIM() but only returning the lower 16 bits in AY for convenience. Also avoids ram bank issue for irqs. %asm {{ - phx php sei jsr cbm.RDTIM @@ -81,7 +77,6 @@ asmsub RDTIM16() -> uword @AY { txa tay pla - plx rts }} } @@ -454,15 +449,12 @@ asmsub mouse_config2(ubyte shape @A) clobbers (A, X, Y) { }} } -asmsub mouse_pos() -> ubyte @A { +asmsub mouse_pos() clobbers(X) -> ubyte @A { ; -- short wrapper around mouse_get() kernal routine: ; -- gets the position of the mouse cursor in cx16.r0 and cx16.r1 (x/y coordinate), returns mouse button status. %asm {{ - phx ldx #cx16.r0 - jsr cx16.mouse_get - plx - rts + jmp cx16.mouse_get }} } @@ -500,7 +492,7 @@ inline asmsub getrambank() -> ubyte @A { }} } -asmsub numbanks() -> uword @AY { +asmsub numbanks() clobbers(X) -> uword @AY { ; -- Returns the number of available RAM banks according to the kernal (each bank is 8 Kb). ; Note that the number of such banks can be 256 so a word is returned. ; But just looking at the A register (the LSB of the result word) could suffice if you know that A=0 means 256 banks: @@ -508,15 +500,13 @@ asmsub numbanks() -> uword @AY { ; Kernal's MEMTOP routine reports 0 in this case but that doesn't mean 'zero banks', instead it means 256 banks, ; as there is no X16 without at least 1 page of banked RAM. So this routine returns 256 instead of 0. %asm {{ - phx sec jsr cbm.MEMTOP ldy #0 cmp #0 bne + iny -+ plx - rts ++ rts }} } @@ -956,10 +946,6 @@ _irq_handler_init sta IRQ_SCRATCH_ZPWORD2 lda P8ZP_SCRATCH_W2+1 sta IRQ_SCRATCH_ZPWORD2+1 - ; Set X to the bottom 32 bytes of the evaluation stack, to HOPEFULLY not clobber it. - ; This leaves 128-32=96 stack entries for the main program, and 32 stack entries for the IRQ handler. - ; We assume IRQ handlers don't contain complex expressions taking up more than that. - ldx #32 cld rts @@ -1079,19 +1065,17 @@ asmsub set_rasterline(uword line @AY) { void cx16.i2c_write_byte($42, $05, activity) } - asmsub wait(uword jiffies @AY) { + asmsub wait(uword jiffies @AY) clobbers(X) { ; --- wait approximately the given number of jiffies (1/60th seconds) (N or N+1) ; note: the system irq handler has to be active for this to work as it depends on the system jiffy clock ; note: this routine cannot be used from inside a irq handler %asm {{ - phx sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 _loop lda P8ZP_SCRATCH_W1 ora P8ZP_SCRATCH_W1+1 bne + - plx rts + sei diff --git a/compiler/res/prog8lib/cx16/textio.p8 b/compiler/res/prog8lib/cx16/textio.p8 index 3876e92c6..6eb1bb88e 100644 --- a/compiler/res/prog8lib/cx16/textio.p8 +++ b/compiler/res/prog8lib/cx16/textio.p8 @@ -42,11 +42,10 @@ asmsub column(ubyte col @A) clobbers(A, X, Y) { }} } -asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { +asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A, X) { ; ---- fill the character screen with the given fill character and character color. %asm {{ sty _ly+1 - phx pha jsr cbm.SCREEN ; get dimensions in X/Y txa @@ -75,8 +74,7 @@ _ly ldy #1 ; modified stz cx16.VERA_ADDR_L inc cx16.VERA_ADDR_M ; next line bra _lx -+ plx - rts ++ rts set_vera_textmatrix_addresses: stz cx16.VERA_CTRL @@ -90,11 +88,10 @@ set_vera_textmatrix_addresses: }} } -asmsub clear_screenchars (ubyte char @ A) clobbers(Y) { +asmsub clear_screenchars (ubyte char @ A) clobbers(X, Y) { ; ---- clear the character screen with the given fill character (leaves colors) ; (assumes screen matrix is at the default address) %asm {{ - phx pha jsr cbm.SCREEN ; get dimensions in X/Y txa @@ -116,16 +113,14 @@ _lx ldx #0 ; modified stz cx16.VERA_ADDR_L inc cx16.VERA_ADDR_M ; next line bra _lx -+ plx - rts ++ rts }} } -asmsub clear_screencolors (ubyte color @ A) clobbers(Y) { +asmsub clear_screencolors (ubyte color @ A) clobbers(X, Y) { ; ---- clear the character screen colors with the given color (leaves characters). ; (assumes color matrix is at the default address) %asm {{ - phx sta _la+1 jsr cbm.SCREEN ; get dimensions in X/Y txa @@ -150,8 +145,7 @@ _la lda #0 ; modified sta cx16.VERA_ADDR_L inc cx16.VERA_ADDR_M ; next line bra _lx -+ plx - rts ++ rts }} } @@ -192,11 +186,10 @@ sub iso_off() { } -asmsub scroll_left() clobbers(A, Y) { +asmsub scroll_left() clobbers(A, X, Y) { ; ---- scroll the whole screen 1 character to the left ; contents of the rightmost column are unchanged, you should clear/refill this yourself %asm {{ - phx jsr cbm.SCREEN dex stx _lx+1 @@ -233,16 +226,14 @@ _lx ldx #0 ; modified lda #0 sta cx16.VERA_CTRL - plx rts }} } -asmsub scroll_right() clobbers(A,Y) { +asmsub scroll_right() clobbers(A,X,Y) { ; ---- scroll the whole screen 1 character to the right ; contents of the leftmost column are unchanged, you should clear/refill this yourself %asm {{ - phx jsr cbm.SCREEN dex stx _lx+1 @@ -287,16 +278,14 @@ _lx ldx #0 ; modified lda #0 sta cx16.VERA_CTRL - plx rts }} } -asmsub scroll_up() clobbers(A, Y) { +asmsub scroll_up() clobbers(A, X, Y) { ; ---- scroll the whole screen 1 character up ; contents of the bottom row are unchanged, you should refill/clear this yourself %asm {{ - phx jsr cbm.SCREEN stx _nextline+1 dey @@ -337,16 +326,14 @@ _nextline + lda #0 sta cx16.VERA_CTRL - plx rts }} } -asmsub scroll_down() clobbers(A, Y) { +asmsub scroll_down() clobbers(A, X, Y) { ; ---- scroll the whole screen 1 character down ; contents of the top row are unchanged, you should refill/clear this yourself %asm {{ - phx jsr cbm.SCREEN stx _nextline+1 dey @@ -393,7 +380,6 @@ _nextline + lda #0 sta cx16.VERA_CTRL - plx rts }} } @@ -418,10 +404,9 @@ asmsub print (str text @ AY) clobbers(A,Y) { }} } -asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub0 (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) %asm {{ - phx jsr conv.ubyte2decimal pha tya @@ -429,16 +414,13 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) { pla jsr cbm.CHROUT txa - jsr cbm.CHROUT - plx - rts + jmp cbm.CHROUT }} } -asmsub print_ub (ubyte value @ A) clobbers(A,Y) { +asmsub print_ub (ubyte value @ A) clobbers(A,X,Y) { ; ---- print the ubyte in A in decimal form, without left padding 0s %asm {{ - phx jsr conv.ubyte2decimal _print_byte_digits pha @@ -454,16 +436,13 @@ _print_byte_digits beq _ones jsr cbm.CHROUT _ones txa - jsr cbm.CHROUT - plx - rts + jmp cbm.CHROUT }} } -asmsub print_b (byte value @ A) clobbers(A,Y) { +asmsub print_b (byte value @ A) clobbers(A,X,Y) { ; ---- print the byte in A in decimal form, without left padding 0s %asm {{ - phx pha cmp #0 bpl + @@ -475,10 +454,9 @@ asmsub print_b (byte value @ A) clobbers(A,Y) { }} } -asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) %asm {{ - phx bcc + pha lda #'$' @@ -487,16 +465,13 @@ asmsub print_ubhex (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr conv.ubyte2hex jsr cbm.CHROUT tya - jsr cbm.CHROUT - plx - rts + jmp cbm.CHROUT }} } -asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ - phx sta P8ZP_SCRATCH_B1 bcc + lda #'%' @@ -509,12 +484,11 @@ asmsub print_ubbin (ubyte value @ A, bool prefix @ Pc) clobbers(A,Y) { + jsr cbm.CHROUT dey bne - - plx rts }} } -asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well) %asm {{ pha @@ -526,7 +500,7 @@ asmsub print_uwbin (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { +asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,X,Y) { ; ---- print the uword in A/Y in hexadecimal form (4 digits) ; (if Carry is set, a radix prefix '$' is printed as well) %asm {{ @@ -539,10 +513,9 @@ asmsub print_uwhex (uword value @ AY, bool prefix @ Pc) clobbers(A,Y) { }} } -asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { +asmsub print_uw0 (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total) %asm {{ - phx jsr conv.uword2decimal ldy #0 - lda conv.uword2decimal.decTenThousands,y @@ -550,17 +523,14 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) { jsr cbm.CHROUT iny bne - -+ plx - rts ++ rts }} } -asmsub print_uw (uword value @ AY) clobbers(A,Y) { +asmsub print_uw (uword value @ AY) clobbers(A,X,Y) { ; ---- print the uword in A/Y in decimal form, without left padding 0s %asm {{ - phx jsr conv.uword2decimal - plx ldy #0 - lda conv.uword2decimal.decTenThousands,y beq _allzero @@ -581,7 +551,7 @@ _allzero }} } -asmsub print_w (word value @ AY) clobbers(A,Y) { +asmsub print_w (word value @ AY) clobbers(A,X,Y) { ; ---- print the (signed) word in A/Y in decimal form, without left padding 0's %asm {{ cpy #0 @@ -704,12 +674,11 @@ asmsub getclr (ubyte col @A, ubyte row @Y) -> ubyte @ A { }} } -sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) { +sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) { ; ---- set char+color at the given position on the screen ; note: color handling is the same as on the C64: it only sets the foreground color and leaves the background color as is. ; Use setcc2 if you want Cx-16 specific feature of setting both Bg+Fg colors (is faster as well). %asm {{ - phx lda column asl a tax @@ -732,7 +701,6 @@ sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) { and #$f0 ora P8ZP_SCRATCH_B1 sta cx16.VERA_DATA0 - plx rts }} } @@ -742,7 +710,6 @@ sub setcc2 (ubyte column, ubyte row, ubyte char, ubyte colors) { ; note: on the CommanderX16 this allows you to set both Fg and Bg colors; ; use the high nybble in A to set the Bg color! Is a bit faster than setcc() too. %asm {{ - phx lda column asl a tax @@ -760,20 +727,14 @@ sub setcc2 (ubyte column, ubyte row, ubyte char, ubyte colors) { inc cx16.VERA_ADDR_L lda colors sta cx16.VERA_DATA0 - plx rts }} } -asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { - ; ---- safe wrapper around PLOT kernal routine, to save the X register. +asmsub plot (ubyte col @ Y, ubyte row @ X) { %asm {{ - phx - tax clc - jsr cbm.PLOT - plx - rts + jmp cbm.PLOT }} } diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 51334a6c7..44378f6da 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -455,13 +455,11 @@ io_error: sta P8ZP_SCRATCH_W1 lda address+1 sta P8ZP_SCRATCH_W1+1 - stx P8ZP_SCRATCH_REG lda #value jsr MOVFM ; load float into fac1 @@ -18,8 +17,7 @@ sub print_f(float value) { jsr cbm.CHROUT iny bne - -+ ldx floats_store_reg - rts ++ rts }} } @@ -44,10 +42,7 @@ sub sin(float angle) -> float { lda #angle jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr SIN - ldx P8ZP_SCRATCH_REG - rts + jmp SIN }} } @@ -56,9 +51,7 @@ sub cos(float angle) -> float { lda #angle jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr COS - ldx P8ZP_SCRATCH_REG + jmp COS rts }} } @@ -68,10 +61,7 @@ sub tan(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr TAN - ldx P8ZP_SCRATCH_REG - rts + jmp TAN }} } @@ -80,10 +70,7 @@ sub atan(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr ATN - ldx P8ZP_SCRATCH_REG - rts + jmp ATN }} } @@ -92,10 +79,7 @@ sub ln(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr LOG - ldx P8ZP_SCRATCH_REG - rts + jmp LOG }} } @@ -104,15 +88,12 @@ sub log2(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG jsr LOG jsr MOVEF lda #FL_LOG2_const jsr MOVFM - jsr FDIVT - ldx P8ZP_SCRATCH_REG - rts + jmp FDIVT }} } @@ -122,12 +103,9 @@ sub rad(float angle) -> float { lda #angle jsr MOVFM - stx P8ZP_SCRATCH_REG lda #<_pi_div_180 ldy #>_pi_div_180 - jsr FMULT - ldx P8ZP_SCRATCH_REG - rts + jmp FMULT _pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180 }} } @@ -138,11 +116,9 @@ sub deg(float angle) -> float { lda #angle jsr MOVFM - stx P8ZP_SCRATCH_REG lda #<_one_over_pi_div_180 ldy #>_one_over_pi_div_180 - jsr FMULT - ldx P8ZP_SCRATCH_REG + jmp FMULT rts _one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180) }} @@ -153,11 +129,8 @@ sub round(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG jsr FADDH - jsr INT - ldx P8ZP_SCRATCH_REG - rts + jmp INT }} } @@ -166,10 +139,7 @@ sub floor(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG - jsr INT - ldx P8ZP_SCRATCH_REG - rts + jmp INT }} } @@ -179,7 +149,6 @@ sub ceil(float value) -> float { lda #value jsr MOVFM - stx P8ZP_SCRATCH_REG ldx #fmath_float1 jsr MOVMF @@ -192,8 +161,7 @@ sub ceil(float value) -> float { lda #FL_ONE_const jsr FADD -+ ldx P8ZP_SCRATCH_REG - rts ++ rts }} } @@ -202,14 +170,11 @@ sub rndseedf(float seed) { seed = -seed ; make sure fp seed is always negative %asm {{ - stx floats_store_reg lda #seed jsr MOVFM ; load float into fac1 lda #-1 - jsr floats.RND - ldx floats_store_reg - rts + jmp floats.RND }} } diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index fa1ffa011..abbbbc3bb 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -7,9 +7,6 @@ ; -math_store_reg .byte 0 ; temporary storage - - multiply_bytes .proc ; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned) sta P8ZP_SCRATCH_B1 ; num1 @@ -30,7 +27,6 @@ multiply_bytes_into_word .proc ; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned) sta P8ZP_SCRATCH_B1 sty P8ZP_SCRATCH_REG - stx math_store_reg lda #0 ldx #8 lsr P8ZP_SCRATCH_B1 @@ -43,7 +39,6 @@ multiply_bytes_into_word .proc bne - tay lda P8ZP_SCRATCH_B1 - ldx math_store_reg rts .pend @@ -55,7 +50,6 @@ multiply_words .proc sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 - stx P8ZP_SCRATCH_REG mult16 lda #0 sta result+2 ; clear upper bits of product @@ -77,7 +71,6 @@ mult16 lda #0 ror result dex bne - - ldx P8ZP_SCRATCH_REG lda result ldy result+1 rts @@ -124,7 +117,6 @@ divmod_ub_asm .proc ; division by zero will result in quotient = 255 and remainder = original number sty P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_B1 - stx math_store_reg lda #0 ldx #8 @@ -137,7 +129,6 @@ divmod_ub_asm .proc dex bne - ldy P8ZP_SCRATCH_B1 - ldx math_store_reg rts .pend @@ -197,7 +188,6 @@ result = dividend ;save memory by reusing divident to store the result sta _divisor sty _divisor+1 - stx P8ZP_SCRATCH_REG lda #0 ;preset remainder to 0 sta remainder sta remainder+1 @@ -224,7 +214,6 @@ result = dividend ;save memory by reusing divident to store the result lda result ldy result+1 - ldx P8ZP_SCRATCH_REG rts _divisor .word 0 .pend @@ -257,501 +246,6 @@ b1=*+1 randbyte = randword ; -- 8 bit pseudo random number generator into A (by just reusing randword) -; ----------- optimized multiplications (stack) : --------- -stack_mul_byte_3 .proc - ; X + X*2 - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_3 .proc - ; W*2 + W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - - -stack_mul_byte_5 .proc - ; X*4 + X - lda P8ESTACK_LO+1,x - asl a - asl a - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_5 .proc - ; W*4 + W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - - -stack_mul_byte_6 .proc - ; (X*2 + X)*2 - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - asl a - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_6 .proc - ; (W*2 + W)*2 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol a - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_7 .proc - ; X*8 - X - lda P8ESTACK_LO+1,x - asl a - asl a - asl a - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_7 .proc - ; W*8 - W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - sbc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_9 .proc - ; X*8 + X - lda P8ESTACK_LO+1,x - asl a - asl a - asl a - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_9 .proc - ; W*8 + W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_10 .proc - ; (X*4 + X)*2 - lda P8ESTACK_LO+1,x - asl a - asl a - clc - adc P8ESTACK_LO+1,x - asl a - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_10 .proc - ; (W*4 + W)*2 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol a - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_11 .proc - ; (X*2 + X)*4 - X - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - asl a - asl a - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -; mul_word_11 is skipped (too much code) - -stack_mul_byte_12 .proc - ; (X*2 + X)*4 - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - asl a - asl a - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_12 .proc - ; (W*2 + W)*4 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol a - asl P8ESTACK_LO+1,x - rol a - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_13 .proc - ; (X*2 + X)*4 + X - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - asl a - asl a - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -; mul_word_13 is skipped (too much code) - -stack_mul_byte_14 .proc - ; (X*8 - X)*2 - lda P8ESTACK_LO+1,x - asl a - asl a - asl a - sec - sbc P8ESTACK_LO+1,x - asl a - sta P8ESTACK_LO+1,x - rts - .pend - -; mul_word_14 is skipped (too much code) - -stack_mul_byte_15 .proc - ; X*16 - X - lda P8ESTACK_LO+1,x - asl a - asl a - asl a - asl a - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_15 .proc - ; W*16 - W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - sbc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_20 .proc - ; (X*4 + X)*4 - lda P8ESTACK_LO+1,x - asl a - asl a - clc - adc P8ESTACK_LO+1,x - asl a - asl a - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_20 .proc - ; (W*4 + W)*4 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol a - asl P8ESTACK_LO+1,x - rol a - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_25 .proc - ; (X*2 + X)*8 + X - lda P8ESTACK_LO+1,x - asl a - clc - adc P8ESTACK_LO+1,x - asl a - asl a - asl a - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_25 .proc - ; W = (W*2 + W) *8 + W - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_W1+1 - clc - adc P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 - adc P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - lda P8ZP_SCRATCH_W1 - asl a - rol P8ZP_SCRATCH_W1+1 - asl a - rol P8ZP_SCRATCH_W1+1 - asl a - rol P8ZP_SCRATCH_W1+1 - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_W1+1 - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_40 .proc - lda P8ESTACK_LO+1,x - and #7 - tay - lda mul_byte_40._forties,y - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_40 .proc - ; (W*4 + W)*8 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_REG - lda P8ESTACK_LO+1,x - asl a - rol P8ZP_SCRATCH_REG - asl a - rol P8ZP_SCRATCH_REG - clc - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_REG - adc P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol a - asl P8ESTACK_LO+1,x - rol a - asl P8ESTACK_LO+1,x - rol a - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_50 .proc - lda P8ESTACK_LO+1,x - and #7 - tay - lda mul_byte_50._fifties, y - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_50 .proc - ; W = W * 25 * 2 - jsr stack_mul_word_25 - asl P8ESTACK_LO+1,x - rol P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_80 .proc - lda P8ESTACK_LO+1,x - and #3 - tay - lda mul_byte_80._eighties, y - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_80 .proc - ; W = W * 40 * 2 - jsr stack_mul_word_40 - asl P8ESTACK_LO+1,x - rol P8ESTACK_HI+1,x - rts - .pend - -stack_mul_byte_100 .proc - lda P8ESTACK_LO+1,x - and #3 - tay - lda mul_byte_100._hundreds, y - sta P8ESTACK_LO+1,x - rts - .pend - -stack_mul_word_100 .proc - ; W = W * 25 * 4 - jsr stack_mul_word_25 - asl P8ESTACK_LO+1,x - rol P8ESTACK_HI+1,x - asl P8ESTACK_LO+1,x - rol P8ESTACK_HI+1,x - rts - .pend - -stack_mul_word_320 .proc - ; stackW = stackLo * 256 + stackLo * 64 (stackHi doesn't matter) - ldy P8ESTACK_LO+1,x - lda #0 - sta P8ESTACK_HI+1,x - tya - asl a - rol P8ESTACK_HI+1,x - asl a - rol P8ESTACK_HI+1,x - asl a - rol P8ESTACK_HI+1,x - asl a - rol P8ESTACK_HI+1,x - asl a - rol P8ESTACK_HI+1,x - asl a - rol P8ESTACK_HI+1,x - sta P8ESTACK_LO+1,x - tya - clc - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -stack_mul_word_640 .proc - ; stackW = (stackLo * 2 * 320) (stackHi doesn't matter) - asl P8ESTACK_LO+1,x - jmp stack_mul_word_320 - .pend - - ; ----------- optimized multiplications (in-place A (byte) and ?? (word)) : --------- mul_byte_3 .proc ; A = A + A*2 @@ -1252,250 +746,69 @@ mul_word_640 .proc ; ----------- end optimized multiplications ----------- -; bit shifts. -; anything below 3 is done inline. anything above 7 is done via other optimizations. - -shift_left_w_7 .proc - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_LO+1,x - - asl a - rol P8ZP_SCRATCH_B1 -_shift6 asl a - rol P8ZP_SCRATCH_B1 -_shift5 asl a - rol P8ZP_SCRATCH_B1 -_shift4 asl a - rol P8ZP_SCRATCH_B1 -_shift3 asl a - rol P8ZP_SCRATCH_B1 - asl a - rol P8ZP_SCRATCH_B1 - asl a - rol P8ZP_SCRATCH_B1 - - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_B1 - sta P8ESTACK_HI+1,x - rts - .pend - -shift_left_w_6 .proc - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_LO+1,x - jmp shift_left_w_7._shift6 - .pend - -shift_left_w_5 .proc - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_LO+1,x - jmp shift_left_w_7._shift5 - .pend - -shift_left_w_4 .proc - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_LO+1,x - jmp shift_left_w_7._shift4 - .pend - -shift_left_w_3 .proc - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_LO+1,x - jmp shift_left_w_7._shift3 - .pend - - -shift_left_w .proc - ; -- variable number of shifts left - inx - ldy P8ESTACK_LO,x - bne _shift - rts -_shift asl P8ESTACK_LO+1,x - rol P8ESTACK_HI+1,x - dey - bne _shift - rts - .pend - -shift_right_uw .proc - ; -- uword variable number of shifts right - inx - ldy P8ESTACK_LO,x - bne _shift - rts -_shift lsr P8ESTACK_HI+1,x - ror P8ESTACK_LO+1,x - dey - bne _shift - rts - .pend - -shift_right_uw_7 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_HI+1,x - - lsr a - ror P8ZP_SCRATCH_B1 -_shift6 lsr a - ror P8ZP_SCRATCH_B1 -_shift5 lsr a - ror P8ZP_SCRATCH_B1 -_shift4 lsr a - ror P8ZP_SCRATCH_B1 -_shift3 lsr a - ror P8ZP_SCRATCH_B1 - lsr a - ror P8ZP_SCRATCH_B1 - lsr a - ror P8ZP_SCRATCH_B1 - - sta P8ESTACK_HI+1,x - lda P8ZP_SCRATCH_B1 - sta P8ESTACK_LO+1,x - rts - .pend - -shift_right_uw_6 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_HI+1,x - jmp shift_right_uw_7._shift6 - .pend - -shift_right_uw_5 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_HI+1,x - jmp shift_right_uw_7._shift5 - .pend - -shift_right_uw_4 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_HI+1,x - jmp shift_right_uw_7._shift4 - .pend - -shift_right_uw_3 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_B1 - lda P8ESTACK_HI+1,x - jmp shift_right_uw_7._shift3 - .pend - - -shift_right_w_7 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - - asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - - lda P8ZP_SCRATCH_W1+1 -_shift6 asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 -_shift5 asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 -_shift4 asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 -_shift3 asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 - asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - lda P8ZP_SCRATCH_W1+1 - asl a - ror P8ZP_SCRATCH_W1+1 - ror P8ZP_SCRATCH_W1 - - lda P8ZP_SCRATCH_W1 - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_W1+1 - sta P8ESTACK_HI+1,x - rts - .pend - -shift_right_w_6 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - jmp shift_right_w_7._shift6 - .pend - -shift_right_w_5 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - jmp shift_right_w_7._shift5 - .pend - -shift_right_w_4 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - jmp shift_right_w_7._shift4 - .pend - -shift_right_w_3 .proc - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - jmp shift_right_w_7._shift3 - .pend - - -shift_right_w .proc - ; -- signed word variable number of shifts right - inx - ldy P8ESTACK_LO,x - bne _shift - rts -_shift lda P8ESTACK_HI+1,x - asl a - ror P8ESTACK_HI+1,x - ror P8ESTACK_LO+1,x - dey - bne _shift - rts - .pend - - ; support for bit shifting that is too large to be unrolled: lsr_byte_A .proc - ; -- lsr signed byte in A times the value in Y (assume >0) + ; -- lsr signed byte in A times the value in Y (>1) cmp #0 - bmi _negative + bpl lsr_ubyte_A +- sec + ror a + dey + bne - + rts + .pend + +lsr_ubyte_A .proc + ; -- lsr unsigned byte in A times the value in Y (>1) - lsr a dey bne - rts -_negative lsr a - ora #$80 + .pend + +asl_byte_A .proc + ; -- asl any byte in A times the value in Y (>1) +- asl a dey + bne - + rts + .pend + + +lsr_word_AY .proc + ; -- lsr signed word in AY times the value in X (>1) + cpy #0 + bpl lsr_uword_AY + sty P8ZP_SCRATCH_B1 +_negative sec + ror P8ZP_SCRATCH_B1 + ror a + dex bne _negative + ldy P8ZP_SCRATCH_B1 + rts + .pend + +lsr_uword_AY .proc + ; -- lsr unsigned word in AY times the value in X (>1) + sty P8ZP_SCRATCH_B1 +- lsr P8ZP_SCRATCH_B1 + ror a + dex + bne - + ldy P8ZP_SCRATCH_B1 + rts + .pend + +asl_word_AY .proc + ; -- asl any word in AY times the value in X (>1) + sty P8ZP_SCRATCH_B1 +- asl a + rol P8ZP_SCRATCH_B1 + dex + bne - + ldy P8ZP_SCRATCH_B1 rts .pend @@ -1525,7 +838,6 @@ tempsq = P8ZP_SCRATCH_B1 ; temp byte for intermediate result sta numberl sty numberh - stx P8ZP_SCRATCH_REG lda #$00 ; clear a sta squarel ; clear square low byte @@ -1563,7 +875,6 @@ _nosqadd: lda squarel ldy squareh - ldx P8ZP_SCRATCH_REG rts .pend diff --git a/compiler/res/prog8lib/prog8_funcs.asm b/compiler/res/prog8lib/prog8_funcs.asm index cdb5f2bb1..4c59bb36b 100644 --- a/compiler/res/prog8lib/prog8_funcs.asm +++ b/compiler/res/prog8lib/prog8_funcs.asm @@ -1,20 +1,6 @@ ; ---- builtin functions -func_any_b_stack .proc - jsr func_any_b_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - -func_all_b_stack .proc - jsr func_all_b_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_any_b_into_A .proc ; -- any(array), array in P8ZP_SCRATCH_W1, num bytes in A sta _cmp_mod+1 ; self-modifying code @@ -49,14 +35,6 @@ func_any_w_into_A .proc jmp func_any_b_into_A .pend -func_any_w_stack .proc - asl a - jsr func_any_b_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_all_w_into_A .proc ; -- all(warray), array in P8ZP_SCRATCH_W1, num bytes in A asl a ; times 2 because of word @@ -77,22 +55,6 @@ _cmp_mod cpy #255 ; modified rts .pend -func_all_w_stack .proc - jsr func_all_w_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - -abs_b_stack .proc - ; -- push abs(A) on stack (as unsigned word) - jsr abs_b_into_A - sta P8ESTACK_LO,x - stz P8ESTACK_HI,x - dex - rts - .pend - abs_b_into_A .proc ; -- A = abs(A) cmp #0 @@ -104,16 +66,6 @@ abs_b_into_A .proc rts .pend -abs_w_stack .proc - ; -- push abs(AY) on stack (as word) - jsr abs_w_into_AY - sta P8ESTACK_LO,x - tya - sta P8ESTACK_HI,x - dex - rts - .pend - abs_w_into_AY .proc ; -- AY = abs(AY) cpy #0 @@ -142,13 +94,6 @@ _neg lda #-1 rts .pend -func_sign_b_stack .proc - jsr func_sign_b_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_sign_ub_into_A .proc cmp #0 bne _pos @@ -157,13 +102,6 @@ _pos lda #1 rts .pend -func_sign_ub_stack .proc - jsr func_sign_ub_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_sign_uw_into_A .proc cpy #0 beq _possibly_zero @@ -174,13 +112,6 @@ _possibly_zero cmp #0 rts .pend -func_sign_uw_stack .proc - jsr func_sign_uw_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_sign_w_into_A .proc cpy #0 beq _possibly_zero @@ -195,26 +126,10 @@ _possibly_zero cmp #0 .pend -func_sign_w_stack .proc - jsr func_sign_w_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - -func_sqrt16_stack .proc - jsr func_sqrt16_into_A - sta P8ESTACK_LO,x - dex - rts - .pend - func_sqrt16_into_A .proc ; integer square root from http://6502org.wikidot.com/software-math-sqrt sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - txa - pha lda #0 sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_REG @@ -237,8 +152,6 @@ func_sqrt16_into_A .proc rol P8ZP_SCRATCH_REG dex bne - - pla - tax lda P8ZP_SCRATCH_B1 rts .pend diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index e5e21b61b..d63a768df 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -4,10 +4,8 @@ orig_stackpointer .byte 0 ; stores the Stack pointer register at program start -read_byte_from_address_on_stack .proc - ; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged) - lda P8ESTACK_LO+1,x - ldy P8ESTACK_HI+1,x + +read_byte_from_address_in_AY .proc sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 ldy #0 @@ -16,318 +14,16 @@ read_byte_from_address_on_stack .proc .pend -write_byte_to_address_on_stack .proc - ; -- write the byte in A to the memory address on the top of the stack (stack remains unchanged) - ldy P8ESTACK_LO+1,x - sty P8ZP_SCRATCH_W2 - ldy P8ESTACK_HI+1,x +write_byte_X_to_address_in_AY .proc + sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 ldy #0 + txa sta (P8ZP_SCRATCH_W2),y rts .pend - -neg_b .proc - lda #0 - sec - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - rts - .pend - -neg_w .proc - sec - lda #0 - sbc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda #0 - sbc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -inv_word .proc - lda P8ESTACK_LO+1,x - eor #255 - sta P8ESTACK_LO+1,x - lda P8ESTACK_HI+1,x - eor #255 - sta P8ESTACK_HI+1,x - rts - .pend - -bitand_b .proc - ; -- bitwise and (of 2 bytes) - lda P8ESTACK_LO+2,x - and P8ESTACK_LO+1,x - inx - sta P8ESTACK_LO+1,x - rts - .pend - -bitor_b .proc - ; -- bitwise or (of 2 bytes) - lda P8ESTACK_LO+2,x - ora P8ESTACK_LO+1,x - inx - sta P8ESTACK_LO+1,x - rts - .pend - -bitxor_b .proc - ; -- bitwise xor (of 2 bytes) - lda P8ESTACK_LO+2,x - eor P8ESTACK_LO+1,x - inx - sta P8ESTACK_LO+1,x - rts - .pend - -bitand_w .proc - ; -- bitwise and (of 2 words) - lda P8ESTACK_LO+2,x - and P8ESTACK_LO+1,x - sta P8ESTACK_LO+2,x - lda P8ESTACK_HI+2,x - and P8ESTACK_HI+1,x - sta P8ESTACK_HI+2,x - inx - rts - .pend - -bitor_w .proc - ; -- bitwise or (of 2 words) - lda P8ESTACK_LO+2,x - ora P8ESTACK_LO+1,x - sta P8ESTACK_LO+2,x - lda P8ESTACK_HI+2,x - ora P8ESTACK_HI+1,x - sta P8ESTACK_HI+2,x - inx - rts - .pend - -bitxor_w .proc - ; -- bitwise xor (of 2 bytes) - lda P8ESTACK_LO+2,x - eor P8ESTACK_LO+1,x - sta P8ESTACK_LO+2,x - lda P8ESTACK_HI+2,x - eor P8ESTACK_HI+1,x - sta P8ESTACK_HI+2,x - inx - rts - .pend - - -add_w .proc - ; -- push word+word / uword+uword - inx - clc - lda P8ESTACK_LO,x - adc P8ESTACK_LO+1,x - sta P8ESTACK_LO+1,x - lda P8ESTACK_HI,x - adc P8ESTACK_HI+1,x - sta P8ESTACK_HI+1,x - rts - .pend - -sub_w .proc - ; -- push word-word - inx - sec - lda P8ESTACK_LO+1,x - sbc P8ESTACK_LO,x - sta P8ESTACK_LO+1,x - lda P8ESTACK_HI+1,x - sbc P8ESTACK_HI,x - sta P8ESTACK_HI+1,x - rts - .pend - -mul_byte .proc - ; -- b*b->b (signed and unsigned) - inx - lda P8ESTACK_LO,x - ldy P8ESTACK_LO+1,x - jsr math.multiply_bytes - sta P8ESTACK_LO+1,x - rts - .pend - -mul_word .proc - inx - lda P8ESTACK_LO,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI,x - sta P8ZP_SCRATCH_W1+1 - lda P8ESTACK_LO+1,x - ldy P8ESTACK_HI+1,x - jsr math.multiply_words - sta P8ESTACK_LO+1,x - tya - sta P8ESTACK_HI+1,x - rts - .pend - -idiv_b .proc - ; signed division: use unsigned division and fix sign of result afterwards - inx - lda P8ESTACK_LO,x - eor P8ESTACK_LO+1,x - php ; save sign of result - lda P8ESTACK_LO,x - bpl + - eor #$ff - sec - adc #0 ; make num1 positive -+ tay - inx - lda P8ESTACK_LO,x - bpl + - eor #$ff - sec - adc #0 ; make num2 positive -+ jsr math.divmod_ub_asm - sta _remainder - tya - plp ; get sign of result - bpl + - eor #$ff - sec - adc #0 ; negate result -+ sta P8ESTACK_LO,x - dex - rts -_remainder .byte 0 - .pend - -idiv_ub .proc - inx - ldy P8ESTACK_LO,x - lda P8ESTACK_LO+1,x - jsr math.divmod_ub_asm - tya - sta P8ESTACK_LO+1,x - rts - .pend - -idiv_w .proc - ; signed division: use unsigned division and fix sign of result afterwards - lda P8ESTACK_HI+2,x - eor P8ESTACK_HI+1,x - php ; save sign of result - lda P8ESTACK_HI+1,x - bpl + - jsr neg_w ; make value positive -+ inx - lda P8ESTACK_HI+1,x - bpl + - jsr neg_w ; make value positive -+ lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - jsr math.divmod_uw_asm - sta P8ESTACK_LO+1,x - tya - sta P8ESTACK_HI+1,x - plp - bpl + - jmp neg_w ; negate result -+ rts - .pend - -idiv_uw .proc - inx - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - jsr math.divmod_uw_asm - sta P8ESTACK_LO+1,x - tya - sta P8ESTACK_HI+1,x - rts - .pend - -remainder_ub .proc - inx - ldy P8ESTACK_LO,x ; right operand - lda P8ESTACK_LO+1,x ; left operand - jsr math.divmod_ub_asm - sta P8ESTACK_LO+1,x - rts - .pend - -remainder_uw .proc - inx - lda P8ESTACK_LO+1,x - sta P8ZP_SCRATCH_W1 - lda P8ESTACK_HI+1,x - sta P8ZP_SCRATCH_W1+1 - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - jsr math.divmod_uw_asm - lda P8ZP_SCRATCH_W2 - sta P8ESTACK_LO+1,x - lda P8ZP_SCRATCH_W2+1 - sta P8ESTACK_HI+1,x - rts - .pend - -equal_w .proc - ; -- are the two words on the stack identical? - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - bne equal_b._equal_b_false - lda P8ESTACK_HI+1,x - cmp P8ESTACK_HI+2,x - bne equal_b._equal_b_false - beq equal_b._equal_b_true - .pend - -notequal_b .proc - ; -- are the two bytes on the stack different? - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - beq equal_b._equal_b_false - bne equal_b._equal_b_true - .pend - -notequal_w .proc - ; -- are the two words on the stack different? - lda P8ESTACK_HI+1,x - cmp P8ESTACK_HI+2,x - beq notequal_b - bne equal_b._equal_b_true - .pend - -less_ub .proc - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - bcc equal_b._equal_b_true - bcs equal_b._equal_b_false - .pend - -less_b .proc - ; see http://www.6502.org/tutorials/compare_beyond.html - lda P8ESTACK_LO+2,x - sec - sbc P8ESTACK_LO+1,x - bvc + - eor #$80 -+ bmi equal_b._equal_b_true - bpl equal_b._equal_b_false - .pend - reg_less_uw .proc ; AY < P8ZP_SCRATCH_W2? cpy P8ZP_SCRATCH_W2+1 @@ -341,17 +37,6 @@ _true lda #1 rts .pend -less_uw .proc - lda P8ESTACK_HI+2,x - cmp P8ESTACK_HI+1,x - bcc equal_b._equal_b_true - bne equal_b._equal_b_false - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - bcc equal_b._equal_b_true - bcs equal_b._equal_b_false - .pend - reg_less_w .proc ; -- AY < P8ZP_SCRATCH_W2? cmp P8ZP_SCRATCH_W2 @@ -366,48 +51,6 @@ _true lda #1 rts .pend -less_w .proc - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - lda P8ESTACK_HI+2,x - sbc P8ESTACK_HI+1,x - bvc + - eor #$80 -+ bmi equal_b._equal_b_true - bpl equal_b._equal_b_false - .pend - -equal_b .proc - ; -- are the two bytes on the stack identical? - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - bne _equal_b_false -_equal_b_true lda #1 -_equal_b_store inx - sta P8ESTACK_LO+1,x - rts -_equal_b_false lda #0 - beq _equal_b_store - .pend - -lesseq_ub .proc - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - bcs equal_b._equal_b_true - bcc equal_b._equal_b_false - .pend - -lesseq_b .proc - ; see http://www.6502.org/tutorials/compare_beyond.html - lda P8ESTACK_LO+2,x - clc - sbc P8ESTACK_LO+1,x - bvc + - eor #$80 -+ bmi equal_b._equal_b_true - bpl equal_b._equal_b_false - .pend - reg_lesseq_uw .proc ; AY <= P8ZP_SCRATCH_W2? cpy P8ZP_SCRATCH_W2+1 @@ -424,17 +67,6 @@ _true lda #1 rts .pend -lesseq_uw .proc - lda P8ESTACK_HI+1,x - cmp P8ESTACK_HI+2,x - bcc equal_b._equal_b_false - bne equal_b._equal_b_true - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - bcs equal_b._equal_b_true - bcc equal_b._equal_b_false - .pend - reg_lesseq_w .proc ; -- P8ZP_SCRATCH_W2 <= AY ? (note: order different from other routines) cmp P8ZP_SCRATCH_W2 @@ -449,224 +81,6 @@ reg_lesseq_w .proc rts .pend -lesseq_w .proc - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - lda P8ESTACK_HI+1,x - sbc P8ESTACK_HI+2,x - bvc + - eor #$80 -+ bpl equal_b._equal_b_true - bmi equal_b._equal_b_false - .pend - -greater_ub .proc - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - beq equal_b._equal_b_false - bcs equal_b._equal_b_true - bcc equal_b._equal_b_false - .pend - -greater_b .proc - ; see http://www.6502.org/tutorials/compare_beyond.html - lda P8ESTACK_LO+2,x - clc - sbc P8ESTACK_LO+1,x - bvc + - eor #$80 -+ bpl equal_b._equal_b_true - bmi equal_b._equal_b_false - .pend - -greater_uw .proc - lda P8ESTACK_HI+1,x - cmp P8ESTACK_HI+2,x - bcc equal_b._equal_b_true - bne equal_b._equal_b_false - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - bcc equal_b._equal_b_true - bcs equal_b._equal_b_false - .pend - -greater_w .proc - lda P8ESTACK_LO+1,x - cmp P8ESTACK_LO+2,x - lda P8ESTACK_HI+1,x - sbc P8ESTACK_HI+2,x - bvc + - eor #$80 -+ bmi equal_b._equal_b_true - bpl equal_b._equal_b_false - .pend - -greatereq_ub .proc - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - bcs equal_b._equal_b_true - bcc equal_b._equal_b_false - .pend - -greatereq_b .proc - ; see http://www.6502.org/tutorials/compare_beyond.html - lda P8ESTACK_LO+2,x - sec - sbc P8ESTACK_LO+1,x - bvc + - eor #$80 -+ bpl equal_b._equal_b_true - bmi equal_b._equal_b_false - .pend - -greatereq_uw .proc - lda P8ESTACK_HI+2,x - cmp P8ESTACK_HI+1,x - bcc equal_b._equal_b_false - bne equal_b._equal_b_true - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - bcs equal_b._equal_b_true - bcc equal_b._equal_b_false - .pend - -greatereq_w .proc - lda P8ESTACK_LO+2,x - cmp P8ESTACK_LO+1,x - lda P8ESTACK_HI+2,x - sbc P8ESTACK_HI+1,x - bvc + - eor #$80 -+ bmi equal_b._equal_b_false - bpl equal_b._equal_b_true - .pend - - -shiftleft_b .proc - inx - ldy P8ESTACK_LO,x - bne + - rts -+ lda P8ESTACK_LO+1,x -- asl a - dey - bne - - sta P8ESTACK_LO+1,x - rts - .pend - -shiftright_b .proc - inx - ldy P8ESTACK_LO,x - bne + - rts -+ lda P8ESTACK_LO+1,x -- lsr a - dey - bne - - sta P8ESTACK_LO+1,x - rts - .pend - - -equalzero_b .proc - lda P8ESTACK_LO+1,x - beq _true - bne _false -_true lda #1 - sta P8ESTACK_LO+1,x - rts -_false lda #0 - sta P8ESTACK_LO+1,x - rts - .pend - -equalzero_w .proc - lda P8ESTACK_LO+1,x - ora P8ESTACK_HI+1,x - beq equalzero_b._true - bne equalzero_b._false - .pend - -notequalzero_b .proc - lda P8ESTACK_LO+1,x - beq equalzero_b._false - bne equalzero_b._true - .pend - -notequalzero_w .proc - lda P8ESTACK_LO+1,x - ora P8ESTACK_HI+1,x - beq equalzero_b._false - bne equalzero_b._true - .pend - -lesszero_b .proc - lda P8ESTACK_LO+1,x - bmi equalzero_b._true - jmp equalzero_b._false - .pend - -lesszero_w .proc - lda P8ESTACK_HI+1,x - bmi equalzero_b._true - jmp equalzero_b._false - .pend - -greaterzero_ub .proc - lda P8ESTACK_LO+1,x - bne equalzero_b._true - beq equalzero_b._false - .pend - -greaterzero_sb .proc - lda P8ESTACK_LO+1,x - beq equalzero_b._false - bpl equalzero_b._true - bmi equalzero_b._false - .pend - -greaterzero_uw .proc - lda P8ESTACK_LO+1,x - ora P8ESTACK_HI+1,x - bne equalzero_b._true - beq equalzero_b._false - .pend - -greaterzero_sw .proc - lda P8ESTACK_HI+1,x - bmi equalzero_b._false - ora P8ESTACK_LO+1,x - beq equalzero_b._false - bne equalzero_b._true - .pend - -lessequalzero_sb .proc - lda P8ESTACK_LO+1,x - bmi equalzero_b._true - beq equalzero_b._true - bne equalzero_b._false - .pend - -lessequalzero_sw .proc - lda P8ESTACK_HI+1,x - bmi equalzero_b._true - ora P8ESTACK_LO+1,x - beq equalzero_b._true - bne equalzero_b._false - .pend - -greaterequalzero_sb .proc - lda P8ESTACK_LO+1,x - bpl equalzero_b._true - bmi equalzero_b._false - .pend - -greaterequalzero_sw .proc - lda P8ESTACK_HI+1,x - bpl equalzero_b._true - bmi equalzero_b._false - .pend memcopy16_up .proc ; -- copy memory UP from (P8ZP_SCRATCH_W1) to (P8ZP_SCRATCH_W2) of length X/Y (16-bit, X=lo, Y=hi) @@ -996,21 +410,6 @@ _arg_s1 .word 0 _arg_s2 .word 0 .pend -strcmp_stack .proc - ; -- compare strings, both on stack. - ; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y. - inx - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - sta P8ZP_SCRATCH_W2 - sty P8ZP_SCRATCH_W2+1 - inx - lda P8ESTACK_LO,x - ldy P8ESTACK_HI,x - jmp strcmp_mem - .pend - - strcmp_mem .proc ; -- compares strings in s1 (AY) and s2 (P8ZP_SCRATCH_W2). ; Returns -1,0,1 in A, depeding on the ordering. Clobbers Y. @@ -1041,16 +440,6 @@ _return_minusone .pend -sign_extend_stack_byte .proc - ; -- sign extend the (signed) byte on the stack to full 16 bits - lda P8ESTACK_LO+1,x - ora #$7f - bmi + - lda #0 -+ sta P8ESTACK_HI+1,x - rts - .pend - strlen .proc ; -- returns the number of bytes in the string in AY, in Y. sta P8ZP_SCRATCH_W1 diff --git a/compiler/res/prog8lib/string.p8 b/compiler/res/prog8lib/string.p8 index 41835f066..84e79c19a 100644 --- a/compiler/res/prog8lib/string.p8 +++ b/compiler/res/prog8lib/string.p8 @@ -282,7 +282,6 @@ _done rts str = P8ZP_SCRATCH_W1 - stx P8ZP_SCRATCH_REG sta str sty str+1 lda cx16.r0 @@ -294,7 +293,6 @@ str = P8ZP_SCRATCH_W1 jsr _match lda #0 rol a - ldx P8ZP_SCRATCH_REG rts diff --git a/compiler/res/prog8lib/test_stack.p8 b/compiler/res/prog8lib/test_stack.p8 index 11f18d0ef..6a7fa33bf 100644 --- a/compiler/res/prog8lib/test_stack.p8 +++ b/compiler/res/prog8lib/test_stack.p8 @@ -1,4 +1,4 @@ -; utility debug code to print the X (evalstack) and SP (cpu stack) registers. +; utility debug code to print the SP (cpu stack pointer) register. %import textio @@ -7,7 +7,6 @@ test_stack { asmsub test() { %asm {{ - stx _saveX lda #13 jsr txt.chrout lda #'-' @@ -17,14 +16,6 @@ test_stack { bne - lda #13 jsr txt.chrout - lda #'x' - jsr txt.chrout - lda #'=' - jsr txt.chrout - lda _saveX - jsr txt.print_ub - lda #' ' - jsr txt.chrout lda #'s' jsr txt.chrout lda #'p' @@ -43,9 +34,7 @@ test_stack { bne - lda #13 jsr txt.chrout - ldx _saveX rts -_saveX .byte 0 }} } } diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 04806cb3f..396ff4496 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -3,7 +3,6 @@ package prog8 import kotlinx.cli.* import prog8.ast.base.AstException import prog8.code.core.CbmPrgLauncherType -import prog8.code.core.toHex import prog8.code.target.* import prog8.code.target.virtual.VirtualMachineDefinition import prog8.compiler.CompilationResult @@ -39,16 +38,13 @@ private fun compileMain(args: Array): Boolean { val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM) val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well") val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple() - val evalStackAddrString by cli.option(ArgType.String, fullName = "esa", description = "override the eval-stack base address (must be page aligned)") val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation") val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation") val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen") val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code") val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations") val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") - val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") - val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation") val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}', '${VMTarget.NAME}') (required)") val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM") @@ -101,25 +97,6 @@ private fun compileMain(args: Array): Boolean { return runVm(moduleFiles.first()) } - var evalStackAddr: UInt? = null - if(evalStackAddrString!=null) { - try { - evalStackAddr = if (evalStackAddrString!!.startsWith("0x")) - evalStackAddrString!!.substring(2).toUInt(16) - else if (evalStackAddrString!!.startsWith("$")) - evalStackAddrString!!.substring(1).toUInt(16) - else - evalStackAddrString!!.toUInt() - } catch(nx: NumberFormatException) { - System.err.println("invalid address for evalstack: $evalStackAddrString") - return false - } - if(evalStackAddr !in 256u..65536u-512u || (evalStackAddr and 255u != 0u)) { - System.err.println("invalid address for evalstack: ${evalStackAddr.toHex()}") - return false - } - } - val processedSymbols = processSymbolDefs(symbolDefs) ?: return false if(watchMode==true) { @@ -134,15 +111,12 @@ private fun compileMain(args: Array): Boolean { val compilerArgs = CompilerArguments( filepath, dontOptimize != true, - optimizeFloatExpressions == true, dontWriteAssembly != true, - slowCodegenWarnings == true, quietAssembler == true, asmListfile == true, experimentalCodegen == true, varsHighBank, compilationTarget!!, - evalStackAddr, splitWordArrays == true, processedSymbols, srcdirs, @@ -203,15 +177,12 @@ private fun compileMain(args: Array): Boolean { val compilerArgs = CompilerArguments( filepath, dontOptimize != true, - optimizeFloatExpressions == true, dontWriteAssembly != true, - slowCodegenWarnings == true, quietAssembler == true, asmListfile == true, experimentalCodegen == true, varsHighBank, compilationTarget!!, - evalStackAddr, splitWordArrays == true, processedSymbols, srcdirs, diff --git a/compiler/src/prog8/buildversion/BuildVersion.kt b/compiler/src/prog8/buildversion/BuildVersion.kt index 931d56c39..e5e79b7d7 100644 --- a/compiler/src/prog8/buildversion/BuildVersion.kt +++ b/compiler/src/prog8/buildversion/BuildVersion.kt @@ -6,10 +6,10 @@ package prog8.buildversion const val MAVEN_GROUP = "prog8" const val MAVEN_NAME = "compiler" const val VERSION = "9.2-SNAPSHOT" -const val GIT_REVISION = 3964 -const val GIT_SHA = "aaa30e4a583fa7c8da61998cf7cbb2a60b52afb0" -const val GIT_DATE = "2023-07-16T21:16:18Z" -const val GIT_BRANCH = "master" -const val BUILD_DATE = "2023-07-16T21:16:23Z" -const val BUILD_UNIX_TIME = 1689542183583L +const val GIT_REVISION = 3980 +const val GIT_SHA = "9f247901d484ca36d047cdcf77f5b905ba772f82" +const val GIT_DATE = "2023-07-16T21:45:04Z" +const val GIT_BRANCH = "remove_evalstack" +const val BUILD_DATE = "2023-07-17T23:11:43Z" +const val BUILD_UNIX_TIME = 1689635503506L const val DIRTY = 1 diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 58b1c5659..9848db539 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -29,15 +29,12 @@ class CompilationResult(val compilerAst: Program, // deprecated, use codegenAs class CompilerArguments(val filepath: Path, val optimize: Boolean, - val optimizeFloatExpressions: Boolean, val writeAssembly: Boolean, - val slowCodegenWarnings: Boolean, val quietAssembler: Boolean, val asmListfile: Boolean, val experimentalCodegen: Boolean, val varsHighBank: Int?, val compilationTarget: String, - val evalStackBaseAddress: UInt?, val splitWordArrays: Boolean, val symbolDefs: Map, val sourceDirs: List = emptyList(), @@ -49,8 +46,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { lateinit var program: Program lateinit var importedFiles: List - val optimizeFloatExpr = if(args.optimize) args.optimizeFloatExpressions else false - val compTarget = when(args.compilationTarget) { C64Target.NAME -> C64Target() @@ -70,14 +65,11 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { compilationOptions = options with(compilationOptions) { - slowCodegenWarnings = args.slowCodegenWarnings optimize = args.optimize - optimizeFloatExpressions = optimizeFloatExpr asmQuiet = args.quietAssembler asmListfile = args.asmListfile experimentalCodegen = args.experimentalCodegen varsHighBank = args.varsHighBank - evalStackBaseAddress = args.evalStackBaseAddress splitWordArrays = args.splitWordArrays outputDir = args.outputDir.normalize() symbolDefs = args.symbolDefs @@ -85,10 +77,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { program = programresult importedFiles = imported - if(compilationOptions.evalStackBaseAddress!=null) { - compTarget.machine.overrideEvalStack(compilationOptions.evalStackBaseAddress!!) - } - processAst(program, args.errors, compilationOptions) if (compilationOptions.optimize) { // println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************") @@ -367,12 +355,11 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e while (true) { // keep optimizing expressions and statements until no more steps remain val optsDone1 = program.simplifyExpressions(errors, compTarget) - val optsDone2 = program.splitBinaryExpressions(compilerOptions) - val optsDone3 = program.optimizeStatements(errors, functions, compilerOptions) - val optsDone4 = program.inlineSubroutines(compilerOptions) + val optsDone2 = program.optimizeStatements(errors, functions, compilerOptions) + val optsDone3 = program.inlineSubroutines(compilerOptions) program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away errors.report() - if (optsDone1 + optsDone2 + optsDone3 + optsDone4 == 0) + if (optsDone1 + optsDone2 + optsDone3 == 0) break } val remover2 = UnusedCodeRemover(program, errors, compTarget) diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 30ce50201..e33b39b5b 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -27,7 +27,7 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO boolRemover.visit(this) boolRemover.applyModifications() - val fixer = BeforeAsmAstChanger(this, compilerOptions, errors) + val fixer = BeforeAsmAstChanger(this, compilerOptions) fixer.visit(this) while (errors.noErrors() && fixer.applyModifications() > 0) { fixer.visit(this) @@ -108,9 +108,6 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, options: Compilati checker2.visit(this) if(errors.noErrors()) { - val transforms = AstOnetimeTransforms(this, options) - transforms.visit(this) - transforms.applyModifications() val lit2decl = LiteralsToAutoVars(this, options.compTarget, errors) lit2decl.visit(this) if(errors.noErrors()) diff --git a/compiler/src/prog8/compiler/astprocessing/AstOnetimeTransforms.kt b/compiler/src/prog8/compiler/astprocessing/AstOnetimeTransforms.kt deleted file mode 100644 index 6c8b0b989..000000000 --- a/compiler/src/prog8/compiler/astprocessing/AstOnetimeTransforms.kt +++ /dev/null @@ -1,62 +0,0 @@ -package prog8.compiler.astprocessing - -import prog8.ast.Node -import prog8.ast.Program -import prog8.ast.expressions.* -import prog8.ast.statements.AssignTarget -import prog8.ast.statements.Assignment -import prog8.ast.statements.DirectMemoryWrite -import prog8.ast.statements.VarDecl -import prog8.ast.walk.AstWalker -import prog8.ast.walk.IAstModification -import prog8.code.core.CompilationOptions -import prog8.code.core.DataType -import prog8.code.target.VMTarget - - -internal class AstOnetimeTransforms(private val program: Program, private val options: CompilationOptions) : AstWalker() { - - override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { - if(parent !is VarDecl) { - if(options.compTarget.name == VMTarget.NAME) - return noModifications // vm codegen deals correctly with all cases - // Don't replace the initializer value in a vardecl - this will be moved to a separate - // assignment statement soon in after(VarDecl) - return replacePointerVarIndexWithMemreadOrMemwrite(arrayIndexedExpression, parent) - } - return noModifications - } - - private fun replacePointerVarIndexWithMemreadOrMemwrite(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { - // note: The CodeDesugarer already does something similar, but that is meant ONLY to take - // into account the case where the index value is a word type. - // The replacement here is to fix missing cases in the 6502 codegen. (VM codegen doesn't use this workaround) - // TODO make the 6502 codegen better so this workaround can be removed - val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program) - if(arrayVar!=null && arrayVar.datatype == DataType.UWORD) { - if(parent is AssignTarget) { - val assignment = parent.parent as? Assignment - if(assignment?.value is NumericLiteral || assignment?.value is IdentifierReference) { - // the codegen contains correct optimized code ONLY for a constant assignment, or direct variable assignment. - return noModifications - } - // Other cases aren't covered correctly by the 6502 codegen, and there are a LOT of cases. - // So rewrite assignment target pointervar[index] into @(pointervar+index) - // (the 6502 codegen covers all cases correctly for a direct memory assignment). - val indexer = arrayIndexedExpression.indexer - val add: Expression = - if(indexer.indexExpr.constValue(program)?.number==0.0) - arrayIndexedExpression.arrayvar.copy() - else - BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", indexer.indexExpr, arrayIndexedExpression.position) - val memwrite = DirectMemoryWrite(add, arrayIndexedExpression.position) - val newtarget = AssignTarget(null, null, memwrite, arrayIndexedExpression.position) - return listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent)) - } - } - - return noModifications - } -} - - diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 0f794f4f4..7e5feda9a 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -9,8 +9,6 @@ import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* import prog8.code.target.C64Target -import prog8.code.target.Cx16Target -import prog8.code.target.VMTarget class AstPreprocessor(val program: Program, @@ -25,15 +23,10 @@ class AstPreprocessor(val program: Program, relocateCx16VirtualRegisters(program, 0x0004u) } } - else if(options.compTarget.name !in setOf(Cx16Target.NAME, VMTarget.NAME)) { - relocateCx16VirtualRegisters(program, options.compTarget.machine.ESTACK_HI) - } return noModifications } private fun relocateCx16VirtualRegisters(program: Program, baseAddress: UInt) { - // reset the address of the virtual registers to be inside the evaluation stack. - // (we don't do this on CommanderX16 itself as the registers have a fixed location in Zeropage there) val cx16block = program.allBlocks.single { it.name == "cx16" } val memVars = cx16block.statements .filterIsInstance() diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt index e4344ebe4..7288c9e93 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt @@ -9,14 +9,10 @@ import prog8.ast.getTempVar import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.ast.walk.IAstVisitor import prog8.code.core.* import prog8.code.target.VMTarget -internal class BeforeAsmAstChanger(val program: Program, - private val options: CompilationOptions, - private val errors: IErrorReporter -) : AstWalker() { +internal class BeforeAsmAstChanger(val program: Program, private val options: CompilationOptions) : AstWalker() { override fun before(breakStmt: Break, parent: Node): Iterable { throw InternalCompilerException("break should have been replaced by goto $breakStmt") @@ -56,9 +52,6 @@ internal class BeforeAsmAstChanger(val program: Program, && !assignment.target.isIOAddress(options.compTarget.machine)) { val binExpr = assignment.value as? BinaryExpression - if(binExpr!=null && binExpr.inferType(program) istype DataType.FLOAT && !options.optimizeFloatExpressions) - return noModifications - if (binExpr != null && binExpr.operator !in ComparisonOperators) { if (binExpr.left !is BinaryExpression) { if (binExpr.right.referencesIdentifier(assignment.target.identifier!!.nameInSource)) { @@ -222,12 +215,6 @@ internal class BeforeAsmAstChanger(val program: Program, override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { if(options.compTarget.name!=VMTarget.NAME) { // don't apply this optimization/check for Vm target - val containingStatement = getContainingStatement(arrayIndexedExpression) - if(getComplexArrayIndexedExpressions(containingStatement).size > 1) { - errors.err("it's not possible to use more than one complex array indexing expression in a single statement; break it up via a temporary variable for instance", containingStatement.position) - return noModifications - } - val index = arrayIndexedExpression.indexer.indexExpr if (index !is NumericLiteral && index !is IdentifierReference) { // replace complex indexing expression with a temp variable to hold the computed index first @@ -238,42 +225,6 @@ internal class BeforeAsmAstChanger(val program: Program, return noModifications } - private fun getComplexArrayIndexedExpressions(stmt: Statement): List { - - class Searcher : IAstVisitor { - val complexArrayIndexedExpressions = mutableListOf() - override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { - val ix = arrayIndexedExpression.indexer.indexExpr - if(ix !is NumericLiteral && ix !is IdentifierReference) - complexArrayIndexedExpressions.add(arrayIndexedExpression) - } - - override fun visit(branch: ConditionalBranch) {} - - override fun visit(forLoop: ForLoop) {} - - override fun visit(ifElse: IfElse) { - ifElse.condition.accept(this) - } - - override fun visit(untilLoop: UntilLoop) { - untilLoop.condition.accept(this) - } - } - - val searcher = Searcher() - stmt.accept(searcher) - return searcher.complexArrayIndexedExpressions - } - - private fun getContainingStatement(expression: Expression): Statement { - var node: Node = expression - while(node !is Statement) - node = node.parent - - return node - } - private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList { val modifications = mutableListOf() val statement = expr.containingStatement diff --git a/compiler/test/TestAstChecks.kt b/compiler/test/TestAstChecks.kt index e8aff3ea2..008bce992 100644 --- a/compiler/test/TestAstChecks.kt +++ b/compiler/test/TestAstChecks.kt @@ -11,7 +11,7 @@ import prog8tests.helpers.compileText class TestAstChecks: FunSpec({ - test("conditional expression w/float works even without tempvar to split it") { + test("conditional expression w/float works") { val text = """ %import floats main { diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index 0a3175424..09a3f8b0a 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -26,15 +26,12 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat val args = CompilerArguments( filepath, optimize, - optimizeFloatExpressions = true, writeAssembly = true, - slowCodegenWarnings = false, quietAssembler = true, asmListfile = false, experimentalCodegen = false, varsHighBank = null, compilationTarget = target.name, - evalStackBaseAddress = null, splitWordArrays = false, symbolDefs = emptyMap(), outputDir = outputDir diff --git a/compiler/test/TestCompilerOptionLibdirs.kt b/compiler/test/TestCompilerOptionLibdirs.kt index d9261dcb3..020323237 100644 --- a/compiler/test/TestCompilerOptionLibdirs.kt +++ b/compiler/test/TestCompilerOptionLibdirs.kt @@ -43,15 +43,12 @@ class TestCompilerOptionSourcedirs: FunSpec({ val args = CompilerArguments( filepath = filePath, optimize = false, - optimizeFloatExpressions = false, writeAssembly = true, - slowCodegenWarnings = false, quietAssembler = true, asmListfile = false, experimentalCodegen = false, varsHighBank = null, compilationTarget = Cx16Target.NAME, - evalStackBaseAddress = null, splitWordArrays = false, symbolDefs = emptyMap(), sourceDirs, diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 31b97659e..2754f5bbd 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -120,36 +120,31 @@ class TestOptimization: FunSpec({ // load_location = 12345 // word llw // llw = 12345 -// cx16.r0 = load_location -// cx16.r0 += 10000 -// cx16.r2 = load_location -// cx16.r2 += 10000 -// cx16.r4 = load_location -// cx16.r4 += 22 -// cx16.r5s = llw -// cx16.r5s -= 1899 -// cx16.r7s = llw -// cx16.r7s += 99 +// cx16.r0 = load_location + 10000 +// cx16.r2 = load_location + 10000 +// cx16.r4 = load_location + 22 +// cx16.r5s = llw - 1899 +// cx16.r7s = llw + 99 val stmts = result.compilerAst.entrypoint.statements - stmts.size shouldBe 14 + stmts.size shouldBe 9 - val addR0value = (stmts[5] as Assignment).value + val addR0value = (stmts[4] as Assignment).value val binexpr0 = addR0value as BinaryExpression binexpr0.operator shouldBe "+" binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY) - val addR2value = (stmts[7] as Assignment).value + val addR2value = (stmts[5] as Assignment).value val binexpr2 = addR2value as BinaryExpression binexpr2.operator shouldBe "+" binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 10000.0, Position.DUMMY) - val addR4value = (stmts[9] as Assignment).value + val addR4value = (stmts[6] as Assignment).value val binexpr4 = addR4value as BinaryExpression binexpr4.operator shouldBe "+" binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 22.0, Position.DUMMY) - val subR5value = (stmts[11] as Assignment).value + val subR5value = (stmts[7] as Assignment).value val binexpr5 = subR5value as BinaryExpression binexpr5.operator shouldBe "-" binexpr5.right shouldBe NumericLiteral(DataType.UWORD, 1899.0, Position.DUMMY) - val subR7value = (stmts[13] as Assignment).value + val subR7value = (stmts[8] as Assignment).value val binexpr7 = subR7value as BinaryExpression binexpr7.operator shouldBe "+" binexpr7.right shouldBe NumericLiteral(DataType.UWORD, 99.0, Position.DUMMY) @@ -171,44 +166,34 @@ class TestOptimization: FunSpec({ // expected: // word llw // llw = 300 -// cx16.r0s = llw -// cx16.r0s *= 180 -// cx16.r1s = llw -// cx16.r1s *= 180 -// cx16.r2s = llw -// cx16.r2s /= 90 -// cx16.r3s = llw -// cx16.r3s *= 5 -// cx16.r4s = llw -// cx16.r4s *= 90 -// cx16.r4s /= 5 +// cx16.r0s = llw * 180 +// cx16.r1s = llw * 180 +// cx16.r2s = llw / 90 +// cx16.r3s = llw * 5 +// cx16.r4s = llw * 90 / 5 val stmts = result.compilerAst.entrypoint.statements - stmts.size shouldBe 13 + stmts.size shouldBe 7 - val mulR0Value = (stmts[3] as Assignment).value + val mulR0Value = (stmts[2] as Assignment).value val binexpr0 = mulR0Value as BinaryExpression binexpr0.operator shouldBe "*" binexpr0.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY) - val mulR1Value = (stmts[5] as Assignment).value + val mulR1Value = (stmts[3] as Assignment).value val binexpr1 = mulR1Value as BinaryExpression binexpr1.operator shouldBe "*" binexpr1.right shouldBe NumericLiteral(DataType.UWORD, 180.0, Position.DUMMY) - val divR2Value = (stmts[7] as Assignment).value + val divR2Value = (stmts[4] as Assignment).value val binexpr2 = divR2Value as BinaryExpression binexpr2.operator shouldBe "/" binexpr2.right shouldBe NumericLiteral(DataType.UWORD, 90.0, Position.DUMMY) - val mulR3Value = (stmts[9] as Assignment).value + val mulR3Value = (stmts[5] as Assignment).value val binexpr3 = mulR3Value as BinaryExpression binexpr3.operator shouldBe "*" binexpr3.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY) - val mulR4Value = (stmts[11] as Assignment).value + val mulR4Value = (stmts[6] as Assignment).value val binexpr4 = mulR4Value as BinaryExpression - binexpr4.operator shouldBe "*" - binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 90.0, Position.DUMMY) - val divR4Value = (stmts[12] as Assignment).value - val binexpr4b = divR4Value as BinaryExpression - binexpr4b.operator shouldBe "/" - binexpr4b.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY) + binexpr4.operator shouldBe "/" + binexpr4.right shouldBe NumericLiteral(DataType.UWORD, 5.0, Position.DUMMY) } test("constantfolded and silently typecasted for initializervalues") { @@ -377,14 +362,12 @@ class TestOptimization: FunSpec({ uword z4 z4 = 0 ubyte z5 - z5 = z1 - z5 += 5 + z5 = z1 + 5 ubyte z6 - z6 = z1 - z6 -= 5 + z6 = z1 - 5 */ val statements = result.compilerAst.entrypoint.statements - statements.size shouldBe 14 + statements.size shouldBe 12 val z1decl = statements[0] as VarDecl val z1init = statements[1] as Assignment val z2decl = statements[2] as VarDecl @@ -395,10 +378,8 @@ class TestOptimization: FunSpec({ val z4init = statements[7] as Assignment val z5decl = statements[8] as VarDecl val z5init = statements[9] as Assignment - val z5plus = statements[10] as Assignment - val z6decl = statements[11] as VarDecl - val z6init = statements[12] as Assignment - val z6plus = statements[13] as Assignment + val z6decl = statements[10] as VarDecl + val z6init = statements[11] as Assignment z1decl.name shouldBe "z1" z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY) @@ -409,15 +390,11 @@ class TestOptimization: FunSpec({ z4decl.name shouldBe "z4" z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) z5decl.name shouldBe "z5" - (z5init.value as? IdentifierReference)?.nameInSource shouldBe listOf("z1") - z5plus.isAugmentable shouldBe true - (z5plus.value as BinaryExpression).operator shouldBe "+" - (z5plus.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) + (z5init.value as BinaryExpression).operator shouldBe "+" + (z5init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) z6decl.name shouldBe "z6" - (z6init.value as? IdentifierReference)?.nameInSource shouldBe listOf("z1") - z6plus.isAugmentable shouldBe true - (z6plus.value as BinaryExpression).operator shouldBe "-" - (z6plus.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) + (z6init.value as BinaryExpression).operator shouldBe "-" + (z6init.value as BinaryExpression).right shouldBe NumericLiteral(DataType.UBYTE, 5.0, Position.DUMMY) } test("force_output option should work with optimizing memwrite assignment") { @@ -435,7 +412,7 @@ class TestOptimization: FunSpec({ val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!! val stmts = result.compilerAst.entrypoint.statements - stmts.size shouldBe 6 + stmts.size shouldBe 5 val assign=stmts.last() as Assignment (assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa") } @@ -452,7 +429,7 @@ class TestOptimization: FunSpec({ """ val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!! val stmts = result.compilerAst.entrypoint.statements - stmts.size shouldBe 6 + stmts.size shouldBe 5 val assign=stmts.last() as Assignment (assign.target.memoryAddress?.addressExpression as IdentifierReference).nameInSource shouldBe listOf("aa") } @@ -548,9 +525,9 @@ class TestOptimization: FunSpec({ xx += 6 */ val stmts = result.compilerAst.entrypoint.statements - stmts.size shouldBe 8 + stmts.size shouldBe 7 stmts.filterIsInstance().size shouldBe 3 - stmts.filterIsInstance().size shouldBe 5 + stmts.filterIsInstance().size shouldBe 4 } test("only substitue assignments with 0 after a =0 initializer if it is the same variable") { diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index 889d2032c..52464c000 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -95,19 +95,16 @@ main { ubyte ub3 ub3 = 1 ubyte @shared bvalue - bvalue = ub1 - bvalue ^= ub2 - bvalue ^= ub3 - bvalue ^= 1 + bvalue = ub1 ^ ub2 ^ ub3 ^ true bvalue = (((ub1^ub2)^ub3)^(ftrue(99)!=0)) bvalue = ((ub1&ub2)&(ftrue(99)!=0)) return */ - stmts.size shouldBe 14 - val assignValue1 = (stmts[7] as Assignment).value as IdentifierReference - val assignValue2 = (stmts[11] as Assignment).value as BinaryExpression - val assignValue3 = (stmts[12] as Assignment).value as BinaryExpression - assignValue1.nameInSource shouldBe listOf("ub1") + stmts.size shouldBe 11 + val assignValue1 = (stmts[7] as Assignment).value as BinaryExpression + val assignValue2 = (stmts[8] as Assignment).value as BinaryExpression + val assignValue3 = (stmts[9] as Assignment).value as BinaryExpression + assignValue1.operator shouldBe "^" assignValue2.operator shouldBe "^" assignValue3.operator shouldBe "&" val right2 = assignValue2.right as BinaryExpression diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index 83fbe7ae9..16010c595 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -17,22 +17,18 @@ internal fun compileFile( outputDir: Path = prog8tests.helpers.outputDir, errors: IErrorReporter? = null, writeAssembly: Boolean = true, - optFloatExpr: Boolean = true, ) : CompilationResult? { val filepath = fileDir.resolve(fileName) assumeReadableFile(filepath) val args = CompilerArguments( filepath, optimize, - optimizeFloatExpressions = optFloatExpr, writeAssembly = writeAssembly, - slowCodegenWarnings = false, quietAssembler = true, asmListfile = false, experimentalCodegen = false, varsHighBank = null, platform.name, - evalStackBaseAddress = null, symbolDefs = emptyMap(), outputDir = outputDir, errors = errors ?: ErrorReporterForTests(), @@ -52,11 +48,10 @@ internal fun compileText( sourceText: String, errors: IErrorReporter? = null, writeAssembly: Boolean = true, - optFloatExpr: Boolean = true, ) : CompilationResult? { val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8") // we don't assumeNotExists(filePath) - should be ok to just overwrite it filePath.toFile().writeText(sourceText) return compileFile(platform, optimize, filePath.parent, filePath.name, - errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr) + errors=errors, writeAssembly=writeAssembly) } diff --git a/docs/source/compiling.rst b/docs/source/compiling.rst index bbd5f1801..ba2f4a065 100644 --- a/docs/source/compiling.rst +++ b/docs/source/compiling.rst @@ -151,10 +151,6 @@ One or more .p8 module files Note that it is possible to use the watch mode with multiple modules as well, but it will recompile everything in that list even if only one of the files got updated. -``-slowwarn`` - Shows debug warnings about slow or problematic assembly code generation. - Ideally, the compiler should use as few stack based evaluations as possible. - ``-quietasm`` Don't print assembler output results. @@ -176,12 +172,6 @@ One or more .p8 module files Add this user-defined symbol directly to the beginning of the generated assembly file. Can be repeated to define multiple symbols. -``-esa
`` - Override the base address of the evaluation stack. Has to be page-aligned. - You can specify an integer or hexadecimal address. - When not compiling for the Commander X16 target, the location of the 16 virtual registers cx16.r0..r15 - is changed accordingly (to keep them in the same memory space as the evaluation stack). - ``-varshigh `` Places the non-zeropage variables in a separate high memory area, instead of inside the program itself. This results in an increase of the amount of system ram available for the program diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 1bb90ba6f..289c64f90 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -945,15 +945,12 @@ syscall (callnr), syscall1 (callnr, arg), syscall2 (callnr, arg1, arg2), syscall specific memory locations. So these builtin function calls are not useful yet except for experimentation in new code generation targets. -rsave, rsavex +rsave Saves all registers including status (or only X) on the stack - It's not needed to rsave()/rsavex() before an asm subroutine that clobbers the X register - (which is used by prog8 as the internal evaluation stack pointer); - the compiler will take care of this situation automatically. Note: the 16 bit 'virtual' registers of the Commander X16 are *not* saved, but you can use ``cx16.save_virtual_registers()`` for that. -rrestore, rrestorex +rrestore Restore all registers including status (or only X) back from the cpu hardware stack Note: the 16 bit 'virtual' registers of the Commander X16 are *not* restored, but you can use ``cx16.restore_virtual_registers()`` for that. diff --git a/docs/source/targetsystem.rst b/docs/source/targetsystem.rst index 1d70525a5..2c39ad021 100644 --- a/docs/source/targetsystem.rst +++ b/docs/source/targetsystem.rst @@ -56,35 +56,31 @@ Both systems have ways to alter the memory map and/or to switch memory banks, bu Footnotes for the Commander X16 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *Golden Ram $0400 - $07FF* - *reserved:* $0700 - $07FF (expression evaluation stack) - - *free to use:* $0400 - $06FF + *free to use.* *Zero Page $0000 - $00FF* $00 and $01 are hardwired as Rom and Ram banking registers. $02 - $21 are the 16 virtual cx16 registers R0-R15. - $22 - $7F are free to use, and Prog8 utilizes this to put variables in automatically. + $22 - $7F are used by Prog8 to put variables in. The top half of the ZP ($80-$FF) is reserved for use by the Kernal and Basic in normal operation. Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options - may free up more locations for use by Prog8. + may free up more locations for use by Prog8 or to reserve them for other things. Footnotes for the Commodore 64 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *RAM $C000-$CFFF* - *reserved:* $CF00 - $CFFF (expression evaluation stack) - *this includes:* $CF00 - $CF20 for the 16 virtual cx16 registers R0-R15 - - *free to use:* $C000 - $CEFF + *free to use:* $C000 - $CFDF + *reserved:* $CFE0 - $CFFF for the 16 virtual cx16 registers R0-R15 *Zero Page $0000 - $00FF* Consider the full zero page to be reserved for use by the Kernal and Basic in normal operation. Zero page use by Prog8 can be manipulated with the ``%zeropage`` directive, various options - may free up more locations for use by Prog8. + may free up more locations for use by Prog8 or to reserve them for other things. Zero page usage by the Prog8 compiler @@ -127,8 +123,6 @@ Directly Usable Registers The hardware CPU registers are not directly accessible from regular Prog8 code. If you need to mess with them, you'll have to use inline assembly. -Be extra wary of the ``X`` register because it is used as an evaluation stack pointer and -changing its value you will destroy the evaluation stack and likely crash the program. The status register (P) carry flag and interrupt disable flag can be written via a couple of special builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``), diff --git a/docs/source/technical.rst b/docs/source/technical.rst index 77373c483..fc1c2ed65 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -44,28 +44,6 @@ All elements in scoped names such as ``main.routine.var1`` are prefixed so this }} -Software stack for expression evaluation ----------------------------------------- - -Prog8 uses a software stack to evaluate complex expressions that it can't calculate in-place or -directly into the target variable, register, or memory location. - -'software stack' means: seperated and not using the processor's hardware stack. - -The software stack is implemented as follows: - -- 2*128 bytes = 1 page of memory allocated for this, exact locations vary per machine target. - For the C64 this page is at $cf00-$cfff. - For the Commander X16 it is at $0700-$07ff (top of the "golden ram" area). - This default location can be overridden using the `-esa` command line option. -- these are the high and low bytes of the values on the stack (it's a 'split 16 bit word stack') -- for byte values just the lsb page is used, for word values both pages -- float values (5 bytes) are chopped up into 2 words and 1 byte on this stack. -- the X register is permanently allocated to be the stack pointer in the software stack. -- you can use the X register as long as you're not using the software stack. - But you *must* make sure it is saved and restored after the code that modifies it, - otherwise the evaluation stack gets corrupted. - Subroutine Calling Convention ----------------------------- @@ -94,8 +72,7 @@ regular subroutines ^^^^^^^^^^^^^^^^^^^ - subroutine parameters are just variables scoped to the subroutine. -- the arguments passed in a call are evaluated (using the eval-stack if needed) and then - copied into those variables. +- the arguments passed in a call are evaluated and then copied into those variables. Using variables for this sometimes can seem inefficient but it's required to allow subroutines to work locally with their parameters and allow them to modify them as required, without changing the variables used in the call's arguments. If you want to get rid of this overhead you'll @@ -118,40 +95,6 @@ doing something with that returnvalue. This can be on purpose if you're simply n Use the ``void`` keyword in front of the subroutine call to get rid of the warning in that case. -The 6502 CPU's X-register: off-limits -------------------------------------- - -Prog8 uses the cpu's X-register as a pointer in its internal expression evaluation stack. -When only writing code in Prog8, this is taken care of behind the scenes for you by the compiler. -However when you are including or linking with assembly routines or Kernal/ROM calls that *do* -use the X register (either clobbering it internally, or using it as a parameter, or return value register), -those calls will destroy Prog8's stack pointer and this will result in invalid calculations. - -You should avoid using the X register in your assembly code, or take preparations. -If you make sure that the value of the X register is preserved before calling a routine -that uses it, and restored when the routine is done, you'll be ok. - -Routines that return a value in the X register can be called from Prog8 but the return value is -inaccessible unless you write a short piece of inline assembly code to deal with it yourself, such as:: - - ubyte returnvalue - - %asm {{ - stx P8ZP_SCRATCH_REG ; use 'phx/plx' if using 65c02 cpu - ldx #10 - jsr routine_using_x - stx returnvalue - ldx P8ZP_SCRATCH_REG - }} - ; now use 'returnvalue' variable - -Prog8 also provides some help to deal with this: - -- you should use a ``clobbers(X)`` specification for asmsub routines that modify the X register; the compiler will preserve it for you automatically when such a routine is called -- the ``rsavex()`` and ``rrestorex()`` builtin functions can preserve and restore the X register -- the ``rsave()`` and ``rrestore()`` builtin functions can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X) - - Compiler Internals ------------------ diff --git a/docs/source/todo.rst b/docs/source/todo.rst index e38dc43c6..8fd4a6dba 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -48,16 +48,6 @@ Libraries: - c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking) -Expressions: (see remove_evalstack branch): - -- Once the evalstack-free expression codegen is in place, the Eval Stack can be removed from the compiler. - Machinedefinition, .p8 and .asm library files, all routines operationg on estack, and everything saving/restoring the X register related to this stack. -- Or rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code - that, for instance, uses a fixed number of predetermined value 'variables'? - The VM IL solves this already (by using unlimited registers) but that still lacks a translation to 6502. -- this removes the need for the BinExprSplitter? (which is problematic and very limited now) - and perhaps the assignment splitting in BeforeAsmAstChanger too - Optimizations: - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? diff --git a/examples/cx16/cobramk3-gfx.p8 b/examples/cx16/cobramk3-gfx.p8 index 1b4a0d4d5..f52fe583e 100644 --- a/examples/cx16/cobramk3-gfx.p8 +++ b/examples/cx16/cobramk3-gfx.p8 @@ -63,9 +63,8 @@ main { cx16.GRAPH_put_next_char(c) } - asmsub print_number_gfx(ubyte num @ A) clobbers(A,Y) { + asmsub print_number_gfx(ubyte num @ A) clobbers(A,X,Y) { %asm {{ - phx jsr conv.ubyte2decimal phx pha @@ -81,9 +80,7 @@ main { beq _ones jsr cx16.GRAPH_put_char _ones pla - jsr cx16.GRAPH_put_char - plx - rts + jmp cx16.GRAPH_put_char }} } diff --git a/examples/cx16/keyboardhandler.p8 b/examples/cx16/keyboardhandler.p8 index f53b3dd9c..614bc1eb4 100644 --- a/examples/cx16/keyboardhandler.p8 +++ b/examples/cx16/keyboardhandler.p8 @@ -2,21 +2,24 @@ %zeropage basicsafe %option no_sysinit -; The documentation for custom PS2 key handlers can be found here: -; https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2002%20-%20Editor.md#custom-keyboard-scancode-handler +; The documentation for custom key handlers can be found here: +; https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2002%20-%20Editor.md#custom-keyboard-keynum-code-handler main { + bool stop_program = false + sub start() { txt.print("custom key handler test - press keys! esc to quit!\n") sys.set_irqd() uword old_keyhdl = cx16.KEYHDL - cx16.KEYHDL = &keyboard_scancode_handler + cx16.KEYHDL = &keyboard_handler sys.clear_irqd() - while handle_keyboard_event() { + while not stop_program { + ; wait } sys.set_irqd() @@ -24,55 +27,23 @@ main { sys.clear_irqd() } - ; Keyboard handler communication variables. - ; these need to be in block scope instead of in a subroutine, - ; so that they won't get overwritten with initialization values every time. - ; The assembly keyboard handler will set these, prog8 will read them. - bool @shared keyhdl_event ; is there a keyboard event to handle? - ubyte @shared keyhdl_scancode - - sub handle_keyboard_event() -> bool { - ; Potentially handle keyboard event. - ; Note that we do this from the program's main loop instead of - ; the actual keyboard handler routine itself. - ; The reason for this is documented below in the handler assembly routine. - if not keyhdl_event - return true - keyhdl_event = false - txt.print_ubhex(keyhdl_scancode, true) + sub keyboard_handler(ubyte keynum) -> ubyte { + ; NOTE: this handler routine expects the keynum in A and return value in A + ; which is thankfully how prog8 translates this subroutine's calling convention. + ; NOTE: it may be better to store the keynum somewhere else and let the main program + ; loop figure out what to do with it, rather than putting it all in the handler routine + txt.print_ubhex(keynum, true) txt.spc() - if keyhdl_scancode & $80 + if keynum & $80 txt.chrout('u') else txt.chrout('d') txt.nl() - return keyhdl_scancode!=$6e ; escape breaks the loop - } - asmsub keyboard_scancode_handler() { - ; NOTE that the keyboard handler is an asm subroutine. - ; Unfortunately is it not possible to use prog8 code or calls here, - ; because the X register gets overwritten here by the kernal. - ; Pog8 uses the X register internally (for the software eval stack). - ; So it is unsafe to call prog8 code from here because the evaluation stack pointer - ; will be invalid which produces undefined results. - ; So, instead, we store the various keyboard event bytes and signal - ; the main prog8 program that a keyboard event has occurred. - ; It then processes it independently from the assembly code here. - ; - ; Unfortunately this also means you cannot decide easily from that prog8 code - ; if the keyboard press should be consumed/ignored or put into the keyboard queue - ; (this is controlled by returning 0 or 1 in register A here) - - %asm {{ - pha - sta p8_keyhdl_scancode - lda #1 - sta p8_keyhdl_event - pla - - lda #0 ; By setting A=0 we will eat this key event. leave A unchanged to pass it through. - rts - }} + if keynum==$6e { + ; escape stops the program + main.stop_program = true + } + return 0 ; By returning 0 (in A) we will eat this key event. Return the original keynum value to pass it through. } } diff --git a/examples/cx16/mandelbrot.p8 b/examples/cx16/mandelbrot.p8 index 58a1d5dba..78f02a87f 100644 --- a/examples/cx16/mandelbrot.p8 +++ b/examples/cx16/mandelbrot.p8 @@ -9,6 +9,7 @@ main { sub start() { txt.print("calculating mandelbrot fractal...\n\n") + cbm.SETTIM(0,0,0) ubyte pixelx ubyte pixely @@ -37,5 +38,10 @@ main { } txt.nl() } + + float duration = (cbm.RDTIM16() as float) / 60 + txt.print("\nfinished in ") + floats.print_f(duration) + txt.print(" seconds!\n") } } diff --git a/httpCompilerService/src/prog8/http/TestHttp.kt b/httpCompilerService/src/prog8/http/TestHttp.kt index 36b086775..15265fd1c 100644 --- a/httpCompilerService/src/prog8/http/TestHttp.kt +++ b/httpCompilerService/src/prog8/http/TestHttp.kt @@ -33,11 +33,8 @@ class RequestParser : Take { val args = CompilerArguments( Path(a), optimize = true, - optimizeFloatExpressions = false, writeAssembly = true, - slowCodegenWarnings = true, compilationTarget = "c64", - evalStackBaseAddress = null, symbolDefs = emptyMap(), quietAssembler = false, asmListfile = false, diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index bc4736fe1..3777b6f6e 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -88,7 +88,6 @@ class IRFileReader { val zpReserved = mutableListOf() var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS var optimize = true - var evalStackBaseAddress: UInt? = null var outputDir = Path("") if(text.isNotBlank()) { @@ -109,7 +108,6 @@ class IRFileReader { "launcher" -> launcher = CbmPrgLauncherType.valueOf(value) "zeropage" -> zeropage = ZeropageType.valueOf(value) "loadAddress" -> loadAddress = parseIRValue(value).toUInt() - "evalStackBaseAddress" -> evalStackBaseAddress = if(value=="") null else parseIRValue(value).toUInt() "zpReserved" -> { val (zpstart, zpend) = value.split(',') zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt())) @@ -130,7 +128,6 @@ class IRFileReader { false, target, loadAddress, - evalStackBaseAddress = evalStackBaseAddress, outputDir = outputDir, optimize = optimize ) diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 58f4abf05..122a43608 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -110,7 +110,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { is IRInlineAsmChunk -> writeInlineAsm(chunk) is IRInlineBinaryChunk -> writeInlineBytes(chunk) is IRCodeChunk -> writeCodeChunk(chunk) - else -> throw InternalCompilerException("invalid chunk") } } xml.writeEndElement() @@ -171,7 +170,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n") xml.writeCharacters("optimize=${irProgram.options.optimize}\n") - xml.writeCharacters("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex() ?: ""}\n") xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n") // other options not yet useful here? xml.writeEndElement() diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index ca2335dc8..2a496e57a 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -168,7 +168,6 @@ class IRProgram(val name: String, } } is IRInlineBinaryChunk -> { } - else -> throw AssemblyError("invalid chunk") } } } diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 04aec5a15..764997695 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -48,7 +48,6 @@ output=PRG launcher=BASIC zeropage=KERNALSAFE loadAddress=$0000 -evalStackBaseAddress= diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 5aafc7d53..ee0dd01c3 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -1,6 +1,5 @@ package prog8.vm -import prog8.code.core.AssemblyError import prog8.intermediate.FunctionCallArgs import prog8.intermediate.IRDataType import kotlin.math.* @@ -484,7 +483,6 @@ object SysCalls { val result = floor(radians/2.0/PI*256.0) returnValue(callspec.returns!!, result, vm) } - else -> throw AssemblyError("missing syscall ${call.name}") } } } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 496805bbf..405457f74 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -173,7 +173,7 @@ class VmProgramLoader { subroutines.forEach { it.value.chunks.forEach { chunk -> - chunk.instructions.withIndex().forEach { (index, ins) -> + chunk.instructions.withIndex().forEach { (_, ins) -> if(ins.opcode==Opcode.CALL) { val fcallspec = ins.fcallArgs!! val argsWithAddresses = fcallspec.arguments.map { arg ->