mirror of
https://github.com/irmen/prog8.git
synced 2025-02-27 03:29:22 +00:00
ir syscalls args via stack instead of fixed r65500+
This commit is contained in:
parent
9b37ac483f
commit
dd1592b03b
@ -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)
|
||||
|
@ -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}")
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
@ -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
|
||||
}}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
...
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,5 +23,3 @@ enum class IMSyscall(val number: Int) {
|
||||
BYTEARRAY_CONTAINS(10015),
|
||||
WORDARRAY_CONTAINS(10016)
|
||||
}
|
||||
|
||||
const val SyscallRegisterBase = 65500
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user