From 79462b34481f88a4b41ef93cf58ddad13331ef07 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 20 Oct 2018 23:45:03 +0200 Subject: [PATCH] fixed some problems with builtin functions --- compiler/examples/cube3d.p8 | 36 ++++---- compiler/examples/mandelbrot.p8 | 14 +-- compiler/examples/numbergame.p8 | 40 ++++----- compiler/examples/swirl.p8 | 4 +- compiler/examples/test.p8 | 55 +++++++++++- compiler/src/prog8/CompilerMain.kt | 2 + compiler/src/prog8/ast/AST.kt | 11 +++ compiler/src/prog8/ast/AstChecker.kt | 15 ++-- compiler/src/prog8/ast/StmtReorderer.kt | 2 +- compiler/src/prog8/compiler/Compiler.kt | 86 ++++++++++++------- .../src/prog8/compiler/target/c64/AsmGen.kt | 56 ++++++++---- .../compiler/target/c64/AssemblyProgram.kt | 4 +- .../src/prog8/functions/BuiltinFunctions.kt | 32 +++---- compiler/src/prog8/stackvm/Program.kt | 6 +- compiler/src/prog8/stackvm/StackVm.kt | 52 ++++++----- 15 files changed, 265 insertions(+), 150 deletions(-) diff --git a/compiler/examples/cube3d.p8 b/compiler/examples/cube3d.p8 index 1e94ee098..b78b654ed 100644 --- a/compiler/examples/cube3d.p8 +++ b/compiler/examples/cube3d.p8 @@ -33,12 +33,12 @@ while(1) { if irq.time_changed { irq.time_changed = 0 - _vm_gfx_clearscr(0) - _vm_gfx_text(8, 6, 1, "Spin") - _vm_gfx_text(29, 11, 1, "to Win !") + vm_gfx_clearscr(0) + vm_gfx_text(8, 6, 1, "Spin") + vm_gfx_text(29, 11, 1, "to Win !") for uword i in 0 to width//10 { - _vm_gfx_line(i*2+width//2-width//10, 130, i*10.w, 199, 6) + vm_gfx_line(i*2+width//2-width//10, 130, i*10.w, 199, 6) } rotate_vertices(flt(irq.global_time) / 30.0) @@ -90,7 +90,7 @@ for uword edge in edges { ubyte e_from = msb(edge) ubyte e_to = lsb(edge) - _vm_gfx_line(toscreenx(rotatedx[e_from], rotatedz[e_from]), toscreeny(rotatedy[e_from], rotatedz[e_from]), + vm_gfx_line(toscreenx(rotatedx[e_from], rotatedz[e_from]), toscreeny(rotatedy[e_from], rotatedz[e_from]), toscreenx(rotatedx[e_to], rotatedz[e_to]), toscreeny(rotatedy[e_to], rotatedz[e_to]), e_from+e_to) } @@ -99,19 +99,19 @@ word sx = toscreenx(rotatedx[i], rotatedz[i]) word sy = toscreeny(rotatedy[i], rotatedz[i]) ubyte color=i+2 - _vm_gfx_pixel(sx-1, sy-1, color) - _vm_gfx_pixel(sx, sy-1, color) - _vm_gfx_pixel(sx+1, sy-1, color) - _vm_gfx_pixel(sx-1, sy, color) - _vm_gfx_pixel(sx, sy, color) - _vm_gfx_pixel(sx+1, sy, color) - _vm_gfx_pixel(sx-1, sy+1, color) - _vm_gfx_pixel(sx, sy+1, color) - _vm_gfx_pixel(sx+1, sy+1, color) - _vm_gfx_pixel(sx, sy-2, color) - _vm_gfx_pixel(sx+2, sy, color) - _vm_gfx_pixel(sx, sy+2, color) - _vm_gfx_pixel(sx-2, sy, color) + vm_gfx_pixel(sx-1, sy-1, color) + vm_gfx_pixel(sx, sy-1, color) + vm_gfx_pixel(sx+1, sy-1, color) + vm_gfx_pixel(sx-1, sy, color) + vm_gfx_pixel(sx, sy, color) + vm_gfx_pixel(sx+1, sy, color) + vm_gfx_pixel(sx-1, sy+1, color) + vm_gfx_pixel(sx, sy+1, color) + vm_gfx_pixel(sx+1, sy+1, color) + vm_gfx_pixel(sx, sy-2, color) + vm_gfx_pixel(sx+2, sy, color) + vm_gfx_pixel(sx, sy+2, color) + vm_gfx_pixel(sx-2, sy, color) } } } diff --git a/compiler/examples/mandelbrot.p8 b/compiler/examples/mandelbrot.p8 index db7fc43fb..36c1353f7 100644 --- a/compiler/examples/mandelbrot.p8 +++ b/compiler/examples/mandelbrot.p8 @@ -7,8 +7,8 @@ const uword yoffset = 30 sub start() { - _vm_gfx_clearscr(11) - _vm_gfx_text(2, 1, 1, "Calculating Mandelbrot Fractal...") + vm_gfx_clearscr(11) + vm_gfx_text(2, 1, 1, "Calculating Mandelbrot Fractal...") for ubyte pixely in yoffset to yoffset+height-1 { float yy = flt((pixely-yoffset))/height/3.6+0.4 @@ -30,10 +30,10 @@ iter++ } - _vm_gfx_pixel(pixelx, pixely, iter) + vm_gfx_pixel(pixelx, pixely, iter) } } - _vm_gfx_text(11, 21, 1, "Finished!") + vm_gfx_text(11, 21, 1, "Finished!") } } @@ -47,9 +47,9 @@ memory ubyte jiffyclockLo = $a2 sub irq() { - _vm_gfx_pixel(jiffyclockLo,190,jiffyclockHi) - _vm_gfx_pixel(jiffyclockLo,191,jiffyclockMid) - _vm_gfx_pixel(jiffyclockLo,192,jiffyclockLo) + vm_gfx_pixel(jiffyclockLo,190,jiffyclockHi) + vm_gfx_pixel(jiffyclockLo,191,jiffyclockMid) + vm_gfx_pixel(jiffyclockLo,192,jiffyclockLo) return } } diff --git a/compiler/examples/numbergame.p8 b/compiler/examples/numbergame.p8 index ad16aa224..470ed9aa8 100644 --- a/compiler/examples/numbergame.p8 +++ b/compiler/examples/numbergame.p8 @@ -4,37 +4,37 @@ str guess = "000000" 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") + 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(guess) + 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(guess) ubyte guessednumber = str2ubyte(guess) if guessednumber==secretnumber { - _vm_write_str("\nYou guessed it, impressive!\n") - _vm_write_str("Thanks for playing.\n") + vm_write_str("\nYou guessed it, impressive!\n") + vm_write_str("Thanks for playing.\n") return } else { - _vm_write_str("That is too ") + vm_write_str("That is too ") if guessednumber) { // error will be printed by the astchecker } val zpReserved = moduleAst.statements + .asSequence() .filter{it is Directive && it.directive=="%zpreserved"} .map{ (it as Directive).args } .map{ it[0].int!! .. it[1].int!! } + .toList() val compilerOptions = CompilationOptions( if(outputType==null) OutputType.PRG else OutputType.valueOf(outputType), diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 47d003a63..e74322dd7 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -693,6 +693,17 @@ data class AssignTarget(val register: Register?, fun process(processor: IAstProcessor) = processor.process(this) + companion object { + fun fromExpr(expr: IExpression): AssignTarget { + return when (expr) { + is RegisterExpr -> AssignTarget(expr.register, null, null, expr.position) + is IdentifierReference -> AssignTarget(null, expr, null, expr.position) + is ArrayIndexedExpression -> AssignTarget(null, null, expr, expr.position) + else -> throw FatalAstException("invalid expression object $expr") + } + } + } + fun determineDatatype(namespace: INameScope, heap: HeapValues, stmt: IStatement): DataType? { if(register!=null) return when(register){ diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index e3790a5f4..f2e680b80 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -335,13 +335,12 @@ class AstChecker(private val namespace: INameScope, // check augmented assignment: // A /= 3 -> check as if it was A = A / 3 val target: IExpression = - if(assignment.target.register!=null) - RegisterExpr(assignment.target.register!!, assignment.target.position) - else if(assignment.target.identifier!=null) - assignment.target.identifier!! - else if(assignment.target.arrayindexed!=null) { - assignment.target.arrayindexed!! - } else throw FatalAstException("strange assignment") + when { + assignment.target.register!=null -> RegisterExpr(assignment.target.register!!, assignment.target.position) + assignment.target.identifier!=null -> assignment.target.identifier!! + assignment.target.arrayindexed!=null -> assignment.target.arrayindexed!! + else -> throw FatalAstException("strange assignment") + } val expression = BinaryExpression(target, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position) expression.linkParents(assignment.parent) @@ -883,7 +882,7 @@ class AstChecker(private val namespace: INameScope, if(arraySpecSize!=null && arraySpecSize>0) { val constX = arrayspec.x.constValue(namespace, heap) val constY = arrayspec.y?.constValue(namespace, heap) - if (constX?.asIntegerValue == null || (constY!=null && constY?.asIntegerValue == null)) + if (constX?.asIntegerValue == null || (constY!=null && constY.asIntegerValue == null)) return err("matrix size specifiers must be constant integer values") val matrix = heap.get(value.heapId!!).array!! val expectedSize = diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index 66864d8fd..c0f94c122 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -21,7 +21,7 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He super.process(module) val (blocks, other) = module.statements.partition { it is Block } - module.statements = other.plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList() + module.statements = other.asSequence().plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList() val mainBlock = module.statements.single { it is Block && it.name=="main" } if((mainBlock as Block).address==null) { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 45f745486..27f53e038 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -593,7 +593,6 @@ private class StatementTranslator(private val prog: IntermediateProgram, val target = expr.target.targetStatement(namespace) if(target is BuiltinFunctionStatementPlaceholder) { // call to a builtin function (some will just be an opcode!) - expr.arglist.forEach { translate(it) } val funcname = expr.target.nameInSource[0] translateFunctionCall(funcname, expr.arglist) } else { @@ -696,7 +695,6 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.line(stmt.position) val targetStmt = stmt.target.targetStatement(namespace)!! if(targetStmt is BuiltinFunctionStatementPlaceholder) { - stmt.arglist.forEach { translate(it) } val funcname = stmt.target.nameInSource[0] translateFunctionCall(funcname, stmt.arglist) return @@ -720,9 +718,9 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun translateFunctionCall(funcname: String, args: List) { // some functions are implemented as vm opcodes - // note: the arguments of the call have already been translated and put on the eval stack! + args.forEach { translate(it) } // place function argument(s) on the stack when (funcname) { - "flt" -> { + "flt" -> { // todo: this is translated ok! // 1 argument, type determines the exact opcode to use val arg = args.single() when (arg.resultingDatatype(namespace, heap)) { @@ -734,64 +732,82 @@ private class StatementTranslator(private val prog: IntermediateProgram, else -> throw CompilerException("wrong datatype for flt()") } } - "msb" -> prog.instr(Opcode.MSB) - "lsb" -> prog.instr(Opcode.LSB) - "b2ub" -> prog.instr(Opcode.B2UB) - "ub2b" -> prog.instr(Opcode.UB2B) + "msb" -> prog.instr(Opcode.MSB) // todo: is translated ok! + "lsb" -> prog.instr(Opcode.LSB) // todo: is translated ok! + "b2ub" -> prog.instr(Opcode.B2UB) // todo: is translated ok! + "ub2b" -> prog.instr(Opcode.UB2B) // todo: is translated ok! "lsl" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE -> prog.instr(Opcode.SHL_BYTE) DataType.UWORD -> prog.instr(Opcode.SHL_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } "lsr" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE -> prog.instr(Opcode.SHR_BYTE) DataType.UWORD -> prog.instr(Opcode.SHR_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } "rol" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE -> prog.instr(Opcode.ROL_BYTE) DataType.UWORD -> prog.instr(Opcode.ROL_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } "ror" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR_BYTE) DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } "rol2" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROL2_BYTE) DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROL2_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } "ror2" -> { val arg = args.single() - when (arg.resultingDatatype(namespace, heap)) { + val dt = arg.resultingDatatype(namespace, heap) + when (dt) { DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR2_BYTE) DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR2_WORD) else -> throw CompilerException("wrong datatype") } + // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again + popValueIntoTarget(AssignTarget.fromExpr(arg), dt) } - "set_carry" -> prog.instr(Opcode.SEC) - "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) + "set_carry" -> prog.instr(Opcode.SEC) // todo: compiled ok!! + "clear_carry" -> prog.instr(Opcode.CLC)// todo: compiled ok!! + "set_irqd" -> prog.instr(Opcode.SEI)// todo: compiled ok!! + "clear_irqd" -> prog.instr(Opcode.CLI)// todo: compiled ok!! + "rsave" -> prog.instr(Opcode.RSAVE)// todo: compiled ok!! + "rrestore" -> prog.instr(Opcode.RRESTORE)// todo: compiled ok!! else -> createSyscall(funcname) // call builtin function } } @@ -1056,8 +1072,8 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun createSyscall(funcname: String) { val function = ( - if (funcname.startsWith("_vm_")) - funcname.substring(4) + if (funcname.startsWith("vm_")) + funcname else "FUNC_$funcname" ).toUpperCase() @@ -1181,30 +1197,34 @@ private class StatementTranslator(private val prog: IntermediateProgram, } // pop the result value back into the assignment target + val datatype = stmt.target.determineDatatype(namespace, heap, stmt)!! + popValueIntoTarget(stmt.target, datatype) + } + + private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) { when { - stmt.target.identifier!=null -> { - val target = stmt.target.identifier!!.targetStatement(namespace)!! + assignTarget.identifier != null -> { + val target = assignTarget.identifier.targetStatement(namespace)!! if (target is VarDecl) { - when(target.type) { + when (target.type) { VarDeclType.VAR -> { - val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt)!!) + val opcode = opcodePopvar(datatype) prog.instr(opcode, callLabel = target.scopedname) } VarDeclType.MEMORY -> { - val opcode = opcodePopmem(stmt.target.determineDatatype(namespace, heap, stmt)!!) + val opcode = opcodePopmem(datatype) val address = target.value?.constValue(namespace, heap)!!.asIntegerValue!! prog.instr(opcode, Value(DataType.UWORD, address)) } VarDeclType.CONST -> throw CompilerException("cannot assign to const") } - } - else throw CompilerException("invalid assignment target type ${target::class}") + } else throw CompilerException("invalid assignment target type ${target::class}") } - stmt.target.register!=null -> { - val opcode=opcodePopvar(stmt.target.register!!) - prog.instr(opcode, callLabel = stmt.target.register.toString()) + assignTarget.register != null -> { + val opcode = opcodePopvar(assignTarget.register) + prog.instr(opcode, callLabel = assignTarget.register.toString()) } - stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, true) // write value to it + assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it } } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index f1182f504..24c848190 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -1,8 +1,10 @@ package prog8.compiler.target.c64 import prog8.ast.DataType +import prog8.ast.StringDatatypes import prog8.compiler.* import prog8.compiler.intermediate.* +import prog8.stackvm.syscallsForStackVm import java.io.File import java.io.PrintWriter import java.util.* @@ -15,6 +17,7 @@ class AssemblyError(msg: String) : RuntimeException(msg) class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues) { private val globalFloatConsts = mutableMapOf() private lateinit var output: PrintWriter + private var breakpointCounter = 0 init { // Because 64tass understands scoped names via .proc / .block, @@ -638,7 +641,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("\tsta ${(nextIns.arg.integerValue()+1).toHex()}") return 1 // skip 1 } - pushWord(ins.arg!!.integerValue()) + if(ins.arg!!.type in StringDatatypes) { + TODO("strings from heap") + } + pushWord(ins.arg.integerValue()) } Opcode.PUSH_MEM_UW, Opcode.PUSH_MEM_W -> { val nextIns = block.getIns(insIdx+1) @@ -878,12 +884,40 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("+\tsta ${(ESTACK_LO+1).toHex()},x") out("\tsta ${(ESTACK_HI+1).toHex()},x") } + Opcode.SYSCALL -> { + if(ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr }) + throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}") + TODO("syscall $ins") + } + Opcode.BREAKPOINT -> { + breakpointCounter++ + out("_prog8_breakpoint_$breakpointCounter\tnop") + } + Opcode.BCS -> out("\tbcs ${ins.callLabel}") + Opcode.BCC -> out("\tbcc ${ins.callLabel}") + Opcode.BZ -> out("\tbeq ${ins.callLabel}") + Opcode.BNZ -> out("\tbne ${ins.callLabel}") + Opcode.BNEG -> out("\tbmi ${ins.callLabel}") + Opcode.BPOS -> out("\tbpl ${ins.callLabel}") + Opcode.POP_MEM_W, Opcode.POP_MEM_UW -> { + popWordAY() + out("\tsta ${ins.callLabel}") + out("\tsty ${ins.callLabel}+1") + } + Opcode.SHL_BYTE -> out("\tasl ${ESTACK_LO.toHex()},x") + Opcode.SHR_BYTE -> out("\tlsr ${ESTACK_LO.toHex()},x") + Opcode.ROL_BYTE -> out("\trol ${ESTACK_LO.toHex()},x") // 9-bit rotate (w/carry) + Opcode.ROR_BYTE -> out("\tror ${ESTACK_LO.toHex()},x") // 9-bit rotate (w/carry) + Opcode.ROL2_BYTE -> out("\tcmp #$80\n\trol") // 8-bit rotate + Opcode.ROR2_BYTE -> { // 8 bit rotate + out("\tlsr a") + out("\tbcc +") + out("\tora #$80") + out("+") + } else-> TODO("asm for $ins") -// Opcode.POP_MEM_W -> TODO() -// Opcode.POP_MEM_UW -> TODO() // Opcode.POP_MEM_FLOAT -> TODO() -// Opcode.POP_VAR_WORD -> TODO() // Opcode.POP_VAR_FLOAT -> TODO() // Opcode.COPY_VAR_FLOAT -> TODO() // Opcode.INC_VAR_W -> TODO() @@ -923,37 +957,31 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // Opcode.POW_F -> TODO() // Opcode.NEG_W -> TODO() // Opcode.NEG_F -> TODO() -// Opcode.SHL_BYTE -> TODO() // Opcode.SHL_WORD -> TODO() // Opcode.SHL_MEM_BYTE -> TODO() // Opcode.SHL_MEM_WORD -> TODO() // Opcode.SHL_VAR_BYTE -> TODO() // Opcode.SHL_VAR_WORD -> TODO() -// Opcode.SHR_BYTE -> TODO() // Opcode.SHR_WORD -> TODO() // Opcode.SHR_MEM_BYTE -> TODO() // Opcode.SHR_MEM_WORD -> TODO() // Opcode.SHR_VAR_BYTE -> TODO() // Opcode.SHR_VAR_WORD -> TODO() -// Opcode.ROL_BYTE -> TODO() // Opcode.ROL_WORD -> TODO() // Opcode.ROL_MEM_BYTE -> TODO() // Opcode.ROL_MEM_WORD -> TODO() // Opcode.ROL_VAR_BYTE -> TODO() // Opcode.ROL_VAR_WORD -> TODO() -// Opcode.ROR_BYTE -> TODO() // Opcode.ROR_WORD -> TODO() // Opcode.ROR_MEM_BYTE -> TODO() // Opcode.ROR_MEM_WORD -> TODO() // Opcode.ROR_VAR_BYTE -> TODO() // Opcode.ROR_VAR_WORD -> TODO() -// Opcode.ROL2_BYTE -> TODO() // Opcode.ROL2_WORD -> TODO() // Opcode.ROL2_MEM_BYTE -> TODO() // Opcode.ROL2_MEM_WORD -> TODO() // Opcode.ROL2_VAR_BYTE -> TODO() // Opcode.ROL2_VAR_WORD -> TODO() -// Opcode.ROR2_BYTE -> TODO() // Opcode.ROR2_WORD -> TODO() // Opcode.ROR2_MEM_BYTE -> TODO() // Opcode.ROR2_MEM_WORD -> TODO() @@ -1012,14 +1040,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // Opcode.WRITE_INDEXED_VAR_BYTE -> TODO() // Opcode.WRITE_INDEXED_VAR_WORD -> TODO() // Opcode.WRITE_INDEXED_VAR_FLOAT -> TODO() -// Opcode.BCS -> TODO() -// Opcode.BCC -> TODO() -// Opcode.BZ -> TODO() -// Opcode.BNZ -> TODO() -// Opcode.BNEG -> TODO() -// Opcode.BPOS -> TODO() -// Opcode.SYSCALL -> TODO() -// Opcode.BREAKPOINT -> TODO() } return 0 } diff --git a/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt b/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt index 4f949cb81..dde437607 100644 --- a/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt +++ b/compiler/src/prog8/compiler/target/c64/AssemblyProgram.kt @@ -42,11 +42,11 @@ class AssemblyProgram(val name: String) { private fun generateBreakpointList() { // builds list of breakpoints, appends to monitor list file val breakpoints = mutableListOf() - val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // todo what's with the _prog8_breakpoint_? how to find breakpoint? + val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that's generated for them for(line in File(viceMonListFile).readLines()) { val match = pattern.matchEntire(line) if(match!=null) - breakpoints.add("break \$" + match.groupValues[0]) // todo check + breakpoints.add("break \$" + match.groupValues[0]) // todo check this } val num = breakpoints.size breakpoints.add(0, "; vice monitor breakpoint list now follows") diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index a71d3ace8..9805b50c7 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -5,7 +5,6 @@ import prog8.compiler.HeapValues import kotlin.math.log2 - class BuiltinFunctionParam(val name: String, val possibleDatatypes: Set) class FunctionSignature(val pure: Boolean, // does it have side effects? @@ -15,12 +14,18 @@ class FunctionSignature(val pure: Boolean, // does it have side effects? val BuiltinFunctions = mapOf( + // this set of function have no return value and operate in-place: "rol" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "ror" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "rol2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "ror2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + // these few have a return value depending on the argument list: + "max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args + "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args + "sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args + // normal functions follow: "sin" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sin) }, "cos" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::cos) }, "acos" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::acos) }, @@ -38,9 +43,6 @@ val BuiltinFunctions = mapOf( "round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::round) }, "floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::floor) }, "ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::ceil) }, - "max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args - "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args - "sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args "len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes)), DataType.UWORD, ::builtinLen), "any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }}, "all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }}, @@ -65,24 +67,24 @@ val BuiltinFunctions = mapOf( "str2word" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.WORD), "str2uword" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.UWORD), "str2float" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.FLOAT), - "_vm_write_memchr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), - "_vm_write_memstr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), - "_vm_write_num" to FunctionSignature(false, listOf(BuiltinFunctionParam("number", NumericDatatypes)), null), - "_vm_write_char" to FunctionSignature(false, listOf(BuiltinFunctionParam("char", setOf(DataType.UBYTE))), null), - "_vm_write_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("string", StringDatatypes)), null), - "_vm_input_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("intovar", StringDatatypes)), null), - "_vm_gfx_clearscr" to FunctionSignature(false, listOf(BuiltinFunctionParam("color", setOf(DataType.UBYTE))), null), - "_vm_gfx_pixel" to FunctionSignature(false, listOf( + "vm_write_memchr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), + "vm_write_memstr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), + "vm_write_num" to FunctionSignature(false, listOf(BuiltinFunctionParam("number", NumericDatatypes)), null), + "vm_write_char" to FunctionSignature(false, listOf(BuiltinFunctionParam("char", setOf(DataType.UBYTE))), null), + "vm_write_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("string", StringDatatypes)), null), + "vm_input_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("intovar", StringDatatypes)), null), + "vm_gfx_clearscr" to FunctionSignature(false, listOf(BuiltinFunctionParam("color", setOf(DataType.UBYTE))), null), + "vm_gfx_pixel" to FunctionSignature(false, listOf( BuiltinFunctionParam("x", IntegerDatatypes), BuiltinFunctionParam("y", IntegerDatatypes), BuiltinFunctionParam("color", IntegerDatatypes)), null), - "_vm_gfx_line" to FunctionSignature(false, listOf( + "vm_gfx_line" to FunctionSignature(false, listOf( BuiltinFunctionParam("x1", IntegerDatatypes), BuiltinFunctionParam("y1", IntegerDatatypes), BuiltinFunctionParam("x2", IntegerDatatypes), BuiltinFunctionParam("y2", IntegerDatatypes), BuiltinFunctionParam("color", IntegerDatatypes)), null), - "_vm_gfx_text" to FunctionSignature(false, listOf( + "vm_gfx_text" to FunctionSignature(false, listOf( BuiltinFunctionParam("x", IntegerDatatypes), BuiltinFunctionParam("y", IntegerDatatypes), BuiltinFunctionParam("color", IntegerDatatypes), @@ -157,7 +159,7 @@ fun builtinFunctionReturnType(function: String, args: List, namespa DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UWORD } } - else -> throw FatalAstException("unknown result type for builtin function $function") + else -> return null } } diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index 14d28640b..f4e121a1d 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -54,7 +54,7 @@ class Program (val name: String, labels: MutableMap) { while(true) { - val (lineNr, line) = lines.next() + val (_, line) = lines.next() if(line.isEmpty()) continue else if(line=="%end_block") @@ -73,7 +73,7 @@ class Program (val name: String, val splitpattern = Pattern.compile("\\s+") val heapvalues = mutableListOf>() while(true) { - val (lineNr, line) = lines.next() + val (_, line) = lines.next() if (line == "%end_heap") break val parts = line.split(splitpattern, limit=3) @@ -185,7 +185,7 @@ class Program (val name: String, vars: MutableMap): Map { val splitpattern = Pattern.compile("\\s+") while(true) { - val (lineNr, line) = lines.next() + val (_, line) = lines.next() if(line=="%end_variables") return vars val (name, typeStr, valueStr) = line.split(splitpattern, limit = 3) diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index d6976e7ee..bbee727dc 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -15,16 +15,16 @@ import kotlin.math.* enum class Syscall(val callNr: Short) { - WRITE_MEMCHR(10), // print a single char from the memory address popped from stack - WRITE_MEMSTR(11), // print a 0-terminated petscii string from the memory address popped from stack - WRITE_NUM(12), // pop from the evaluation stack and print it as a number - WRITE_CHAR(13), // pop from the evaluation stack and print it as a single petscii character - WRITE_STR(14), // pop from the evaluation stack and print it as a string - INPUT_STR(15), // user input a string onto the stack, with max length (truncated) given by value on stack - GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order - GFX_CLEARSCR(17), // clear the screen with color pushed on stack - GFX_TEXT(18), // write text on screen at cursor position (x,y,color,text) pushed on stack in that order (pixel pos= x*8, y*8) - GFX_LINE(19), // draw line on screen at (x1,y1,x2,y2,color) pushed on stack in that order + VM_WRITE_MEMCHR(10), // print a single char from the memory address popped from stack + VM_WRITE_MEMSTR(11), // print a 0-terminated petscii string from the memory address popped from stack + VM_WRITE_NUM(12), // pop from the evaluation stack and print it as a number + VM_WRITE_CHAR(13), // pop from the evaluation stack and print it as a single petscii character + VM_WRITE_STR(14), // pop from the evaluation stack and print it as a string + VM_INPUT_STR(15), // user input a string onto the stack, with max length (truncated) given by value on stack + VM_GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order + VM_GFX_CLEARSCR(17), // clear the screen with color pushed on stack + VM_GFX_TEXT(18), // write text on screen at cursor position (x,y,color,text) pushed on stack in that order (pixel pos= x*8, y*8) + VM_GFX_LINE(19), // draw line on screen at (x1,y1,x2,y2,color) pushed on stack in that order FUNC_SIN(66), FUNC_COS(67), @@ -64,6 +64,18 @@ enum class Syscall(val callNr: Short) { // some of them are straight opcodes (such as MSB, LSB, LSL, LSR, ROL_BYTE, ROR, ROL2, ROR2, and FLT)! } +val syscallsForStackVm = setOf( + Syscall.VM_WRITE_MEMCHR, + Syscall.VM_WRITE_MEMSTR, + Syscall.VM_WRITE_NUM, + Syscall.VM_WRITE_CHAR, + Syscall.VM_WRITE_STR, + Syscall.VM_INPUT_STR, + Syscall.VM_GFX_PIXEL, + Syscall.VM_GFX_CLEARSCR, + Syscall.VM_GFX_TEXT, + Syscall.VM_GFX_LINE +) class VmExecutionException(msg: String?) : Exception(msg) @@ -1329,21 +1341,21 @@ class StackVm(private var traceOutputFile: String?) { val callId = ins.arg!!.integerValue().toShort() val syscall = Syscall.values().first { it.callNr == callId } when (syscall) { - Syscall.WRITE_MEMCHR -> { + Syscall.VM_WRITE_MEMCHR -> { val address = evalstack.pop().integerValue() print(Petscii.decodePetscii(listOf(mem.getUByte(address)), true)) } - Syscall.WRITE_MEMSTR -> { + Syscall.VM_WRITE_MEMSTR -> { val address = evalstack.pop().integerValue() print(mem.getString(address)) } - Syscall.WRITE_NUM -> { + Syscall.VM_WRITE_NUM -> { print(evalstack.pop().numericValue()) } - Syscall.WRITE_CHAR -> { + Syscall.VM_WRITE_CHAR -> { print(Petscii.decodePetscii(listOf(evalstack.pop().integerValue().toShort()), true)) } - Syscall.WRITE_STR -> { + Syscall.VM_WRITE_STR -> { val value = evalstack.pop() when(value.type){ DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> print(value.numericValue()) @@ -1353,31 +1365,31 @@ class StackVm(private var traceOutputFile: String?) { DataType.ARRAY_F -> print(heap.get(value.heapId).doubleArray!!.toList()) } } - Syscall.INPUT_STR -> { + Syscall.VM_INPUT_STR -> { val variable = evalstack.pop() val value = heap.get(variable.heapId) val maxlen = value.str!!.length val input = readLine() ?: "" heap.update(variable.heapId, input.padEnd(maxlen, '\u0000').substring(0, maxlen)) } - Syscall.GFX_PIXEL -> { + Syscall.VM_GFX_PIXEL -> { // plot pixel at (x, y, color) from stack val color = evalstack.pop() val (y, x) = evalstack.pop2() canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue()) } - Syscall.GFX_LINE -> { + Syscall.VM_GFX_LINE -> { // draw line at (x1, y1, x2, y2, color) from stack val color = evalstack.pop() val (y2, x2) = evalstack.pop2() val (y1, x1) = evalstack.pop2() canvas?.drawLine(x1.integerValue(), y1.integerValue(), x2.integerValue(), y2.integerValue(), color.integerValue()) } - Syscall.GFX_CLEARSCR -> { + Syscall.VM_GFX_CLEARSCR -> { val color = evalstack.pop() canvas?.clearScreen(color.integerValue()) } - Syscall.GFX_TEXT -> { + Syscall.VM_GFX_TEXT -> { val textPtr = evalstack.pop() val color = evalstack.pop() val (cy, cx) = evalstack.pop2()