mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +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)
|
require(type!=DataType.UNDEFINED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val segments: List<PtExpression>
|
||||||
|
get() = children.map { it as PtExpression }
|
||||||
|
|
||||||
override fun printProperties() {}
|
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 += exprGen.translateExpression(call.args[1], lsbReg)
|
||||||
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=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 -> {
|
else -> {
|
||||||
TODO("builtinfunc ${call.name}")
|
TODO("builtinfunc ${call.name}")
|
||||||
// code += VmCodeInstruction(Opcode.NOP))
|
// code += VmCodeInstruction(Opcode.NOP))
|
||||||
|
@ -16,22 +16,30 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
||||||
|
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
val vmDt = codeGen.vmType(expr.type)
|
|
||||||
|
|
||||||
when (expr) {
|
when (expr) {
|
||||||
is PtNumber -> {
|
is PtNumber -> {
|
||||||
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
|
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 {
|
||||||
val mem = codeGen.allocations.get(expr.targetName)
|
val mem = codeGen.allocations.get(expr.targetName)
|
||||||
code += if(expr.type in PassByValueDatatypes) {
|
code += if (expr.type in PassByValueDatatypes) {
|
||||||
VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem)
|
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
|
||||||
} else {
|
} else {
|
||||||
// for strings and arrays etc., load the *address* of the value instead
|
// for strings and arrays etc., load the *address* of the value instead
|
||||||
VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
|
val vmDt = codeGen.vmType(expr.type)
|
||||||
val mem = codeGen.allocations.get(expr.identifier.targetName)
|
val mem = codeGen.allocations.get(expr.identifier.targetName)
|
||||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
|
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 {
|
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 {
|
private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk {
|
||||||
|
@ -211,8 +211,14 @@ class IntermediateAstMaker(val program: Program) {
|
|||||||
|
|
||||||
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
|
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
|
||||||
val (target, _) = targetOf(srcCall.target)
|
val (target, _) = targetOf(srcCall.target)
|
||||||
val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
val type = srcCall.inferType(program).getOrElse {
|
||||||
val call = PtFunctionCall(target, false, type, srcCall.position)
|
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)
|
for (arg in srcCall.args)
|
||||||
call.add(transformExpression(arg))
|
call.add(transformExpression(arg))
|
||||||
return call
|
return call
|
||||||
@ -291,8 +297,7 @@ class IntermediateAstMaker(val program: Program) {
|
|||||||
PtLabel(label.name, label.position)
|
PtLabel(label.name, label.position)
|
||||||
|
|
||||||
private fun transform(srcPipe: Pipe): PtPipe {
|
private fun transform(srcPipe: Pipe): PtPipe {
|
||||||
val type = srcPipe.segments.last().inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
val pipe = PtPipe(DataType.UNDEFINED, true, srcPipe.position)
|
||||||
val pipe = PtPipe(type, true, srcPipe.position)
|
|
||||||
pipe.add(transformExpression(srcPipe.source))
|
pipe.add(transformExpression(srcPipe.source))
|
||||||
for (segment in srcPipe.segments)
|
for (segment in srcPipe.segments)
|
||||||
pipe.add(transformExpression(segment))
|
pipe.add(transformExpression(segment))
|
||||||
|
@ -3,8 +3,8 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm codegen: Pipe expression
|
|
||||||
- vm: support no globals re-init option
|
- 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 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: 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
|
- 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 {
|
main {
|
||||||
|
|
||||||
sub calculate(ubyte value) -> uword {
|
sub func1(ubyte arg1) -> uword {
|
||||||
when value {
|
return arg1 * 3
|
||||||
1 -> return "one"
|
|
||||||
2 -> return "two"
|
|
||||||
3 -> return "three"
|
|
||||||
4,5,6 -> return "four to six"
|
|
||||||
else -> return "other"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub func2(uword arg1) -> uword {
|
||||||
|
return arg1+1000
|
||||||
|
}
|
||||||
|
|
||||||
|
sub func3(uword arg1) {
|
||||||
|
txt.print_uw(arg1+2000)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
txt.print(calculate(0))
|
ubyte source = 99
|
||||||
|
|
||||||
|
uword result = func2(func1(cos8u(sin8u(source))))
|
||||||
|
txt.print_uw(result) ; 1043
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print(calculate(1))
|
result = source |> sin8u() |> cos8u() |> func1() |> func2()
|
||||||
txt.nl()
|
txt.print_uw(result) ; 1043
|
||||||
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))
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
source |> sin8u() |> cos8u() |> func1() |> func3() ; 2043
|
||||||
|
|
||||||
; a "pixelshader":
|
; a "pixelshader":
|
||||||
; syscall1(8, 0) ; enable lo res creen
|
; syscall1(8, 0) ; enable lo res creen
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
import kotlin.math.min
|
import kotlin.math.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -20,6 +20,8 @@ SYSCALLS:
|
|||||||
11 = rnd ; random BYTE
|
11 = rnd ; random BYTE
|
||||||
12 = wait ; wait certain amount of jiffies (1/60 sec)
|
12 = wait ; wait certain amount of jiffies (1/60 sec)
|
||||||
13 = waitvsync ; wait on vsync
|
13 = waitvsync ; wait on vsync
|
||||||
|
14 = sin8u
|
||||||
|
15 = cos8u
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum class Syscall {
|
enum class Syscall {
|
||||||
@ -37,7 +39,8 @@ enum class Syscall {
|
|||||||
RND,
|
RND,
|
||||||
WAIT,
|
WAIT,
|
||||||
WAITVSYNC,
|
WAITVSYNC,
|
||||||
TMP_PRINT_UW
|
SIN8U,
|
||||||
|
COS8U
|
||||||
}
|
}
|
||||||
|
|
||||||
object SysCalls {
|
object SysCalls {
|
||||||
@ -92,8 +95,17 @@ object SysCalls {
|
|||||||
Thread.sleep(millis)
|
Thread.sleep(millis)
|
||||||
}
|
}
|
||||||
Syscall.WAITVSYNC -> vm.waitvsync()
|
Syscall.WAITVSYNC -> vm.waitvsync()
|
||||||
Syscall.TMP_PRINT_UW -> {
|
Syscall.SIN8U -> {
|
||||||
println("VM: UW=${vm.registers.getUW(0)}")
|
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}")
|
else -> TODO("syscall ${call.name}")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user