ir syscalls args via stack instead of fixed r65500+

This commit is contained in:
Irmen de Jong 2023-04-10 16:59:08 +02:00
parent 9b37ac483f
commit dd1592b03b
15 changed files with 182 additions and 159 deletions

View File

@ -81,12 +81,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val result = mutableListOf<IRCodeChunkBase>()
val left = exprGen.translateExpression(call.args[0])
val right = exprGen.translateExpression(call.args[1])
val targetReg = codeGen.registers.nextFree()
addToResult(result, left, SyscallRegisterBase, -1)
addToResult(result, right, SyscallRegisterBase+1, -1)
addToResult(result, left, left.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=left.resultReg), null)
addToResult(result, right, right.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=right.resultReg), null)
addInstr(result, IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.COMPARE_STRINGS.number), null)
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=targetReg), null)
return ExpressionCodeResult(result, IRDataType.BYTE, targetReg, -1)
addInstr(result, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=left.resultReg), null)
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
}
private fun funcCmp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
@ -116,9 +117,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
}
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -139,9 +142,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
}
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
@ -265,9 +270,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
}
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
@ -288,9 +295,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
}
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args[0])
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = tr.resultReg, immediate = array.length)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1 = tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = syscall.number)
}
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)

View File

@ -111,42 +111,47 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
when(iterable.dt) {
DataType.STR -> {
tr = translateExpression(check.element)
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, SyscallRegisterBase+1, -1)
val resultReg = codeGen.registers.nextFree()
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.STRING_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
tr = translateExpression(check.element)
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, SyscallRegisterBase+1, -1)
val resultReg = codeGen.registers.nextFree()
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.BYTEARRAY_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
// SysCall call convention: return value in register r0
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
tr = translateExpression(check.element)
addToResult(result, tr, SyscallRegisterBase, -1)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg), null)
tr = translateExpression(check.iterable)
addToResult(result, tr, SyscallRegisterBase+1, -1)
val resultReg = codeGen.registers.nextFree()
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, tr.resultReg)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=tr.resultReg, immediate = iterable.length!!)
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, tr.resultReg)
it += IRInstruction(Opcode.SYSCALL, immediate = IMSyscall.WORDARRAY_CONTAINS.number)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=resultReg)
it += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=tr.resultReg)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
}
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.name}")

View File

@ -1,11 +1,7 @@
package prog8.codegen.intermediate
import prog8.code.core.AssemblyError
import prog8.intermediate.SyscallRegisterBase
internal class RegisterPool {
// reserve 0,1,2 for return values of subroutine calls and syscalls
// TODO set this back to 0 once 'resultRegister' has been removed everywhere and DIVMOD fixed to not use r0?
// reserve 0,1,2 for return values of subroutine calls and syscalls in IR assembly code
private var firstFree: Int=3
private var firstFreeFloat: Int=3
@ -15,16 +11,12 @@ internal class RegisterPool {
fun nextFree(): Int {
val result = firstFree
firstFree++
if(firstFree >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (int)")
return result
}
fun nextFreeFloat(): Int {
val result = firstFreeFloat
firstFreeFloat++
if(firstFreeFloat >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (fp)")
return result
}
}

View File

@ -196,7 +196,8 @@ sub str2uword(str string) -> uword {
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
%ir {{
loadm.w r65500,conv.str2uword.string
loadm.w r65535,conv.str2uword.string
push.w r65535
syscall 11
pop.w r0
returnreg.w r0
@ -208,7 +209,8 @@ sub str2word(str string) -> word {
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
%ir {{
loadm.w r65500,conv.str2word.string
loadm.w r65535,conv.str2word.string
push.w r65535
syscall 12
pop.w r0
returnreg.w r0

View File

@ -10,7 +10,8 @@ floats {
sub print_f(float value) {
; ---- prints the floating point value (without a newline).
%ir {{
loadm.f fr65500,floats.print_f.value
loadm.f fr65535,floats.print_f.value
push.f fr65535
syscall 25
return
}}
@ -134,7 +135,8 @@ sub rndf() -> float {
sub rndseedf(float seed) {
%ir {{
loadm.f fr65500,floats.rndseedf.seed
loadm.f fr65535,floats.rndseedf.seed
push.f fr65535
syscall 32
}}
}

View File

@ -178,8 +178,10 @@ math {
sub rndseed(uword seed1, uword seed2) {
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
%ir {{
loadm.w r65500,math.rndseed.seed1
loadm.w r65501,math.rndseed.seed2
loadm.w r65535,math.rndseed.seed1
push.w r65535
loadm.w r65535,math.rndseed.seed2
push.w r65535
syscall 31
return
}}

View File

@ -84,8 +84,10 @@ string {
; Note that you can also directly compare strings and string values with eachother using
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
%ir {{
loadm.w r65500,string.compare.st1
loadm.w r65501,string.compare.st2
loadm.w r65535,string.compare.st1
push.w r65535
loadm.w r65535,string.compare.st2
push.w r65535
syscall 29
pop.b r0
returnreg.b r0

View File

@ -15,7 +15,8 @@ sys {
sub wait(uword jiffies) {
; --- wait approximately the given number of jiffies (1/60th seconds)
%ir {{
loadm.w r65500,sys.wait.jiffies
loadm.w r65535,sys.wait.jiffies
push.w r65535
syscall 13
}}
}
@ -62,7 +63,8 @@ sys {
sub exit(ubyte returnvalue) {
; -- immediately exit the program with a return code in the A register
%ir {{
loadm.b r65500,sys.exit.returnvalue
loadm.b r65535,sys.exit.returnvalue
push.b r65535
syscall 1
}}
}
@ -82,31 +84,38 @@ sys {
sub gfx_enable(ubyte mode) {
%ir {{
loadm.b r65500,sys.gfx_enable.mode
loadm.b r65535,sys.gfx_enable.mode
push.b r65535
syscall 8
}}
}
sub gfx_clear(ubyte color) {
%ir {{
loadm.b r65500,sys.gfx_clear.color
loadm.b r65535,sys.gfx_clear.color
push.b r65535
syscall 9
}}
}
sub gfx_plot(uword xx, uword yy, ubyte color) {
%ir {{
loadm.w r65500,sys.gfx_plot.xx
loadm.w r65501,sys.gfx_plot.yy
loadm.b r65502,sys.gfx_plot.color
loadm.w r65535,sys.gfx_plot.xx
push.w r65535
loadm.w r65535,sys.gfx_plot.yy
push.w r65535
loadm.b r65535,sys.gfx_plot.color
push.b r65535
syscall 10
}}
}
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
%ir {{
loadm.w r65500,sys.gfx_getpixel.xx
loadm.w r65501,sys.gfx_getpixel.yy
loadm.w r65535,sys.gfx_getpixel.xx
push.w r65535
loadm.w r65535,sys.gfx_getpixel.yy
push.w r65535
syscall 30
pop.b r0
returnreg.b r0

View File

@ -15,7 +15,8 @@ sub height() -> ubyte {
sub clear_screen() {
str @shared sequence = "\x1b[2J\x1B[H"
%ir {{
load.w r65500,txt.clear_screen.sequence
load.w r65535,txt.clear_screen.sequence
push.w r65535
syscall 3
}}
}
@ -38,14 +39,16 @@ sub uppercase() {
sub chrout(ubyte char) {
%ir {{
loadm.b r65500,txt.chrout.char
loadm.b r65535,txt.chrout.char
push.b r65535
syscall 2
}}
}
sub print (str text) {
%ir {{
loadm.w r65500,txt.print.text
loadm.w r65535,txt.print.text
push.w r65535
syscall 3
}}
}
@ -122,7 +125,8 @@ sub input_chars (uword buffer) -> ubyte {
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
; It assumes the keyboard is selected as I/O channel!
%ir {{
loadm.w r65500,txt.input_chars.buffer
loadm.w r65535,txt.input_chars.buffer
push.w r65535
syscall 6
pop.b r0
returnreg.b r0

View File

@ -3,7 +3,7 @@ TODO
For next minor release
^^^^^^^^^^^^^^^^^^^^^^
change syscalls to take parameters on value stack (not in r65500+ registers)
test vm array reverse, sort, string containment, string input, float array containment (how translated? there is no syscall)
...

View File

@ -1,12 +1,11 @@
%import textio
%zeropage basicsafe
%import math
%import floats
%import string
main {
sub start() {
cx16.r1=0
for cx16.r0 in 0 to 10 {
cx16.r1++
}
txt.print_uw(cx16.r1)
math.rndseed(11111,22222)
}
}

View File

@ -23,5 +23,3 @@ enum class IMSyscall(val number: Int) {
BYTEARRAY_CONTAINS(10015),
WORDARRAY_CONTAINS(10016)
}
const val SyscallRegisterBase = 65500

View File

@ -7,7 +7,7 @@ package prog8.vm
*/
class Registers {
private val registers = Array<UShort>(65536) { 0u }
private val floatRegisters = Array(65535) { 0f }
private val floatRegisters = Array(65536) { 0f }
var cpuA: UByte = 0u
var cpuX: UByte = 0u
var cpuY: UByte = 0u

View File

@ -1,7 +1,6 @@
package prog8.vm
import prog8.code.core.AssemblyError
import prog8.intermediate.SyscallRegisterBase
import kotlin.math.min
/*
@ -92,14 +91,14 @@ object SysCalls {
vm.reset(false)
}
Syscall.EXIT ->{
vm.exit(vm.registers.getUB(SyscallRegisterBase).toInt())
vm.exit(vm.valueStack.pop().toInt())
}
Syscall.PRINT_C -> {
val char = vm.registers.getUB(SyscallRegisterBase).toInt()
val char = vm.valueStack.pop().toInt()
print(Char(char))
}
Syscall.PRINT_S -> {
var addr = vm.registers.getUW(SyscallRegisterBase).toInt()
var addr = vm.valueStack.popw().toInt()
while(true) {
val char = vm.memory.getUB(addr).toInt()
if(char==0)
@ -109,21 +108,21 @@ object SysCalls {
}
}
Syscall.PRINT_U8 -> {
print(vm.registers.getUB(SyscallRegisterBase))
print(vm.valueStack.pop())
}
Syscall.PRINT_U16 -> {
print(vm.registers.getUW(SyscallRegisterBase))
print(vm.valueStack.popw())
}
Syscall.INPUT -> {
var input = readln()
val maxlen = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val maxlen = vm.valueStack.pop().toInt()
if(maxlen>0)
input = input.substring(0, min(input.length, maxlen))
vm.memory.setString(vm.registers.getUW(SyscallRegisterBase).toInt(), input, true)
vm.memory.setString(vm.valueStack.popw().toInt(), input, true)
vm.valueStack.pushw(input.length.toUShort())
}
Syscall.SLEEP -> {
val duration = vm.registers.getUW(SyscallRegisterBase).toLong()
val duration = vm.valueStack.popw().toLong()
Thread.sleep(duration)
}
Syscall.GFX_ENABLE -> vm.gfx_enable()
@ -131,13 +130,13 @@ object SysCalls {
Syscall.GFX_PLOT -> vm.gfx_plot()
Syscall.GFX_GETPIXEL ->vm.gfx_getpixel()
Syscall.WAIT -> {
val millis = vm.registers.getUW(SyscallRegisterBase).toLong() * 1000/60
val millis = vm.valueStack.popw().toLong() * 1000/60
Thread.sleep(millis)
}
Syscall.WAITVSYNC -> vm.waitvsync()
Syscall.SORT_UBYTE -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.sorted()
@ -146,8 +145,8 @@ object SysCalls {
}
}
Syscall.SORT_BYTE -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getSB(it)
}.sorted()
@ -156,8 +155,8 @@ object SysCalls {
}
}
Syscall.SORT_UWORD -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.sorted()
@ -166,8 +165,8 @@ object SysCalls {
}
}
Syscall.SORT_WORD -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getSW(it)
}.sorted()
@ -176,8 +175,8 @@ object SysCalls {
}
}
Syscall.REVERSE_BYTES -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.reversed()
@ -186,8 +185,8 @@ object SysCalls {
}
}
Syscall.REVERSE_WORDS -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.reversed()
@ -196,8 +195,8 @@ object SysCalls {
}
}
Syscall.REVERSE_FLOATS -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val array = IntProgression.fromClosedRange(address, address+length*4-2, 4).map {
vm.memory.getFloat(it)
}.reversed()
@ -206,8 +205,8 @@ object SysCalls {
}
}
Syscall.ANY_BYTE -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.any { vm.memory.getUB(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -215,8 +214,8 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.ANY_WORD -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.any { vm.memory.getUW(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -224,8 +223,8 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.ANY_FLOAT -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4)
if(addresses.any { vm.memory.getFloat(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -233,8 +232,8 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.ALL_BYTE -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.all { vm.memory.getUB(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -242,8 +241,8 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.ALL_WORD -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.all { vm.memory.getUW(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -251,8 +250,8 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.ALL_FLOAT -> {
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val length = vm.valueStack.pop().toInt()
val address = vm.valueStack.popw().toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4)
if(addresses.all { vm.memory.getFloat(it).toInt()!=0 })
vm.valueStack.push(1u)
@ -260,11 +259,10 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.PRINT_F -> {
val value = vm.registers.getFloat(SyscallRegisterBase)
print(value)
print(vm.valueStack.popf())
}
Syscall.STR_TO_UWORD -> {
val stringAddr = vm.registers.getUW(SyscallRegisterBase)
val stringAddr = vm.valueStack.popw()
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
val value = try {
string.toUShort()
@ -274,7 +272,7 @@ object SysCalls {
vm.valueStack.pushw(value)
}
Syscall.STR_TO_WORD -> {
val stringAddr = vm.registers.getUW(SyscallRegisterBase)
val stringAddr = vm.valueStack.popw()
val memstring = vm.memory.getString(stringAddr.toInt())
val match = Regex("^[+-]?\\d+").find(memstring)
if(match==null) {
@ -289,8 +287,8 @@ object SysCalls {
vm.valueStack.pushw(value.toUShort())
}
Syscall.COMPARE_STRINGS -> {
val firstAddr = vm.registers.getUW(SyscallRegisterBase)
val secondAddr = vm.registers.getUW(SyscallRegisterBase+1)
val secondAddr = vm.valueStack.popw()
val firstAddr = vm.valueStack.popw()
val first = vm.memory.getString(firstAddr.toInt())
val second = vm.memory.getString(secondAddr.toInt())
val comparison = first.compareTo(second)
@ -302,15 +300,15 @@ object SysCalls {
vm.valueStack.push(1u)
}
Syscall.RNDFSEED -> {
val seed = vm.registers.getFloat(SyscallRegisterBase)
val seed = vm.valueStack.popf()
if(seed>0) // always use negative seed, this mimics the behavior on CBM machines
vm.randomSeedFloat(-seed)
else
vm.randomSeedFloat(seed)
}
Syscall.RNDSEED -> {
val seed1 = vm.registers.getUW(SyscallRegisterBase)
val seed2 = vm.registers.getUW(SyscallRegisterBase+1)
val seed2 = vm.valueStack.popw()
val seed1 = vm.valueStack.popw()
vm.randomSeed(seed1, seed2)
}
Syscall.RND -> {
@ -323,15 +321,15 @@ object SysCalls {
vm.valueStack.pushf(vm.randomGeneratorFloats.nextFloat())
}
Syscall.STRING_CONTAINS -> {
val char = vm.registers.getUB(SyscallRegisterBase).toInt().toChar()
val stringAddr = vm.registers.getUW(SyscallRegisterBase+1)
val stringAddr = vm.valueStack.popw()
val char = vm.valueStack.pop().toInt().toChar()
val string = vm.memory.getString(stringAddr.toInt())
vm.valueStack.push(if(char in string) 1u else 0u)
}
Syscall.BYTEARRAY_CONTAINS -> {
val value = vm.registers.getUB(SyscallRegisterBase)
var array = vm.registers.getUW(SyscallRegisterBase+1).toInt()
var length = vm.registers.getUB(SyscallRegisterBase+2)
var length = vm.valueStack.pop()
var array = vm.valueStack.popw().toInt()
val value = vm.valueStack.pop()
while(length>0u) {
if(vm.memory.getUB(array)==value) {
vm.valueStack.push(1u)
@ -343,10 +341,9 @@ object SysCalls {
vm.valueStack.push(0u)
}
Syscall.WORDARRAY_CONTAINS -> {
// r0.w = value, r1.w = array, r2.b = array length
val value = vm.registers.getUW(SyscallRegisterBase)
var array = vm.registers.getUW(SyscallRegisterBase+1).toInt()
var length = vm.registers.getUB(SyscallRegisterBase+2)
var length = vm.valueStack.pop()
var array = vm.valueStack.popw().toInt()
val value = vm.valueStack.popw()
while(length>0u) {
if(vm.memory.getUW(array)==value) {
vm.valueStack.push(1u)

View File

@ -117,17 +117,14 @@ class VirtualMachine(irProgram: IRProgram) {
private fun stepNextChunk() {
do {
val nextChunk = pcChunk.next
when (nextChunk) {
when (val nextChunk = pcChunk.next) {
is IRCodeChunk -> {
pcChunk = nextChunk
pcIndex = 0
}
null -> {
exit(0) // end of program reached
}
else -> {
throw IllegalArgumentException("VM cannot run code from non-code chunk $nextChunk")
}
@ -142,8 +139,7 @@ class VirtualMachine(irProgram: IRProgram) {
}
private fun branchTo(i: IRInstruction) {
val target = i.branchTarget
when (target) {
when (val target = i.branchTarget) {
is IRCodeChunk -> {
pcChunk = target
pcIndex = 0
@ -154,7 +150,11 @@ class VirtualMachine(irProgram: IRProgram) {
else
throw IllegalArgumentException("no branchtarget in $i")
}
else -> throw IllegalArgumentException("VM can't execute code in a non-codechunk: $target")
is IRInlineAsmChunk -> TODO()
is IRInlineBinaryChunk -> TODO()
else -> {
throw IllegalArgumentException("VM can't execute code in a non-codechunk: $target")
}
}
}
@ -335,7 +335,8 @@ class VirtualMachine(irProgram: IRProgram) {
valueStack.pushw(value)
}
IRDataType.FLOAT -> {
throw IllegalArgumentException("can't PUSH a float")
val value = registers.getFloat(i.fpReg1!!)
valueStack.pushf(value)
}
}
nextPc()
@ -343,26 +344,9 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsPOP(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> {
val value = valueStack.pop().toInt()
setResultReg(i.reg1!!, value, i.type!!)
}
IRDataType.WORD -> {
val msb = valueStack.pop()
val lsb = valueStack.pop()
val value = (msb.toInt() shl 8) + lsb.toInt()
setResultReg(i.reg1!!, value, i.type!!)
}
IRDataType.FLOAT -> {
// pop float; lsb is on bottom, msb on top
val b0 = valueStack.pop()
val b1 = valueStack.pop()
val b2 = valueStack.pop()
val b3 = valueStack.pop()
val bits = b3 + 256u*b2 + 65536u*b1 + 16777216u*b0
val value = Float.fromBits(bits.toInt())
registers.setFloat(i.fpReg1!!, value)
}
IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.pop().toInt(), i.type!!)
IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().toInt(), i.type!!)
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf())
}
nextPc()
}
@ -2289,7 +2273,7 @@ class VirtualMachine(irProgram: IRProgram) {
private var window: GraphicsWindow? = null
fun gfx_enable() {
window = when(registers.getUB(SyscallRegisterBase).toInt()) {
window = when(valueStack.pop().toInt()) {
0 -> GraphicsWindow(320, 240, 3)
1 -> GraphicsWindow(640, 480, 2)
else -> throw IllegalArgumentException("invalid screen mode")
@ -2298,21 +2282,23 @@ class VirtualMachine(irProgram: IRProgram) {
}
fun gfx_clear() {
window?.clear(registers.getUB(SyscallRegisterBase).toInt())
window?.clear(valueStack.pop().toInt())
}
fun gfx_plot() {
window?.plot(registers.getUW(SyscallRegisterBase).toInt(),
registers.getUW(SyscallRegisterBase+1).toInt(),
registers.getUB(SyscallRegisterBase+2).toInt())
val color = valueStack.pop()
val y = valueStack.popw()
val x = valueStack.popw()
window?.plot(x.toInt(), y.toInt(), color.toInt())
}
fun gfx_getpixel() {
if(window==null)
registers.setUB(0, 0u)
else {
val color = Color(window!!.getpixel(registers.getUW(SyscallRegisterBase).toInt(),
registers.getUW(SyscallRegisterBase+1).toInt()))
val y = valueStack.popw()
val x = valueStack.popw()
val color = Color(window!!.getpixel(x.toInt(), y.toInt()))
registers.setUB(0, color.green.toUByte())
}
}
@ -2351,6 +2337,22 @@ internal fun Stack<UByte>.pushf(value: Float) {
push(bits.toUByte())
}
internal fun Stack<UByte>.popw(): UShort {
val msb = pop()
val lsb = pop()
return ((msb.toInt() shl 8) + lsb.toInt()).toUShort()
}
internal fun Stack<UByte>.popf(): Float {
// pop float; lsb is on bottom, msb on top
val b0 = pop()
val b1 = pop()
val b2 = pop()
val b3 = pop()
val bits = b3 + 256u*b2 + 65536u*b1 + 16777216u*b0
return Float.fromBits(bits.toInt())
}
// probably called via reflection
class VmRunner: IVirtualMachineRunner {
override fun runProgram(irSource: String) {