mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
added for loop over constant ranges
This commit is contained in:
parent
0dc592b819
commit
0a0c58d450
@ -126,8 +126,8 @@ class PtRange(type: DataType, position: Position) : PtExpression(type, position)
|
|||||||
get() = children[0] as PtExpression
|
get() = children[0] as PtExpression
|
||||||
val to: PtExpression
|
val to: PtExpression
|
||||||
get() = children[1] as PtExpression
|
get() = children[1] as PtExpression
|
||||||
val step: PtExpression
|
val step: PtNumber
|
||||||
get() = children[2] as PtExpression
|
get() = children[2] as PtNumber
|
||||||
|
|
||||||
override fun printProperties() {}
|
override fun printProperties() {}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
vmprog.addBlock(translate(block))
|
vmprog.addBlock(translate(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("Vm codegen: amount of vm registers=${vmRegisters.peekNext()}")
|
||||||
|
|
||||||
return vmprog
|
return vmprog
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +105,7 @@ 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")
|
||||||
}
|
}
|
||||||
if(code.lines.isNotEmpty())
|
if(code.lines.isNotEmpty() && node.position.line!=0)
|
||||||
code.lines.add(0, VmCodeComment(node.position.toString()))
|
code.lines.add(0, VmCodeComment(node.position.toString()))
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -114,9 +116,10 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
when(iterable) {
|
when(iterable) {
|
||||||
is PtRange -> {
|
is PtRange -> {
|
||||||
TODO("forloop ${loopvar.dt} ${loopvar.scopedName} in range ${iterable} ")
|
if(iterable.from is PtNumber && iterable.to is PtNumber)
|
||||||
iterable.printIndented(0)
|
code += translateForInConstantRange(forLoop, loopvar)
|
||||||
TODO("forloop over range")
|
else
|
||||||
|
code += translateForInNonConstantRange(forLoop, loopvar)
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
val arrayAddress = allocations.get(iterable.targetName)
|
val arrayAddress = allocations.get(iterable.targetName)
|
||||||
@ -139,19 +142,9 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
} else {
|
} else {
|
||||||
// iterate over array
|
// iterate over array
|
||||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||||
val elementSize = program.memsizer.memorySize(elementDt).toUInt()
|
val elementSize = program.memsizer.memorySize(elementDt)
|
||||||
val lengthBytes = iterableVar.length!! * elementSize.toInt()
|
val lengthBytes = iterableVar.length!! * elementSize
|
||||||
val lengthReg = vmRegisters.nextFree()
|
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(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)
|
||||||
@ -159,7 +152,7 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
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 += addConst(VmDataType.BYTE, indexReg, elementSize)
|
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
||||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
||||||
code += VmCodeLabel(endLabel)
|
code += VmCodeLabel(endLabel)
|
||||||
}
|
}
|
||||||
@ -169,17 +162,111 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addConst(dt: VmDataType, reg: Int, value: UInt): VmCodeChunk {
|
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
|
||||||
|
val iterable = forLoop.iterable as PtRange
|
||||||
|
TODO("forloop ${loopvar.dt} ${loopvar.scopedName} in non-constant range ${iterable} ")
|
||||||
|
iterable.printIndented(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
|
||||||
|
val iterable = forLoop.iterable as PtRange
|
||||||
|
val step = iterable.step.number.toInt()
|
||||||
|
val range = IntProgression.fromClosedRange(
|
||||||
|
(iterable.from as PtNumber).number.toInt(),
|
||||||
|
(iterable.to as PtNumber).number.toInt() + step,
|
||||||
|
step)
|
||||||
|
if (range.isEmpty() || range.step==0)
|
||||||
|
throw AssemblyError("empty range or step 0")
|
||||||
|
|
||||||
|
val loopLabel = createLabelName()
|
||||||
|
val loopvarAddress = allocations.get(loopvar.scopedName)
|
||||||
|
val indexReg = vmRegisters.nextFree()
|
||||||
|
val endvalueReg = vmRegisters.nextFree()
|
||||||
|
val vmDt = vmType(loopvar.dt)
|
||||||
|
val code = VmCodeChunk()
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=endvalueReg, value=range.last)
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=indexReg, value=range.first)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=indexReg, value=loopvarAddress)
|
||||||
|
code += VmCodeLabel(loopLabel)
|
||||||
|
code += translateNode(forLoop.statements)
|
||||||
|
if(range.step==1 || range.step==2) {
|
||||||
|
code += addConstMem(vmDt, loopvarAddress.toUInt(), range.step)
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = indexReg, value = loopvarAddress)
|
||||||
|
} else {
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = indexReg, value = loopvarAddress)
|
||||||
|
code += addConstReg(vmDt, indexReg, range.step)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = indexReg, value = loopvarAddress)
|
||||||
|
}
|
||||||
|
code += VmCodeInstruction(Opcode.BNE, vmDt, reg1=indexReg, reg2=endvalueReg, symbol=loopLabel)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addConstReg(dt: VmDataType, reg: Int, value: Int): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
when(value) {
|
when(value) {
|
||||||
0u -> { /* do nothing */ }
|
0 -> { /* do nothing */ }
|
||||||
1u -> {
|
1 -> {
|
||||||
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
}
|
}
|
||||||
|
2 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
|
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||||
|
}
|
||||||
|
-1 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
|
}
|
||||||
|
-2 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
|
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val valueReg = vmRegisters.nextFree()
|
val valueReg = vmRegisters.nextFree()
|
||||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value.toInt())
|
if(value>0) {
|
||||||
code += VmCodeInstruction(Opcode.ADD, dt, reg1=reg, reg2=reg, reg3=valueReg)
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value= value)
|
||||||
|
code += VmCodeInstruction(Opcode.ADD, dt, reg1 = reg, reg2 = reg, reg3 = valueReg)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value= -value)
|
||||||
|
code += VmCodeInstruction(Opcode.SUB, dt, reg1 = reg, reg2 = reg, reg3 = valueReg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addConstMem(dt: VmDataType, address: UInt, value: Int): VmCodeChunk {
|
||||||
|
val code = VmCodeChunk()
|
||||||
|
when(value) {
|
||||||
|
0 -> { /* do nothing */ }
|
||||||
|
1 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||||
|
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||||
|
}
|
||||||
|
-1 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||||
|
}
|
||||||
|
-2 -> {
|
||||||
|
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||||
|
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val valueReg = vmRegisters.nextFree()
|
||||||
|
val operandReg = vmRegisters.nextFree()
|
||||||
|
if(value>0) {
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, dt, reg1=valueReg, value=address.toInt())
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=operandReg, value=value)
|
||||||
|
code += VmCodeInstruction(Opcode.ADD, dt, reg1 = valueReg, reg2 = valueReg, reg3 = operandReg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=valueReg, value=address.toInt())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, dt, reg1=valueReg, value=address.toInt())
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=operandReg, value=-value)
|
||||||
|
code += VmCodeInstruction(Opcode.SUB, dt, reg1 = valueReg, reg2 = valueReg, reg3 = operandReg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=valueReg, value=address.toInt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
|
@ -483,7 +483,7 @@ class IntermediateAstMaker(val program: Program) {
|
|||||||
val range=PtRange(type, srcRange.position)
|
val range=PtRange(type, srcRange.position)
|
||||||
range.add(transformExpression(srcRange.from))
|
range.add(transformExpression(srcRange.from))
|
||||||
range.add(transformExpression(srcRange.to))
|
range.add(transformExpression(srcRange.to))
|
||||||
range.add(transformExpression(srcRange.step))
|
range.add(transformExpression(srcRange.step) as PtNumber)
|
||||||
return range
|
return range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +34,11 @@ main {
|
|||||||
txt.print_uw(ww) ; 11
|
txt.print_uw(ww) ; 11
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
for bc in 10 to 20 step 3 {
|
const ubyte rfrom = 10
|
||||||
; 10,13,16,19
|
const ubyte rto = 17
|
||||||
|
|
||||||
|
for bc in rfrom to rto step 2 {
|
||||||
|
; 10,12,14,16
|
||||||
txt.print_ub(bc)
|
txt.print_ub(bc)
|
||||||
txt.spc()
|
txt.spc()
|
||||||
ww++
|
ww++
|
||||||
@ -43,7 +46,7 @@ main {
|
|||||||
txt.print_uw(ww) ; 15
|
txt.print_uw(ww) ; 15
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
for bc in 30 to 10 step -4 {
|
for bc in 30 to 0 step -4 {
|
||||||
; 30,26,22,18,14,10,6,2
|
; 30,26,22,18,14,10,6,2
|
||||||
txt.print_ub(bc)
|
txt.print_ub(bc)
|
||||||
txt.spc()
|
txt.spc()
|
||||||
|
@ -61,28 +61,28 @@ BRANCHING
|
|||||||
---------
|
---------
|
||||||
All have type b or w.
|
All have type b or w.
|
||||||
|
|
||||||
bz reg1, value - branch if reg1 is zero
|
bz reg1, location - branch to location if reg1 is zero
|
||||||
bnz reg1, value - branch if reg1 is not zero
|
bnz reg1, location - branch to location if reg1 is not zero
|
||||||
beq reg1, reg2, value - jump to location in program given by value, if reg1 == reg2
|
beq reg1, reg2, location - jump to location in program given by location, if reg1 == reg2
|
||||||
bne reg1, reg2, value - jump to location in program given by value, if reg1 != reg2
|
bne reg1, reg2, location - jump to location in program given by location, if reg1 != reg2
|
||||||
blt reg1, reg2, value - jump to location in program given by value, if reg1 < reg2 (unsigned)
|
blt reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (unsigned)
|
||||||
blts reg1, reg2, value - jump to location in program given by value, if reg1 < reg2 (signed)
|
blts reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (signed)
|
||||||
ble reg1, reg2, value - jump to location in program given by value, if reg1 <= reg2 (unsigned)
|
ble reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (unsigned)
|
||||||
bles reg1, reg2, value - jump to location in program given by value, if reg1 <= reg2 (signed)
|
bles reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (signed)
|
||||||
bgt reg1, reg2, value - jump to location in program given by value, if reg1 > reg2 (unsigned)
|
bgt reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
||||||
bgts reg1, reg2, value - jump to location in program given by value, if reg1 > reg2 (signed)
|
bgts reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (signed)
|
||||||
bge reg1, reg2, value - jump to location in program given by value, if reg1 >= reg2 (unsigned)
|
bge reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
||||||
bges reg1, reg2, value - jump to location in program given by value, if reg1 >= reg2 (signed)
|
bges reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (signed)
|
||||||
seq reg1, reg2, reg3 - set reg=1 if reg2 == reg3, otherwise set reg1=0
|
seq reg1, reg2, reg3 - set reg=1 if reg2 == reg3, otherwise set reg1=0
|
||||||
sne reg1, reg2, reg3 - set reg=1 if reg2 != reg3, otherwise set reg1=0
|
sne reg1, reg2, reg3 - set reg=1 if reg2 != reg3, otherwise set reg1=0
|
||||||
slt reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (unsigned), otherwise set reg1=0
|
slt reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (unsigned), otherwise set reg1=0
|
||||||
slts reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (signed), otherwise set reg1=0
|
slts reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (signed), otherwise set reg1=0
|
||||||
sle reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (unsigned), otherwise set reg1=0
|
sle reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (unsigned), otherwise set reg1=0
|
||||||
sles reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (signed), otherwise set reg1=0
|
sles reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (signed), otherwise set reg1=0
|
||||||
sgt reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (unsigned), otherwise set reg1=0
|
sgt reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (unsigned), otherwise set reg1=0
|
||||||
sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), otherwise set reg1=0
|
sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), otherwise set reg1=0
|
||||||
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
|
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
|
||||||
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
|
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
|
||||||
|
|
||||||
TODO: support for the prog8 special branching instructions if_XX (bcc, bcs etc.)
|
TODO: support for the prog8 special branching instructions if_XX (bcc, bcs etc.)
|
||||||
but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird
|
but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird
|
||||||
@ -95,7 +95,9 @@ All have type b or w. Note: result types are the same as operand types! E.g. byt
|
|||||||
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
|
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
|
||||||
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
|
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
|
||||||
inc reg1 - reg1 = reg1+1
|
inc reg1 - reg1 = reg1+1
|
||||||
|
incm address - memory at address += 1
|
||||||
dec reg1 - reg1 = reg1-1
|
dec reg1 - reg1 = reg1-1
|
||||||
|
decm address - memory at address -= 1
|
||||||
neg reg1 - reg1 = sign negation of reg1
|
neg reg1 - reg1 = sign negation of reg1
|
||||||
add reg1, reg2, reg3 - reg1 = reg2+reg3 (unsigned + signed)
|
add reg1, reg2, reg3 - reg1 = reg2+reg3 (unsigned + signed)
|
||||||
sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signed)
|
sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signed)
|
||||||
@ -181,7 +183,9 @@ enum class Opcode {
|
|||||||
SGES,
|
SGES,
|
||||||
|
|
||||||
INC,
|
INC,
|
||||||
|
INCM,
|
||||||
DEC,
|
DEC,
|
||||||
|
DECM,
|
||||||
NEG,
|
NEG,
|
||||||
ADD,
|
ADD,
|
||||||
SUB,
|
SUB,
|
||||||
@ -225,19 +229,22 @@ data class Instruction(
|
|||||||
val value: Int?=null, // 0-$ffff
|
val value: Int?=null, // 0-$ffff
|
||||||
val symbol: List<String>?=null // alternative to value
|
val symbol: List<String>?=null // alternative to value
|
||||||
) {
|
) {
|
||||||
override fun toString(): String {
|
init {
|
||||||
val result = mutableListOf(opcode.name.lowercase())
|
|
||||||
val format = instructionFormats.getValue(opcode)
|
val format = instructionFormats.getValue(opcode)
|
||||||
if(format.datatypes.isNotEmpty() && type==null)
|
if(format.datatypes.isNotEmpty() && type==null)
|
||||||
throw IllegalArgumentException("missing type")
|
throw IllegalArgumentException("missing type")
|
||||||
|
|
||||||
if(format.reg1 && reg1==null ||
|
if(format.reg1 && reg1==null ||
|
||||||
format.reg2 && reg2==null ||
|
format.reg2 && reg2==null ||
|
||||||
format.reg3 && reg3==null)
|
format.reg3 && reg3==null)
|
||||||
throw IllegalArgumentException("missing a register")
|
throw IllegalArgumentException("missing a register")
|
||||||
|
|
||||||
if(format.value && (value==null && symbol==null))
|
if(format.value && (value==null && symbol==null))
|
||||||
throw IllegalArgumentException("missing a value or symbol")
|
throw IllegalArgumentException("missing a value or symbol")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val result = mutableListOf(opcode.name.lowercase())
|
||||||
|
|
||||||
when(type) {
|
when(type) {
|
||||||
VmDataType.BYTE -> result.add(".b ")
|
VmDataType.BYTE -> result.add(".b ")
|
||||||
@ -320,7 +327,9 @@ val instructionFormats = mutableMapOf(
|
|||||||
Opcode.SGES to InstructionFormat(BW, true, true, true, false),
|
Opcode.SGES to InstructionFormat(BW, true, true, true, false),
|
||||||
|
|
||||||
Opcode.INC to InstructionFormat(BW, true, false, false, false),
|
Opcode.INC to InstructionFormat(BW, true, false, false, false),
|
||||||
|
Opcode.INCM to InstructionFormat(BW, false, false, false, true ),
|
||||||
Opcode.DEC to InstructionFormat(BW, true, false, false, false),
|
Opcode.DEC to InstructionFormat(BW, true, false, false, false),
|
||||||
|
Opcode.DECM to InstructionFormat(BW, false, false, false, true ),
|
||||||
Opcode.NEG to InstructionFormat(BW, true, false, false, false),
|
Opcode.NEG to InstructionFormat(BW, true, false, false, false),
|
||||||
Opcode.ADD to InstructionFormat(BW, true, true, true, false),
|
Opcode.ADD to InstructionFormat(BW, true, true, true, false),
|
||||||
Opcode.SUB to InstructionFormat(BW, true, true, true, false),
|
Opcode.SUB to InstructionFormat(BW, true, true, true, false),
|
||||||
|
@ -121,7 +121,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.SGES -> InsSGES(ins)
|
Opcode.SGES -> InsSGES(ins)
|
||||||
|
|
||||||
Opcode.INC -> InsINC(ins)
|
Opcode.INC -> InsINC(ins)
|
||||||
|
Opcode.INCM -> InsINCM(ins)
|
||||||
Opcode.DEC -> InsDEC(ins)
|
Opcode.DEC -> InsDEC(ins)
|
||||||
|
Opcode.DECM -> InsDECM(ins)
|
||||||
Opcode.NEG -> InsNEG(ins)
|
Opcode.NEG -> InsNEG(ins)
|
||||||
Opcode.ADD -> InsADD(ins)
|
Opcode.ADD -> InsADD(ins)
|
||||||
Opcode.SUB -> InsSUB(ins)
|
Opcode.SUB -> InsSUB(ins)
|
||||||
@ -507,6 +509,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsINCM(i: Instruction) {
|
||||||
|
when(i.type!!) {
|
||||||
|
VmDataType.BYTE -> memory.setUB(i.value!!, (memory.getUB(i.value)+1u).toUByte())
|
||||||
|
VmDataType.WORD -> memory.setUW(i.value!!, (memory.getUW(i.value)+1u).toUShort())
|
||||||
|
}
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsDEC(i: Instruction) {
|
private fun InsDEC(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1)-1u).toUByte())
|
VmDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1)-1u).toUByte())
|
||||||
@ -515,6 +525,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsDECM(i: Instruction) {
|
||||||
|
when(i.type!!) {
|
||||||
|
VmDataType.BYTE -> memory.setUB(i.value!!, (memory.getUB(i.value)-1u).toUByte())
|
||||||
|
VmDataType.WORD -> memory.setUW(i.value!!, (memory.getUW(i.value)-1u).toUShort())
|
||||||
|
}
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsNEG(i: Instruction) {
|
private fun InsNEG(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1).toInt()).toUByte())
|
VmDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1).toInt()).toUByte())
|
||||||
|
@ -47,23 +47,20 @@ class TestInstructions: FunSpec({
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("missing type should fail") {
|
test("missing type should fail") {
|
||||||
val ins = Instruction(Opcode.BZ, reg1=42, value=9999)
|
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrow<IllegalArgumentException> {
|
||||||
ins.toString()
|
Instruction(Opcode.BZ, reg1=42, value=9999)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("missing registers should fail") {
|
test("missing registers should fail") {
|
||||||
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, value=9999)
|
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrow<IllegalArgumentException> {
|
||||||
ins.toString()
|
Instruction(Opcode.BZ, VmDataType.BYTE, value=9999)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("missing value should fail") {
|
test("missing value should fail") {
|
||||||
val ins = Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
|
|
||||||
shouldThrow<IllegalArgumentException> {
|
shouldThrow<IllegalArgumentException> {
|
||||||
ins.toString()
|
Instruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user