mirror of
https://github.com/irmen/prog8.git
synced 2025-01-13 10:29:52 +00:00
vm: and/or/xor/not are all bitwise operations again
This commit is contained in:
parent
ef92451d1a
commit
435d6f6f3f
@ -22,9 +22,9 @@ class ConstExprEvaluator {
|
||||
"&" -> bitwiseand(left, right)
|
||||
"|" -> bitwiseor(left, right)
|
||||
"^" -> bitwisexor(left, right)
|
||||
"and" -> logicaland(left, right)
|
||||
"or" -> logicalor(left, right)
|
||||
"xor" -> logicalxor(left, right)
|
||||
"and" -> logicaland(left, right) // TODO bitwise and?
|
||||
"or" -> logicalor(left, right) // TODO bitwise or?
|
||||
"xor" -> logicalxor(left, right) // TODO bitwise xor?
|
||||
"<" -> NumericLiteral.fromBoolean(left < right, left.position)
|
||||
">" -> NumericLiteral.fromBoolean(left > right, left.position)
|
||||
"<=" -> NumericLiteral.fromBoolean(left <= right, left.position)
|
||||
@ -59,7 +59,7 @@ class ConstExprEvaluator {
|
||||
}
|
||||
|
||||
private fun logicalxor(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
|
||||
val error = "cannot compute $left locical-bitxor $right"
|
||||
val error = "cannot compute $left logical-xor $right"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.fromBoolean((left.number.toInt() != 0) xor (right.number.toInt() != 0), left.position)
|
||||
@ -76,7 +76,7 @@ class ConstExprEvaluator {
|
||||
}
|
||||
|
||||
private fun logicalor(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
|
||||
val error = "cannot compute $left locical-or $right"
|
||||
val error = "cannot compute $left logical-or $right"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.fromBoolean(left.number.toInt() != 0 || right.number.toInt() != 0, left.position)
|
||||
@ -93,7 +93,7 @@ class ConstExprEvaluator {
|
||||
}
|
||||
|
||||
private fun logicaland(left: NumericLiteral, right: NumericLiteral): NumericLiteral {
|
||||
val error = "cannot compute $left locical-and $right"
|
||||
val error = "cannot compute $left logical-and $right"
|
||||
return when (left.type) {
|
||||
in IntegerDatatypes -> when (right.type) {
|
||||
in IntegerDatatypes -> NumericLiteral.fromBoolean(left.number.toInt() != 0 && right.number.toInt() != 0, left.position)
|
||||
|
@ -12,10 +12,7 @@ import prog8.ast.statements.IfElse
|
||||
import prog8.ast.statements.Jump
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.AssociativeOperators
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IntegerDatatypes
|
||||
import prog8.code.core.NumericDatatypes
|
||||
import prog8.code.core.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.log2
|
||||
import kotlin.math.pow
|
||||
@ -220,8 +217,8 @@ class ExpressionSimplifier(private val program: Program) : AstWalker() {
|
||||
when {
|
||||
leftVal != null && !leftVal.asBooleanValue -> expr.right
|
||||
rightVal != null && !rightVal.asBooleanValue -> expr.left
|
||||
leftVal != null && leftVal.asBooleanValue -> PrefixExpression("not", expr.right, expr.right.position)
|
||||
rightVal != null && rightVal.asBooleanValue -> PrefixExpression("not", expr.left, expr.left.position)
|
||||
leftVal != null && leftVal.asBooleanValue -> BinaryExpression(expr.right, "==", NumericLiteral.optimalInteger(0, Position.DUMMY), expr.right.position)
|
||||
rightVal != null && rightVal.asBooleanValue -> BinaryExpression(expr.left, "==", NumericLiteral.optimalInteger(0, Position.DUMMY), expr.left.position)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@ -104,22 +104,28 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
||||
// 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)
|
||||
IAstModification.ReplaceNodeSafe(expr.left, wrapWithBooleanConversion(expr.left), expr),
|
||||
IAstModification.ReplaceNodeSafe(expr.right, wrapWithBooleanConversion(expr.right), expr)
|
||||
)
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator == "not") {
|
||||
// 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.
|
||||
|
||||
// not(x) --> boolean(x)==0
|
||||
val replacement = BinaryExpression(wrapWithBooleanConversion(expr.expression), "==", NumericLiteral.optimalInteger(0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@ -156,4 +162,13 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun wrapWithBooleanConversion(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)
|
||||
}
|
||||
}
|
||||
|
@ -107,15 +107,10 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
val logical = parent as? BinaryExpression
|
||||
if(logical!=null && logical.operator in LogicalOperators) {
|
||||
// not x as operand in a logical expression --> cast it to ubyte
|
||||
// TODO is this cast really necessary or does boolean() wrapping take care of it?
|
||||
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
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ 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() {
|
||||
@ -250,20 +249,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
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
|
||||
}
|
||||
|
@ -285,12 +285,12 @@ class TestOptimization: FunSpec({
|
||||
"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||
|
||||
// bb = (not bb or (not ww as ubyte) )
|
||||
// bb = ((boolean(bb)==0) or (boolean(ww)==0))
|
||||
val bbAssign = result.program.entrypoint.statements.last() as Assignment
|
||||
val expr = bbAssign.value as BinaryExpression
|
||||
expr.operator shouldBe "or"
|
||||
expr.left shouldBe instanceOf<PrefixExpression>()
|
||||
expr.right shouldBe instanceOf<TypecastExpression>() // not of word typecast into ubyte
|
||||
expr.left shouldBe instanceOf<BinaryExpression>()
|
||||
expr.right shouldBe instanceOf<BinaryExpression>()
|
||||
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
|
||||
@ -303,33 +303,33 @@ class TestOptimization: FunSpec({
|
||||
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
printProgram(result.program)
|
||||
|
||||
// TODO this is no longer the case:
|
||||
// assignment is now split into:
|
||||
// bb = not bb
|
||||
// bb = (bb or (not ww as ubyte)
|
||||
|
||||
val assigns = result.program.entrypoint.statements.filterIsInstance<Assignment>()
|
||||
val bbAssigns = assigns.filter { it.value !is NumericLiteral }
|
||||
bbAssigns.size shouldBe 2
|
||||
|
||||
bbAssigns[0].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
bbAssigns[0].value shouldBe instanceOf<PrefixExpression>()
|
||||
(bbAssigns[0].value as PrefixExpression).operator shouldBe "not"
|
||||
((bbAssigns[0].value as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
bbAssigns[0].value.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
|
||||
bbAssigns[1].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
val bbAssigns1expr = bbAssigns[1].value as BinaryExpression
|
||||
bbAssigns1expr.operator shouldBe "or"
|
||||
(bbAssigns1expr.left as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
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)
|
||||
asm shouldNotBe null
|
||||
asm!!.name.shouldNotBeBlank()
|
||||
// val assigns = result.program.entrypoint.statements.filterIsInstance<Assignment>()
|
||||
// val bbAssigns = assigns.filter { it.value !is NumericLiteral }
|
||||
// bbAssigns.size shouldBe 2
|
||||
//
|
||||
// bbAssigns[0].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
// bbAssigns[0].value shouldBe instanceOf<PrefixExpression>()
|
||||
// (bbAssigns[0].value as PrefixExpression).operator shouldBe "not"
|
||||
// ((bbAssigns[0].value as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
// bbAssigns[0].value.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
//
|
||||
// bbAssigns[1].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
// val bbAssigns1expr = bbAssigns[1].value as BinaryExpression
|
||||
// bbAssigns1expr.operator shouldBe "or"
|
||||
// (bbAssigns1expr.left as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
// 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)
|
||||
// asm shouldNotBe null
|
||||
// asm!!.name.shouldNotBeBlank()
|
||||
}
|
||||
|
||||
test("intermediate assignment steps generated for typecasted expression") {
|
||||
@ -455,13 +455,15 @@ class TestOptimization: FunSpec({
|
||||
}
|
||||
}"""
|
||||
val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!!
|
||||
printProgram(result.program)
|
||||
/* expected:
|
||||
ubyte z1
|
||||
z1 = 10
|
||||
ubyte z2
|
||||
z2 = 255
|
||||
ubyte z3
|
||||
z3 = 1
|
||||
z3 = 0
|
||||
z3 = (boolean(z3)==0)
|
||||
uword z4
|
||||
z4 = 0
|
||||
ubyte z5
|
||||
@ -472,28 +474,30 @@ class TestOptimization: FunSpec({
|
||||
z6 -= 5
|
||||
*/
|
||||
val statements = result.program.entrypoint.statements
|
||||
statements.size shouldBe 14
|
||||
statements.size shouldBe 15
|
||||
val z1decl = statements[0] as VarDecl
|
||||
val z1init = statements[1] as Assignment
|
||||
val z2decl = statements[2] as VarDecl
|
||||
val z2init = statements[3] as Assignment
|
||||
val z3decl = statements[4] as VarDecl
|
||||
val z3init = statements[5] as Assignment
|
||||
val z4decl = statements[6] as VarDecl
|
||||
val z4init = statements[7] as Assignment
|
||||
val z5decl = statements[8] as VarDecl
|
||||
val z5init = statements[9] as Assignment
|
||||
val z5plus = statements[10] as Assignment
|
||||
val z6decl = statements[11] as VarDecl
|
||||
val z6init = statements[12] as Assignment
|
||||
val z6plus = statements[13] as Assignment
|
||||
val z3not = statements[6] as Assignment
|
||||
val z4decl = statements[7] as VarDecl
|
||||
val z4init = statements[8] as Assignment
|
||||
val z5decl = statements[9] as VarDecl
|
||||
val z5init = statements[10] as Assignment
|
||||
val z5plus = statements[11] as Assignment
|
||||
val z6decl = statements[12] as VarDecl
|
||||
val z6init = statements[13] as Assignment
|
||||
val z6plus = statements[14] as Assignment
|
||||
|
||||
z1decl.name shouldBe "z1"
|
||||
z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY)
|
||||
z2decl.name shouldBe "z2"
|
||||
z2init.value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY)
|
||||
z3decl.name shouldBe "z3"
|
||||
z3init.value shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
|
||||
z3init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||
z3not.value shouldBe instanceOf<BinaryExpression>()
|
||||
z4decl.name shouldBe "z4"
|
||||
z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||
z5decl.name shouldBe "z5"
|
||||
|
@ -152,7 +152,6 @@ class TestTypecasts: FunSpec({
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||
printProgram(result.program)
|
||||
val statements = result.program.entrypoint.statements
|
||||
statements.size shouldBe 27
|
||||
}
|
||||
@ -181,7 +180,7 @@ class TestTypecasts: FunSpec({
|
||||
}"""
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||
val statements = result.program.entrypoint.statements
|
||||
statements.size shouldBe 14
|
||||
statements.size shouldBe 13
|
||||
}
|
||||
|
||||
test("no infinite typecast loop in assignment asmgen") {
|
||||
|
@ -62,6 +62,7 @@ main {
|
||||
else
|
||||
txt.print(" / fail")
|
||||
txt.nl()
|
||||
|
||||
bvalue = bvalue and 128
|
||||
txt.print("bvl 1: ")
|
||||
txt.print_ub(bvalue)
|
||||
@ -121,9 +122,9 @@ main {
|
||||
txt.print(" / fail")
|
||||
txt.nl()
|
||||
txt.print(" or 1: ")
|
||||
bvalue = ub4 or ub4 or 64
|
||||
bvalue = ub4 or ub4 or ub1
|
||||
txt.print_ub(bvalue)
|
||||
if ub4 or ub4 or 64
|
||||
if ub4 or ub4 or ub1
|
||||
txt.print(" / ok")
|
||||
else
|
||||
txt.print(" / fail")
|
||||
@ -169,6 +170,5 @@ main {
|
||||
txt.print(" / fail")
|
||||
else
|
||||
txt.print(" / ok")
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,18 @@ interface IAstModification {
|
||||
}
|
||||
}
|
||||
|
||||
class ReplaceNodeSafe(val node: Node, private val replacement: Node, private val parent: Node) :
|
||||
IAstModification {
|
||||
override fun perform() {
|
||||
try {
|
||||
parent.replaceChildNode(node, replacement)
|
||||
replacement.linkParents(parent)
|
||||
} catch (fa: FatalAstException) {
|
||||
// possibly because of another replacement. Ignore here, we try again later.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SwapOperands(private val expr: BinaryExpression): IAstModification {
|
||||
override fun perform() {
|
||||
require(expr.operator in AssociativeOperators)
|
||||
|
@ -3,10 +3,20 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- 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
|
||||
- 6502: also fix logical and/or/xor routines to just be bitwise routines.
|
||||
|
||||
- get rid of logical and/or/xor/not in the codegen (6502+vm)
|
||||
because bitwise versions + correct use of boolean() operand wrapping are equivalent?
|
||||
can do this for instance by replacing and/or/xor/not with their bitwise versions &, |, ^, ~
|
||||
|
||||
- compiling logical.p8 to virtual with optimization generates a lot larger code as without optimizations.
|
||||
this is not the case for the 6502 codegen.
|
||||
|
||||
- add optimizations: not a or not b -> not(a and b) , not a and not b -> not(a or b)
|
||||
add unit tests for that.
|
||||
- bin expr splitter: split logical expressions on ands/ors/xors ?
|
||||
|
||||
- add some more optimizations in vmPeepholeOptimizer
|
||||
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
||||
|
@ -124,7 +124,7 @@ All have type b or w.
|
||||
and reg1, reg2 - reg1 = reg1 bitwise and reg2
|
||||
or reg1, reg2 - reg1 = reg1 bitwise or reg2
|
||||
xor reg1, reg2 - reg1 = reg1 bitwise xor reg2
|
||||
not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0)
|
||||
not reg1 - reg1 = bitwise not of reg1 (all bits flipped)
|
||||
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
|
||||
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
|
||||
@ -138,7 +138,7 @@ roxl reg1 - rotate reg1 left by 1 bits, using
|
||||
andm reg1 address - memory = memory bitwise and reg1
|
||||
orm reg1, address - memory = memory bitwise or reg1
|
||||
xorm reg1, address - memory = memory bitwise xor reg1
|
||||
notm address - memory = boolean not of that memory (0->1 , ~0 -> 0)
|
||||
notm address - memory = bitwise not of that memory (all bits flipped)
|
||||
lsrnm reg1, address - multi-shift memoryright by reg1 bits + set Carry to shifted bit
|
||||
asrnm reg1, address - multi-shift memory right by reg1 bits (signed) + set Carry to shifted bit
|
||||
lslnm reg1, address - multi-shift memory left by reg1 bits + set Carry to shifted bit
|
||||
|
@ -1132,14 +1132,8 @@ 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 (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
|
||||
val left = booleanValue(leftV)
|
||||
val right = booleanValue(rightV)
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left and right).toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left and right).toUShort())
|
||||
@ -1152,13 +1146,13 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
val address = i.value!!
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
val left = booleanValue(memory.getUB(address))
|
||||
val right = booleanValue(registers.getUB(i.reg1!!))
|
||||
val left = memory.getUB(address)
|
||||
val right = 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!!))
|
||||
val left = memory.getUW(address)
|
||||
val right = registers.getUW(i.reg1!!)
|
||||
memory.setUW(address, left and right)
|
||||
}
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
@ -1167,9 +1161,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
}
|
||||
|
||||
private fun InsOR(i: Instruction) {
|
||||
val (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
|
||||
val left = booleanValue(leftV)
|
||||
val right = booleanValue(rightV)
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left or right).toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left or right).toUShort())
|
||||
@ -1182,13 +1174,13 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
val address = i.value!!
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
val left = booleanValue(memory.getUB(address))
|
||||
val right = booleanValue(registers.getUB(i.reg1!!))
|
||||
val left = memory.getUB(address)
|
||||
val right = 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!!))
|
||||
val left = memory.getUW(address)
|
||||
val right = registers.getUW(i.reg1!!)
|
||||
memory.setUW(address, left or right)
|
||||
}
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
@ -1197,9 +1189,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
}
|
||||
|
||||
private fun InsXOR(i: Instruction) {
|
||||
val (leftV: UInt, rightV: UInt) = getLogicalOperandsU(i)
|
||||
val left = booleanValue(leftV)
|
||||
val right = booleanValue(rightV)
|
||||
val (left: UInt, right: UInt) = getLogicalOperandsU(i)
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, (left xor right).toUByte())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, (left xor right).toUShort())
|
||||
@ -1212,13 +1202,13 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
val address = i.value!!
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
val left = booleanValue(memory.getUB(address))
|
||||
val right = booleanValue(registers.getUB(i.reg1!!))
|
||||
val left = memory.getUB(address)
|
||||
val right = 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!!))
|
||||
val left = memory.getUW(address)
|
||||
val right = registers.getUW(i.reg1!!)
|
||||
memory.setUW(address, left xor right)
|
||||
}
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
@ -1228,8 +1218,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
|
||||
private fun InsNOT(i: Instruction) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, if(registers.getUB(i.reg1)==0.toUByte()) 1u else 0u)
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, if(registers.getUW(i.reg1)==0.toUShort()) 1u else 0u)
|
||||
VmDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1).inv())
|
||||
VmDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg1).inv())
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
pc++
|
||||
@ -1238,8 +1228,8 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
private fun InsNOTM(i: Instruction) {
|
||||
val address = i.value!!
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> memory.setUB(address, if(memory.getUB(address)==0.toUByte()) 1u else 0u)
|
||||
VmDataType.WORD -> memory.setUW(address, if(memory.getUW(address)==0.toUShort()) 1u else 0u)
|
||||
VmDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv())
|
||||
VmDataType.WORD -> memory.setUW(address, memory.getUW(address).inv())
|
||||
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
pc++
|
||||
|
Loading…
x
Reference in New Issue
Block a user