From d4b3e35bd262a07e2bc138fcaa972735096d003f Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 10 Jul 2019 16:06:11 +0200 Subject: [PATCH] astvm almost complete --- .../ast/processing/StatementReorderer.kt | 33 ++- compiler/src/prog8/compiler/Main.kt | 2 +- compiler/src/prog8/vm/RuntimeValue.kt | 18 +- compiler/src/prog8/vm/astvm/AstVm.kt | 210 ++++++++++++------ compiler/src/prog8/vm/astvm/ScreenDialog.kt | 48 ++-- compiler/src/prog8/vm/stackvm/StackVm.kt | 24 +- examples/test.p8 | 32 +-- 7 files changed, 235 insertions(+), 132 deletions(-) diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index c2e10521a..ba10dd9e1 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -6,9 +6,7 @@ import prog8.ast.base.DataType import prog8.ast.base.FatalAstException import prog8.ast.base.initvarsSubName import prog8.ast.base.printWarning -import prog8.ast.expressions.BinaryExpression -import prog8.ast.expressions.FunctionCall -import prog8.ast.expressions.TypecastExpression +import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.functions.BuiltinFunctions @@ -292,4 +290,33 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi .sortWith(compareBy(nullsLast(), {it.values?.single()?.constValue(program)?.asIntegerValue})) return super.visit(whenStatement) } + + override fun visit(memread: DirectMemoryRead): IExpression { + // make sure the memory address is an uword + val dt = memread.addressExpression.inferType(program) + if(dt!=DataType.UWORD) { + val literaladdr = memread.addressExpression as? LiteralValue + if(literaladdr!=null) { + memread.addressExpression = literaladdr.cast(DataType.UWORD)!! + } else { + memread.addressExpression = TypecastExpression(memread.addressExpression, DataType.UWORD, true, memread.addressExpression.position) + memread.addressExpression.parent = memread + } + } + return super.visit(memread) + } + + override fun visit(memwrite: DirectMemoryWrite) { + val dt = memwrite.addressExpression.inferType(program) + if(dt!=DataType.UWORD) { + val literaladdr = memwrite.addressExpression as? LiteralValue + if(literaladdr!=null) { + memwrite.addressExpression = literaladdr.cast(DataType.UWORD)!! + } else { + memwrite.addressExpression = TypecastExpression(memwrite.addressExpression, DataType.UWORD, true, memwrite.addressExpression.position) + memwrite.addressExpression.parent = memwrite + } + } + super.visit(memwrite) + } } diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 1e9917632..cf92d4cda 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -88,7 +88,7 @@ fun compileProgram(filepath: Path, programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkRecursion() // check if there are recursive subroutine calls - // printAst(programAst) + printAst(programAst) // namespace.debugPrint() if(generateVmCode) { diff --git a/compiler/src/prog8/vm/RuntimeValue.kt b/compiler/src/prog8/vm/RuntimeValue.kt index 2e30fa74f..58c8691ee 100644 --- a/compiler/src/prog8/vm/RuntimeValue.kt +++ b/compiler/src/prog8/vm/RuntimeValue.kt @@ -553,10 +553,22 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= } DataType.UWORD -> { when (targetType) { - DataType.BYTE -> RuntimeValue(DataType.BYTE, integerValue()) - DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue()) + DataType.BYTE -> { + val v=integerValue() + if(v<128) + RuntimeValue(DataType.BYTE, v) + else + RuntimeValue(DataType.BYTE, v-256) + } + DataType.UBYTE -> RuntimeValue(DataType.UBYTE, integerValue() and 255) DataType.UWORD -> this - DataType.WORD -> RuntimeValue(DataType.WORD, integerValue()) + DataType.WORD -> { + val v=integerValue() + if(v<32768) + RuntimeValue(DataType.WORD, v) + else + RuntimeValue(DataType.WORD, v-65536) + } DataType.FLOAT -> RuntimeValue(DataType.FLOAT, numericValue()) else -> throw ArithmeticException("invalid type cast from $type to $targetType") } diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 965850dd9..15498e40b 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -6,6 +6,7 @@ import prog8.ast.base.initvarsSubName import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.LiteralValue import prog8.ast.statements.* +import prog8.compiler.target.c64.Mflpt5 import prog8.vm.RuntimeValue import prog8.vm.RuntimeValueRange import prog8.compiler.target.c64.Petscii @@ -136,8 +137,10 @@ class AstVm(val program: Program) { init { - // observe the jiffyclock + // observe the jiffyclock and screen matrix mem.observe(0xa0, 0xa1, 0xa2) + for(i in 1024..2023) + mem.observe(i) dialog.requestFocusInWindow() @@ -166,6 +169,11 @@ class AstVm(val program: Program) { val jiffies = (time_hi.toInt() shl 16) + (time_mid.toInt() shl 8) + time_lo rtcOffset = bootTime - (jiffies*1000/60) } + if(address in 1024..2023) { + // write to the screen matrix + val scraddr = address-1024 + dialog.canvas.setChar(scraddr % 40, scraddr / 40, value, 1) + } return value } @@ -235,7 +243,11 @@ class AstVm(val program: Program) { if(statusflags.irqd) return // interrupt is disabled - val jiffies = min((timeStamp-rtcOffset)*60/1000, 24*3600*60-1) + var jiffies = (timeStamp-rtcOffset)*60/1000 + if(jiffies>24*3600*60-1) { + jiffies = 0 + rtcOffset = timeStamp + } // update the C-64 60hz jiffy clock in the ZP addresses: mem.setUByte_DMA(0x00a0, (jiffies ushr 16).toShort()) mem.setUByte_DMA(0x00a1, (jiffies ushr 8 and 255).toShort()) @@ -252,7 +264,10 @@ class AstVm(val program: Program) { internal fun executeSubroutine(sub: Subroutine, arguments: List, startlabel: Label?=null): List { - assert(!sub.isAsmSubroutine) + if(sub.isAsmSubroutine) { + return performSyscall(sub, arguments) + } + if (sub.statements.isEmpty()) throw VmTerminationException("scope contains no statements: $sub") if (arguments.size != sub.parameters.size) @@ -352,19 +367,49 @@ class AstVm(val program: Program) { stmt.target.identifier != null -> { val ident = stmt.definingScope().lookup(stmt.target.identifier!!.nameInSource, stmt) as VarDecl val identScope = ident.definingScope() - var value = runtimeVariables.get(identScope, ident.name) - value = when { - stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) - stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) - else -> throw VmExecutionException("strange postincdec operator $stmt") + when(ident.type){ + VarDeclType.VAR -> { + var value = runtimeVariables.get(identScope, ident.name) + value = when { + stmt.operator == "++" -> value.add(RuntimeValue(value.type, 1)) + stmt.operator == "--" -> value.sub(RuntimeValue(value.type, 1)) + else -> throw VmExecutionException("strange postincdec operator $stmt") + } + runtimeVariables.set(identScope, ident.name, value) + } + VarDeclType.MEMORY -> { + val addr=ident.value!!.constValue(program)!!.asIntegerValue!! + val newval = when { + stmt.operator == "++" -> mem.getUByte(addr)+1 and 255 + stmt.operator == "--" -> mem.getUByte(addr)-1 and 255 + else -> throw VmExecutionException("strange postincdec operator $stmt") + } + mem.setUByte(addr,newval.toShort()) + } + VarDeclType.CONST -> throw VmExecutionException("can't be const") } - runtimeVariables.set(identScope, ident.name, value) } stmt.target.memoryAddress != null -> { - TODO("postincrdecr memory $stmt") + val addr = evaluate(stmt.target.memoryAddress!!.addressExpression, evalCtx).integerValue() + val newval = when { + stmt.operator == "++" -> mem.getUByte(addr)+1 and 255 + stmt.operator == "--" -> mem.getUByte(addr)-1 and 255 + else -> throw VmExecutionException("strange postincdec operator $stmt") + } + mem.setUByte(addr,newval.toShort()) } stmt.target.arrayindexed != null -> { - TODO("postincrdecr array $stmt") + val arrayvar = stmt.target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!! + val arrayvalue = runtimeVariables.get(arrayvar.definingScope(), arrayvar.name) + val elementType = stmt.target.arrayindexed!!.inferType(program)!! + val index = evaluate(stmt.target.arrayindexed!!.arrayspec.index, evalCtx).integerValue() + var value = RuntimeValue(elementType, arrayvalue.array!![index].toInt()) + when { + stmt.operator == "++" -> value=value.inc() + stmt.operator == "--" -> value=value.dec() + else -> throw VmExecutionException("strange postincdec operator $stmt") + } + arrayvalue.array[index] = value.numericValue() } stmt.target.register != null -> { var value = runtimeVariables.get(program.namespace, stmt.target.register!!.name) @@ -504,7 +549,7 @@ class AstVm(val program: Program) { DataType.FLOAT -> mem.setFloat(address, value.floatval!!) DataType.STR -> mem.setString(address, value.str!!) DataType.STR_S -> mem.setScreencodeString(address, value.str!!) - else -> TODO("set memvar $decl") + else -> throw VmExecutionException("weird memaddress type $decl") } } else runtimeVariables.set(decl.definingScope(), decl.name, value) @@ -514,46 +559,62 @@ class AstVm(val program: Program) { evalCtx.mem.setUByte(address, value.byteval!!) } target.arrayindexed != null -> { - val array = evaluate(target.arrayindexed.identifier, evalCtx) - val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx) - when (array.type) { - DataType.ARRAY_UB -> { - if (value.type != DataType.UBYTE) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") + val vardecl = target.arrayindexed.identifier.targetVarDecl(program.namespace)!! + if(vardecl.type==VarDeclType.VAR) { + val array = evaluate(target.arrayindexed.identifier, evalCtx) + val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx) + when (array.type) { + DataType.ARRAY_UB -> { + if (value.type != DataType.UBYTE) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + DataType.ARRAY_B -> { + if (value.type != DataType.BYTE) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + DataType.ARRAY_UW -> { + if (value.type != DataType.UWORD) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + DataType.ARRAY_W -> { + if (value.type != DataType.WORD) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + DataType.ARRAY_F -> { + if (value.type != DataType.FLOAT) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + DataType.STR, DataType.STR_S -> { + if (value.type !in ByteDatatypes) + throw VmExecutionException("new value is of different datatype ${value.type} for $array") + } + else -> throw VmExecutionException("strange array type ${array.type}") } - DataType.ARRAY_B -> { - if (value.type != DataType.BYTE) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") + if (array.type in ArrayDatatypes) + array.array!![index.integerValue()] = value.numericValue() + else if (array.type in StringDatatypes) { + val indexInt = index.integerValue() + val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true) + val newstr = array.str!!.replaceRange(indexInt, indexInt + 1, newchr) + val ident = contextStmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, contextStmt) as? VarDecl + ?: throw VmExecutionException("can't find assignment target ${target.identifier}") + val identScope = ident.definingScope() + program.heap.update(array.heapId!!, newstr) + runtimeVariables.set(identScope, ident.name, RuntimeValue(array.type, str = newstr, heapId = array.heapId)) } - DataType.ARRAY_UW -> { - if (value.type != DataType.UWORD) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") - } - DataType.ARRAY_W -> { - if (value.type != DataType.WORD) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") - } - DataType.ARRAY_F -> { - if (value.type != DataType.FLOAT) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") - } - DataType.STR, DataType.STR_S -> { - if (value.type !in ByteDatatypes) - throw VmExecutionException("new value is of different datatype ${value.type} for $array") - } - else -> throw VmExecutionException("strange array type ${array.type}") } - if (array.type in ArrayDatatypes) - array.array!![index.integerValue()] = value.numericValue() - else if (array.type in StringDatatypes) { - val indexInt = index.integerValue() - val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true) - val newstr = array.str!!.replaceRange(indexInt, indexInt + 1, newchr) - val ident = contextStmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, contextStmt) as? VarDecl - ?: throw VmExecutionException("can't find assignment target ${target.identifier}") - val identScope = ident.definingScope() - program.heap.update(array.heapId!!, newstr) - runtimeVariables.set(identScope, ident.name, RuntimeValue(array.type, str = newstr, heapId = array.heapId)) + else { + val address = (vardecl.value as LiteralValue).asIntegerValue!! + val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx).integerValue() + val elementType = target.arrayindexed.inferType(program)!! + when(elementType) { + DataType.UBYTE -> mem.setUByte(address+index, value.byteval!!) + DataType.BYTE -> mem.setSByte(address+index, value.byteval!!) + DataType.UWORD -> mem.setUWord(address+index*2, value.wordval!!) + DataType.WORD -> mem.setSWord(address+index*2, value.wordval!!) + DataType.FLOAT -> mem.setFloat(address+index*Mflpt5.MemorySize, value.floatval!!) + else -> throw VmExecutionException("strange array elt type $elementType") + } } } target.register != null -> { @@ -572,54 +633,57 @@ class AstVm(val program: Program) { private fun evaluate(args: List) = args.map { evaluate(it, evalCtx) } - private fun performSyscall(sub: Subroutine, args: List) { - assert(sub.isAsmSubroutine) + private fun performSyscall(sub: Subroutine, args: List): List { + if(!sub.isAsmSubroutine) + throw VmExecutionException("asmsub expected for syscall $sub") + + val result = mutableListOf() when (sub.scopedname) { "c64scr.print" -> { // if the argument is an UWORD, consider it to be the "address" of the string (=heapId) if (args[0].wordval != null) { val str = program.heap.get(args[0].wordval!!).str!! - dialog.canvas.printText(str, 1, true) + dialog.canvas.printText(str, true) } else - dialog.canvas.printText(args[0].str!!, 1, true) + dialog.canvas.printText(args[0].str!!, true) } "c64scr.print_ub" -> { - dialog.canvas.printText(args[0].byteval!!.toString(), 1, true) + dialog.canvas.printText(args[0].byteval!!.toString(), true) } "c64scr.print_ub0" -> { - dialog.canvas.printText("%03d".format(args[0].byteval!!), 1, true) + dialog.canvas.printText("%03d".format(args[0].byteval!!), true) } "c64scr.print_b" -> { - dialog.canvas.printText(args[0].byteval!!.toString(), 1, true) + dialog.canvas.printText(args[0].byteval!!.toString(), true) } "c64scr.print_uw" -> { - dialog.canvas.printText(args[0].wordval!!.toString(), 1, true) + dialog.canvas.printText(args[0].wordval!!.toString(), true) } "c64scr.print_uw0" -> { - dialog.canvas.printText("%05d".format(args[0].wordval!!), 1, true) + dialog.canvas.printText("%05d".format(args[0].wordval!!), true) } "c64scr.print_w" -> { - dialog.canvas.printText(args[0].wordval!!.toString(), 1, true) + dialog.canvas.printText(args[0].wordval!!.toString(), true) } "c64scr.print_ubhex" -> { val prefix = if (args[0].asBoolean) "$" else "" val number = args[1].byteval!! - dialog.canvas.printText("$prefix${number.toString(16).padStart(2, '0')}", 1, true) + dialog.canvas.printText("$prefix${number.toString(16).padStart(2, '0')}", true) } "c64scr.print_uwhex" -> { val prefix = if (args[0].asBoolean) "$" else "" val number = args[1].wordval!! - dialog.canvas.printText("$prefix${number.toString(16).padStart(4, '0')}", 1, true) + dialog.canvas.printText("$prefix${number.toString(16).padStart(4, '0')}", true) } "c64scr.print_uwbin" -> { val prefix = if (args[0].asBoolean) "%" else "" val number = args[1].wordval!! - dialog.canvas.printText("$prefix${number.toString(2).padStart(16, '0')}", 1, true) + dialog.canvas.printText("$prefix${number.toString(2).padStart(16, '0')}", true) } "c64scr.print_ubbin" -> { val prefix = if (args[0].asBoolean) "%" else "" val number = args[1].byteval!! - dialog.canvas.printText("$prefix${number.toString(2).padStart(8, '0')}", 1, true) + dialog.canvas.printText("$prefix${number.toString(2).padStart(8, '0')}", true) } "c64scr.clear_screenchars" -> { dialog.canvas.clearScreen(6) @@ -633,14 +697,26 @@ class AstVm(val program: Program) { "c64scr.plot" -> { dialog.canvas.setCursorPos(args[0].integerValue(), args[1].integerValue()) } + "c64flt.print_f" -> { + dialog.canvas.printText(args[0].floatval.toString(), true) + } "c64.CHROUT" -> { dialog.canvas.printPetscii(args[0].byteval!!) } - "c64flt.print_f" -> { - dialog.canvas.printText(args[0].floatval.toString(), 1, true) + "c64.CLEARSCR" -> { + dialog.canvas.clearScreen(6) + } + "c64.CHRIN" -> { + while(dialog.keyboardBuffer.isEmpty()) { + Thread.sleep(10) + } + val char=dialog.keyboardBuffer.pop() + result.add(RuntimeValue(DataType.UBYTE, char.toShort())) } else -> TODO("syscall ${sub.scopedname} $sub") } + + return result } private fun performBuiltinFunction(name: String, args: List, statusflags: StatusFlags): RuntimeValue? { @@ -716,7 +792,7 @@ class AstVm(val program: Program) { DataType.UWORD -> args[0] DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble())) DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble())) - else -> TODO("strange abs type") + else -> throw VmExecutionException("strange abs type ${args[0]}") } } "max" -> { @@ -739,7 +815,7 @@ class AstVm(val program: Program) { DataType.UWORD -> RuntimeValue(DataType.UWORD, sum) DataType.WORD -> RuntimeValue(DataType.WORD, sum) DataType.FLOAT -> RuntimeValue(DataType.FLOAT, sum) - else -> TODO("weird sum type") + else -> throw VmExecutionException("weird sum type ${args[0]}") } } "any" -> { diff --git a/compiler/src/prog8/vm/astvm/ScreenDialog.kt b/compiler/src/prog8/vm/astvm/ScreenDialog.kt index b3091eafa..7aa6cd138 100644 --- a/compiler/src/prog8/vm/astvm/ScreenDialog.kt +++ b/compiler/src/prog8/vm/astvm/ScreenDialog.kt @@ -7,6 +7,7 @@ import java.awt.* import java.awt.event.KeyEvent import java.awt.event.KeyListener import java.awt.image.BufferedImage +import java.util.* import javax.swing.JFrame import javax.swing.JPanel import javax.swing.Timer @@ -18,6 +19,7 @@ class BitmapScreenPanel : KeyListener, JPanel() { private val g2d = image.graphics as Graphics2D private var cursorX: Int=0 private var cursorY: Int=0 + val keyboardBuffer: Deque = LinkedList() init { val size = Dimension(image.width * SCALING, image.height * SCALING) @@ -30,14 +32,14 @@ class BitmapScreenPanel : KeyListener, JPanel() { addKeyListener(this) } - override fun keyTyped(p0: KeyEvent?) {} + override fun keyTyped(p0: KeyEvent) { + keyboardBuffer.add(p0.keyChar) + } - override fun keyPressed(p0: KeyEvent?) { - println("pressed: $p0.k") + override fun keyPressed(p0: KeyEvent) { } override fun keyReleased(p0: KeyEvent?) { - println("released: $p0") } override fun paint(graphics: Graphics?) { @@ -61,23 +63,25 @@ class BitmapScreenPanel : KeyListener, JPanel() { g2d.color = Colors.palette[color % Colors.palette.size] g2d.drawLine(x1, y1, x2, y2) } - fun printText(text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) { + + fun printText(text: String, lowercase: Boolean, inverseVideo: Boolean=false) { val t2 = text.substringBefore(0.toChar()) val lines = t2.split('\n') for(line in lines.withIndex()) { - printTextSingleLine(line.value, color, lowercase, inverseVideo) + printTextSingleLine(line.value, lowercase, inverseVideo) if(line.index=(SCREENWIDTH /8)) { cursorY++ @@ -100,6 +104,19 @@ class BitmapScreenPanel : KeyListener, JPanel() { } } + fun writeTextAt(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) { + val colorIdx = (color % Colors.palette.size).toShort() + var xx=x + for(clearx in xx until xx+text.length) { + g2d.clearRect(8*clearx, 8*y, 8, 8) + } + for(sc in Petscii.encodePetscii(text, lowercase)) { + if(sc==0.toShort()) + break + setPetscii(xx++, y, sc, colorIdx, inverseVideo) + } + } + fun setPetscii(x: Int, y: Int, petscii: Short, color: Short, inverseVideo: Boolean) { g2d.clearRect(8*x, 8*y, 8, 8) val colorIdx = (color % Colors.palette.size).toShort() @@ -124,20 +141,6 @@ class BitmapScreenPanel : KeyListener, JPanel() { return Pair(cursorX, cursorY) } - fun writeText(x: Int, y: Int, text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) { - val colorIdx = (color % Colors.palette.size).toShort() - var xx=x - for(clearx in xx until xx+text.length) { - g2d.clearRect(8*clearx, 8*y, 8, 8) - } - for(sc in Petscii.encodePetscii(text, lowercase)) { - if(sc==0.toShort()) - break - setPetscii(xx++, y, sc, colorIdx, inverseVideo) - } - } - - companion object { const val SCREENWIDTH = 320 const val SCREENHEIGHT = 200 @@ -148,6 +151,7 @@ class BitmapScreenPanel : KeyListener, JPanel() { class ScreenDialog(title: String) : JFrame(title) { val canvas = BitmapScreenPanel() + val keyboardBuffer = canvas.keyboardBuffer init { val borderWidth = 16 diff --git a/compiler/src/prog8/vm/stackvm/StackVm.kt b/compiler/src/prog8/vm/stackvm/StackVm.kt index e4cd743bb..9c7007cef 100644 --- a/compiler/src/prog8/vm/stackvm/StackVm.kt +++ b/compiler/src/prog8/vm/stackvm/StackVm.kt @@ -2027,7 +2027,7 @@ class StackVm(private var traceOutputFile: String?) { val color = evalstack.pop() val (cy, cx) = evalstack.pop2() val text = heap.get(textPtr) - canvas?.writeText(cx.integerValue(), cy.integerValue(), text.str!!, color.integerValue().toShort(), true) + canvas?.writeTextAt(cx.integerValue(), cy.integerValue(), text.str!!, color.integerValue().toShort(), true) } Syscall.FUNC_RND -> evalstack.push(RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255)) Syscall.FUNC_RNDW -> evalstack.push(RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535)) @@ -2309,54 +2309,54 @@ class StackVm(private var traceOutputFile: String?) { Syscall.SYSASM_c64scr_print -> { val straddr = variables.getValue("A").integerValue() + 256*variables.getValue("Y").integerValue() val str = heap.get(straddr).str!! - canvas?.printText(str, 1, true) + canvas?.printText(str, true) } Syscall.SYSASM_c64scr_print_ub -> { val num = variables.getValue("A").integerValue() - canvas?.printText(num.toString(), 1, true) + canvas?.printText(num.toString(), true) } Syscall.SYSASM_c64scr_print_ub0 -> { val num = variables.getValue("A").integerValue() - canvas?.printText("%03d".format(num), 1, true) + canvas?.printText("%03d".format(num), true) } Syscall.SYSASM_c64scr_print_b -> { val num = variables.getValue("A").integerValue() if(num<=127) - canvas?.printText(num.toString(), 1, true) + canvas?.printText(num.toString(), true) else - canvas?.printText("-${256-num}", 1, true) + canvas?.printText("-${256-num}", true) } Syscall.SYSASM_c64scr_print_uw -> { val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() val number = lo+256*hi - canvas?.printText(number.toString(), 1, true) + canvas?.printText(number.toString(), true) } Syscall.SYSASM_c64scr_print_uw0 -> { val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() val number = lo+256*hi - canvas?.printText("%05d".format(number), 1, true) + canvas?.printText("%05d".format(number), true) } Syscall.SYSASM_c64scr_print_uwhex -> { val prefix = if(this.P_carry) "$" else "" val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() val number = lo+256*hi - canvas?.printText("$prefix${number.toString(16).padStart(4, '0')}", 1, true) + canvas?.printText("$prefix${number.toString(16).padStart(4, '0')}", true) } Syscall.SYSASM_c64scr_print_w -> { val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() val number = lo+256*hi if(number<=32767) - canvas?.printText(number.toString(), 1, true) + canvas?.printText(number.toString(), true) else - canvas?.printText("-${65536-number}", 1, true) + canvas?.printText("-${65536-number}", true) } Syscall.SYSASM_c64flt_print_f -> { val number = variables.getValue("c64flt.print_f.value").numericValue() - canvas?.printText(number.toString(), 1, true) + canvas?.printText(number.toString(), true) } Syscall.SYSASM_c64scr_setcc -> { val x = variables.getValue("c64scr.setcc.column").integerValue() diff --git a/examples/test.p8 b/examples/test.p8 index 93f701e03..a48559000 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,33 +1,17 @@ %import c64utils %zeropage basicsafe -%import c64flt ~ main { sub start() { - ubyte xx=99 - ubyte yy=99 - ubyte aa=99 - - rsave() - c64flt.GETADR() - rrestore() - c64scr.print_ub(yy) - c64.CHROUT(',') - c64scr.print_ub(aa) - c64.CHROUT('\n') - - rsave() - c64utils.ubyte2hex($9c) - rrestore() - c64scr.print_ub(aa) - c64.CHROUT(',') - c64scr.print_ub(yy) - c64.CHROUT('\n') - -; rsave() -; A,Y=c64flt.FOUT() ; @ todo accept A,Y for AY response -; rrestore() + while true { + c64scr.print_ub(c64.TIME_HI) + c64.CHROUT(':') + c64scr.print_ub(c64.TIME_MID) + c64.CHROUT(':') + c64scr.print_ub(c64.TIME_LO) + c64.CHROUT('\n') + } } }