fix logical expressions on arbitrary values, for now with boolean() around the operands

This commit is contained in:
Irmen de Jong 2022-06-27 22:26:40 +02:00
parent 06184bdcb1
commit ef92451d1a
12 changed files with 336 additions and 203 deletions

View File

@ -323,6 +323,7 @@ internal class AssignmentAsmGen(private val program: Program,
return false
// optimized code for logical expressions
// note: due to boolean() wrapping of operands, we can use simple bitwise and/or/xor
// TODO assume (hope) cx16.r9 isn't used for anything else during the use of this...
if(expr.operator=="and") {
val iDt = expr.left.inferType(program)
@ -2150,10 +2151,7 @@ internal class AssignmentAsmGen(private val program: Program,
RegisterOrPair.XY -> asmgen.out(" ldx #0 | ldy #0")
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
in Cx16VirtualRegisters -> {
asmgen.out(
" stz cx16.${
target.register.toString().lowercase()
} | stz cx16.${target.register.toString().lowercase()}+1")
asmgen.out(" stz cx16.${target.register.toString().lowercase()} | stz cx16.${target.register.toString().lowercase()}+1")
}
else -> throw AssemblyError("weird register")
}

View File

@ -1,5 +1,6 @@
package prog8.compiler.astprocessing
import prog8.ast.IFunctionCall
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.SyntaxError
@ -7,10 +8,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.Encoding
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter
import prog8.code.core.NumericDatatypes
import prog8.code.core.*
class AstPreprocessor(val program: Program, val errors: IErrorReporter, val compTarget: ICompilationTarget) : AstWalker() {
@ -98,6 +96,30 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
val containment = ContainmentCheck(expr.left, expr.right, expr.position)
return listOf(IAstModification.ReplaceNode(expr, containment, parent))
}
// To enable simple bitwise and/or/xor/not instructions in the codegen for the logical and/or/xor/not,
// we wrap the operands in a call to boolean() if required so that they are 0 or 1 as needed.
// Making the codegen more generic to do this by itself all the time will generate much larger
// code because it is hard to decide there if the value conversion to 0 or 1 is needed or not,
// so a lot of useless checks and conversions are added. Here we can be smarter so the codegen
// can just rely on the correct value of the operands (0 or 1) if they're boolean, and just use bitwise instructions.
if(expr.operator in LogicalOperators) {
fun wrapped(expr: Expression): Expression {
return if(expr is IFunctionCall && expr.target.nameInSource==listOf("boolean"))
expr
else if(expr is BinaryExpression && expr.operator in LogicalOperators+ComparisonOperators)
expr
else
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
}
return listOf(
IAstModification.ReplaceNode(expr.left, wrapped(expr.left), expr),
IAstModification.ReplaceNode(expr.right, wrapped(expr.right), expr)
)
}
return noModifications
}

View File

@ -190,7 +190,6 @@ internal class StatementReorderer(val program: Program,
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
// ConstValue <associativeoperator> X --> X <associativeoperator> ConstValue
// (this should be done by the ExpressionSimplifier when optimizing is enabled,
// but the current assembly code generator for IF statements now also depends on it, so we do it here regardless of optimization.)
@ -247,38 +246,6 @@ internal class StatementReorderer(val program: Program,
else -> return noModifications
}
}
else if(expr.operator in LogicalOperators) {
fun wrapped(expr: Expression): Expression {
return if(expr is IFunctionCall && expr.target.nameInSource==listOf("boolean"))
expr
else
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
}
fun isLogicalExpr(expr: Expression?): Boolean {
if(expr is BinaryExpression && expr.operator in (LogicalOperators + ComparisonOperators))
return true
if(expr is PrefixExpression && expr.operator in LogicalOperators)
return true
return false
}
return if(isLogicalExpr(expr.left)) {
if(isLogicalExpr(expr.right))
noModifications
else
listOf(IAstModification.ReplaceNode(expr.right, wrapped(expr.right), expr))
} else {
if(isLogicalExpr(expr.right))
listOf(IAstModification.ReplaceNode(expr.left, wrapped(expr.left), expr))
else {
listOf(
IAstModification.ReplaceNode(expr.left, wrapped(expr.left), expr),
IAstModification.ReplaceNode(expr.right, wrapped(expr.right), expr)
)
}
}
}
return noModifications
}

View File

@ -102,6 +102,24 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
return noModifications
}
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator=="not") {
val logical = parent as? BinaryExpression
if(logical!=null && logical.operator in LogicalOperators) {
// not x as operand in a logical expression --> cast it to ubyte
val cast = TypecastExpression(expr, DataType.UBYTE, true, expr.position)
return listOf(IAstModification.ReplaceNode(expr, cast, parent))
}
val boolCast = parent as? IFunctionCall
if(boolCast!=null && boolCast.target.nameInSource==listOf("boolean")) {
// boolean(not x) --> (not x) as ubyte
val cast = TypecastExpression(expr, DataType.UBYTE, true, expr.position)
return listOf(IAstModification.ReplaceNode(boolCast as Node, cast, boolCast.parent))
}
}
return noModifications
}
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
// see if a typecast is needed to convert the value's type into the proper target type
val valueItype = assignment.value.inferType(program)

View File

@ -12,6 +12,7 @@ import prog8.ast.statements.FunctionCallStatement
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
import prog8.code.target.VMTarget
internal class VariousCleanups(val program: Program, val errors: IErrorReporter, val options: CompilationOptions): AstWalker() {
@ -233,5 +234,38 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
}
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
if(functionCallExpr.target.nameInSource==listOf("boolean")) {
// boolean(expr) can be removed if expr is a logical expression or comparison expression itself, or boolean()
val binexpr = functionCallExpr.args.single() as? BinaryExpression
if(binexpr!=null && binexpr.operator in LogicalOperators + ComparisonOperators) {
return listOf(IAstModification.ReplaceNode(functionCallExpr, binexpr, parent))
}
val prefixExpression = functionCallExpr.args.single() as? PrefixExpression
if(prefixExpression!=null && prefixExpression.operator in LogicalOperators) {
return listOf(IAstModification.ReplaceNode(functionCallExpr, prefixExpression, parent))
}
val fcall = functionCallExpr.args.single() as? IFunctionCall
if(fcall!=null && fcall.target.nameInSource==listOf("boolean")) {
return listOf(IAstModification.ReplaceNode(functionCallExpr, fcall as Node, parent))
}
if(options.compTarget.name == VMTarget.NAME) {
// if target is Virtual, remove ALL boolean() conversions of operands to logical expressions
// we can do this because the logical and/or/xor/not in the virtual machine behave correctly
// with operand values other than 0 and 1 (0 = false, everything else=true, result is always 0 or 1)
val logicalExpr = functionCallExpr.parent as? BinaryExpression
if(logicalExpr!=null && logicalExpr.operator in LogicalOperators + ComparisonOperators) {
return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args.single(), parent))
}
val prefixExpr = functionCallExpr.parent as? PrefixExpression
if(prefixExpr!=null && prefixExpr.operator in LogicalOperators) {
return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args.single(), parent))
}
}
}
return noModifications
}
}

View File

@ -285,14 +285,14 @@ class TestOptimization: FunSpec({
"""
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
// bb = (( not bb as uword) or not ww)
// bb = (not bb or (not ww as ubyte) )
val bbAssign = result.program.entrypoint.statements.last() as Assignment
val expr = bbAssign.value as BinaryExpression
expr.operator shouldBe "or"
expr.left shouldBe instanceOf<TypecastExpression>() // casted to word
expr.right shouldBe instanceOf<PrefixExpression>()
expr.left.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UWORD
expr.right.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UWORD
expr.left shouldBe instanceOf<PrefixExpression>()
expr.right shouldBe instanceOf<TypecastExpression>() // not of word typecast into ubyte
expr.left.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
expr.right.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val options = CompilationOptions(OutputType.PRG, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(),
@ -301,10 +301,11 @@ class TestOptimization: FunSpec({
compTarget = C64Target(),
loadAddress = 0u, outputDir= outputDir)
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
printProgram(result.program)
// assignment is now split into:
// bb = not bb
// bb = (bb or not ww)
// bb = (bb or (not ww as ubyte)
val assigns = result.program.entrypoint.statements.filterIsInstance<Assignment>()
val bbAssigns = assigns.filter { it.value !is NumericLiteral }
@ -320,9 +321,10 @@ class TestOptimization: FunSpec({
val bbAssigns1expr = bbAssigns[1].value as BinaryExpression
bbAssigns1expr.operator shouldBe "or"
(bbAssigns1expr.left as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
bbAssigns1expr.right shouldBe instanceOf<PrefixExpression>()
(bbAssigns1expr.right as PrefixExpression).operator shouldBe "not"
((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
bbAssigns1expr.right shouldBe instanceOf<TypecastExpression>()
val castedValue = (bbAssigns1expr.right as TypecastExpression).expression as PrefixExpression
castedValue.operator shouldBe "not"
(castedValue.expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val asm = generateAssembly(result.program, options)

View File

@ -0,0 +1,174 @@
%import textio
%zeropage basicsafe
main {
sub ftrue(ubyte arg) -> ubyte {
arg++
return 128
}
sub ffalse(ubyte arg) -> ubyte {
arg++
return 0
}
sub start() {
ubyte ub1 = 2
ubyte ub2 = 4
ubyte ub3 = 8
ubyte ub4 = 0
ubyte bvalue
txt.print("bitwise or 14: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4)
txt.nl()
txt.print("bitwise or 142: ")
txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128)
txt.nl()
txt.print("bitwise and 0: ")
txt.print_ub(ub1 & ub2 & ub3 & ub4)
txt.nl()
txt.print("bitwise and 8: ")
txt.print_ub(ub3 & ub3 & 127)
txt.nl()
txt.print("bitwise xor 14: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4)
txt.nl()
txt.print("bitwise xor 6: ")
txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8)
txt.nl()
txt.print("bitwise not 247: ")
txt.print_ub(~ub3)
txt.nl()
txt.print("bitwise not 255: ")
txt.print_ub(~ub4)
txt.nl()
txt.print("not 0: ")
bvalue = not ub3
txt.print_ub(bvalue)
if not ub1
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("not 1: ")
bvalue = not ub4
txt.print_ub(bvalue)
if not ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
bvalue = bvalue and 128
txt.print("bvl 1: ")
txt.print_ub(bvalue)
if bvalue and 128
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3
txt.print_ub(bvalue)
if ub1 and ub2 and ub3
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and 64
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and 64
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 1: ")
bvalue = ub1 and ub2 and ub3 and ftrue(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ub4
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ub4
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("and 0: ")
bvalue = ub1 and ub2 and ub3 and ffalse(99)
txt.print_ub(bvalue)
if ub1 and ub2 and ub3 and ffalse(99)
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ub4
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub4 or ub4 or 64
txt.print_ub(bvalue)
if ub4 or ub4 or 64
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print(" or 1: ")
bvalue = ub1 or ub2 or ub3 or ftrue(99)
txt.print_ub(bvalue)
if ub1 or ub2 or ub3 or ftrue(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 1: ")
bvalue = ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ffalse(99)
txt.print(" / ok")
else
txt.print(" / fail")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ub4 xor true
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
txt.print("xor 0: ")
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print_ub(bvalue)
if ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print(" / fail")
else
txt.print(" / ok")
txt.nl()
}
}

View File

@ -124,6 +124,10 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
return when(operator) {
"+" -> inferred
"~", "not" -> {
// note: "not" should ideally result in UBYTE (boolean) but the way the type system
// currently works means the result of an operator is the same type as the operand(s).
// So not(byte)->byte, not(word)->word. This is taken care of via a cast to ubyte later.
// If we give not a BYTE type here, the asmassignment validation will sometimes crash.
when(inferred.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> InferredTypes.knownFor(DataType.UBYTE)
in WordDatatypes -> InferredTypes.knownFor(DataType.UWORD)

View File

@ -3,7 +3,11 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- can we optimize redundant calls to boolean() away? imageviewer.prg got larger because of them
- vm: fix and/or/xor to be bitwise again (need to remove optimization from VariousCleanups too?)
- vm: fix not to be bitwise not instead of boolean not
- 6502: fix not codegen to be bitwise not instead of boolean not (maybe need to change boolean() wrapping / variouscleanups)
all these testable with compiler/test/arithmetic/logical.p8
- add some more optimizations in vmPeepholeOptimizer
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
this info is needed for more advanced optimizations and later code generation steps.

View File

@ -5,147 +5,23 @@
main {
sub funcFalse() -> ubyte {
txt.print("false() ")
return false
}
sub funcFalseWord() -> uword {
txt.print("falseword() ")
return 0
}
sub funcTrue() -> ubyte {
txt.print("ftrue() ")
return true
}
sub func1(ubyte a1) -> ubyte {
txt.print("func1() ")
return a1>1
}
sub func2(ubyte a1) -> ubyte {
txt.print("func2() ")
return a1>2
}
sub func3(ubyte a1) -> ubyte {
txt.print("func3() ")
return a1>3
}
sub func4(ubyte a1) -> ubyte {
txt.print("func4() ")
return a1>4
}
sub funcw() -> uword {
txt.print("funcw() ")
return 9999
}
sub start() {
ubyte value
uword wvalue
ubyte ub1 = 11
ubyte ub2 = 22
ubyte ub3 = 33
ubyte ub4 = 44
ubyte ub5 = 55
ub4 = 0
txt.print("and with bytes: ")
ub5 = ub1 and ub2 and ub3 and ub4 and ub5
txt.print_ub(ub5)
txt.nl()
ub4 = 0
txt.print("or with bytes: ")
ub5 = ub1 or ub2 or ub3 or ub4 or ub5
txt.print_ub(ub5)
txt.nl()
txt.print("short and with false (word): ")
wvalue = funcw() and funcFalseWord() and funcw() and funcw()
txt.print_uw(wvalue)
txt.nl()
txt.print("short and with false: ")
value = func1(25) and funcFalse()
txt.print_ub(value)
txt.nl()
txt.print("short or with true: ")
value = func1(25) or funcTrue()
txt.print_ub(value)
txt.nl()
txt.print("short xor with false: ")
value = func1(25) xor funcFalse()
txt.print_ub(value)
txt.nl()
txt.print("and with false: ")
value = func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
txt.print_ub(value)
txt.nl()
txt.print("and with true: ")
value = func1(25) and func2(25) and funcTrue() and func3(25) and func4(25)
txt.print_ub(value)
txt.nl()
txt.print("or with false: ")
value = func1(0) or func2(0) or funcFalse() or func3(25) or func4(25)
txt.print_ub(value)
txt.nl()
txt.print("or with true: ")
value = func1(0) or func2(0) or funcTrue() or func3(25) or func4(25)
txt.print_ub(value)
txt.nl()
txt.print("xor with false: ")
value = func1(25) xor func2(25) xor funcFalse() xor func3(25) xor func4(25)
txt.print_ub(value)
txt.nl()
txt.print("xor with true: ")
value = func1(25) xor func2(25) xor funcTrue() xor func3(25) xor func4(25)
txt.print_ub(value)
txt.nl()
txt.print("\nif and with false: [nothing]: ")
if func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
txt.print("failure!")
txt.print("\nif and with true: [ok]: ")
if func1(25) and func2(25) and funcTrue() and func3(25) and func4(25)
txt.print("ok!")
txt.print("\nif or with false: [ok]: ")
if func1(0) or func2(0) or funcFalse() or func3(25) or func4(25)
txt.print("ok!")
txt.print("\nif or with true: [ok]: ")
if func1(0) or func2(0) or funcTrue() or func3(25) or func4(25)
txt.print("ok!")
txt.print("\nif xor with false: [nothing]: ")
if func1(25) xor func2(25) xor funcFalse() xor func3(25) xor func4(25)
txt.print("failure!")
txt.print("\nif xor with true: [ok]: ")
if func1(25) xor func2(25) xor funcTrue() xor func3(25) xor func4(25)
txt.print("ok!")
txt.nl()
; a "pixelshader":
; sys.gfx_enable(0) ; enable lo res screen
; ubyte shifter
;
; repeat {
; uword xx
; uword yy = 0
; repeat 240 {
; xx = 0
; repeat 320 {
; sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
; xx++
; }
; yy++
; }
; shifter+=4
; }
sys.gfx_enable(0) ; enable lo res screen
ubyte shifter
repeat {
uword xx
uword yy = 0
repeat 240 {
xx = 0
repeat 320 {
sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
xx++
}
yy++
}
shifter+=4
}
}
}

View File

@ -8,9 +8,9 @@ Virtual machine:
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status registers: Carry, Zero, Negative.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
Program to execute is not stored in this memory, it's just a separate list of instructions.
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
Currently NO support for 24 or 32 bits integers.
Floating point operations are just 'f' typed regular instructions, and additionally there are

View File

@ -39,7 +39,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
numIns++
if(throttle && stepCount and 32767 == 0) {
Thread.sleep(0, 10) // avoid 100% cpu core usage
Thread.sleep(1) // avoid 100% cpu core usage
}
if(stepCount and 0xffffff == 0) {
@ -1132,8 +1132,14 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun booleanValue(number: UInt): UInt = if(number == 0u) 0u else 1u
private fun booleanValue(number: UByte): UByte = if(number == 0u.toUByte()) 0u else 1u
private fun booleanValue(number: UShort): UShort = if(number == 0u.toUShort()) 0u else 1u
private fun InsAND(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
val (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
val left = booleanValue(leftV)
val right = booleanValue(rightV)
when(i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left and right).toUByte())
VmDataType.WORD -> registers.setUW(i.reg1!!, (left and right).toUShort())
@ -1145,15 +1151,25 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsANDM(i: Instruction) {
val address = i.value!!
when(i.type!!) {
VmDataType.BYTE -> memory.setUB(address, (memory.getUB(address) and registers.getUB(i.reg1!!)))
VmDataType.WORD -> memory.setUW(address, (memory.getUW(address) and registers.getUW(i.reg1!!)))
VmDataType.BYTE -> {
val left = booleanValue(memory.getUB(address))
val right = booleanValue(registers.getUB(i.reg1!!))
memory.setUB(address, left and right)
}
VmDataType.WORD -> {
val left = booleanValue(memory.getUW(address))
val right = booleanValue(registers.getUW(i.reg1!!))
memory.setUW(address, left and right)
}
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
}
pc++
}
private fun InsOR(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
val (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
val left = booleanValue(leftV)
val right = booleanValue(rightV)
when(i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left or right).toUByte())
VmDataType.WORD -> registers.setUW(i.reg1!!, (left or right).toUShort())
@ -1165,15 +1181,25 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsORM(i: Instruction) {
val address = i.value!!
when(i.type!!) {
VmDataType.BYTE -> memory.setUB(address, (memory.getUB(address) or registers.getUB(i.reg1!!)))
VmDataType.WORD -> memory.setUW(address, (memory.getUW(address) or registers.getUW(i.reg1!!)))
VmDataType.BYTE -> {
val left = booleanValue(memory.getUB(address))
val right = booleanValue(registers.getUB(i.reg1!!))
memory.setUB(address, left or right)
}
VmDataType.WORD -> {
val left = booleanValue(memory.getUW(address))
val right = booleanValue(registers.getUW(i.reg1!!))
memory.setUW(address, left or right)
}
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
}
pc++
}
private fun InsXOR(i: Instruction) {
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
val (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
val left = booleanValue(leftV)
val right = booleanValue(rightV)
when(i.type!!) {
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left xor right).toUByte())
VmDataType.WORD -> registers.setUW(i.reg1!!, (left xor right).toUShort())
@ -1185,8 +1211,16 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
private fun InsXORM(i: Instruction) {
val address = i.value!!
when(i.type!!) {
VmDataType.BYTE -> memory.setUB(address, (memory.getUB(address) xor registers.getUB(i.reg1!!)))
VmDataType.WORD -> memory.setUW(address, (memory.getUW(address) xor registers.getUW(i.reg1!!)))
VmDataType.BYTE -> {
val left = booleanValue(memory.getUB(address))
val right = booleanValue(registers.getUB(i.reg1!!))
memory.setUB(address, left xor right)
}
VmDataType.WORD -> {
val left = booleanValue(memory.getUW(address))
val right = booleanValue(registers.getUW(i.reg1!!))
memory.setUW(address, left xor right)
}
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
}
pc++