diff --git a/.gitignore b/.gitignore index 8936c0d17..ccc1db02b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,25 @@ -*.py[cod] -*.egg -*.egg-info -/MANIFEST /.idea/ -.tox/ /build/ /dist/ /output/ .*cache/ -.eggs/ *.directory *.prg *.asm *.labels.txt -__pycache__/ -parser.out -parsetab.py -.pytest_cache/ +*.vice-mon-list docs/build out/ **/*.interp **/*.tokens + +*.py[cod] +*.egg +*.egg-info +.eggs/ +/MANIFEST +.tox/ +__pycache__/ +parser.out +parsetab.py +.pytest_cache/ diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index a9fe854cd..71d6d90ed 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -769,6 +769,8 @@ private class StatementTranslator(private val prog: IntermediateProgram, "clear_carry" -> prog.instr(Opcode.CLC) "set_irqd" -> prog.instr(Opcode.SEI) "clear_irqd" -> prog.instr(Opcode.CLI) + "rsave" -> prog.instr(Opcode.RSAVE) + "rrestore" -> prog.instr(Opcode.RRESTORE) else -> createSyscall(funcname) // call builtin function } } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index c6c106052..a77ce89c1 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -221,6 +221,8 @@ enum class Opcode { CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations SEI, // set irq-disable status flag CLI, // clear irq-disable status flag + RSAVE, // save all internal registers and status flags + RRESTORE, // restore all internal registers and status flags NOP, // do nothing BREAKPOINT, // breakpoint TERMINATE, // end the program diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 76de0e79e..8b59979a6 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -108,13 +108,15 @@ class AsmGen(val options: CompilationOptions) { when(ins.opcode) { Opcode.LINE -> out("\t; src line: ${ins.callLabel}") Opcode.NOP -> out("\tnop") // shouldn't be present anymore though + Opcode.TERMINATE -> out("\tbrk\t; terminate!") Opcode.SEC -> out("\tsec") Opcode.CLC -> out("\tclc") Opcode.SEI -> out("\tsei") Opcode.CLI -> out("\tcli") - Opcode.TERMINATE -> out("\tbrk\t; terminate!") Opcode.B2UB -> {} // is a no-op, just carry on with the byte as-is Opcode.UB2B -> {} // is a no-op, just carry on with the byte as-is + Opcode.RSAVE -> out("\tphp\n\tpha\n\ttxa\n\tpha\n\ttya\n\tpha") + Opcode.RRESTORE -> out("\tpla\n\ttay\n\tpla\n\ttax\n\tpla\n\tplp") Opcode.PUSH_BYTE -> { // check if we load a register (X, Y) with constant value val nextIns = block.getIns(insIdx+1) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 580bb6697..a71d3ace8 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -54,6 +54,8 @@ val BuiltinFunctions = mapOf( "rnd" to FunctionSignature(true, emptyList(), DataType.UBYTE), "rndw" to FunctionSignature(true, emptyList(), DataType.UWORD), "rndf" to FunctionSignature(true, emptyList(), DataType.FLOAT), + "rsave" to FunctionSignature(false, emptyList(), null), + "rrestore" to FunctionSignature(false, emptyList(), null), "set_carry" to FunctionSignature(false, emptyList(), null), "clear_carry" to FunctionSignature(false, emptyList(), null), "set_irqd" to FunctionSignature(false, emptyList(), null), diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 41d7e4a9a..5daf4e6ef 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1349,6 +1349,20 @@ class StackVm(private var traceOutputFile: String?) { array.doubleArray!![index] = value.numericValue().toDouble() } } + Opcode.RSAVE -> { + evalstack.push(Value(DataType.UBYTE, if(P_irqd) 1 else 0)) + evalstack.push(Value(DataType.UBYTE, if(P_carry) 1 else 0)) + evalstack.push(variables["X"]) + evalstack.push(variables["Y"]) + evalstack.push(variables["A"]) + } + Opcode.RRESTORE -> { + variables["A"] = evalstack.pop() + variables["X"] = evalstack.pop() + variables["Y"] = evalstack.pop() + P_carry = evalstack.pop().asBooleanValue + P_irqd = evalstack.pop().asBooleanValue + } //else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}") } diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 08c7f8c3b..fbb95e934 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -649,3 +649,11 @@ set_carry() / clear_carry() set_irqd() / clear_irqd() Set (or clear) the CPU status register Interrupt Disable flag. No result value. (translated into ``SEI`` or ``CLI`` cpu instruction) + +rsave() + Saves the CPU registers and the status flags. + You can now more or less 'safely' use the registers directly, until you + restore them again so the generated code can carry on normally. + +rrestore() + Restores the CPU registers and the status flags from previously saved values.