remove syscall() builtin functions

vm code can do this via inline assembly
This commit is contained in:
Irmen de Jong 2022-05-01 00:09:03 +02:00
parent 0ee790969d
commit b32641db87
10 changed files with 177 additions and 198 deletions

View File

@ -119,7 +119,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
"cmp" -> funcCmp(fcall)
"callfar" -> funcCallFar(fcall)
"callrom" -> funcCallRom(fcall)
"syscall", "syscall1", "syscall2", "syscall3", "syscall1fp" -> throw AssemblyError("6502 assembly target doesn't use syscall function interface")
else -> throw AssemblyError("missing asmgen for builtin func ${func.name}")
}
}

View File

@ -5,7 +5,6 @@ import prog8.code.ast.*
import prog8.code.core.ArrayToElementTypes
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.WordDatatypes
import prog8.vm.Opcode
import prog8.vm.Syscall
import prog8.vm.VmDataType
@ -32,11 +31,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"rndw" -> funcRndw(resultRegister)
"callfar" -> throw AssemblyError("callfar() is for cx16 target only")
"callrom" -> throw AssemblyError("callrom() is for cx16 target only")
"syscall" -> funcSyscall(call)
"syscall1" -> funcSyscall1(call)
"syscall2" -> funcSyscall2(call)
"syscall3" -> funcSyscall3(call)
"syscall1fp" -> funcSyscall1fp(call)
"msb" -> funcMsb(call, resultRegister)
"lsb" -> funcLsb(call, resultRegister)
"memory" -> funcMemory(call, resultRegister)
@ -350,60 +344,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code
}
private fun funcSyscall(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val vExpr = call.args.single() as PtNumber
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
return code
}
private fun funcSyscall1(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0, -1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
return code
}
private fun funcSyscall1fp(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], -1, 0)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
return code
}
private fun funcSyscall2(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
while(codeGen.vmRegisters.peekNext()<2) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0, -1)
code += exprGen.translateExpression(call.args[2], 1, -1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
return code
}
private fun funcSyscall3(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
while(codeGen.vmRegisters.peekNext()<3) {
codeGen.vmRegisters.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0, -1)
code += exprGen.translateExpression(call.args[2], 1, -1)
code += exprGen.translateExpression(call.args[3], 2, -1)
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
return code
}
private fun funcRolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk()

View File

@ -19,84 +19,130 @@ sub print_f(float value) {
}
sub pow(float value, float power) -> float {
; TODO
return -42.42
; TODO fpow.f instruction
%asm {{
loadm.f fr0,{floats.pow.value}
loadm.f fr1,{floats.pow.power}
fpow.f fr0,fr0
return
}}
}
sub fabs(float value) -> float {
; TODO
return -42.42
; TODO fabs.f instruction
%asm {{
loadm.f fr0,{floats.fabs.value}
fabs.f fr0,fr0
return
}}
}
sub sin(float angle) -> float {
; TODO sin.f instruction
; TODO fsin.f instruction
%asm {{
loadm.f fr0,{floats.sin.angle}
sin.f fr0,fr0
fsin.f fr0,fr0
return
}}
}
sub cos(float angle) -> float {
; TODO
return -42.42
; TODO fcos.f instruction
%asm {{
loadm.f fr0,{floats.cos.angle}
fcos.f fr0,fr0
return
}}
}
sub tan(float value) -> float {
; TODO
return -42.42
; TODO ftan.f instruction
%asm {{
loadm.f fr0,{floats.tan.value}
ftan.f fr0,fr0
return
}}
}
sub atan(float value) -> float {
; TODO
return -42.42
; TODO fatan.f instruction
%asm {{
loadm.f fr0,{floats.atan.value}
fatan.f fr0,fr0
return
}}
}
sub ln(float value) -> float {
; TODO
return -42.42
; TODO fln.f instruction
%asm {{
loadm.f fr0,{floats.ln.value}
fln.f fr0,fr0
return
}}
}
sub log2(float value) -> float {
; TODO
return -42.42
; TODO flog2.f instruction
%asm {{
loadm.f fr0,{floats.log2.value}
flog2.f fr0,fr0
return
}}
}
sub sqrt(float value) -> float {
; TODO
return -42.42
; TODO fsqrt.f instruction
%asm {{
loadm.f fr0,{floats.sqrt.value}
fsqrt.f fr0,fr0
return
}}
}
sub rad(float angle) -> float {
; -- convert degrees to radians (d * pi / 180)
; TODO
return -42.42
return angle * PI / 180.0
}
sub deg(float angle) -> float {
; -- convert radians to degrees (d * (1/ pi * 180))
; TODO
return -42.42
return angle * 180.0 / PI
}
sub round(float value) -> float {
; TODO
return -42.42
; TODO fround.f instruction
%asm {{
loadm.f fr0,{floats.round.value}
fround.f fr0,fr0
return
}}
}
sub floor(float value) -> float {
; TODO
return -42.42
; TODO ffloor.f instruction
%asm {{
loadm.f fr0,{floats.floor.value}
ffloor.f fr0,fr0
return
}}
}
sub ceil(float value) -> float {
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
; TODO
return -42.42
; TODO fceil.f instruction
%asm {{
loadm.f fr0,{floats.ceil.value}
fceil.f fr0,fr0
return
}}
}
sub rndf() -> float {
; TODO
return -42.42
; TODO frnd.f instruction
%asm {{
frnd.f fr0
return
}}
}
}

View File

@ -8,74 +8,26 @@ sys {
const ubyte target = 255 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL, 255 = virtual
; Syscalls table, taken from Syscall enumeration
; 0 = reset ; resets system
; 1 = exit ; stops program and returns statuscode from r0.w
; 2 = print_c ; print single character
; 3 = print_s ; print 0-terminated string from memory
; 4 = print_u8 ; print unsigned int byte
; 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 r0.w
; 7 = sleep ; sleep amount of milliseconds
; 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
; 10 = gfx_plot ; plot pixel in graphics window, r0.w/r1.w contain X and Y coordinates, r2.b contains brightness
; 11 = set_carry status flag
; 12 = clear_carry status flag
; 13 = wait ; wait certain amount of jiffies (1/60 sec)
; 14 = waitvsync ; wait on vsync
; 15 = sort_ubyte array
; 16 = sort_byte array
; 17 = sort_uword array
; 18 = sort_word array
; 19 = max_ubyte array
; 20 = max_byte array
; 21 = max_uword array
; 22 = max_word array
; 23 = min_ubyte array
; 24 = min_byte array
; 25 = min_uword array
; 26 = min_word array
; 27 = sum_byte array
; 28 = sum_word array
; 29 = any_byte array
; 30 = any_word array
; 31 = all_byte array
; 32 = all_word array
; 33 = reverse_bytes array
; 34 = reverse_words array
; 35 = printf (float arg in fpReg0)
const ubyte SC_RESET = 0
const ubyte SC_EXIT = 1
const ubyte SC_PRINT_C = 2
const ubyte SC_PRINT_S = 3
const ubyte SC_PRINT_U8 = 4
const ubyte SC_PRINT_U16 = 5
const ubyte SC_INPUT = 6
const ubyte SC_SLEEP = 7
const ubyte SC_GFX_ENABLE = 8
const ubyte SC_GFX_CLEAR = 9
const ubyte SC_GFX_PLOT = 10
const ubyte SC_SET_CARRY = 11
const ubyte SC_CLEAR_CARRY = 12
const ubyte SC_WAIT = 13
const ubyte SC_WAITVSYNC = 14
const ubyte SC_PRINTF = 35
sub reset_system() {
; Soft-reset the system back to initial power-on Basic prompt.
void syscall(SC_RESET)
%asm {{
syscall 0
}}
}
sub wait(uword jiffies) {
; --- wait approximately the given number of jiffies (1/60th seconds)
void syscall1(SC_WAIT, jiffies)
%asm {{
loadm.w r0, {sys.wait.jiffies}
syscall 13
}}
}
sub waitvsync() {
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
void syscall(SC_WAITVSYNC)
%asm {{
syscall 14
}}
}
sub internal_stringcopy(uword source, uword target) {
@ -112,15 +64,39 @@ sys {
sub exit(ubyte returnvalue) {
; -- immediately exit the program with a return code in the A register
void syscall1(SC_EXIT, returnvalue)
}
sub clear_carry() {
void syscall(SC_CLEAR_CARRY)
%asm {{
loadm.b r0,{sys.exit.returnvalue}
syscall 1
}}
}
sub set_carry() {
void syscall(SC_SET_CARRY)
%asm {{
sec
}}
}
sub clear_carry() {
%asm {{
clc
}}
}
sub gfx_enable(ubyte mode) {
%asm {{
loadm.b r0, {sys.gfx_enable.mode}
syscall 8
}}
}
sub gfx_plot(uword xx, uword yy, ubyte color) {
%asm {{
loadm.w r0, {sys.gfx_plot.xx}
loadm.w r1, {sys.gfx_plot.yy}
loadm.b r2, {sys.gfx_plot.color}
syscall 10
}}
}
}

View File

@ -7,7 +7,11 @@
txt {
sub clear_screen() {
void syscall1(3, "\x1b[2J\x1B[H")
str @shared sequence = "\x1b[2J\x1B[H"
%asm {{
load.w r0, {txt.clear_screen.sequence}
syscall 3
}}
}
sub nl() {
@ -27,11 +31,17 @@ sub uppercase() {
}
sub chrout(ubyte char) {
void syscall1(2, char)
%asm {{
loadm.b r0, {txt.chrout.char}
syscall 2
}}
}
sub print (str text) {
void syscall1(3, text)
%asm {{
loadm.w r0, {txt.print.text}
syscall 3
}}
}
sub print_ub0 (ubyte value) {
@ -105,7 +115,11 @@ sub print_w (word value) {
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!
return syscall1(6, buffer)
%asm {{
loadm.w r0,{txt.input_chars.buffer}
syscall 6
return
}}
}
}

View File

@ -123,11 +123,6 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
FSignature("syscall" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE))), DataType.UWORD, null),
FSignature("syscall1" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD))), DataType.UWORD, null),
FSignature("syscall1fp" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.FLOAT))), DataType.FLOAT, null),
FSignature("syscall2" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD))), 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))), DataType.UWORD, null),
)
val BuiltinFunctions = functionSignatures.associateBy { it.name }

View File

@ -3,7 +3,7 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: get rid of the syscall() functions in prog8 via inline assembly
- vm: fix fp reg out of bounds
- vm: implement missing floating point functions
- vm: get rid of intermediate floats.xxx() functions somehow, instead generate the float instructions directly?
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.

View File

@ -8,14 +8,23 @@
main {
sub start() {
txt.print("float tests: ")
floats.print_f(-42.42)
float f1 = 1.2345
float f2 = -9.99
float f3
f3 = floats.sin(f3)
floats.print_f(f3)
txt.nl()
float fl = 500.0
txt.print("rad 180 = ")
floats.print_f(floats.rad(180.0))
txt.print("rad 360 = ")
floats.print_f(floats.rad(360.0))
txt.print("deg 2 = ")
floats.print_f(floats.deg(2.0))
txt.print("deg pi = ")
floats.print_f(floats.deg(floats.PI))
sys.exit(42)
; floats.print_f(-42.42)
; float f1 = 1.2345
; float f2 = -9.99
; float f3
; f3 = floats.sin(f3)
; floats.print_f(f3)
; txt.nl()
; float f1 = 1.555
; floats.print_f(floats.sin(f1))
@ -49,23 +58,21 @@ main {
; "deg", "round", "floor", "ceil", "rndf"
; a "pixelshader":
; void syscall1(8, 0) ; enable lo res creen
; ubyte shifter
;
; ; pokemon(1,0)
;
; repeat {
; uword xx
; uword yy = 0
; repeat 240 {
; xx = 0
; repeat 320 {
; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel
; xx++
; }
; yy++
; }
; shifter+=4
; }
sys.gfx_enable(0) ; enable lo res screen
ubyte shifter
repeat {
uword xx
uword yy = 0
repeat 240 {
xx = 0
repeat 320 {
sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
xx++
}
yy++
}
shifter+=4
}
}
}

View File

@ -16,8 +16,8 @@ SYSCALLS:
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
10 = gfx_plot ; plot pixel in graphics window, r0.w/r1.w contain X and Y coordinates, r2.b contains brightness
11 = set_carry status flag
12 = clear_carry status flag
11 = <unused 1>
12 = <unused 2>
13 = wait ; wait certain amount of jiffies (1/60 sec)
14 = waitvsync ; wait on vsync
15 = sort_ubyte array
@ -55,8 +55,8 @@ enum class Syscall {
GFX_ENABLE,
GFX_CLEAR,
GFX_PLOT,
SET_CARRY,
CLEAR_CARRY,
UNUSED_1,
UNUSED_2,
WAIT,
WAITVSYNC,
SORT_UBYTE,
@ -297,8 +297,6 @@ object SysCalls {
else
vm.registers.setUB(0, 0u)
}
Syscall.SET_CARRY -> vm.statusCarry = true
Syscall.CLEAR_CARRY -> vm.statusCarry = false
Syscall.PRINT_F -> {
val value = vm.registers.getFloat(0)
print(value)

View File

@ -61,11 +61,13 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
fun reset() {
registers.reset()
memory.reset()
// memory.reset()
pc = 0
stepCount = 0
callStack.clear()
statusCarry = false
statusNegative = false
statusZero = false
}
fun exit() {
@ -168,6 +170,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.PUSH -> InsPUSH(ins)
Opcode.POP -> InsPOP(ins)
Opcode.BREAKPOINT -> InsBREAKPOINT()
Opcode.CLC -> { statusCarry = false; pc++ }
Opcode.SEC -> { statusCarry = true; pc++ }
else -> throw IllegalArgumentException("invalid opcode ${ins.opcode}")
}
}