working on vm

This commit is contained in:
Irmen de Jong 2022-03-30 21:44:48 +02:00
parent f46300016d
commit 0dc592b819
15 changed files with 372 additions and 145 deletions

View File

@ -4,6 +4,7 @@ import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyProgram
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
import java.io.BufferedWriter
import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
@ -51,7 +52,17 @@ internal class AssemblyProgram(override val name: String,
internal sealed class VmCodeLine
internal class VmCodeInstruction(val ins: Instruction): VmCodeLine()
internal class VmCodeInstruction(
opcode: Opcode,
type: VmDataType?=null,
reg1: Int?=null, // 0-$ffff
reg2: Int?=null, // 0-$ffff
reg3: Int?=null, // 0-$ffff
value: Int?=null, // 0-$ffff
symbol: List<String>?=null // alternative to value
): VmCodeLine() {
val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol)
}
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
internal class VmCodeComment(val comment: String): VmCodeLine()

View File

@ -3,7 +3,6 @@ package prog8.codegen.virtual
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtNumber
import prog8.code.ast.PtString
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.Syscall
import prog8.vm.VmDataType
@ -15,32 +14,32 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
code += VmCodeInstruction(Opcode.SYSCALL, value=vExpr.number.toInt())
}
"syscall1" -> {
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
val callNr = (call.args[0] as PtNumber).number.toInt()
code += exprGen.translateExpression(call.args[1], 0)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
}
"syscall2" -> {
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
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)
code += exprGen.translateExpression(call.args[2], 1)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
}
"syscall3" -> {
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 = 2))
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 0)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2)
while(codeGen.vmRegisters.peekNext()<3) {
codeGen.vmRegisters.nextFree()
}
@ -48,14 +47,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += exprGen.translateExpression(call.args[1], 0)
code += exprGen.translateExpression(call.args[2], 1)
code += exprGen.translateExpression(call.args[3], 2)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Opcode.SYSCALL, value=callNr)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 2)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 1)
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1 = 0)
}
"msb" -> {
code += exprGen.translateExpression(call.args.single(), resultRegister)
code += VmCodeInstruction(Instruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister))
code += VmCodeInstruction(Opcode.SWAP, VmDataType.BYTE, reg1 = resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
}
"lsb" -> {
@ -75,50 +74,50 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
else
existing.first
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt()))
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())
}
"rnd" -> {
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value= Syscall.RND.ordinal))
code += VmCodeInstruction(Opcode.SYSCALL, value= Syscall.RND.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Instruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0))
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
}
"peek" -> {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg))
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
}
"peekw" -> {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg))
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
}
"mkword" -> {
val msbReg = codeGen.vmRegisters.nextFree()
val lsbReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], msbReg)
code += exprGen.translateExpression(call.args[1], lsbReg)
code += VmCodeInstruction(Instruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg))
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)
}
else -> {
TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Instruction(Opcode.NOP))
// code += VmCodeInstruction(Opcode.NOP))
// for (arg in call.args) {
// code += translateExpression(arg, resultRegister)
// code += when(arg.type) {
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
// in ByteDatatypes -> VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=resultRegister))
// else -> throw AssemblyError("weird arg dt")
// }
// }
// code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
// code += VmCodeInstruction(Opcode.CALL), labelArg = listOf("_prog8_builtin", call.name))
// for (arg in call.args) {
// code += when(arg.type) {
// in ByteDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
// in ByteDatatypes -> VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=resultRegister))
// in WordDatatypes -> VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=resultRegister))
// else -> throw AssemblyError("weird arg dt")
// }
// }
// code += VmCodeInstruction(Instruction(Opcode.NOP))
// code += VmCodeInstruction(Opcode.NOP))
}
}
return code

View File

@ -4,10 +4,8 @@ import prog8.code.StStaticVariable
import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.*
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
import java.lang.Math.pow
import kotlin.math.pow
@ -82,7 +80,7 @@ class CodeGen(internal val program: PtProgram,
is PtPostIncrDecr -> translate(node)
is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Instruction(Opcode.BREAKPOINT)))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
is PtAddressOf,
is PtContainmentCheck,
is PtMemoryByte,
@ -129,14 +127,14 @@ class CodeGen(internal val program: PtProgram,
val endLabel = createLabelName()
if(iterableVar.dt==DataType.STR) {
// iterate over a zero-terminated string
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0))
code += VmCodeInstruction(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 += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel)
code += VmCodeInstruction(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 += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
code += VmCodeLabel(endLabel)
} else {
// iterate over array
@ -154,15 +152,15 @@ class CodeGen(internal val program: PtProgram,
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 += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeInstruction(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 += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel)
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(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 += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
code += VmCodeLabel(endLabel)
}
}
@ -176,12 +174,12 @@ class CodeGen(internal val program: PtProgram,
when(value) {
0u -> { /* do nothing */ }
1u -> {
code += VmCodeInstruction(Instruction(Opcode.INC, dt, reg1=reg))
code += VmCodeInstruction(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))
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value.toInt())
code += VmCodeInstruction(Opcode.ADD, dt, reg1=reg, reg2=reg, reg3=valueReg)
}
}
return code
@ -194,17 +192,17 @@ class CodeGen(internal val program: PtProgram,
val pow2 = powersOfTwo.indexOf(factor.toInt())
if(pow2>=1) {
// just shift bits
code += VmCodeInstruction(Instruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2))
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg, reg2=reg, reg3=pow2)
} else {
when(factor) {
0u -> {
code += VmCodeInstruction(Instruction(Opcode.LOAD, dt, reg1=reg, value=0))
code += VmCodeInstruction(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))
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value=factor.toInt())
code += VmCodeInstruction(Opcode.MUL, dt, reg1=reg, reg2=reg, reg3=factorReg)
}
}
}
@ -236,16 +234,16 @@ class CodeGen(internal val program: PtProgram,
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel))
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Instruction(Opcode.JUMP, symbol = afterIfLabel))
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel))
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
}
@ -266,15 +264,15 @@ class CodeGen(internal val program: PtProgram,
val resultReg = vmRegisters.nextFree()
if(ident!=null) {
val address = allocations.get(ident.targetName)
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address))
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address)
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address)
} else if(memory!=null) {
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg)
code += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg))
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg)
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg)
} else if (array!=null) {
TODO("postincrdecr array")
} else
@ -300,8 +298,8 @@ class CodeGen(internal val program: PtProgram,
val repeatLabel = createLabelName()
code += VmCodeLabel(repeatLabel)
code += translateNode(repeat.statements)
code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel))
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)
return code
}
@ -310,9 +308,9 @@ class CodeGen(internal val program: PtProgram,
if(jump.address!=null)
throw AssemblyError("cannot jump to memory location in the vm target")
code += if(jump.generatedLabel!=null)
VmCodeInstruction(Instruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!)))
VmCodeInstruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!))
else if(jump.identifier!=null)
VmCodeInstruction(Instruction(Opcode.JUMP, symbol = jump.identifier!!.targetName))
VmCodeInstruction(Opcode.JUMP, symbol = jump.identifier!!.targetName)
else
throw AssemblyError("weird jump")
return code
@ -336,8 +334,7 @@ class CodeGen(internal val program: PtProgram,
val vmDt = vmType(assignment.value.type)
if(ident!=null) {
val address = allocations.get(ident.targetName)
val ins = Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
code += VmCodeInstruction(ins)
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
}
else if(array!=null) {
val variable = array.variable.targetName
@ -347,23 +344,21 @@ class CodeGen(internal val program: PtProgram,
val vmDtArrayIdx = vmType(array.type)
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr))
code += VmCodeInstruction(Opcode.STOREM, vmDtArrayIdx, reg1 = resultRegister, value=variableAddr)
} else {
val indexReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, indexReg)
code += VmCodeInstruction(Instruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr))
code += VmCodeInstruction(Opcode.STOREX, vmDtArrayIdx, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
}
else if(memory!=null) {
val ins =
if(memory.address is PtNumber) {
Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
val addressRegister = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, addressRegister)
Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
}
code += VmCodeInstruction(ins)
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)
}
}
else
throw AssemblyError("weird assigntarget")
@ -377,7 +372,7 @@ class CodeGen(internal val program: PtProgram,
// Call Convention: return value is always returned in r0
code += expressionEval.translateExpression(value, 0)
}
code += VmCodeInstruction(Instruction(Opcode.RETURN))
code += VmCodeInstruction(Opcode.RETURN)
return code
}

View File

@ -7,7 +7,6 @@ import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
@ -21,20 +20,20 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when (expr) {
is PtNumber -> {
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()))
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(Instruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem))
VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem)
} else {
// for strings and arrays etc., load the *address* of the value instead
VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
}
}
is PtAddressOf -> {
val mem = codeGen.allocations.get(expr.identifier.targetName)
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
}
is PtMemoryByte -> {
val addressRegister = codeGen.vmRegisters.nextFree()
@ -100,11 +99,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(arrayIx.index, idxReg)
if(eltSize>1) {
val factorReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize))
code += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg))
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize)
code += VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg)
}
val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName)
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation))
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
return code
}
@ -115,22 +114,22 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when(expr.operator) {
"+" -> { }
"-" -> {
code += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister))
code += VmCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
}
"~" -> {
val regMask = codeGen.vmRegisters.nextFree()
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask)
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)
}
"not" -> {
val label = codeGen.createLabelName()
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
code += VmCodeInstruction(Opcode.BZ, vmDt, reg1=resultRegister, symbol = label)
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1)
code += VmCodeLabel(label)
val regMask = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value=1)
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask)
}
else -> throw AssemblyError("weird prefix operator")
}
@ -165,11 +164,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> uword: sign extend
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister)
}
DataType.UBYTE -> {
// ubyte -> uword: sign extend
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister)
}
DataType.WORD -> { }
DataType.FLOAT -> {
@ -182,11 +181,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> word: sign extend
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister)
}
DataType.UBYTE -> {
// byte -> word: sign extend
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister)
}
DataType.UWORD -> { }
DataType.FLOAT -> {
@ -228,57 +227,57 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val signed = binExpr.left.type in SignedDatatypes
when(binExpr.operator) {
"+" -> {
code += VmCodeInstruction(Instruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"-" -> {
code += VmCodeInstruction(Instruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"*" -> {
code += VmCodeInstruction(Instruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"/" -> {
code += VmCodeInstruction(Instruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"%" -> {
code += VmCodeInstruction(Instruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"|", "or" -> {
code += VmCodeInstruction(Instruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"&", "and" -> {
code += VmCodeInstruction(Instruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"^", "xor" -> {
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"<<" -> {
code += VmCodeInstruction(Instruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
">>" -> {
val opc = if(signed) Opcode.ASR else Opcode.LSR
code += VmCodeInstruction(Instruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"==" -> {
code += VmCodeInstruction(Instruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"!=" -> {
code += VmCodeInstruction(Instruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"<" -> {
val ins = if(signed) Opcode.SLTS else Opcode.SLT
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
">" -> {
val ins = if(signed) Opcode.SGTS else Opcode.SGT
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
"<=" -> {
val ins = if(signed) Opcode.SLES else Opcode.SLE
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
">=" -> {
val ins = if(signed) Opcode.SGES else Opcode.SGE
code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
else -> throw AssemblyError("weird operator ${binExpr.operator}")
}
@ -293,12 +292,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(arg, argReg)
val vmDt = codeGen.vmType(parameter.type)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem)
}
code += VmCodeInstruction(Instruction(Opcode.CALL, symbol=fcall.functionName))
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
if(!fcall.void && resultRegister!=0) {
// Call convention: result value is in r0, so put it in the required register instead. TODO does this work correctly?
code += VmCodeInstruction(Instruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0))
code += VmCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0)
}
return code
}

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- 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
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

View File

@ -24,8 +24,9 @@ main {
}
txt.print_uw(ww) ; 8
txt.nl()
txt.nl()
for wc in [4096,8192,16384] {
for wc in [4097,8193,16385] {
txt.print_uw(wc)
txt.spc()
ww++
@ -33,19 +34,24 @@ main {
txt.print_uw(ww) ; 11
txt.nl()
; for bc in 10 to 20 step 3 {
; ; 10,13,16,19 -> 4
; ww++
; }
; txt.print_uw(ww)
; txt.nl()
; for bc in 30 to 10 step -4 {
; ; 30,26,22,18,14,10,6,2 -> +8 -> 12
; ww++
; }
; txt.print_uw(ww)
; txt.nl()
;
for bc in 10 to 20 step 3 {
; 10,13,16,19
txt.print_ub(bc)
txt.spc()
ww++
}
txt.print_uw(ww) ; 15
txt.nl()
for bc in 30 to 10 step -4 {
; 30,26,22,18,14,10,6,2
txt.print_ub(bc)
txt.spc()
ww++
}
txt.print_uw(ww) ; 23
txt.nl()
sys.exit(99)

View File

@ -3,6 +3,7 @@ plugins {
id 'java'
id 'application'
id "org.jetbrains.kotlin.jvm"
id "io.kotest" version "0.3.9"
}
java {
@ -26,6 +27,7 @@ compileTestKotlin {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.14"
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.1.0'
}
sourceSets {
@ -37,6 +39,23 @@ sourceSets {
srcDirs = ["${project.projectDir}/res"]
}
}
test {
java {
srcDir "${project.projectDir}/test"
}
}
}
// note: there are no unit tests in this module!
test {
// Enable JUnit 5 (Gradle 4.6+).
useJUnitPlatform()
// Always run tests, even when nothing changed.
dependsOn 'cleanTest'
// Show test results.
testLogging {
events "skipped", "failed"
}
}

View File

@ -40,7 +40,7 @@ class Assembler {
val array = values.split(',').map { parseValue(it.trim(), 0) }
for (value in array) {
memory.setUW(address, value.toUShort())
address++
address += 2
}
}
else -> throw IllegalArgumentException("mem instr $what")

View File

@ -33,7 +33,6 @@ loadm reg1, address - load reg1 with value in memory address
loadi reg1, reg2 - load reg1 with value in memory indirect, memory pointed to by reg2
loadx reg1, reg2, address - load reg1 with value in memory address, indexed by value in reg2
loadr reg1, reg2 - load reg1 with value in register reg2
swapreg reg1, reg2 - swap values in reg1 and reg2
storem reg1, address - store reg1 in memory address
storei reg1, reg2 - store reg1 in memory indirect, memory pointed to by reg2
@ -130,7 +129,8 @@ nop - do nothing
breakpoint - trigger a breakpoint
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte
swap [b, w] reg1, reg2 - reg1 = swapped lsb and msb from register reg2 (16 bits) or lsw and msw (32 bits)
swap [b, w] reg1 - swap lsb and msb in register reg1 (16 bits) or lsw and msw (32 bits)
swapreg reg1, reg2 - swap values in reg1 and reg2
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented, requires 32bits regs)
push [b, w] reg1 - push value in reg1 on the stack
pop [b, w] reg1 - pop value from stack into reg1
@ -227,8 +227,17 @@ data class Instruction(
) {
override fun toString(): String {
val result = mutableListOf(opcode.name.lowercase())
if(instructionFormats.getValue(opcode).datatypes.isNotEmpty() && type==null)
throw IllegalArgumentException("opcode $opcode requires type")
val format = instructionFormats.getValue(opcode)
if(format.datatypes.isNotEmpty() && type==null)
throw IllegalArgumentException("missing type")
if(format.reg1 && reg1==null ||
format.reg2 && reg2==null ||
format.reg3 && reg3==null)
throw IllegalArgumentException("missing a register")
if(format.value && (value==null && symbol==null))
throw IllegalArgumentException("missing a value or symbol")
when(type) {
VmDataType.BYTE -> result.add(".b ")
@ -332,7 +341,7 @@ val instructionFormats = mutableMapOf(
Opcode.COPY to InstructionFormat(NN, true, true, false, true ),
Opcode.COPYZ to InstructionFormat(NN, true, true, false, false),
Opcode.SWAP to InstructionFormat(BW, true, true, false, false),
Opcode.SWAP to InstructionFormat(BW, true, false, false, false),
Opcode.PUSH to InstructionFormat(BW, true, false, false, false),
Opcode.POP to InstructionFormat(BW, true, false, false, false),
Opcode.CONCAT to InstructionFormat(BW, true, true, true, false),

View File

@ -36,7 +36,8 @@ enum class Syscall {
GFX_PLOT,
RND,
WAIT,
WAITVSYNC
WAITVSYNC,
TMP_PRINT_UW
}
object SysCalls {
@ -91,6 +92,9 @@ object SysCalls {
Thread.sleep(millis)
}
Syscall.WAITVSYNC -> vm.waitvsync()
Syscall.TMP_PRINT_UW -> {
println("VM: UW=${vm.registers.getUW(0)}")
}
else -> TODO("syscall ${call.name}")
}
}

View File

@ -694,9 +694,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsSWAP(i: Instruction) {
when(i.type!!) {
VmDataType.BYTE -> {
val value = registers.getUW(i.reg2!!)
val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt()
registers.setUW(i.reg1!!, newValue.toUShort())
val value = registers.getUW(i.reg1!!)
val newValue = 0xea31 // value.toUByte()*256u + (value.toInt() ushr 8).toUInt()
registers.setUW(i.reg1, newValue.toUShort())
}
VmDataType.WORD -> TODO("swap.w requires 32-bits registers")
}

View File

@ -0,0 +1,75 @@
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.VmDataType
import prog8.vm.instructionFormats
class TestInstructions: FunSpec({
test("simple") {
val ins = Instruction(Opcode.NOP)
ins.opcode shouldBe Opcode.NOP
ins.type shouldBe null
ins.reg1 shouldBe null
ins.reg2 shouldBe null
ins.reg3 shouldBe null
ins.value shouldBe null
ins.symbol shouldBe null
ins.toString() shouldBe "nop"
}
test("with value") {
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42, value = 9999)
ins.opcode shouldBe Opcode.BZ
ins.type shouldBe VmDataType.BYTE
ins.reg1 shouldBe 42
ins.reg2 shouldBe null
ins.reg3 shouldBe null
ins.value shouldBe 9999
ins.symbol shouldBe null
ins.toString() shouldBe "bz.b r42,9999"
}
test("with label") {
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, reg2=22, reg3=33, symbol = listOf("a","b","c"))
ins.opcode shouldBe Opcode.BZ
ins.type shouldBe VmDataType.WORD
ins.reg1 shouldBe 11
ins.reg2 shouldBe 22
ins.reg3 shouldBe 33
ins.value shouldBe null
ins.symbol shouldBe listOf("a","b","c")
ins.toString() shouldBe "bz.w r11,r22,r33,_a.b.c"
}
test("missing type should fail") {
val ins = Instruction(Opcode.BZ, reg1=42, value=9999)
shouldThrow<IllegalArgumentException> {
ins.toString()
}
}
test("missing registers should fail") {
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, value=9999)
shouldThrow<IllegalArgumentException> {
ins.toString()
}
}
test("missing value should fail") {
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
shouldThrow<IllegalArgumentException> {
ins.toString()
}
}
test("all instructionformats") {
Opcode.values().forEach {
instructionFormats[it] shouldNotBe null
}
}
})

View File

@ -0,0 +1,67 @@
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import prog8.vm.Memory
class TestMemory: FunSpec({
test("reset") {
val mem = Memory()
mem.setUB(1000, 42u)
mem.getUB(1000) shouldBe 42u
mem.reset()
mem.getUB(1000) shouldBe 0u
}
test("byte access") {
val mem = Memory()
mem.setUB(1000, 123u)
mem.getUB(1000) shouldBe 123u
mem.getSB(1000) shouldBe 123
mem.setUB(1000, 234u)
mem.getUB(1000) shouldBe 234u
mem.getSB(1000) shouldBe -22
mem.setSB(1000, -99)
mem.getSB(1000) shouldBe -99
mem.getUB(1000) shouldBe 157u
}
test("word access") {
val mem = Memory()
mem.setUW(1000, 12345u)
mem.getUW(1000) shouldBe 12345u
mem.getSW(1000) shouldBe 12345
mem.setUW(1000, 55444u)
mem.getUW(1000) shouldBe 55444u
mem.getSW(1000) shouldBe -10092
mem.setSW(1000, -23456)
mem.getSW(1000) shouldBe -23456
mem.getUW(1000) shouldBe 42080u
mem.setUW(1000, 0xea31u)
mem.getUB(1000) shouldBe 0x31u
mem.getUB(1001) shouldBe 0xeau
}
test("setstring and getstring") {
val mem = Memory()
mem.setString(1000, "******************", false)
mem.setString(1000, "Hello world!", true)
mem.getString(1000) shouldBe "Hello world!"
mem.getUB(1012) shouldBe 0u
mem.getUB(1013) shouldBe 42u
mem.setString(1000, "Goodbye", false)
mem.getString(1000) shouldBe "Goodbyeorld!"
}
test("illegal address") {
val mem = Memory()
shouldThrow<ArrayIndexOutOfBoundsException> {
mem.getUB(9999999)
}
shouldThrow<ArrayIndexOutOfBoundsException> {
mem.setUB(9999999, 0u)
}
}
})

View File

@ -0,0 +1,41 @@
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import prog8.vm.Registers
class TestRegisters: FunSpec({
test("reset") {
val regs = Registers()
regs.setUB(1, 42u)
regs.getUB(1) shouldBe 42u
regs.reset()
regs.getUB(1) shouldBe 0u
}
test("byte access") {
val regs = Registers()
regs.setUB(1000, 123u)
regs.getUB(1000) shouldBe 123u
regs.getSB(1000) shouldBe 123
regs.setUB(1000, 234u)
regs.getUB(1000) shouldBe 234u
regs.getSB(1000) shouldBe -22
regs.setSB(1000, -99)
regs.getSB(1000) shouldBe -99
regs.getUB(1000) shouldBe 157u
}
test("word access") {
val regs = Registers()
regs.setUW(1000, 12345u)
regs.getUW(1000) shouldBe 12345u
regs.getSW(1000) shouldBe 12345
regs.setUW(1000, 55444u)
regs.getUW(1000) shouldBe 55444u
regs.getSW(1000) shouldBe -10092
regs.setSW(1000, -23456)
regs.getSW(1000) shouldBe -23456
regs.getUW(1000) shouldBe 42080u
}
})

View File

@ -4,10 +4,13 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
</component>
</module>