mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
vm: added swap()
This commit is contained in:
parent
ec7501782d
commit
ec6ac5bf24
@ -188,5 +188,13 @@ class PtTypeCast(type: DataType, position: Position) : PtExpression(type, positi
|
||||
}
|
||||
|
||||
|
||||
// special node that isn't created from compiling user code, but used internally
|
||||
class PtMachineRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) {
|
||||
override fun printProperties() {
|
||||
print("reg=$register $type")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun constValue(expr: PtExpression): Double? = if(expr is PtNumber) expr.number else null
|
||||
fun constIntValue(expr: PtExpression): Int? = if(expr is PtNumber) expr.number.toInt() else null
|
||||
|
@ -62,7 +62,7 @@ class PtAssignTarget(position: Position) : PtNode(position) {
|
||||
is PtIdentifier -> tgt.type
|
||||
is PtArrayIndexer -> tgt.type // TODO array to elt type?
|
||||
is PtMemoryByte -> tgt.type
|
||||
else -> throw AssemblyError("weird dt")
|
||||
else -> throw AssemblyError("weird target $tgt")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
"cos8u" -> funcCos8u(call, resultRegister)
|
||||
"sort" -> funcSort(call)
|
||||
"reverse" -> funcReverse(call)
|
||||
"swap" -> funcSwap(call)
|
||||
"rol" -> funcRolRor2(Opcode.ROXL, call, resultRegister)
|
||||
"ror" -> funcRolRor2(Opcode.ROXR, call, resultRegister)
|
||||
"rol2" -> funcRolRor2(Opcode.ROL, call, resultRegister)
|
||||
@ -57,6 +58,19 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcSwap(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val left = call.args[0]
|
||||
val right = call.args[1]
|
||||
val leftReg = codeGen.vmRegisters.nextFree()
|
||||
val rightReg = codeGen.vmRegisters.nextFree()
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(left, leftReg)
|
||||
code += exprGen.translateExpression(right, rightReg)
|
||||
code += assignRegisterTo(left, rightReg)
|
||||
code += assignRegisterTo(right, leftReg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
@ -128,7 +142,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg)
|
||||
// TODO use STOREM if constant address
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2=addressReg)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -138,7 +153,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg)
|
||||
// TODO use STOREM if constant address
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2=addressReg)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -146,6 +162,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||
// TODO use LOADM if constant address
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
|
||||
return code
|
||||
}
|
||||
@ -154,6 +171,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||
// TODO use LOADM if constant address
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
|
||||
return code
|
||||
}
|
||||
@ -252,11 +270,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister)
|
||||
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
val assignment = PtAssignment(call.position)
|
||||
val target = PtAssignTarget(call.position)
|
||||
target.children.add(call.args[0])
|
||||
assignment.children.add(target)
|
||||
assignment.children.add(PtIdentifier(listOf(":vmreg-$resultRegister"), listOf(":vmreg-$resultRegister"), call.args[0].type, call.position))
|
||||
code += assignRegisterTo(call.args[0], resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val assignment = PtAssignment(target.position)
|
||||
val assignTarget = PtAssignTarget(target.position)
|
||||
assignTarget.children.add(target)
|
||||
assignment.children.add(assignTarget)
|
||||
assignment.children.add(PtMachineRegister(register, target.type, target.position))
|
||||
code += codeGen.translateNode(assignment)
|
||||
return code
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
is PtSubroutineParameter,
|
||||
is PtNumber,
|
||||
is PtArray,
|
||||
is PtString -> throw AssemblyError("strings should not occur as separate statement node ${node.position}")
|
||||
is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}")
|
||||
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}")
|
||||
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target ${node.position}")
|
||||
is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}")
|
||||
@ -461,6 +461,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
} else if(memory!=null) {
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg)
|
||||
// TODO use LOADM/STOREM if address is constant
|
||||
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg)
|
||||
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg)
|
||||
@ -533,10 +534,16 @@ class CodeGen(internal val program: PtProgram,
|
||||
|
||||
private fun translate(assignment: PtAssignment): VmCodeChunk {
|
||||
// TODO can in-place assignments be optimized more?
|
||||
|
||||
if(assignment.target.children.single() is PtMachineRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
val code = VmCodeChunk()
|
||||
val resultRegister = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, resultRegister)
|
||||
val resultRegister = if(assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg)
|
||||
reg
|
||||
}
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
@ -561,12 +568,13 @@ class CodeGen(internal val program: PtProgram,
|
||||
}
|
||||
}
|
||||
else if(memory!=null) {
|
||||
require(vmDt==VmDataType.BYTE)
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressRegister = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, addressRegister)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, addressReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -18,24 +18,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val code = VmCodeChunk()
|
||||
|
||||
when (expr) {
|
||||
is PtMachineRegister -> {
|
||||
if(resultRegister!=expr.register) {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
|
||||
}
|
||||
}
|
||||
is PtNumber -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||
}
|
||||
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)
|
||||
val mem = codeGen.allocations.get(expr.targetName)
|
||||
code += if (expr.type in PassByValueDatatypes) {
|
||||
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
|
||||
}
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
@ -45,8 +45,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||
val addressExprCode = translateExpression(expr.address, addressRegister)
|
||||
code += addressExprCode
|
||||
code += translateExpression(expr.address, addressRegister)
|
||||
// TODO use LOADM if adress is constant
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
is PtTypeCast -> code += translate(expr, resultRegister)
|
||||
is PtPrefix -> code += translate(expr, resultRegister)
|
||||
@ -73,12 +74,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
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.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position))
|
||||
segWithArg
|
||||
}
|
||||
is PtBuiltinFunctionCall -> {
|
||||
val segWithArg = PtBuiltinFunctionCall(segment.name, segment.void, segment.hasNoSideEffects, segment.type, segment.position)
|
||||
segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position))
|
||||
segWithArg.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position))
|
||||
segWithArg
|
||||
}
|
||||
else -> throw AssemblyError("weird segment type")
|
||||
|
@ -7,6 +7,7 @@
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
uword other = $fe4a
|
||||
uword value = $ea31
|
||||
uword[] warray = [$aa44, $bb55, $cc66]
|
||||
ubyte upperb = msb(value)
|
||||
@ -28,6 +29,23 @@ main {
|
||||
txt.print_ubhex(upperb, true)
|
||||
txt.print_ubhex(lowerb, false)
|
||||
txt.nl()
|
||||
swap(other, value)
|
||||
txt.print_uwhex(value,true)
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
|
||||
pokew($1000, $ab98)
|
||||
txt.print_ubhex(@($1000),true)
|
||||
txt.print_ubhex(@($1001),false)
|
||||
txt.nl()
|
||||
txt.print_uwhex(peekw($1000),true)
|
||||
txt.nl()
|
||||
swap(@($1000), @($1001))
|
||||
txt.print_uwhex(peekw($1000),true)
|
||||
txt.nl()
|
||||
swap(warray[0], warray[1])
|
||||
txt.print_uwhex(warray[1],true)
|
||||
txt.nl()
|
||||
|
||||
; ; a "pixelshader":
|
||||
; void syscall1(8, 0) ; enable lo res creen
|
||||
|
@ -39,7 +39,7 @@ storem reg1, address - store reg1 in memory address
|
||||
storei reg1, reg2 - store reg1 in memory indirect, memory pointed to by reg2
|
||||
storex reg1, reg2, address - store reg1 in memory address, indexed by value in reg2
|
||||
storez address - store zero in memory address
|
||||
storezi reg1 - store zero in memory pointed to by reg
|
||||
storezi reg1 - store zero in memory pointed to by reg1
|
||||
storezx reg1, address - store zero in memory address, indexed by value in reg
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user