mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
astvm almost complete
This commit is contained in:
parent
a59f7c75dc
commit
d4b3e35bd2
@ -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<WhenChoice, Int?>(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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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<RuntimeValue>, startlabel: Label?=null): List<RuntimeValue> {
|
||||
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<IExpression>) = args.map { evaluate(it, evalCtx) }
|
||||
|
||||
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>) {
|
||||
assert(sub.isAsmSubroutine)
|
||||
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>): List<RuntimeValue> {
|
||||
if(!sub.isAsmSubroutine)
|
||||
throw VmExecutionException("asmsub expected for syscall $sub")
|
||||
|
||||
val result = mutableListOf<RuntimeValue>()
|
||||
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<RuntimeValue>, 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" -> {
|
||||
|
@ -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<Char> = LinkedList<Char>()
|
||||
|
||||
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<lines.size-1) {
|
||||
cursorX=0
|
||||
cursorY++
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun printTextSingleLine(text: String, color: Short, lowercase: Boolean, inverseVideo: Boolean=false) {
|
||||
|
||||
private fun printTextSingleLine(text: String, lowercase: Boolean, inverseVideo: Boolean=false) {
|
||||
for(clearx in cursorX until cursorX+text.length) {
|
||||
g2d.clearRect(8*clearx, 8*y, 8, 8)
|
||||
}
|
||||
for(sc in Petscii.encodePetscii(text, lowercase)) {
|
||||
setPetscii(cursorX, cursorY, sc, color, inverseVideo)
|
||||
setPetscii(cursorX, cursorY, sc, 1, inverseVideo)
|
||||
cursorX++
|
||||
if(cursorX>=(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
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user