mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
vm: implemented Pipe expression
This commit is contained in:
parent
9874fe2c23
commit
d616cb283b
@ -107,6 +107,9 @@ class PtPipe(type: DataType, val void: Boolean, position: Position) : PtExpressi
|
||||
require(type!=DataType.UNDEFINED)
|
||||
}
|
||||
|
||||
val segments: List<PtExpression>
|
||||
get() = children.map { it as PtExpression }
|
||||
|
||||
override fun printProperties() {}
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,18 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
code += exprGen.translateExpression(call.args[1], lsbReg)
|
||||
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
|
||||
}
|
||||
"sin8u" -> {
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.SIN8U.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
}
|
||||
"cos8u" -> {
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.COS8U.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
}
|
||||
else -> {
|
||||
TODO("builtinfunc ${call.name}")
|
||||
// code += VmCodeInstruction(Opcode.NOP))
|
||||
|
@ -16,22 +16,30 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
||||
|
||||
val code = VmCodeChunk()
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
|
||||
when (expr) {
|
||||
is PtNumber -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val mem = codeGen.allocations.get(expr.targetName)
|
||||
code += if(expr.type in PassByValueDatatypes) {
|
||||
VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem)
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
if(expr.targetName[0].startsWith(":vmreg-")) {
|
||||
// special direct reference to a register in the VM
|
||||
val reg = expr.targetName[0].substring(7).toInt()
|
||||
code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=reg)
|
||||
} else {
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
||||
val mem = codeGen.allocations.get(expr.targetName)
|
||||
code += if (expr.type in PassByValueDatatypes) {
|
||||
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
|
||||
} else {
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
|
||||
}
|
||||
}
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val mem = codeGen.allocations.get(expr.identifier.targetName)
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
||||
}
|
||||
@ -57,7 +65,41 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
}
|
||||
|
||||
internal fun translate(pipe: PtPipe, resultRegister: Int): VmCodeChunk {
|
||||
TODO("Not yet implemented: pipe expression")
|
||||
val segments = pipe.segments
|
||||
var valueDt = segments[0].type
|
||||
var valueReg = if(pipe.void) codeGen.vmRegisters.nextFree() else resultRegister
|
||||
|
||||
fun addImplicitArgToSegment(segment: PtExpression, sourceReg: Int, sourceDt: DataType): PtExpression {
|
||||
return when (segment) {
|
||||
is PtFunctionCall -> {
|
||||
val segWithArg = PtFunctionCall(segment.functionName, segment.void, segment.type, segment.position)
|
||||
segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position))
|
||||
segWithArg
|
||||
}
|
||||
is PtBuiltinFunctionCall -> {
|
||||
val segWithArg = PtBuiltinFunctionCall(segment.name, segment.void, segment.type, segment.position)
|
||||
segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position))
|
||||
segWithArg
|
||||
}
|
||||
else -> throw AssemblyError("weird segment type")
|
||||
}
|
||||
}
|
||||
|
||||
val code = VmCodeChunk()
|
||||
code += translateExpression(segments[0], valueReg)
|
||||
for (segment in segments.subList(1, segments.size-1)) {
|
||||
val sourceReg = valueReg
|
||||
val sourceDt = valueDt
|
||||
if(segment.type!=valueDt) {
|
||||
valueDt = segment.type
|
||||
valueReg = codeGen.vmRegisters.nextFree()
|
||||
}
|
||||
val segmentWithImplicitArgument = addImplicitArgToSegment(segment, sourceReg, sourceDt)
|
||||
code += translateExpression(segmentWithImplicitArgument, valueReg)
|
||||
}
|
||||
val segWithArg = addImplicitArgToSegment(segments.last(), valueReg, valueDt)
|
||||
code += translateExpression(segWithArg, resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk {
|
||||
|
@ -211,8 +211,14 @@ class IntermediateAstMaker(val program: Program) {
|
||||
|
||||
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
|
||||
val (target, _) = targetOf(srcCall.target)
|
||||
val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
||||
val call = PtFunctionCall(target, false, type, srcCall.position)
|
||||
val type = srcCall.inferType(program).getOrElse {
|
||||
if((srcCall.parent as? Pipe)?.segments?.last() === srcCall)
|
||||
// for a pipe, the last segment is allowed to be a call to a function not returning anything.
|
||||
DataType.UNDEFINED
|
||||
else
|
||||
throw FatalAstException("unknown dt $srcCall")
|
||||
}
|
||||
val call = PtFunctionCall(target, type==DataType.UNDEFINED, type, srcCall.position)
|
||||
for (arg in srcCall.args)
|
||||
call.add(transformExpression(arg))
|
||||
return call
|
||||
@ -291,8 +297,7 @@ class IntermediateAstMaker(val program: Program) {
|
||||
PtLabel(label.name, label.position)
|
||||
|
||||
private fun transform(srcPipe: Pipe): PtPipe {
|
||||
val type = srcPipe.segments.last().inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
||||
val pipe = PtPipe(type, true, srcPipe.position)
|
||||
val pipe = PtPipe(DataType.UNDEFINED, true, srcPipe.position)
|
||||
pipe.add(transformExpression(srcPipe.source))
|
||||
for (segment in srcPipe.segments)
|
||||
pipe.add(transformExpression(segment))
|
||||
|
@ -3,8 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- vm codegen: Pipe expression
|
||||
- vm: support no globals re-init option
|
||||
- vm: make registers typed? so that it's immediately obvious what type they represent. Much like regular variables in memory.
|
||||
- vm codegen/assembler: variable memory locations should also be referenced by the variable name instead of just the address, to make the output more human-readable
|
||||
- vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us)
|
||||
- vm: rather than being able to jump to any 'address' (IPTR), use 'blocks' that have entry and exit points -> even better dead code elimination possible too
|
||||
|
@ -5,32 +5,30 @@
|
||||
|
||||
main {
|
||||
|
||||
sub calculate(ubyte value) -> uword {
|
||||
when value {
|
||||
1 -> return "one"
|
||||
2 -> return "two"
|
||||
3 -> return "three"
|
||||
4,5,6 -> return "four to six"
|
||||
else -> return "other"
|
||||
}
|
||||
sub func1(ubyte arg1) -> uword {
|
||||
return arg1 * 3
|
||||
}
|
||||
|
||||
sub func2(uword arg1) -> uword {
|
||||
return arg1+1000
|
||||
}
|
||||
|
||||
sub func3(uword arg1) {
|
||||
txt.print_uw(arg1+2000)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub start() {
|
||||
|
||||
txt.print(calculate(0))
|
||||
ubyte source = 99
|
||||
|
||||
uword result = func2(func1(cos8u(sin8u(source))))
|
||||
txt.print_uw(result) ; 1043
|
||||
txt.nl()
|
||||
txt.print(calculate(1))
|
||||
txt.nl()
|
||||
txt.print(calculate(2))
|
||||
txt.nl()
|
||||
txt.print(calculate(3))
|
||||
txt.nl()
|
||||
txt.print(calculate(4))
|
||||
txt.nl()
|
||||
txt.print(calculate(5))
|
||||
txt.nl()
|
||||
txt.print(calculate(50))
|
||||
result = source |> sin8u() |> cos8u() |> func1() |> func2()
|
||||
txt.print_uw(result) ; 1043
|
||||
txt.nl()
|
||||
source |> sin8u() |> cos8u() |> func1() |> func3() ; 2043
|
||||
|
||||
; a "pixelshader":
|
||||
; syscall1(8, 0) ; enable lo res creen
|
||||
|
@ -1,6 +1,6 @@
|
||||
package prog8.vm
|
||||
|
||||
import kotlin.math.min
|
||||
import kotlin.math.*
|
||||
import kotlin.random.Random
|
||||
|
||||
/*
|
||||
@ -20,6 +20,8 @@ SYSCALLS:
|
||||
11 = rnd ; random BYTE
|
||||
12 = wait ; wait certain amount of jiffies (1/60 sec)
|
||||
13 = waitvsync ; wait on vsync
|
||||
14 = sin8u
|
||||
15 = cos8u
|
||||
*/
|
||||
|
||||
enum class Syscall {
|
||||
@ -37,7 +39,8 @@ enum class Syscall {
|
||||
RND,
|
||||
WAIT,
|
||||
WAITVSYNC,
|
||||
TMP_PRINT_UW
|
||||
SIN8U,
|
||||
COS8U
|
||||
}
|
||||
|
||||
object SysCalls {
|
||||
@ -92,8 +95,17 @@ object SysCalls {
|
||||
Thread.sleep(millis)
|
||||
}
|
||||
Syscall.WAITVSYNC -> vm.waitvsync()
|
||||
Syscall.TMP_PRINT_UW -> {
|
||||
println("VM: UW=${vm.registers.getUW(0)}")
|
||||
Syscall.SIN8U -> {
|
||||
val arg = vm.registers.getUB(0).toDouble()
|
||||
val rad = arg /256.0 * 2.0 * PI
|
||||
val answer = truncate(128.0 + 127.5 * sin(rad))
|
||||
vm.registers.setUB(0, answer.toUInt().toUByte())
|
||||
}
|
||||
Syscall.COS8U -> {
|
||||
val arg = vm.registers.getUB(0).toDouble()
|
||||
val rad = arg /256.0 * 2.0 * PI
|
||||
val answer = truncate(128.0 + 127.5 * cos(rad))
|
||||
vm.registers.setUB(0, answer.toUInt().toUByte())
|
||||
}
|
||||
else -> TODO("syscall ${call.name}")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user