From 8adbcb7a26bc6723c2431092e5170602418ba78a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 26 Dec 2018 04:51:21 +0100 Subject: [PATCH] irq routine activated --- compiler/examples/cube3d-c64.p8 | 9 +- compiler/examples/numbergame.p8 | 43 --------- compiler/examples/test.p8 | 84 ++++------------ compiler/examples/test_maxmin.p8 | 95 ------------------- compiler/src/prog8/ast/AST.kt | 12 ++- compiler/src/prog8/ast/AstChecker.kt | 11 ++- compiler/src/prog8/compiler/Compiler.kt | 10 +- .../src/prog8/compiler/intermediate/Opcode.kt | 1 + .../src/prog8/compiler/target/c64/AsmGen.kt | 23 ++++- compiler/src/prog8/stackvm/StackVm.kt | 2 +- 10 files changed, 77 insertions(+), 213 deletions(-) delete mode 100644 compiler/examples/numbergame.p8 delete mode 100644 compiler/examples/test_maxmin.p8 diff --git a/compiler/examples/cube3d-c64.p8 b/compiler/examples/cube3d-c64.p8 index cd175e3c5..589d138a4 100644 --- a/compiler/examples/cube3d-c64.p8 +++ b/compiler/examples/cube3d-c64.p8 @@ -44,7 +44,11 @@ } rotate_vertices(irq.global_time as float / 30.0) - draw_edges() + c64scr.print_ub(X) + c64.CHROUT('\n') + draw_edges() ; @todo doesn't return from the loop... + c64scr.print_ub(X) + c64.CHROUT('\n') } } } @@ -89,7 +93,8 @@ } ; draw all edges of the object - for uword edge in edges { + for uword edge in edges { ; @todo invalid loop code generated? (loop doesn't end?) + ubyte e_from = msb(edge) ubyte e_to = lsb(edge) diff --git a/compiler/examples/numbergame.p8 b/compiler/examples/numbergame.p8 deleted file mode 100644 index 78faf353a..000000000 --- a/compiler/examples/numbergame.p8 +++ /dev/null @@ -1,43 +0,0 @@ -%import c64utils - -~ main { - sub start() { - str name = "????????????????????????????????????????" - str input = "??????????" - ubyte secretnumber = rnd() % 100 - - vm_write_str("Let's play a number guessing game!\n") - vm_write_str("Enter your name: ") - vm_input_str(name) - vm_write_str("\nHello, ") - vm_write_str(name) - vm_write_str(".\nI am thinking of a number from 1 to 100! You'll have to guess it!\n") - - for ubyte attempts_left in 10 to 1 step -1 { - vm_write_str("\nYou have ") - vm_write_num(attempts_left) - vm_write_str(" guess") - if attempts_left>1 - vm_write_str("es") - vm_write_str(" left. What is your next guess? ") - vm_input_str(input) - ubyte guess = c64utils.str2ubyte(input) ; @todo replace with proper stubs for these functions when executing on stackvm. - if guess==secretnumber { - vm_write_str("\nYou guessed it, impressive!\n") - vm_write_str("Thanks for playing.\n") - return - } else { - vm_write_str("That is too ") - if guess word { ;return ((x/4.1* (width as float)) + 160.0) as word ;width // 2 ; @todo fix calculation float wf = width return (x/4.1* wf + wf / 2.0) as word } + sub start() { c64scr.print(" X=") c64scr.print_ub(X) c64.CHROUT('\n') - word w = c64utils.str2word("000") - c64scr.print_w(w) - c64.CHROUT('\n') - w = c64utils.str2word("1") - c64scr.print_w(w) - c64.CHROUT('\n') - w = c64utils.str2word("-15000") - c64scr.print_w(w) - c64.CHROUT('\n') - w = c64utils.str2word("15000") - c64scr.print_w(w) - c64.CHROUT('\n') - c64.CHROUT('\n') - - uword uw = c64utils.str2uword("0") - c64scr.print_uw(uw) - c64.CHROUT('\n') - uw = c64utils.str2uword("1") - c64scr.print_uw(uw) - c64.CHROUT('\n') - uw = c64utils.str2uword("15000") - c64scr.print_uw(uw) - c64.CHROUT('\n') - uw = c64utils.str2uword("65522") - c64scr.print_uw(uw) - c64.CHROUT('\n') - c64.CHROUT('\n') - - byte b = c64utils.str2byte("0") - c64scr.print_b(b) - c64.CHROUT('\n') - b=c64utils.str2byte("10") - c64scr.print_b(b) - c64.CHROUT('\n') - b=c64utils.str2byte("-10") - c64scr.print_b(b) - c64.CHROUT('\n') - b=c64utils.str2byte("-128") - c64scr.print_b(b) - c64.CHROUT('\n') - b=c64utils.str2byte("127") - c64scr.print_b(b) - c64.CHROUT('\n') - c64.CHROUT('\n') - - ubyte ub = c64utils.str2ubyte("0") - c64scr.print_ub(ub) - c64.CHROUT('\n') - ub=c64utils.str2ubyte("10") - c64scr.print_ub(ub) - c64.CHROUT('\n') - ub=c64utils.str2ubyte("10") - c64scr.print_ub(ub) - c64.CHROUT('\n') - ub=c64utils.str2ubyte("128") - c64scr.print_ub(ub) - c64.CHROUT('\n') - ub=c64utils.str2ubyte("255") - c64scr.print_ub(ub) - c64.CHROUT('\n') - c64.CHROUT('\n') - c64scr.print(" X=") c64scr.print_ub(X) c64.CHROUT('\n') } + } +~ irq { + +sub irq() { + memory ubyte[256] screenarray = $0400 + memory ubyte firstscreenchar = $0400 + + screenarray[0]++ ; @todo incorrect code generated? + firstscreenchar++ ; ... this is okay + c64.EXTCOL++ +} + +} diff --git a/compiler/examples/test_maxmin.p8 b/compiler/examples/test_maxmin.p8 deleted file mode 100644 index 9ed735336..000000000 --- a/compiler/examples/test_maxmin.p8 +++ /dev/null @@ -1,95 +0,0 @@ -%import c64utils -%option enable_floats - -~ main { - - sub start() { - - ubyte ub1 - ubyte ub2 - byte b1 = -99 - byte b2 - uword uw1 - uword uw2 - word w1 = -9999 - word w2 - float f1 - float f2 - float f3 - - ubyte[3] uba = [1,2,3] - byte[3] ba = [-1,0,3] - uword[3] uwa = [1000,200,0] - ubyte[3] uba0 = 0 - byte[3] ba0 = 0 - uword[3] uwa0 = 0 - word[3] wa0 = -222 - word[3] wa1 = [-1000.w,2000.w,3000.w] - word[3] wa2 = [1000,2000,3000] - float[3] fa0 = 0.0 - float[3] fa1 = [-1000,44.555, 99.999] - float[3] fa2 = [-1000,44.555, 0] - str string = "hello" - str_p pstring = "hello1" - str_s sstring = "hello12" - str_ps psstring = "hello123" - - c64.CHROUT('x') - c64scr.print_ub(X) - c64.CHROUT('\n') - - ; @todo implement max and min, AND FIX STACKPTR (X) ERRORS! - - ub1 = max(uba) - c64scr.print_ub(ub1) - c64.CHROUT('\n') - b1 = max(ba) - c64scr.print_b(b1) - c64.CHROUT('\n') - uw1 = max(uwa) - c64scr.print_uw(uw1) - c64.CHROUT('\n') - w1 = max(wa0) - c64scr.print_w(w1) - c64.CHROUT('\n') - w1 = max(wa1) - c64scr.print_w(w1) - c64.CHROUT('\n') - w1 = max(wa2) - c64scr.print_w(w1) - c64.CHROUT('\n') - f1 = max(fa1) - c64flt.print_f(f1) - c64.CHROUT('\n') - c64.CHROUT('x') - c64scr.print_ub(X) - c64.CHROUT('\n') - - ub1 = min(uba) - c64scr.print_ub(ub1) - c64.CHROUT('\n') - b1 = min(ba) - c64scr.print_b(b1) - c64.CHROUT('\n') - uw1 = min(uwa) - c64scr.print_uw(uw1) - c64.CHROUT('\n') - w1 = min(wa0) - c64scr.print_w(w1) - c64.CHROUT('\n') - w1 = min(wa1) - c64scr.print_w(w1) - c64.CHROUT('\n') - w1 = min(wa2) - c64scr.print_w(w1) - c64.CHROUT('\n') - f1 = min(fa1) - c64flt.print_f(f1) - c64.CHROUT('\n') - c64.CHROUT('x') - c64scr.print_ub(X) - c64.CHROUT('\n') - - } -} - diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 8fb39fce9..f3a134b06 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -552,7 +552,7 @@ data class Label(val name: String, override val position: Position) : IStatement } -class Return(var values: List, override val position: Position) : IStatement { +open class Return(var values: List, override val position: Position) : IStatement { override lateinit var parent: Node override fun linkParents(parent: Node) { @@ -580,6 +580,16 @@ class Return(var values: List, override val position: Position) : I } } + +class ReturnFromIrq(override val position: Position) : Return(emptyList(), position) { + override fun process(processor: IAstProcessor) = this + + override fun toString(): String { + return "ReturnFromIrq(pos=$position)" + } +} + + class Continue(override val position: Position) : IStatement { override lateinit var parent: Node diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index e7a75e0a8..820f60390 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -237,8 +237,13 @@ class AstChecker(private val namespace: INameScope, err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)") } // if there's no return statement, we add the implicit one at the end, but only if it's not a kernel routine. - if(subroutine.asmAddress==null) - subroutine.statements.add(Return(emptyList(), subroutine.position)) + // @todo move this out of the astchecker + if(subroutine.asmAddress==null) { + if(subroutine.name=="irq" && subroutine.definingScope().name=="irq") { + subroutine.statements.add(ReturnFromIrq(subroutine.position)) + } else + subroutine.statements.add(Return(emptyList(), subroutine.position)) + } } } @@ -783,7 +788,7 @@ class AstChecker(private val namespace: INameScope, } else { val dt = (target as VarDecl).datatype - if(dt !in NumericDatatypes) + if(dt !in NumericDatatypes && dt !in ArrayDatatypes) checkResult.add(SyntaxError("can only increment or decrement a byte/float/word", postIncrDecr.position)) } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index d2780d5aa..e710ce065 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -153,7 +153,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, override fun process(block: Block): IStatement { prog.newBlock(block.scopedname, block.name, block.address) processVariables(block) // @todo optimize initializations with same value: load the value only once (sort on initalization value, datatype ?) - prog.label(block.scopedname) + prog.label("block."+block.scopedname) prog.line(block.position) translate(block.statements) return super.process(block) @@ -199,7 +199,6 @@ private class StatementTranslator(private val prog: IntermediateProgram, generatedLabelSequenceNumber++ when (stmt) { is Label -> translate(stmt) - is Return -> translate(stmt) is VariableInitializationAssignment -> translate(stmt) // for initializing vars in a scope is Assignment -> translate(stmt) // normal and augmented assignments is PostIncrDecr -> translate(stmt) @@ -213,6 +212,8 @@ private class StatementTranslator(private val prog: IntermediateProgram, is WhileLoop -> translate(stmt) is RepeatLoop -> translate(stmt) is AnonymousScope -> translate(stmt) + is ReturnFromIrq -> translate(stmt) + is Return -> translate(stmt) is Directive, is VarDecl, is Subroutine -> {} // skip this, already processed these. is InlineAssembly -> translate(stmt) else -> TODO("translate statement $stmt to stackvm") @@ -1526,6 +1527,11 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.RETURN) } + private fun translate(stmt: ReturnFromIrq) { + prog.line(stmt.position) + prog.instr(Opcode.RETURNFROMIRQ) + } + private fun translate(stmt: Label) { prog.label(stmt.scopedname) } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index 1e34e768f..2dae39c1e 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -220,6 +220,7 @@ enum class Opcode { // subroutine calling CALL, RETURN, + RETURNFROMIRQ, SYSCALL, // misc diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 6f20a1b97..b72ae0150 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -113,6 +113,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, var name = if (scoped.startsWith("${block.shortname}.")) { blockLocal = true scoped.substring(block.shortname.length+1) + } else if (scoped.startsWith("block.")) { + blockLocal = false + scoped } else { blockLocal = false scoped @@ -176,6 +179,19 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("\tldx #\$ff\t; init estack pointer") out("\tclc") + + val irqBlock = program.blocks.singleOrNull { it.scopedname=="irq" } + val haveIrqSub = irqBlock?.instructions?.any { it is LabelInstr && it.name=="irq"} + if(haveIrqSub==true) { + out("\t; install custom irq vector") + out("\tsei") + out("\tlda #irq.irq") + out("\tsta c64.CINV+1") + out("\tcli") + } + out("\tjmp main.start\t; jump to program entrypoint") out("") @@ -386,7 +402,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, private fun simpleInstr2Asm(ins: Instruction): String? { // a label 'instruction' is simply translated into a asm label if(ins is LabelInstr) { - if(ins.name==block.shortname) + if(ins.name.startsWith("block.")) return "" return if(ins.name.startsWith("${block.shortname}.")) ins.name.substring(block.shortname.length+1) @@ -406,6 +422,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.JUMP -> " jmp ${ins.callLabel}" Opcode.CALL -> " jsr ${ins.callLabel}" Opcode.RETURN -> " rts" + Opcode.RETURNFROMIRQ -> " jmp c64.IRQDFRT\t\t; continue with normal kernel irq routine" Opcode.RSAVE -> { // save cpu status flag and all registers A, X, Y. // see http://6502.org/tutorials/register_preservation.html @@ -705,8 +722,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, sta ${(ESTACK_LO + 1).toHex()},x """ } - Opcode.ADD_W, Opcode.ADD_UW -> " jsr prog8_lib.add_word" - Opcode.SUB_W, Opcode.SUB_UW -> " jsr prog8_lib.sub_word" + Opcode.ADD_W, Opcode.ADD_UW -> " jsr prog8_lib.add_w" + Opcode.SUB_W, Opcode.SUB_UW -> " jsr prog8_lib.sub_w" Opcode.MUL_B, Opcode.MUL_UB -> " jsr prog8_lib.mul_byte" Opcode.MUL_W, Opcode.MUL_UW -> " jsr prog8_lib.mul_word" Opcode.ADD_F -> " jsr prog8_lib.add_f" diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 2e954a58b..642eb217a 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -751,7 +751,7 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.CALL -> callstack.push(ins.nextAlt) - Opcode.RETURN -> { + Opcode.RETURN, Opcode.RETURNFROMIRQ -> { if(callstack.empty()) throw VmTerminationException("return instruction with empty call stack") return callstack.pop()