mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
vm: implemented some self-assign instructions
This commit is contained in:
parent
4e1184a400
commit
181b98ef9e
@ -12,27 +12,24 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
|||||||
print(type)
|
print(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun isSameTargetAs(other: PtExpression): Boolean = when(this) {
|
infix fun isSameAs(other: PtExpression): Boolean {
|
||||||
is PtArrayIndexer -> {
|
return when(this) {
|
||||||
if(other is PtArrayIndexer && other.type==type) {
|
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
|
||||||
if(other.variable isSameTargetAs variable) {
|
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index
|
||||||
other.index isSameTargetAs index
|
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
|
||||||
}
|
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
|
||||||
}
|
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
|
||||||
false
|
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
|
||||||
|
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
|
||||||
|
is PtNumber -> other is PtNumber && other.type==type && other.number==number
|
||||||
|
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
|
||||||
|
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
|
||||||
|
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
|
||||||
|
else -> false
|
||||||
}
|
}
|
||||||
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
|
|
||||||
is PtMachineRegister -> other is PtMachineRegister && other.register==register
|
|
||||||
is PtMemoryByte -> other is PtMemoryByte && address isSameTargetAs other.address
|
|
||||||
is PtNumber -> other is PtNumber && other.type == type && other.number==number
|
|
||||||
is PtAddressOf -> other is PtAddressOf && other.identifier isSameTargetAs identifier
|
|
||||||
is PtPrefix -> other is PtPrefix && other.operator==operator && other.value isSameTargetAs value
|
|
||||||
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameTargetAs value
|
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
||||||
val identifier: PtIdentifier
|
val identifier: PtIdentifier
|
||||||
get() = children.single() as PtIdentifier
|
get() = children.single() as PtIdentifier
|
||||||
|
@ -48,14 +48,33 @@ class PtAssignment(position: Position) : PtNode(position) {
|
|||||||
|
|
||||||
val isInplaceAssign: Boolean by lazy {
|
val isInplaceAssign: Boolean by lazy {
|
||||||
val target = target.children.single() as PtExpression
|
val target = target.children.single() as PtExpression
|
||||||
if(value is PtBinaryExpression) {
|
when(val source = value) {
|
||||||
target isSameTargetAs (value as PtBinaryExpression).left
|
is PtArrayIndexer -> {
|
||||||
} else
|
if(target is PtArrayIndexer && source.type==target.type) {
|
||||||
target isSameTargetAs value
|
if(target.variable isSameAs source.variable) {
|
||||||
|
target.index isSameAs source.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
is PtIdentifier -> target is PtIdentifier && target.type==source.type && target.targetName==source.targetName
|
||||||
|
is PtMachineRegister -> target is PtMachineRegister && target.register==source.register
|
||||||
|
is PtMemoryByte -> target is PtMemoryByte && target.address isSameAs source.address
|
||||||
|
is PtNumber -> target is PtNumber && target.type == source.type && target.number==source.number
|
||||||
|
is PtAddressOf -> target is PtAddressOf && target.identifier isSameAs source.identifier
|
||||||
|
is PtPrefix -> {
|
||||||
|
(target is PtPrefix && target.operator==source.operator && target.value isSameAs source.value)
|
||||||
|
||
|
||||||
|
(target is PtIdentifier && (source.value as? PtIdentifier)?.targetName==target.targetName)
|
||||||
|
}
|
||||||
|
is PtTypeCast -> target is PtTypeCast && target.type==source.type && target.value isSameAs source.value
|
||||||
|
is PtBinaryExpression ->
|
||||||
|
target isSameAs source.left
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PtAssignTarget(position: Position) : PtNode(position) {
|
class PtAssignTarget(position: Position) : PtNode(position) {
|
||||||
val identifier: PtIdentifier?
|
val identifier: PtIdentifier?
|
||||||
get() = children.single() as? PtIdentifier
|
get() = children.single() as? PtIdentifier
|
||||||
|
@ -81,9 +81,9 @@ internal class VmCodeInstruction(
|
|||||||
fpReg2: Int?=null, // 0-$ffff
|
fpReg2: Int?=null, // 0-$ffff
|
||||||
value: Int?=null, // 0-$ffff
|
value: Int?=null, // 0-$ffff
|
||||||
fpValue: Float?=null,
|
fpValue: Float?=null,
|
||||||
symbol: List<String>?=null // alternative to value
|
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
|
||||||
): VmCodeLine() {
|
): VmCodeLine() {
|
||||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, symbol)
|
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(reg1!=null && (reg1<0 || reg1>65536))
|
if(reg1!=null && (reg1<0 || reg1>65536))
|
||||||
|
@ -3,12 +3,16 @@ package prog8.codegen.virtual
|
|||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.AssemblyError
|
import prog8.code.core.AssemblyError
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
|
import prog8.code.core.Position
|
||||||
import prog8.vm.Opcode
|
import prog8.vm.Opcode
|
||||||
import prog8.vm.VmDataType
|
import prog8.vm.VmDataType
|
||||||
|
|
||||||
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
|
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
|
||||||
|
|
||||||
internal fun translate(assignment: PtAssignment): VmCodeChunk {
|
internal fun translate(assignment: PtAssignment): VmCodeChunk {
|
||||||
|
if(assignment.target.children.single() is PtMachineRegister)
|
||||||
|
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||||
|
|
||||||
return if (assignment.isInplaceAssign)
|
return if (assignment.isInplaceAssign)
|
||||||
translateInplaceAssign(assignment)
|
translateInplaceAssign(assignment)
|
||||||
else
|
else
|
||||||
@ -16,14 +20,104 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
|
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
|
||||||
// TODO can in-place assignments be optimized more? use special memory versions of instructions instead of register ones?
|
val ident = assignment.target.identifier
|
||||||
return translateRegularAssign(assignment)
|
val memory = assignment.target.memory
|
||||||
|
val array = assignment.target.array
|
||||||
|
|
||||||
|
return if(ident!=null) {
|
||||||
|
val address = codeGen.allocations.get(ident.targetName)
|
||||||
|
assignSelfInMemory(address, assignment.value, assignment.position, assignment)
|
||||||
|
} else if(memory != null) {
|
||||||
|
if(memory.address is PtNumber) {
|
||||||
|
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment.position, assignment)
|
||||||
|
} else {
|
||||||
|
fallbackAssign(assignment)
|
||||||
|
}
|
||||||
|
} else if(array!=null) {
|
||||||
|
// TODO in-place array element assignment?
|
||||||
|
fallbackAssign(assignment)
|
||||||
|
} else {
|
||||||
|
fallbackAssign(assignment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignSelfInMemory(
|
||||||
|
targetAddress: Int,
|
||||||
|
value: PtExpression,
|
||||||
|
position: Position,
|
||||||
|
origAssign: PtAssignment
|
||||||
|
): VmCodeChunk {
|
||||||
|
val vmDt = codeGen.vmType(value.type)
|
||||||
|
val code = VmCodeChunk()
|
||||||
|
when(value) {
|
||||||
|
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||||
|
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
|
||||||
|
is PtPrefix -> return inplacePrefix(value.operator, vmDt, targetAddress)
|
||||||
|
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, targetAddress, origAssign)
|
||||||
|
is PtMemoryByte -> {
|
||||||
|
return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.toUInt()))
|
||||||
|
code // do nothing, mem=mem null assignment.
|
||||||
|
else {
|
||||||
|
// read and write a (i/o) memory location to itself.
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = targetAddress.toInt())
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress.toInt())
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> return fallbackAssign(origAssign)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fallbackAssign(origAssign: PtAssignment): VmCodeChunk {
|
||||||
|
if (codeGen.options.slowCodegenWarnings)
|
||||||
|
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
||||||
|
return translateRegularAssign(origAssign)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun inplaceBinexpr(
|
||||||
|
operator: String,
|
||||||
|
right: PtExpression,
|
||||||
|
vmDt: VmDataType,
|
||||||
|
targetAddress: Int,
|
||||||
|
origAssign: PtAssignment
|
||||||
|
): VmCodeChunk {
|
||||||
|
when(operator) {
|
||||||
|
"+" -> { /* TODO */ }
|
||||||
|
"-" -> { /* TODO */ }
|
||||||
|
"*" -> { /* TODO */ }
|
||||||
|
"/" -> { /* TODO */ }
|
||||||
|
"|" -> { /* TODO */ }
|
||||||
|
"&" -> { /* TODO */ }
|
||||||
|
"^" -> { /* TODO */ }
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
return fallbackAssign(origAssign)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk {
|
||||||
|
val code= VmCodeChunk()
|
||||||
|
when(operator) {
|
||||||
|
"+" -> { }
|
||||||
|
"-" -> {
|
||||||
|
code += VmCodeInstruction(Opcode.NEGM, vmDt, value = address)
|
||||||
|
}
|
||||||
|
"~" -> {
|
||||||
|
val regMask = codeGen.vmRegisters.nextFree()
|
||||||
|
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||||
|
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
|
||||||
|
}
|
||||||
|
"not" -> {
|
||||||
|
code += VmCodeInstruction(Opcode.NOTM, vmDt, value = address)
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird prefix operator")
|
||||||
|
}
|
||||||
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
|
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
|
||||||
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
||||||
if(assignment.target.children.single() is PtMachineRegister)
|
|
||||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into 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
|
||||||
|
@ -116,7 +116,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
val notNegativeLabel = codeGen.createLabelName()
|
val notNegativeLabel = codeGen.createLabelName()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=andReg, value=0x80)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=andReg, value=0x80)
|
||||||
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=andReg, reg2=resultRegister)
|
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=andReg, reg2=resultRegister)
|
||||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, symbol = notNegativeLabel)
|
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, labelSymbol = notNegativeLabel)
|
||||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||||
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||||
code += VmCodeLabel(notNegativeLabel)
|
code += VmCodeLabel(notNegativeLabel)
|
||||||
@ -126,7 +126,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
val notNegativeLabel = codeGen.createLabelName()
|
val notNegativeLabel = codeGen.createLabelName()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=andReg, value=0x8000)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=andReg, value=0x8000)
|
||||||
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=andReg, reg2=resultRegister)
|
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=andReg, reg2=resultRegister)
|
||||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, symbol = notNegativeLabel)
|
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, labelSymbol = notNegativeLabel)
|
||||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||||
code += VmCodeLabel(notNegativeLabel)
|
code += VmCodeLabel(notNegativeLabel)
|
||||||
}
|
}
|
||||||
|
@ -123,19 +123,19 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
|
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
|
||||||
code += when(branch.condition) {
|
code += when(branch.condition) {
|
||||||
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, symbol = elseLabel)
|
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
||||||
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, symbol = elseLabel)
|
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
||||||
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, symbol = elseLabel)
|
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
||||||
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, symbol = elseLabel)
|
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||||
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, symbol = elseLabel)
|
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||||
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, symbol = elseLabel)
|
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||||
BranchCondition.VC,
|
BranchCondition.VC,
|
||||||
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
||||||
}
|
}
|
||||||
code += translateNode(branch.trueScope)
|
code += translateNode(branch.trueScope)
|
||||||
if(branch.falseScope.children.isNotEmpty()) {
|
if(branch.falseScope.children.isNotEmpty()) {
|
||||||
val endLabel = createLabelName()
|
val endLabel = createLabelName()
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
code += VmCodeLabel(elseLabel)
|
code += VmCodeLabel(elseLabel)
|
||||||
code += translateNode(branch.falseScope)
|
code += translateNode(branch.falseScope)
|
||||||
code += VmCodeLabel(endLabel)
|
code += VmCodeLabel(endLabel)
|
||||||
@ -163,21 +163,21 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
val values = choice.values.children.map {it as PtNumber}
|
val values = choice.values.children.map {it as PtNumber}
|
||||||
if(values.size==1) {
|
if(values.size==1) {
|
||||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||||
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, symbol = skipLabel)
|
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||||
code += translateNode(choice.statements)
|
code += translateNode(choice.statements)
|
||||||
if(choice.statements.children.last() !is PtReturn)
|
if(choice.statements.children.last() !is PtReturn)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
} else {
|
} else {
|
||||||
val matchLabel = createLabelName()
|
val matchLabel = createLabelName()
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||||
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, symbol = matchLabel)
|
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||||
}
|
}
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = skipLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||||
code += VmCodeLabel(matchLabel)
|
code += VmCodeLabel(matchLabel)
|
||||||
code += translateNode(choice.statements)
|
code += translateNode(choice.statements)
|
||||||
if(choice.statements.children.last() !is PtReturn)
|
if(choice.statements.children.last() !is PtReturn)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||||
}
|
}
|
||||||
code += VmCodeLabel(skipLabel)
|
code += VmCodeLabel(skipLabel)
|
||||||
}
|
}
|
||||||
@ -209,11 +209,11 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||||
code += VmCodeLabel(loopLabel)
|
code += VmCodeLabel(loopLabel)
|
||||||
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress)
|
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.BZ, VmDataType.BYTE, reg1=0, labelSymbol = endLabel)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress)
|
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||||
code += VmCodeLabel(endLabel)
|
code += VmCodeLabel(endLabel)
|
||||||
} else {
|
} else {
|
||||||
// iterate over array
|
// iterate over array
|
||||||
@ -224,12 +224,12 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||||
code += VmCodeLabel(loopLabel)
|
code += VmCodeLabel(loopLabel)
|
||||||
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel)
|
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = endLabel)
|
||||||
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
|
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
|
||||||
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress)
|
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress)
|
||||||
code += translateNode(forLoop.statements)
|
code += translateNode(forLoop.statements)
|
||||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||||
code += VmCodeLabel(endLabel)
|
code += VmCodeLabel(endLabel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
||||||
}
|
}
|
||||||
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
||||||
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, symbol=loopLabel)
|
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,9 +303,9 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
||||||
}
|
}
|
||||||
code += if(rangeEndWrapped==0) {
|
code += if(rangeEndWrapped==0) {
|
||||||
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, symbol = loopLabel)
|
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
||||||
} else {
|
} else {
|
||||||
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, symbol = loopLabel)
|
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -492,16 +492,16 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
// if and else parts
|
// if and else parts
|
||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = elseLabel)
|
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||||
code += VmCodeLabel(elseLabel)
|
code += VmCodeLabel(elseLabel)
|
||||||
code += translateNode(ifElse.elseScope)
|
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(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = afterIfLabel)
|
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += VmCodeLabel(afterIfLabel)
|
code += VmCodeLabel(afterIfLabel)
|
||||||
}
|
}
|
||||||
@ -516,16 +516,16 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
// if and else parts
|
// if and else parts
|
||||||
val elseLabel = createLabelName()
|
val elseLabel = createLabelName()
|
||||||
val afterIfLabel = createLabelName()
|
val afterIfLabel = createLabelName()
|
||||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = elseLabel)
|
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
|
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||||
code += VmCodeLabel(elseLabel)
|
code += VmCodeLabel(elseLabel)
|
||||||
code += translateNode(ifElse.elseScope)
|
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(elseBranch, vmDt, reg1=leftReg, symbol = afterIfLabel)
|
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||||
code += translateNode(ifElse.ifScope)
|
code += translateNode(ifElse.ifScope)
|
||||||
code += VmCodeLabel(afterIfLabel)
|
code += VmCodeLabel(afterIfLabel)
|
||||||
}
|
}
|
||||||
@ -629,7 +629,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
code += VmCodeLabel(repeatLabel)
|
code += VmCodeLabel(repeatLabel)
|
||||||
code += translateNode(repeat.statements)
|
code += translateNode(repeat.statements)
|
||||||
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||||
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)
|
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,9 +638,9 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
if(jump.address!=null)
|
if(jump.address!=null)
|
||||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||||
code += if(jump.generatedLabel!=null)
|
code += if(jump.generatedLabel!=null)
|
||||||
VmCodeInstruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!))
|
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
|
||||||
else if(jump.identifier!=null)
|
else if(jump.identifier!=null)
|
||||||
VmCodeInstruction(Opcode.JUMP, symbol = jump.identifier!!.targetName)
|
VmCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
|
||||||
else
|
else
|
||||||
throw AssemblyError("weird jump")
|
throw AssemblyError("weird jump")
|
||||||
return code
|
return code
|
||||||
|
@ -410,7 +410,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
val valueReg = codeGen.vmRegisters.nextFree()
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
||||||
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, symbol = label)
|
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
||||||
code += VmCodeLabel(label)
|
code += VmCodeLabel(label)
|
||||||
}
|
}
|
||||||
@ -664,7 +664,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
|
code += VmCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName)
|
||||||
if(fcall.type==DataType.FLOAT) {
|
if(fcall.type==DataType.FLOAT) {
|
||||||
if (!fcall.void && resultFpRegister != 0) {
|
if (!fcall.void && resultFpRegister != 0) {
|
||||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
// Call convention: result value is in fr0, so put it in the required register instead.
|
||||||
|
@ -3,8 +3,8 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm: implement the sin/cos functions in math.p8 and make an example 'shader' that uses them
|
- vm: implement the missing in-place operators in inplaceBinexpr()
|
||||||
- vm: add more instructions operating directly on memory instead of only registers? (translate assignment self-assigns in AssignmentGen)
|
- vm: implement the new in-memory instructions in the VirtualMachine eval loop itself.
|
||||||
- complete the Inliner
|
- complete the Inliner
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ Future Things and Ideas
|
|||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
- vm: codeGen: various TODOs to tweak code
|
- vm: codeGen: various TODOs to tweak code
|
||||||
|
- vm: implement remaining sin/cos functions in math.p8
|
||||||
- vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8
|
- vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8
|
||||||
- vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans.
|
- vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans.
|
||||||
- vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us)
|
- vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us)
|
||||||
|
@ -4,19 +4,26 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
|
byte xx
|
||||||
|
byte yy
|
||||||
|
ubyte ubx
|
||||||
|
|
||||||
; a "pixelshader":
|
xx = xx
|
||||||
sys.gfx_enable(0) ; enable lo res screen
|
xx = xx*9
|
||||||
|
xx = yy*9
|
||||||
|
xx = xx+3*yy
|
||||||
|
xx = xx/yy
|
||||||
|
xx = -xx
|
||||||
|
@($4000) = @($4000)
|
||||||
|
@($4000) = @($4000) + 2
|
||||||
|
xx = xx | yy
|
||||||
|
xx = xx & yy
|
||||||
|
xx = xx ^ yy
|
||||||
|
xx = (not xx) as byte
|
||||||
|
xx = (~xx) as byte
|
||||||
|
xx++
|
||||||
|
|
||||||
ubyte angle
|
ubx = not ubx
|
||||||
|
ubx = ~ubx
|
||||||
for angle in 0 to 180 {
|
|
||||||
ubyte xx = math.sinr8u(angle)
|
|
||||||
ubyte yy = math.cosr8u(angle) / 2
|
|
||||||
sys.gfx_plot(xx, yy, 255)
|
|
||||||
}
|
|
||||||
|
|
||||||
repeat {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,6 @@ Currently NO support for 24 or 32 bits integers.
|
|||||||
Floating point operations are just 'f' typed regular instructions, and additionally there are
|
Floating point operations are just 'f' typed regular instructions, and additionally there are
|
||||||
a few fp conversion instructions to
|
a few fp conversion instructions to
|
||||||
|
|
||||||
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
|
|
||||||
|
|
||||||
|
|
||||||
LOAD/STORE
|
LOAD/STORE
|
||||||
----------
|
----------
|
||||||
@ -96,6 +94,7 @@ incm address - memory at address += 1
|
|||||||
dec reg1 - reg1 = reg1-1
|
dec reg1 - reg1 = reg1-1
|
||||||
decm address - memory at address -= 1
|
decm address - memory at address -= 1
|
||||||
neg reg1 - reg1 = sign negation of reg1
|
neg reg1 - reg1 = sign negation of reg1
|
||||||
|
negm address - sign negate memory at address
|
||||||
add reg1, reg2 - reg1 += reg2 (unsigned + signed)
|
add reg1, reg2 - reg1 += reg2 (unsigned + signed)
|
||||||
sub reg1, reg2 - reg1 -= reg2 (unsigned + signed)
|
sub reg1, reg2 - reg1 -= reg2 (unsigned + signed)
|
||||||
mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
|
mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
|
||||||
@ -116,7 +115,9 @@ All have type b or w.
|
|||||||
and reg1, reg2 - reg1 = reg1 bitwise and reg2
|
and reg1, reg2 - reg1 = reg1 bitwise and reg2
|
||||||
or reg1, reg2 - reg1 = reg1 bitwise or reg2
|
or reg1, reg2 - reg1 = reg1 bitwise or reg2
|
||||||
xor reg1, reg2 - reg1 = reg1 bitwise xor reg2
|
xor reg1, reg2 - reg1 = reg1 bitwise xor reg2
|
||||||
|
xorm reg1, address - memory = memory bitwise xor reg1
|
||||||
not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0)
|
not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0)
|
||||||
|
notm address - memory = boolean not of that memory (0->1 , ~0 -> 0)
|
||||||
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
|
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
|
||||||
asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit
|
asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit
|
||||||
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
|
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
|
||||||
@ -211,6 +212,7 @@ enum class Opcode {
|
|||||||
DEC,
|
DEC,
|
||||||
DECM,
|
DECM,
|
||||||
NEG,
|
NEG,
|
||||||
|
NEGM,
|
||||||
ADD,
|
ADD,
|
||||||
SUB,
|
SUB,
|
||||||
MUL,
|
MUL,
|
||||||
@ -226,7 +228,9 @@ enum class Opcode {
|
|||||||
AND,
|
AND,
|
||||||
OR,
|
OR,
|
||||||
XOR,
|
XOR,
|
||||||
|
XORM,
|
||||||
NOT,
|
NOT,
|
||||||
|
NOTM,
|
||||||
ASRN,
|
ASRN,
|
||||||
LSRN,
|
LSRN,
|
||||||
LSLN,
|
LSLN,
|
||||||
@ -277,7 +281,10 @@ val OpcodesWithAddress = setOf(
|
|||||||
Opcode.STOREZM,
|
Opcode.STOREZM,
|
||||||
Opcode.STOREZX,
|
Opcode.STOREZX,
|
||||||
Opcode.INCM,
|
Opcode.INCM,
|
||||||
Opcode.DECM
|
Opcode.DECM,
|
||||||
|
Opcode.NEGM,
|
||||||
|
Opcode.NOTM,
|
||||||
|
Opcode.XORM
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -297,7 +304,7 @@ data class Instruction(
|
|||||||
val fpReg2: Int?=null, // 0-$ffff
|
val fpReg2: Int?=null, // 0-$ffff
|
||||||
val value: Int?=null, // 0-$ffff
|
val value: Int?=null, // 0-$ffff
|
||||||
val fpValue: Float?=null,
|
val fpValue: Float?=null,
|
||||||
val symbol: List<String>?=null // alternative to value
|
val labelSymbol: List<String>?=null // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
val formats = instructionFormats.getValue(opcode)
|
val formats = instructionFormats.getValue(opcode)
|
||||||
@ -318,11 +325,11 @@ data class Instruction(
|
|||||||
throw IllegalArgumentException("too many registers (float)")
|
throw IllegalArgumentException("too many registers (float)")
|
||||||
|
|
||||||
if (type==VmDataType.FLOAT) {
|
if (type==VmDataType.FLOAT) {
|
||||||
if(format.fpValue && (fpValue==null && symbol==null))
|
if(format.fpValue && (fpValue==null && labelSymbol==null))
|
||||||
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
|
throw IllegalArgumentException("$opcode: missing a fp-value or labelsymbol")
|
||||||
} else {
|
} else {
|
||||||
if(format.value && (value==null && symbol==null))
|
if(format.value && (value==null && labelSymbol==null))
|
||||||
throw IllegalArgumentException("$opcode: missing a value or symbol")
|
throw IllegalArgumentException("$opcode: missing a value or labelsymbol")
|
||||||
if (fpReg1 != null || fpReg2 != null)
|
if (fpReg1 != null || fpReg2 != null)
|
||||||
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
||||||
}
|
}
|
||||||
@ -361,7 +368,7 @@ data class Instruction(
|
|||||||
result.add(it.toString())
|
result.add(it.toString())
|
||||||
result.add(",")
|
result.add(",")
|
||||||
}
|
}
|
||||||
symbol?.let {
|
labelSymbol?.let {
|
||||||
result.add("_" + it.joinToString("."))
|
result.add("_" + it.joinToString("."))
|
||||||
}
|
}
|
||||||
if(result.last() == ",")
|
if(result.last() == ",")
|
||||||
@ -464,6 +471,7 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.DEC to InstructionFormat.from("BW,r1"),
|
Opcode.DEC to InstructionFormat.from("BW,r1"),
|
||||||
Opcode.DECM to InstructionFormat.from("BW,v"),
|
Opcode.DECM to InstructionFormat.from("BW,v"),
|
||||||
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
|
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
|
||||||
|
Opcode.NEGM to InstructionFormat.from("BW,v | F,v"),
|
||||||
Opcode.ADD to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
Opcode.ADD to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||||
Opcode.SUB to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
Opcode.SUB to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||||
Opcode.MUL to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
Opcode.MUL to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||||
@ -478,7 +486,9 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.AND to InstructionFormat.from("BW,r1,r2"),
|
Opcode.AND to InstructionFormat.from("BW,r1,r2"),
|
||||||
Opcode.OR to InstructionFormat.from("BW,r1,r2"),
|
Opcode.OR to InstructionFormat.from("BW,r1,r2"),
|
||||||
Opcode.XOR to InstructionFormat.from("BW,r1,r2"),
|
Opcode.XOR to InstructionFormat.from("BW,r1,r2"),
|
||||||
|
Opcode.XORM to InstructionFormat.from("BW,r1,v"),
|
||||||
Opcode.NOT to InstructionFormat.from("BW,r1"),
|
Opcode.NOT to InstructionFormat.from("BW,r1"),
|
||||||
|
Opcode.NOTM to InstructionFormat.from("BW,v"),
|
||||||
Opcode.ASRN to InstructionFormat.from("BW,r1,r2"),
|
Opcode.ASRN to InstructionFormat.from("BW,r1,r2"),
|
||||||
Opcode.LSRN to InstructionFormat.from("BW,r1,r2"),
|
Opcode.LSRN to InstructionFormat.from("BW,r1,r2"),
|
||||||
Opcode.LSLN to InstructionFormat.from("BW,r1,r2"),
|
Opcode.LSLN to InstructionFormat.from("BW,r1,r2"),
|
||||||
|
@ -17,7 +17,7 @@ class TestInstructions: FunSpec({
|
|||||||
ins.reg1 shouldBe null
|
ins.reg1 shouldBe null
|
||||||
ins.reg2 shouldBe null
|
ins.reg2 shouldBe null
|
||||||
ins.value shouldBe null
|
ins.value shouldBe null
|
||||||
ins.symbol shouldBe null
|
ins.labelSymbol shouldBe null
|
||||||
ins.toString() shouldBe "nop"
|
ins.toString() shouldBe "nop"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,18 +28,18 @@ class TestInstructions: FunSpec({
|
|||||||
ins.reg1 shouldBe 42
|
ins.reg1 shouldBe 42
|
||||||
ins.reg2 shouldBe null
|
ins.reg2 shouldBe null
|
||||||
ins.value shouldBe 9999
|
ins.value shouldBe 9999
|
||||||
ins.symbol shouldBe null
|
ins.labelSymbol shouldBe null
|
||||||
ins.toString() shouldBe "bz.b r42,9999"
|
ins.toString() shouldBe "bz.b r42,9999"
|
||||||
}
|
}
|
||||||
|
|
||||||
test("with label") {
|
test("with label") {
|
||||||
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, symbol = listOf("a","b","c"))
|
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = listOf("a","b","c"))
|
||||||
ins.opcode shouldBe Opcode.BZ
|
ins.opcode shouldBe Opcode.BZ
|
||||||
ins.type shouldBe VmDataType.WORD
|
ins.type shouldBe VmDataType.WORD
|
||||||
ins.reg1 shouldBe 11
|
ins.reg1 shouldBe 11
|
||||||
ins.reg2 shouldBe null
|
ins.reg2 shouldBe null
|
||||||
ins.value shouldBe null
|
ins.value shouldBe null
|
||||||
ins.symbol shouldBe listOf("a","b","c")
|
ins.labelSymbol shouldBe listOf("a","b","c")
|
||||||
ins.toString() shouldBe "bz.w r11,_a.b.c"
|
ins.toString() shouldBe "bz.w r11,_a.b.c"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user