ir/vm: syscall params in high base register to avoid push/pop

This commit is contained in:
Irmen de Jong 2022-11-06 12:40:39 +01:00
parent 469e042216
commit 38efaae7b2
14 changed files with 186 additions and 193 deletions

View File

@ -71,11 +71,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
if (resultRegister != 0)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
}
return result
@ -94,11 +94,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
if (resultRegister != 0)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
}
return result
@ -213,9 +213,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type to reverse")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
}
return result
@ -235,9 +235,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
else -> throw IllegalArgumentException("weird type to sort")
}
val result = mutableListOf<IRCodeChunkBase>()
result += exprGen.translateExpression(call.args[0], 0, -1)
result += exprGen.translateExpression(call.args[0], SyscallRegisterBase, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = SyscallRegisterBase+1, value = array.length)
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
}
return result

View File

@ -10,7 +10,7 @@ import prog8.intermediate.*
internal class ExpressionGen(private val codeGen: IRCodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunks {
require(codeGen.registers.peekNext() > resultRegister)
require(codeGen.registers.peekNext() > resultRegister || resultRegister >= SyscallRegisterBase)
return when (expr) {
is PtMachineRegister -> {
@ -101,49 +101,33 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) {
DataType.STR -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.STRING_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.BYTEARRAY_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
push += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=2)
result += push
result += translateExpression(check.element, 0, -1)
result += translateExpression(check.iterable, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=2, value = iterable.length!!)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=2)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
result += syscall
result += translateExpression(check.element, SyscallRegisterBase, -1)
result += translateExpression(check.iterable, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=SyscallRegisterBase+2, value = iterable.length!!)
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.WORDARRAY_CONTAINS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
}
}
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}")
@ -332,23 +316,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0)
syscall += if(greaterEquals)
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=1)
else
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0)
it += if (greaterEquals)
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
else
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@ -388,23 +367,18 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
syscall += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=0)
syscall += if(lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=1)
else
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=1)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = 0)
it += if (lessEquals)
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
else
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1 = resultRegister, reg2 = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)
@ -440,21 +414,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
require(codeGen.registers.peekNext() > 1)
val push = IRCodeChunk(null, null)
push += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=1)
result += push
result += translateExpression(binExpr.left, 0, -1)
result += translateExpression(binExpr.right, 1, -1)
val syscall = IRCodeChunk(null, null)
syscall += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
syscall += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=1)
if(resultRegister!=0)
syscall += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=0)
if(!notEquals)
syscall += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister)
syscall += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
result += syscall
result += translateExpression(binExpr.left, SyscallRegisterBase, -1)
result += translateExpression(binExpr.right, SyscallRegisterBase+1, -1)
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SYSCALL, value = IMSyscall.COMPARE_STRINGS.number)
if(resultRegister!=0)
it += IRInstruction(Opcode.LOADR, vmDt, reg1 = resultRegister, reg2 = 0)
if (!notEquals)
it += IRInstruction(Opcode.INV, vmDt, reg1 = resultRegister)
it += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value = 1)
}
} else {
val rightResultReg = codeGen.registers.nextFree()
result += translateExpression(binExpr.left, resultRegister, -1)

View File

@ -1,10 +1,12 @@
package prog8.codegen.intermediate
import prog8.code.core.AssemblyError
import prog8.intermediate.SyscallRegisterBase
internal class RegisterPool {
private var firstFree: Int=3 // integer registers 0,1,2 are reserved
private var firstFreeFloat: Int=0
// reserve 0,1,2 for return values of subroutine calls and syscalls
private var firstFree: Int=3
private var firstFreeFloat: Int=3
fun peekNext() = firstFree
fun peekNextFloat() = firstFreeFloat
@ -12,7 +14,7 @@ internal class RegisterPool {
fun nextFree(): Int {
val result = firstFree
firstFree++
if(firstFree>65535)
if(firstFree >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (int)")
return result
}
@ -20,7 +22,7 @@ internal class RegisterPool {
fun nextFreeFloat(): Int {
val result = firstFreeFloat
firstFreeFloat++
if(firstFreeFloat>65535)
if(firstFreeFloat >= SyscallRegisterBase)
throw AssemblyError("out of virtual registers (fp)")
return result
}

View File

@ -196,7 +196,7 @@ 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 r0,conv.str2uword.string
loadm.w r65500,conv.str2uword.string
syscall 11
return
}}
@ -207,7 +207,7 @@ 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 r0,conv.str2word.string
loadm.w r65500,conv.str2word.string
syscall 12
return
}}

View File

@ -10,7 +10,7 @@ floats {
sub print_f(float value) {
; ---- prints the floating point value (without a newline).
%ir {{
loadm.f fr0,floats.print_f.value
loadm.f fr65500,floats.print_f.value
syscall 25
return
}}
@ -133,9 +133,9 @@ sub rndf() -> float {
sub rndseedf(ubyte s1, ubyte s2, ubyte s3) {
%ir {{
loadm.b r0,floats.rndseedf.s1
loadm.b r1,floats.rndseedf.s2
loadm.b r2,floats.rndseedf.s3
loadm.b r65500,floats.rndseedf.s1
loadm.b r65501,floats.rndseedf.s2
loadm.b r65502,floats.rndseedf.s3
syscall 32
}}
}

View File

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

View File

@ -84,8 +84,8 @@ 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 r0,string.compare.st1
loadm.w r1,string.compare.st2
loadm.w r65500,string.compare.st1
loadm.w r65501,string.compare.st2
syscall 29
return
}}

View File

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

View File

@ -7,7 +7,7 @@ txt {
sub clear_screen() {
str @shared sequence = "\x1b[2J\x1B[H"
%ir {{
load.w r0,txt.clear_screen.sequence
load.w r65500,txt.clear_screen.sequence
syscall 3
}}
}
@ -30,14 +30,14 @@ sub uppercase() {
sub chrout(ubyte char) {
%ir {{
loadm.b r0,txt.chrout.char
loadm.b r65500,txt.chrout.char
syscall 2
}}
}
sub print (str text) {
%ir {{
loadm.w r0,txt.print.text
loadm.w r65500,txt.print.text
syscall 3
}}
}
@ -114,7 +114,7 @@ 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 r0,txt.input_chars.buffer
loadm.w r65500,txt.input_chars.buffer
syscall 6
return
}}

View File

@ -3,6 +3,9 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- add a pget() to gfx2 to get the pixel color value
- ir: write addresses as hex into p8ir file
...
@ -17,14 +20,13 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- ir/vm: SYSCALL opcode should take args in r65500, r65501 etc instead of r0, r1. Then also remove excess PUSH/POP of regs to save them.
- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
- ir peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out!)
- ir: add more optimizations in IRPeepholeOptimizer
- ir: write addresses as hex into p8ir file
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
this is documented behavior to now loop around but it's too easy to forget about!
Lot of work because of so many special cases in ForLoopsAsmgen.....
@ -55,7 +57,6 @@ Libraries:
- optimize several inner loops in gfx2 even further?
- add modes 3 and perhaps even 2 to gfx2 (lores 16 color and 4 color)?
- add a flood fill (span fill/scanline fill) routine to gfx2?
- add a pget() to gfx2 to get the pixel color value
Expressions:

View File

@ -1,4 +1,5 @@
%import textio
%import floats
%import string
%zeropage basicsafe
@ -6,13 +7,26 @@ main {
str name1 = "abc"
str name2 = "irmen"
ubyte[] arr1 = [11,22,33]
uword[] arr2 = [1111,2222,3333]
ubyte[] arr1 = [11,22,0,33]
uword[] arr2 = [1111,2222,0,3333]
sub start() {
sys.exit(42)
floats.rndseedf(11,22,33)
floats.print_f(floats.rndf())
txt.nl()
floats.print_f(floats.rndf())
txt.nl()
floats.print_f(floats.rndf())
txt.nl()
ubyte @shared xx
ubyte value = 33
uword value2 = 3333
txt.print_ub(all(arr1))
txt.print_ub(any(arr1))
reverse(arr1)
sort(arr1)
txt.print_ub(value in name1)
txt.print_ub('c' in name1)
txt.print_ub(value in arr1)

View File

@ -22,4 +22,6 @@ enum class IMSyscall(val number: Int) {
STRING_CONTAINS(10014),
BYTEARRAY_CONTAINS(10015),
WORDARRAY_CONTAINS(10016)
}
}
const val SyscallRegisterBase = 65500

View File

@ -1,6 +1,7 @@
package prog8.vm
import prog8.code.core.AssemblyError
import prog8.intermediate.SyscallRegisterBase
import kotlin.math.min
/*
@ -85,19 +86,20 @@ enum class Syscall {
object SysCalls {
fun call(call: Syscall, vm: VirtualMachine) {
when(call) {
Syscall.RESET -> {
vm.reset()
}
Syscall.EXIT ->{
vm.exit()
vm.exit(vm.registers.getUB(SyscallRegisterBase).toInt())
}
Syscall.PRINT_C -> {
val char = vm.registers.getUB(0).toInt()
val char = vm.registers.getUB(SyscallRegisterBase).toInt()
print(Char(char))
}
Syscall.PRINT_S -> {
var addr = vm.registers.getUW(0).toInt()
var addr = vm.registers.getUW(SyscallRegisterBase).toInt()
while(true) {
val char = vm.memory.getUB(addr).toInt()
if(char==0)
@ -107,21 +109,21 @@ object SysCalls {
}
}
Syscall.PRINT_U8 -> {
print(vm.registers.getUB(0))
print(vm.registers.getUB(SyscallRegisterBase))
}
Syscall.PRINT_U16 -> {
print(vm.registers.getUW(0))
print(vm.registers.getUW(SyscallRegisterBase))
}
Syscall.INPUT -> {
var input = readln()
val maxlen = vm.registers.getUB(1).toInt()
val maxlen = vm.registers.getUB(SyscallRegisterBase+1).toInt()
if(maxlen>0)
input = input.substring(0, min(input.length, maxlen))
vm.memory.setString(vm.registers.getUW(0).toInt(), input, true)
vm.memory.setString(vm.registers.getUW(SyscallRegisterBase).toInt(), input, true)
vm.registers.setUW(0, input.length.toUShort())
}
Syscall.SLEEP -> {
val duration = vm.registers.getUW(0).toLong()
val duration = vm.registers.getUW(SyscallRegisterBase).toLong()
Thread.sleep(duration)
}
Syscall.GFX_ENABLE -> vm.gfx_enable()
@ -129,13 +131,13 @@ object SysCalls {
Syscall.GFX_PLOT -> vm.gfx_plot()
Syscall.GFX_GETPIXEL ->vm.gfx_getpixel()
Syscall.WAIT -> {
val millis = vm.registers.getUW(0).toLong() * 1000/60
val millis = vm.registers.getUW(SyscallRegisterBase).toLong() * 1000/60
Thread.sleep(millis)
}
Syscall.WAITVSYNC -> vm.waitvsync()
Syscall.SORT_UBYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.sorted()
@ -144,8 +146,8 @@ object SysCalls {
}
}
Syscall.SORT_BYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getSB(it)
}.sorted()
@ -154,8 +156,8 @@ object SysCalls {
}
}
Syscall.SORT_UWORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.sorted()
@ -164,8 +166,8 @@ object SysCalls {
}
}
Syscall.SORT_WORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getSW(it)
}.sorted()
@ -174,8 +176,8 @@ object SysCalls {
}
}
Syscall.REVERSE_BYTES -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length-1, 1).map {
vm.memory.getUB(it)
}.reversed()
@ -184,8 +186,8 @@ object SysCalls {
}
}
Syscall.REVERSE_WORDS -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*2-2, 2).map {
vm.memory.getUW(it)
}.reversed()
@ -194,8 +196,8 @@ object SysCalls {
}
}
Syscall.REVERSE_FLOATS -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val array = IntProgression.fromClosedRange(address, address+length*4-2, 4).map {
vm.memory.getFloat(it)
}.reversed()
@ -204,8 +206,8 @@ object SysCalls {
}
}
Syscall.ANY_BYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.any { vm.memory.getUB(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -213,8 +215,8 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.ANY_WORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.any { vm.memory.getUW(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -222,8 +224,8 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.ANY_FLOAT -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4)
if(addresses.any { vm.memory.getFloat(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -231,8 +233,8 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.ALL_BYTE -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.all { vm.memory.getUB(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -240,8 +242,8 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.ALL_WORD -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
if(addresses.all { vm.memory.getUW(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -249,8 +251,8 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.ALL_FLOAT -> {
val address = vm.registers.getUW(0).toInt()
val length = vm.registers.getUB(1).toInt()
val address = vm.registers.getUW(SyscallRegisterBase).toInt()
val length = vm.registers.getUB(SyscallRegisterBase+1).toInt()
val addresses = IntProgression.fromClosedRange(address, address+length*4-2, 4)
if(addresses.all { vm.memory.getFloat(it).toInt()!=0 })
vm.registers.setUB(0, 1u)
@ -258,11 +260,11 @@ object SysCalls {
vm.registers.setUB(0, 0u)
}
Syscall.PRINT_F -> {
val value = vm.registers.getFloat(0)
val value = vm.registers.getFloat(SyscallRegisterBase)
print(value)
}
Syscall.STR_TO_UWORD -> {
val stringAddr = vm.registers.getUW(0)
val stringAddr = vm.registers.getUW(SyscallRegisterBase)
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
val value = try {
string.toUShort()
@ -272,7 +274,7 @@ object SysCalls {
vm.registers.setUW(0, value)
}
Syscall.STR_TO_WORD -> {
val stringAddr = vm.registers.getUW(0)
val stringAddr = vm.registers.getUW(SyscallRegisterBase)
val string = vm.memory.getString(stringAddr.toInt()).takeWhile { it.isDigit() }
val value = try {
string.toShort()
@ -282,8 +284,8 @@ object SysCalls {
vm.registers.setSW(0, value)
}
Syscall.COMPARE_STRINGS -> {
val firstAddr = vm.registers.getUW(0)
val secondAddr = vm.registers.getUW(1)
val firstAddr = vm.registers.getUW(SyscallRegisterBase)
val secondAddr = vm.registers.getUW(SyscallRegisterBase+1)
val first = vm.memory.getString(firstAddr.toInt())
val second = vm.memory.getString(secondAddr.toInt())
val comparison = first.compareTo(second)
@ -295,14 +297,14 @@ object SysCalls {
vm.registers.setSB(0, 1)
}
Syscall.RNDFSEED -> {
val seed1 = vm.registers.getUB(0)
val seed2 = vm.registers.getUB(1)
val seed3 = vm.registers.getUB(2)
val seed1 = vm.registers.getUB(SyscallRegisterBase)
val seed2 = vm.registers.getUB(SyscallRegisterBase+1)
val seed3 = vm.registers.getUB(SyscallRegisterBase+2)
vm.randomSeedFloat(seed1, seed2, seed3)
}
Syscall.RNDSEED -> {
val seed1 = vm.registers.getUW(0)
val seed2 = vm.registers.getUW(1)
val seed1 = vm.registers.getUW(SyscallRegisterBase)
val seed2 = vm.registers.getUW(SyscallRegisterBase+1)
vm.randomSeed(seed1, seed2)
}
Syscall.RND -> {
@ -315,15 +317,15 @@ object SysCalls {
vm.registers.setFloat(0, vm.randomGeneratorFloats.nextFloat())
}
Syscall.STRING_CONTAINS -> {
val char = vm.registers.getUB(0).toInt().toChar()
val stringAddr = vm.registers.getUW(1)
val char = vm.registers.getUB(SyscallRegisterBase).toInt().toChar()
val stringAddr = vm.registers.getUW(SyscallRegisterBase+1)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setUB(0, if(char in string) 1u else 0u)
}
Syscall.BYTEARRAY_CONTAINS -> {
val value = vm.registers.getUB(0)
var array = vm.registers.getUW(1).toInt()
var length = vm.registers.getUB(2)
val value = vm.registers.getUB(SyscallRegisterBase)
var array = vm.registers.getUW(SyscallRegisterBase+1).toInt()
var length = vm.registers.getUB(SyscallRegisterBase+2)
while(length>0u) {
if(vm.memory.getUB(array)==value) {
vm.registers.setUB(0, 1u)
@ -336,9 +338,9 @@ object SysCalls {
}
Syscall.WORDARRAY_CONTAINS -> {
// r0.w = value, r1.w = array, r2.b = array length
val value = vm.registers.getUW(0)
var array = vm.registers.getUW(1).toInt()
var length = vm.registers.getUB(2)
val value = vm.registers.getUW(SyscallRegisterBase)
var array = vm.registers.getUW(SyscallRegisterBase+1).toInt()
var length = vm.registers.getUB(SyscallRegisterBase+2)
while(length>0u) {
if(vm.memory.getUW(array)==value) {
vm.registers.setUB(0, 1u)

View File

@ -92,8 +92,8 @@ class VirtualMachine(irProgram: IRProgram) {
statusZero = false
}
fun exit() {
throw ProgramExitException(registers.getUW(0).toInt())
fun exit(statuscode: Int) {
throw ProgramExitException(statuscode)
}
fun step(count: Int=1) {
@ -118,7 +118,7 @@ class VirtualMachine(irProgram: IRProgram) {
}
null -> {
exit() // end of program reached
exit(0) // end of program reached
}
else -> {
@ -574,7 +574,7 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsRETURN() {
if(callStack.isEmpty())
exit()
exit(0)
else {
val (chunk, idx) = callStack.pop()
pcChunk = chunk
@ -2108,7 +2108,7 @@ class VirtualMachine(irProgram: IRProgram) {
private var window: GraphicsWindow? = null
fun gfx_enable() {
window = when(registers.getUB(0).toInt()) {
window = when(registers.getUB(SyscallRegisterBase).toInt()) {
0 -> GraphicsWindow(320, 240, 3)
1 -> GraphicsWindow(640, 480, 2)
else -> throw IllegalArgumentException("invalid screen mode")
@ -2117,18 +2117,21 @@ class VirtualMachine(irProgram: IRProgram) {
}
fun gfx_clear() {
window?.clear(registers.getUB(0).toInt())
window?.clear(registers.getUB(SyscallRegisterBase).toInt())
}
fun gfx_plot() {
window?.plot(registers.getUW(0).toInt(), registers.getUW(1).toInt(), registers.getUB(2).toInt())
window?.plot(registers.getUW(SyscallRegisterBase).toInt(),
registers.getUW(SyscallRegisterBase+1).toInt(),
registers.getUB(SyscallRegisterBase+2).toInt())
}
fun gfx_getpixel() {
if(window==null)
registers.setUB(0, 0u)
else {
val color = Color(window!!.getpixel(registers.getUW(0).toInt(), registers.getUW(1).toInt()))
val color = Color(window!!.getpixel(registers.getUW(SyscallRegisterBase).toInt(),
registers.getUW(SyscallRegisterBase+1).toInt()))
registers.setUB(0, color.green.toUByte())
}
}