working on vm

This commit is contained in:
Irmen de Jong 2022-03-29 01:16:26 +02:00
parent 3e1a7c6102
commit f46300016d
6 changed files with 249 additions and 167 deletions

View File

@ -8,9 +8,9 @@ import prog8.vm.Opcode
import prog8.vm.Syscall import prog8.vm.Syscall
import prog8.vm.VmDataType import prog8.vm.VmDataType
internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen) { internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: ExpressionGen) {
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
when(call.name) { when(call.name) {
"syscall" -> { "syscall" -> {
@ -20,19 +20,19 @@ internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen)
"syscall1" -> { "syscall1" -> {
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, 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, regUsage) code += exprGen.translateExpression(call.args[1], 0)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr)) code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
} }
"syscall2" -> { "syscall2" -> {
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
while(regUsage.firstFree<2) { while(codeGen.vmRegisters.peekNext()<2) {
regUsage.nextFree() codeGen.vmRegisters.nextFree()
} }
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, regUsage) code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1, regUsage) code += exprGen.translateExpression(call.args[2], 1)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr)) code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
@ -41,25 +41,25 @@ internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen)
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)) code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2))
while(regUsage.firstFree<3) { while(codeGen.vmRegisters.peekNext()<3) {
regUsage.nextFree() codeGen.vmRegisters.nextFree()
} }
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, regUsage) code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1, regUsage) code += exprGen.translateExpression(call.args[2], 1)
code += exprGen.translateExpression(call.args[3], 2, regUsage) code += exprGen.translateExpression(call.args[3], 2)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr)) code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0)) code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
} }
"msb" -> { "msb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister, regUsage) code += exprGen.translateExpression(call.args.single(), resultRegister)
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)) code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister))
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here. // note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
} }
"lsb" -> { "lsb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister, regUsage) code += exprGen.translateExpression(call.args.single(), resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here. // note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
} }
"memory" -> { "memory" -> {
@ -83,27 +83,27 @@ internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen)
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)) code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
} }
"peek" -> { "peek" -> {
val addressReg = regUsage.nextFree() val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg, regUsage) code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)) code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg))
} }
"peekw" -> { "peekw" -> {
val addressReg = regUsage.nextFree() val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg, regUsage) code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)) code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
} }
"mkword" -> { "mkword" -> {
val msbReg = regUsage.nextFree() val msbReg = codeGen.vmRegisters.nextFree()
val lsbReg = regUsage.nextFree() val lsbReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], msbReg, regUsage) code += exprGen.translateExpression(call.args[0], msbReg)
code += exprGen.translateExpression(call.args[1], lsbReg, regUsage) code += exprGen.translateExpression(call.args[1], lsbReg)
code += VmCodeInstruction(Instruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)) code += VmCodeInstruction(Instruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg))
} }
else -> { else -> {
TODO("builtinfunc ${call.name}") TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Instruction(Opcode.NOP)) // code += VmCodeInstruction(Instruction(Opcode.NOP))
// for (arg in call.args) { // for (arg in call.args) {
// code += translateExpression(arg, resultRegister, regUsage) // code += translateExpression(arg, resultRegister)
// code += when(arg.type) { // code += when(arg.type) {
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister)) // in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister)) // in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))

View File

@ -7,6 +7,23 @@ import prog8.code.core.*
import prog8.vm.Instruction import prog8.vm.Instruction
import prog8.vm.Opcode import prog8.vm.Opcode
import prog8.vm.VmDataType import prog8.vm.VmDataType
import java.lang.Math.pow
import kotlin.math.pow
internal class VmRegisterPool() {
private var firstFree: Int=3 // registers 0,1,2 are reserved
fun peekNext() = firstFree
fun nextFree(): Int {
val result = firstFree
firstFree++
if(firstFree>65535)
throw AssemblyError("out of virtual registers")
return result
}
}
class CodeGen(internal val program: PtProgram, class CodeGen(internal val program: PtProgram,
@ -18,6 +35,7 @@ class CodeGen(internal val program: PtProgram,
internal val allocations = VariableAllocator(symbolTable, program, errors) internal val allocations = VariableAllocator(symbolTable, program, errors)
private val expressionEval = ExpressionGen(this) private val expressionEval = ExpressionGen(this)
private val builtinFuncGen = BuiltinFuncGen(this, expressionEval) private val builtinFuncGen = BuiltinFuncGen(this, expressionEval)
internal val vmRegisters = VmRegisterPool()
init { init {
if(options.dontReinitGlobals) if(options.dontReinitGlobals)
@ -30,40 +48,39 @@ class CodeGen(internal val program: PtProgram,
// collect global variables initializers // collect global variables initializers
program.allBlocks().forEach { program.allBlocks().forEach {
val code = VmCodeChunk() val code = VmCodeChunk()
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += translate(assign, RegisterUsage(0)) } it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += translate(assign) }
vmprog.addGlobalInits(code) vmprog.addGlobalInits(code)
} }
val regUsage = RegisterUsage(0)
for (block in program.allBlocks()) { for (block in program.allBlocks()) {
vmprog.addBlock(translate(block, regUsage)) vmprog.addBlock(translate(block))
} }
return vmprog return vmprog
} }
private fun translateNode(node: PtNode, regUsage: RegisterUsage): VmCodeChunk { private fun translateNode(node: PtNode): VmCodeChunk {
val code = when(node) { val code = when(node) {
is PtBlock -> translate(node, regUsage) is PtBlock -> translate(node)
is PtSub -> translate(node, regUsage) is PtSub -> translate(node)
is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table
is PtVariable -> VmCodeChunk() // var should be looked up via symbol table is PtVariable -> VmCodeChunk() // var should be looked up via symbol table
is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table
is PtConstant -> VmCodeChunk() // constants have all been folded into the code is PtConstant -> VmCodeChunk() // constants have all been folded into the code
is PtAssignment -> translate(node, regUsage) is PtAssignment -> translate(node)
is PtNodeGroup -> translateGroup(node.children, regUsage) is PtNodeGroup -> translateGroup(node.children)
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, regUsage.nextFree(), regUsage) is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0)
is PtFunctionCall -> expressionEval.translate(node, regUsage.nextFree(), regUsage) is PtFunctionCall -> expressionEval.translate(node, 0)
is PtNop -> VmCodeChunk() is PtNop -> VmCodeChunk()
is PtReturn -> translate(node) is PtReturn -> translate(node)
is PtJump -> translate(node) is PtJump -> translate(node)
is PtWhen -> TODO("when") is PtWhen -> TODO("when")
is PtPipe -> expressionEval.translate(node, regUsage.nextFree(), regUsage) is PtPipe -> expressionEval.translate(node, 0)
is PtForLoop -> translate(node, regUsage) is PtForLoop -> translate(node)
is PtIfElse -> translate(node, regUsage) is PtIfElse -> translate(node)
is PtPostIncrDecr -> translate(node, regUsage) is PtPostIncrDecr -> translate(node)
is PtRepeatLoop -> translate(node, regUsage) is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName)) is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Instruction(Opcode.BREAKPOINT))) is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Instruction(Opcode.BREAKPOINT)))
is PtAddressOf, is PtAddressOf,
@ -88,35 +105,113 @@ class CodeGen(internal val program: PtProgram,
is PtConditionalBranch -> throw AssemblyError("conditional branches not supported in vm target due to lack of cpu flags ${node.position}") is PtConditionalBranch -> throw AssemblyError("conditional branches not supported in vm target due to lack of cpu flags ${node.position}")
else -> TODO("missing codegen for $node") else -> TODO("missing codegen for $node")
} }
code.lines.add(0, VmCodeComment(node.position.toString())) if(code.lines.isNotEmpty())
code.lines.add(0, VmCodeComment(node.position.toString()))
return code return code
} }
private fun translate(forLoop: PtForLoop, regUsage: RegisterUsage): VmCodeChunk { private fun translate(forLoop: PtForLoop): VmCodeChunk {
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
val iterable = forLoop.iterable val iterable = forLoop.iterable
val code = VmCodeChunk() val code = VmCodeChunk()
when(iterable) { when(iterable) {
is PtRange -> { is PtRange -> {
println("forloop ${loopvar.dt} ${loopvar.scopedName} in range ${iterable} ") TODO("forloop ${loopvar.dt} ${loopvar.scopedName} in range ${iterable} ")
iterable.printIndented(0) iterable.printIndented(0)
TODO() TODO("forloop over range")
} }
is PtIdentifier -> { is PtIdentifier -> {
val address = allocations.get(iterable.targetName) val arrayAddress = allocations.get(iterable.targetName)
val variable = symbolTable.lookup(iterable.targetName) as StStaticVariable val iterableVar = symbolTable.lookup(iterable.targetName) as StStaticVariable
val length = variable.length!! val loopvarAddress = allocations.get(loopvar.scopedName)
println("forloop ${loopvar.dt} ${loopvar.scopedName} in $iterable @${address.toHex()} ${length}") val indexReg = vmRegisters.nextFree()
val indexReg = regUsage.nextFree() val loopLabel = createLabelName()
val loopvarReg = regUsage.nextFree() val endLabel = createLabelName()
TODO() if(iterableVar.dt==DataType.STR) {
// iterate over a zero-terminated string
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0))
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Instruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress))
code += VmCodeInstruction(Instruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel))
code += VmCodeInstruction(Instruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress))
code += translateNode(forLoop.statements)
code += VmCodeInstruction(Instruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg))
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = loopLabel))
code += VmCodeLabel(endLabel)
} else {
// iterate over array
val elementDt = ArrayToElementTypes.getValue(iterable.type)
val elementSize = program.memsizer.memorySize(elementDt).toUInt()
val lengthBytes = iterableVar.length!! * elementSize.toInt()
val lengthReg = vmRegisters.nextFree()
/*
index = 0
_loop:
if index==(length * <element_size>) goto _end
loopvar = read_mem(iterable+index)
<statements>
index += <elementsize>
goto _loop
_end: ...
*/
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0))
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes))
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Instruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel))
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress))
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress))
code += translateNode(forLoop.statements)
code += addConst(VmDataType.BYTE, indexReg, elementSize)
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = loopLabel))
code += VmCodeLabel(endLabel)
}
} }
else -> throw AssemblyError("weird for iterable") else -> throw AssemblyError("weird for iterable")
} }
return code return code
} }
private fun translate(ifElse: PtIfElse, regUsage: RegisterUsage): VmCodeChunk { private fun addConst(dt: VmDataType, reg: Int, value: UInt): VmCodeChunk {
val code = VmCodeChunk()
when(value) {
0u -> { /* do nothing */ }
1u -> {
code += VmCodeInstruction(Instruction(Opcode.INC, dt, reg1=reg))
}
else -> {
val valueReg = vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=valueReg, value=value.toInt()))
code += VmCodeInstruction(Instruction(Opcode.ADD, dt, reg1=reg, reg2=reg, reg3=valueReg))
}
}
return code
}
private val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
private fun multiplyByConst(dt: VmDataType, reg: Int, factor: UInt): VmCodeChunk {
val code = VmCodeChunk()
val pow2 = powersOfTwo.indexOf(factor.toInt())
if(pow2>=1) {
// just shift bits
code += VmCodeInstruction(Instruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2))
} else {
when(factor) {
0u -> {
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=reg, value=0))
}
1u -> { /* do nothing */ }
else -> {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=factorReg, value=factor.toInt()))
code += VmCodeInstruction(Instruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg))
}
}
}
return code
}
private fun translate(ifElse: PtIfElse): VmCodeChunk {
var branch = Opcode.BZ var branch = Opcode.BZ
var condition = ifElse.condition var condition = ifElse.condition
@ -133,31 +228,31 @@ class CodeGen(internal val program: PtProgram,
} }
} }
val conditionReg = regUsage.nextFree() val conditionReg = vmRegisters.nextFree()
val vmDt = vmType(condition.type) val vmDt = vmType(condition.type)
val code = VmCodeChunk() val code = VmCodeChunk()
code += expressionEval.translateExpression(condition, conditionReg, regUsage) code += expressionEval.translateExpression(condition, conditionReg)
if(ifElse.elseScope.children.isNotEmpty()) { if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts // if and else parts
val elseLabel = createLabelName() val elseLabel = createLabelName()
val afterIfLabel = createLabelName() val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel)) code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel))
code += translateNode(ifElse.ifScope, regUsage) code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = afterIfLabel)) code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = afterIfLabel))
code += VmCodeLabel(elseLabel) code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope, regUsage) code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel) code += VmCodeLabel(afterIfLabel)
} else { } else {
// only if part // only if part
val afterIfLabel = createLabelName() val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel)) code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel))
code += translateNode(ifElse.ifScope, regUsage) code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel) code += VmCodeLabel(afterIfLabel)
} }
return code return code
} }
private fun translate(postIncrDecr: PtPostIncrDecr, regUsage: RegisterUsage): VmCodeChunk { private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val operation = when(postIncrDecr.operator) { val operation = when(postIncrDecr.operator) {
"++" -> Opcode.INC "++" -> Opcode.INC
@ -168,15 +263,15 @@ class CodeGen(internal val program: PtProgram,
val memory = postIncrDecr.target.memory val memory = postIncrDecr.target.memory
val array = postIncrDecr.target.array val array = postIncrDecr.target.array
val vmDt = vmType(postIncrDecr.target.type) val vmDt = vmType(postIncrDecr.target.type)
val resultReg = regUsage.nextFree() val resultReg = vmRegisters.nextFree()
if(ident!=null) { if(ident!=null) {
val address = allocations.get(ident.targetName) val address = allocations.get(ident.targetName)
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address)) code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg)) code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address)) code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address))
} else if(memory!=null) { } else if(memory!=null) {
val addressReg = regUsage.nextFree() val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, regUsage) code += expressionEval.translateExpression(memory.address, addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg)) code += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg)) code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg)) code += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg))
@ -188,23 +283,23 @@ class CodeGen(internal val program: PtProgram,
return code return code
} }
private fun translate(repeat: PtRepeatLoop, regUsage: RegisterUsage): VmCodeChunk { private fun translate(repeat: PtRepeatLoop): VmCodeChunk {
if((repeat.count as? PtNumber)?.number==0.0) if((repeat.count as? PtNumber)?.number==0.0)
return VmCodeChunk() return VmCodeChunk()
if((repeat.count as? PtNumber)?.number==1.0) if((repeat.count as? PtNumber)?.number==1.0)
return translateGroup(repeat.children, regUsage) return translateGroup(repeat.children)
if((repeat.count as? PtNumber)?.number==256.0) { if((repeat.count as? PtNumber)?.number==256.0) {
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value. // 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position) repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
} }
val code = VmCodeChunk() val code = VmCodeChunk()
val counterReg = regUsage.nextFree() val counterReg = vmRegisters.nextFree()
val vmDt = vmType(repeat.count.type) val vmDt = vmType(repeat.count.type)
code += expressionEval.translateExpression(repeat.count, counterReg, regUsage) code += expressionEval.translateExpression(repeat.count, counterReg)
val repeatLabel = createLabelName() val repeatLabel = createLabelName()
code += VmCodeLabel(repeatLabel) code += VmCodeLabel(repeatLabel)
code += translateNode(repeat.statements, regUsage) code += translateNode(repeat.statements)
code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg)) code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)) code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel))
return code return code
@ -223,18 +318,18 @@ class CodeGen(internal val program: PtProgram,
return code return code
} }
private fun translateGroup(group: List<PtNode>, regUsage: RegisterUsage): VmCodeChunk { private fun translateGroup(group: List<PtNode>): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
group.forEach { code += translateNode(it, regUsage) } group.forEach { code += translateNode(it) }
return code return code
} }
private fun translate(assignment: PtAssignment, regUsage: RegisterUsage): VmCodeChunk { private fun translate(assignment: PtAssignment): VmCodeChunk {
// TODO can in-place assignments (assignment.augmentable = true) be optimized more? // TODO can in-place assignments (assignment.augmentable = true) be optimized more?
val code = VmCodeChunk() val code = VmCodeChunk()
val resultRegister = regUsage.nextFree() val resultRegister = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, resultRegister, regUsage) code += expressionEval.translateExpression(assignment.value, resultRegister)
val ident = assignment.target.identifier val ident = assignment.target.identifier
val memory = assignment.target.memory val memory = assignment.target.memory
val array = assignment.target.array val array = assignment.target.array
@ -252,11 +347,11 @@ class CodeGen(internal val program: PtProgram,
val vmDtArrayIdx = vmType(array.type) val vmDtArrayIdx = vmType(array.type)
if(fixedIndex!=null) { if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)) code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr))
} else { } else {
val indexReg = regUsage.nextFree() val indexReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, indexReg, regUsage) code += expressionEval.translateExpression(array.index, indexReg)
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)) code += VmCodeInstruction(Instruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr))
} }
} }
else if(memory!=null) { else if(memory!=null) {
@ -264,8 +359,8 @@ class CodeGen(internal val program: PtProgram,
if(memory.address is PtNumber) { if(memory.address is PtNumber) {
Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else { } else {
val addressRegister = regUsage.nextFree() val addressRegister = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, addressRegister, regUsage) code += expressionEval.translateExpression(assignment.value, addressRegister)
Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister) Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
} }
code += VmCodeInstruction(ins) code += VmCodeInstruction(ins)
@ -280,30 +375,30 @@ class CodeGen(internal val program: PtProgram,
val value = ret.value val value = ret.value
if(value!=null) { if(value!=null) {
// Call Convention: return value is always returned in r0 // Call Convention: return value is always returned in r0
code += expressionEval.translateExpression(value, 0, RegisterUsage(1)) code += expressionEval.translateExpression(value, 0)
} }
code += VmCodeInstruction(Instruction(Opcode.RETURN)) code += VmCodeInstruction(Instruction(Opcode.RETURN))
return code return code
} }
private fun translate(sub: PtSub, regUsage: RegisterUsage): VmCodeChunk { private fun translate(sub: PtSub): VmCodeChunk {
// TODO actually inline subroutines marked as inline // TODO actually inline subroutines marked as inline
val code = VmCodeChunk() val code = VmCodeChunk()
code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}") code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
code += VmCodeLabel(sub.scopedName) code += VmCodeLabel(sub.scopedName)
for (child in sub.children) { for (child in sub.children) {
code += translateNode(child, regUsage) code += translateNode(child)
} }
code += VmCodeComment("SUB-END '${sub.name}'") code += VmCodeComment("SUB-END '${sub.name}'")
return code return code
} }
private fun translate(block: PtBlock, regUsage: RegisterUsage): VmCodeChunk { private fun translate(block: PtBlock): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}") code += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children) { for (child in block.children) {
if(child !is PtAssignment) // global variable initialization is done elsewhere if(child !is PtAssignment) // global variable initialization is done elsewhere
code += translateNode(child, regUsage) code += translateNode(child)
} }
code += VmCodeComment("BLOCK-END '${block.name}'") code += VmCodeComment("BLOCK-END '${block.name}'")
return code return code
@ -327,6 +422,6 @@ class CodeGen(internal val program: PtProgram,
return listOf("generated$labelSequenceNumber") return listOf("generated$labelSequenceNumber")
} }
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk = internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
builtinFuncGen.translate(call, resultRegister, regUsage) builtinFuncGen.translate(call, resultRegister)
} }

View File

@ -12,18 +12,9 @@ import prog8.vm.Opcode
import prog8.vm.VmDataType import prog8.vm.VmDataType
internal class RegisterUsage(var firstFree: Int=0) { internal class ExpressionGen(private val codeGen: CodeGen) {
fun nextFree(): Int { fun translateExpression(expr: PtExpression, resultRegister: Int): VmCodeChunk {
val result = firstFree require(codeGen.vmRegisters.peekNext() > resultRegister)
firstFree++
return result
}
}
internal class ExpressionGen(val codeGen: CodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
require(regUsage.firstFree > resultRegister)
val code = VmCodeChunk() val code = VmCodeChunk()
val vmDt = codeGen.vmType(expr.type) val vmDt = codeGen.vmType(expr.type)
@ -46,18 +37,18 @@ internal class ExpressionGen(val codeGen: CodeGen) {
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)) code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
} }
is PtMemoryByte -> { is PtMemoryByte -> {
val addressRegister = regUsage.nextFree() val addressRegister = codeGen.vmRegisters.nextFree()
val addressExprCode = translateExpression(expr.address, addressRegister, regUsage) val addressExprCode = translateExpression(expr.address, addressRegister)
code += addressExprCode code += addressExprCode
} }
is PtTypeCast -> code += translate(expr, resultRegister, regUsage) is PtTypeCast -> code += translate(expr, resultRegister)
is PtPrefix -> code += translate(expr, resultRegister, regUsage) is PtPrefix -> code += translate(expr, resultRegister)
is PtArrayIndexer -> code += translate(expr, resultRegister, regUsage) is PtArrayIndexer -> code += translate(expr, resultRegister)
is PtBinaryExpression -> code += translate(expr, resultRegister, regUsage) is PtBinaryExpression -> code += translate(expr, resultRegister)
is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister, regUsage) is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister)
is PtFunctionCall -> code += translate(expr, resultRegister, regUsage) is PtFunctionCall -> code += translate(expr, resultRegister)
is PtContainmentCheck -> code += translate(expr, resultRegister, regUsage) is PtContainmentCheck -> code += translate(expr, resultRegister)
is PtPipe -> code += translate(expr, resultRegister, regUsage) is PtPipe -> code += translate(expr, resultRegister)
is PtRange, is PtRange,
is PtArray, is PtArray,
is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression") is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression")
@ -66,34 +57,34 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
internal fun translate(pipe: PtPipe, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { internal fun translate(pipe: PtPipe, resultRegister: Int): VmCodeChunk {
TODO("Not yet implemented: pipe expression") TODO("Not yet implemented: pipe expression")
} }
private fun translate(check: PtContainmentCheck, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { private fun translate(check: PtContainmentCheck, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += translateExpression(check.element, resultRegister, regUsage) // load the element to check in resultRegister code += translateExpression(check.element, resultRegister) // load the element to check in resultRegister
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) { when(iterable.dt) {
DataType.STR -> { DataType.STR -> {
val call = PtFunctionCall(listOf("prog8_lib", "string_contains"), false, DataType.UBYTE, check.position) val call = PtFunctionCall(listOf("prog8_lib", "string_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element) call.children.add(check.element)
call.children.add(check.iterable) call.children.add(check.iterable)
code += translate(call, resultRegister, regUsage) code += translate(call, resultRegister)
} }
DataType.ARRAY_UB, DataType.ARRAY_B -> { DataType.ARRAY_UB, DataType.ARRAY_B -> {
val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position) val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element) call.children.add(check.element)
call.children.add(check.iterable) call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position)) call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
code += translate(call, resultRegister, regUsage) code += translate(call, resultRegister)
} }
DataType.ARRAY_UW, DataType.ARRAY_W -> { DataType.ARRAY_UW, DataType.ARRAY_W -> {
val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position) val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position)
call.children.add(check.element) call.children.add(check.element)
call.children.add(check.iterable) call.children.add(check.iterable)
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position)) call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
code += translate(call, resultRegister, regUsage) code += translate(call, resultRegister)
} }
DataType.ARRAY_F -> TODO("containment check in float-array") DataType.ARRAY_F -> TODO("containment check in float-array")
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}") else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}")
@ -101,14 +92,14 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int): VmCodeChunk {
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type) val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
val vmDt = codeGen.vmType(arrayIx.type) val vmDt = codeGen.vmType(arrayIx.type)
val code = VmCodeChunk() val code = VmCodeChunk()
val idxReg = regUsage.nextFree() val idxReg = codeGen.vmRegisters.nextFree()
code += translateExpression(arrayIx.index, idxReg, regUsage) code += translateExpression(arrayIx.index, idxReg)
if(eltSize>1) { if(eltSize>1) {
val factorReg = regUsage.nextFree() val factorReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize)) code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize))
code += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg)) code += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg))
} }
@ -117,9 +108,9 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
private fun translate(expr: PtPrefix, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
code += translateExpression(expr.value, resultRegister, regUsage) code += translateExpression(expr.value, resultRegister)
val vmDt = codeGen.vmType(expr.type) val vmDt = codeGen.vmType(expr.type)
when(expr.operator) { when(expr.operator) {
"+" -> { } "+" -> { }
@ -127,7 +118,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
code += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister)) code += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister))
} }
"~" -> { "~" -> {
val regMask = regUsage.nextFree() val regMask = codeGen.vmRegisters.nextFree()
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask)) code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)) code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
@ -137,7 +128,7 @@ internal class ExpressionGen(val codeGen: CodeGen) {
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label)) code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1)) code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
code += VmCodeLabel(label) code += VmCodeLabel(label)
val regMask = regUsage.nextFree() val regMask = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1)) code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)) code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
} }
@ -146,11 +137,11 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
private fun translate(cast: PtTypeCast, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { private fun translate(cast: PtTypeCast, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
if(cast.type==cast.value.type) if(cast.type==cast.value.type)
return code return code
code += translateExpression(cast.value, resultRegister, regUsage) code += translateExpression(cast.value, resultRegister)
when(cast.type) { when(cast.type) {
DataType.UBYTE -> { DataType.UBYTE -> {
when(cast.value.type) { when(cast.value.type) {
@ -223,14 +214,14 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { private fun translate(binExpr: PtBinaryExpression, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val leftResultReg = regUsage.nextFree() val leftResultReg = codeGen.vmRegisters.nextFree()
val rightResultReg = regUsage.nextFree() val rightResultReg = codeGen.vmRegisters.nextFree()
// TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. But only if this would result in a different opcode such as ADD 1 -> INC, MUL 1 -> NOP // TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. But only if this would result in a different opcode such as ADD 1 -> INC, MUL 1 -> NOP
// actually optimizing the code should not be done here but in a tailored code optimizer step. // actually optimizing the code should not be done here but in a tailored code optimizer step.
val leftCode = translateExpression(binExpr.left, leftResultReg, regUsage) val leftCode = translateExpression(binExpr.left, leftResultReg)
val rightCode = translateExpression(binExpr.right, rightResultReg, regUsage) val rightCode = translateExpression(binExpr.right, rightResultReg)
code += leftCode code += leftCode
code += rightCode code += rightCode
val vmDt = codeGen.vmType(binExpr.left.type) val vmDt = codeGen.vmType(binExpr.left.type)
@ -294,12 +285,12 @@ internal class ExpressionGen(val codeGen: CodeGen) {
return code return code
} }
fun translate(fcall: PtFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { fun translate(fcall: PtFunctionCall, resultRegister: Int): VmCodeChunk {
val subroutine = codeGen.symbolTable.flat.getValue(fcall.functionName) as StSub val subroutine = codeGen.symbolTable.flat.getValue(fcall.functionName) as StSub
val code = VmCodeChunk() val code = VmCodeChunk()
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) { for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
val argReg = regUsage.nextFree() val argReg = codeGen.vmRegisters.nextFree()
code += translateExpression(arg, argReg, regUsage) code += translateExpression(arg, argReg)
val vmDt = codeGen.vmType(parameter.type) val vmDt = codeGen.vmType(parameter.type)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name) val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem)) code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))

View File

@ -3,7 +3,7 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- vm codegen: fix primes endless loop stuck on '2' - vm: memory: reading/writing of words seems buggy. add tests+fix
- x16: check additional FP lib changes https://github.com/commanderx16/x16-rom/commit/ae608673f0210953172d6837acfbb231d62ddbd1 - x16: check additional FP lib changes https://github.com/commanderx16/x16-rom/commit/ae608673f0210953172d6837acfbb231d62ddbd1
and https://github.com/commanderx16/x16-docs/commit/21238aedc641da91df88e04c4ce9bf3324a3c12d and https://github.com/commanderx16/x16-docs/commit/21238aedc641da91df88e04c4ce9bf3324a3c12d
- x16: check joystick support (petaxian, own stuff) because of api change in r39 kernal https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md#function-name-joystick_get - x16: check joystick support (petaxian, own stuff) because of api change in r39 kernal https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md#function-name-joystick_get

View File

@ -4,39 +4,35 @@
main { main {
sub start() { sub start() {
ubyte x1 = $ea txt.clear_screen()
ubyte x2 = $31 txt.print("Welcome to a prog8 pixel shader :-)\n")
uword uw = mkword(x1, $99) uword ww = 0
txt.print_uwhex(uw, true) ubyte bc
txt.nl() uword wc
uw = mkword(x1, x2)
txt.print_uwhex(uw, true) for bc in "irmen" {
txt.chrout(bc)
ww++
}
txt.print_uw(ww) ; 5
txt.nl() txt.nl()
sys.exit(99) for bc in [10,11,12] {
txt.print_ub(bc)
txt.spc()
ww++
}
txt.print_uw(ww) ; 8
txt.nl()
for wc in [4096,8192,16384] {
txt.print_uw(wc)
txt.spc()
ww++
}
txt.print_uw(ww) ; 11
txt.nl()
; txt.clear_screen()
; txt.print("Welcome to a prog8 pixel shader :-)\n")
; uword ww = 0
; ubyte bc
; uword wc
;
; for bc in "irmen" {
; ; +5 -> 17
; txt.chrout(bc)
; ww++
; }
; txt.print_uw(ww)
; txt.nl()
;
; for wc in [1000,1111,1222] {
; txt.print_uw(wc)
; txt.spc()
; ww++ ; +3 -> 20
; }
; txt.print_uw(ww)
; txt.nl()
;
; for bc in 10 to 20 step 3 { ; for bc in 10 to 20 step 3 {
; ; 10,13,16,19 -> 4 ; ; 10,13,16,19 -> 4
; ww++ ; ww++
@ -50,8 +46,8 @@ main {
; txt.print_uw(ww) ; txt.print_uw(ww)
; txt.nl() ; txt.nl()
; ;
;
; sys.exit(99) sys.exit(99)
; the "pixelshader": ; the "pixelshader":

View File

@ -27,22 +27,22 @@ class Memory {
} }
fun getUW(address: Int): UShort { fun getUW(address: Int): UShort {
return (256u*mem[address] + mem[address+1]).toUShort() return (256u*mem[address+1] + mem[address]).toUShort()
} }
fun getSW(address: Int): Short { fun getSW(address: Int): Short {
return (mem[address].toInt()*256 + mem[address+1].toInt()).toShort() return (mem[address+1].toInt()*256 + mem[address].toInt()).toShort()
} }
fun setUW(address: Int, value: UShort) { fun setUW(address: Int, value: UShort) {
mem[address] = (value.toInt() ushr 8).toUByte() mem[address+1] = (value.toInt() ushr 8).toUByte()
mem[address+1] = value.toUByte() mem[address] = value.toUByte()
} }
fun setSW(address: Int, value: Short) { fun setSW(address: Int, value: Short) {
val uv = value.toUShort() val uv = value.toUShort()
mem[address] = (uv.toInt() ushr 8).toUByte() mem[address+1] = (uv.toInt() ushr 8).toUByte()
mem[address+1] = uv.toUByte() mem[address] = uv.toUByte()
} }
// for now, no LONG 32-bits and no FLOAT support. // for now, no LONG 32-bits and no FLOAT support.