vm: syscalls can now return value

This commit is contained in:
Irmen de Jong 2022-04-05 20:46:34 +02:00
parent 461b38e653
commit a8cf9f5cc4
7 changed files with 34 additions and 53 deletions

View File

@ -1,13 +1,11 @@
package prog8.codegen.virtual package prog8.codegen.virtual
import prog8.code.StArray
import prog8.code.StStaticVariable import prog8.code.StStaticVariable
import prog8.code.ast.PtBuiltinFunctionCall import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtIdentifier import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber import prog8.code.ast.PtNumber
import prog8.code.ast.PtString import prog8.code.ast.PtString
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.code.core.WordDatatypes
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.Syscall import prog8.vm.Syscall
import prog8.vm.VmDataType import prog8.vm.VmDataType
@ -22,14 +20,11 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt()) code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
} }
"syscall1" -> { "syscall1" -> {
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
val callNr = (call.args[0] as PtNumber).number.toInt() val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0) code += exprGen.translateExpression(call.args[1], 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
} }
"syscall2" -> { "syscall2" -> {
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1) code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
while(codeGen.vmRegisters.peekNext()<2) { while(codeGen.vmRegisters.peekNext()<2) {
codeGen.vmRegisters.nextFree() codeGen.vmRegisters.nextFree()
@ -39,10 +34,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += exprGen.translateExpression(call.args[2], 1) code += exprGen.translateExpression(call.args[2], 1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1) code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
} }
"syscall3" -> { "syscall3" -> {
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1) code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2) code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
while(codeGen.vmRegisters.peekNext()<3) { while(codeGen.vmRegisters.peekNext()<3) {
@ -55,7 +48,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr) code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2) code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1) code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
} }
"msb" -> { "msb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister) code += exprGen.translateExpression(call.args.single(), resultRegister)

View File

@ -39,17 +39,17 @@ sys {
sub reset_system() { sub reset_system() {
; Soft-reset the system back to initial power-on Basic prompt. ; Soft-reset the system back to initial power-on Basic prompt.
syscall(SC_RESET) void syscall(SC_RESET)
} }
sub wait(uword jiffies) { sub wait(uword jiffies) {
; --- wait approximately the given number of jiffies (1/60th seconds) ; --- wait approximately the given number of jiffies (1/60th seconds)
syscall1(SC_WAIT, jiffies) void syscall1(SC_WAIT, jiffies)
} }
sub waitvsync() { sub waitvsync() {
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
syscall(SC_WAITVSYNC) void syscall(SC_WAITVSYNC)
} }
sub memcopy(uword source, uword target, uword count) { sub memcopy(uword source, uword target, uword count) {
@ -76,7 +76,7 @@ sys {
sub exit(ubyte returnvalue) { sub exit(ubyte returnvalue) {
; -- immediately exit the program with a return code in the A register ; -- immediately exit the program with a return code in the A register
syscall1(SC_EXIT, returnvalue) void syscall1(SC_EXIT, returnvalue)
} }
} }

View File

@ -8,7 +8,7 @@
txt { txt {
sub clear_screen() { sub clear_screen() {
syscall1(3, "\x1b[2J\x1B[H") void syscall1(3, "\x1b[2J\x1B[H")
} }
sub nl() { sub nl() {
@ -28,11 +28,11 @@ sub uppercase() {
} }
sub chrout(ubyte char) { sub chrout(ubyte char) {
syscall1(2, char) void syscall1(2, char)
} }
sub print (str text) { sub print (str text) {
syscall1(3, text) void syscall1(3, text)
} }
sub print_ub0 (ubyte value) { sub print_ub0 (ubyte value) {
@ -164,8 +164,7 @@ sub print_w (word value) {
sub input_chars (uword buffer) -> ubyte { 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) ; ---- 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! ; It assumes the keyboard is selected as I/O channel!
; TODO return syscall1(6, buffer)
return 0
} }
} }

View File

@ -166,10 +166,10 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), false, null), FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), false, null),
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null), FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null), FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
FSignature("syscall" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE))), false, null, null), FSignature("syscall" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE))), true, DataType.UWORD, null),
FSignature("syscall1" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD))), false, null, null), FSignature("syscall1" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
FSignature("syscall2" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD))), false, null, null), FSignature("syscall2" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
FSignature("syscall3" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD)), FParam("arg3", arrayOf(DataType.UWORD))), false, null, null), FSignature("syscall3" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD)), FParam("arg3", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
) )
val BuiltinFunctions = functionSignatures.associateBy { it.name } val BuiltinFunctions = functionSignatures.associateBy { it.name }

View File

@ -4,7 +4,7 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
- make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment) - make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment)
but this requires all identifiers in the inlined expression to be changed to fully scoped names. but this requires all identifiers in the inlined expression to be changed to fully scoped names.
@ -48,7 +48,7 @@ Compiler:
Perhaps replace all uses of .proc/.pend by .block/.bend will fix that? Perhaps replace all uses of .proc/.pend by .block/.bend will fix that?
(but we lose the optimizing aspect of the assembler where it strips out unused code. (but we lose the optimizing aspect of the assembler where it strips out unused code.
There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other) There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other)
Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) - Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that)
- add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 - add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256
Libraries: Libraries:
@ -82,6 +82,5 @@ Optimizations:
- AssignmentAsmGen.assignExpression() -> better code gen for assigning boolean comparison expressions - AssignmentAsmGen.assignExpression() -> better code gen for assigning boolean comparison expressions
- when a for loop's loopvariable isn't referenced in the body, and the iterations are known, replace the loop by a repeatloop - when a for loop's loopvariable isn't referenced in the body, and the iterations are known, replace the loop by a repeatloop
but we have no efficient way right now to see if the body references a variable. but we have no efficient way right now to see if the body references a variable.
- AssignmentAsmGen: "real optimized code for comparison expressions that yield a boolean result value"
- automatically convert if statements that test for multiple values (if X==1 or X==2..) to if X in [1,2,..] statements, instead of just a warning. - automatically convert if statements that test for multiple values (if X==1 or X==2..) to if X in [1,2,..] statements, instead of just a warning.
- introduce byte-index operator to avoid index multiplications in loops over arrays? see github issue #4 - introduce byte-index operator to avoid index multiplications in loops over arrays? see github issue #4

View File

@ -5,34 +5,25 @@
; NOTE: meant to test to virtual machine output target (use -target vitual) ; NOTE: meant to test to virtual machine output target (use -target vitual)
main { main {
sub start() { sub start() {
uword[] array = [1111,2222,3333,4444,5555]
txt.print_uw(array[3])
txt.nl()
; a "pixelshader": ; a "pixelshader":
; syscall1(8, 0) ; enable lo res creen void syscall1(8, 0) ; enable lo res creen
; ubyte shifter ubyte shifter
;
; shifter >>= 1 shifter >>= 1
;
; repeat { repeat {
; uword xx uword xx
; uword yy = 0 uword yy = 0
; repeat 240 { repeat 240 {
; xx = 0 xx = 0
; repeat 320 { repeat 320 {
; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
; xx++ xx++
; } }
; yy++ yy++
; } }
; shifter+=4 shifter+=4
; }
; txt.print_ub(shifter)
; txt.nl()
; }
} }
} }

View File

@ -12,7 +12,7 @@ SYSCALLS:
3 = print_s ; print 0-terminated string from memory 3 = print_s ; print 0-terminated string from memory
4 = print_u8 ; print unsigned int byte 4 = print_u8 ; print unsigned int byte
5 = print_u16 ; print unsigned int word 5 = print_u16 ; print unsigned int word
6 = input ; reads a line of text entered by the user, r0.w = memory buffer, r1.b = maxlength (0-255, 0=unlimited). Zero-terminates the string. Returns length in r65535.w 6 = input ; reads a line of text entered by the user, r0.w = memory buffer, r1.b = maxlength (0-255, 0=unlimited). Zero-terminates the string. Returns length in r0.w
7 = sleep ; sleep amount of milliseconds 7 = sleep ; sleep amount of milliseconds
8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480 8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480
9 = gfx_clear ; clear graphics window with shade in r0.b 9 = gfx_clear ; clear graphics window with shade in r0.b
@ -90,7 +90,7 @@ object SysCalls {
if(maxlen>0) if(maxlen>0)
input = input.substring(0, min(input.length, maxlen)) input = input.substring(0, min(input.length, maxlen))
vm.memory.setString(vm.registers.getUW(0).toInt(), input, true) vm.memory.setString(vm.registers.getUW(0).toInt(), input, true)
vm.registers.setUW(65535, input.length.toUShort()) vm.registers.setUW(0, input.length.toUShort())
} }
Syscall.SLEEP -> { Syscall.SLEEP -> {
val duration = vm.registers.getUW(0).toLong() val duration = vm.registers.getUW(0).toLong()