From a2b9d78cf335f04bfabbef2bccb4b76f44fff630 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 17 Sep 2025 01:04:26 +0200 Subject: [PATCH] start with introducing LONG datatype (32 bits signed integer) --- .../codegen/intermediate/RegisterPool.kt | 3 + .../optimizer/ConstantFoldingOptimizer.kt | 2 +- compiler/res/prog8lib/conv.p8 | 16 + .../prog8lib/shared_cbm_textio_functions.p8 | 5 + compiler/res/prog8lib/virtual/conv.p8 | 12 +- compiler/res/prog8lib/virtual/textio.p8 | 8 + .../compiler/astprocessing/AstChecker.kt | 26 -- examples/test.p8 | 42 ++- .../src/prog8/intermediate/IRInstructions.kt | 200 +++++----- intermediate/src/prog8/intermediate/Utils.kt | 9 +- virtualmachine/src/prog8/vm/Memory.kt | 12 + virtualmachine/src/prog8/vm/Registers.kt | 20 +- virtualmachine/src/prog8/vm/SysCalls.kt | 27 ++ virtualmachine/src/prog8/vm/VirtualMachine.kt | 356 +++++++++++++++++- .../src/prog8/vm/VmProgramLoader.kt | 2 + 15 files changed, 591 insertions(+), 149 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt index 880ac385f..239731d8a 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/RegisterPool.kt @@ -7,6 +7,7 @@ internal class RegisterPool { // everything from 99000 onwards is reserved for special purposes: // 99000 - 99099 : WORD registers for syscall arguments and response value(s) // 99100 - 99199 : BYTE registers for syscall arguments and response value(s) + // 99200 - 99299 : LONG registers for syscall arguments and response value(s) private var nextRegister: Int=1 private val registerTypes: MutableMap = mutableMapOf() @@ -18,6 +19,8 @@ internal class RegisterPool { registerTypes[i] = IRDataType.WORD for(i in 99100..99199) registerTypes[i] = IRDataType.BYTE + for(i in 99200..99299) + registerTypes[i] = IRDataType.LONG } fun next(type: IRDataType): Int { diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index e6adce821..04cc41f79 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -35,7 +35,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: override fun after(numLiteral: NumericLiteral, parent: Node): Iterable { - if(numLiteral.type==BaseDataType.LONG) { + if(numLiteral.type==BaseDataType.LONG && parent !is Assignment) { // see if LONG values may be reduced to something smaller val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position) if(smaller.type!=BaseDataType.LONG) { diff --git a/compiler/res/prog8lib/conv.p8 b/compiler/res/prog8lib/conv.p8 index f37ccf6cc..061533e49 100644 --- a/compiler/res/prog8lib/conv.p8 +++ b/compiler/res/prog8lib/conv.p8 @@ -228,6 +228,22 @@ asmsub str_w (word value @ AY) clobbers(X) -> str @AY { }} } +asmsub str_l (uword msw @ R0, uword lsw @ R1) clobbers(X) -> str @AY { + ; ---- convert the long in R0:R1 into decimal string form, without left padding 0s + %asm {{ + lda #'?' + sta string_out + lda #'?' + sta string_out+1 + lda #0 + sta string_out+2 + ; TODO implement this! + sta string_out + lda #string_out + rts + }} +} ; ---- string conversion to numbers ----- diff --git a/compiler/res/prog8lib/shared_cbm_textio_functions.p8 b/compiler/res/prog8lib/shared_cbm_textio_functions.p8 index 538cedca4..84de87ac2 100644 --- a/compiler/res/prog8lib/shared_cbm_textio_functions.p8 +++ b/compiler/res/prog8lib/shared_cbm_textio_functions.p8 @@ -165,6 +165,11 @@ _allzero lda #'0' }} } + sub print_l (long value) { + ; ---- print the (signed) long in decimal form, without left padding 0's + print(conv.str_l(msw(value), lsw(value))) + } + asmsub input_chars (^^ubyte buffer @ AY) clobbers(A) -> ubyte @ Y { ; ---- Input a string (max. 80 chars) from the keyboard, in PETSCII encoding. ; Returns length in Y. (string is terminated with a 0 byte as well) diff --git a/compiler/res/prog8lib/virtual/conv.p8 b/compiler/res/prog8lib/virtual/conv.p8 index a8ebdcf77..81435ff75 100644 --- a/compiler/res/prog8lib/virtual/conv.p8 +++ b/compiler/res/prog8lib/virtual/conv.p8 @@ -141,7 +141,7 @@ sub str_uw (uword value) -> str { } sub str_w (word value) -> str { - ; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's + ; ---- convert the (signed) word into decimal string form, without left padding 0's ^^ubyte out_ptr = &string_out if value<0 { @(out_ptr) = '-' @@ -152,6 +152,16 @@ sub str_w (word value) -> str { return string_out } +sub str_l (long value) -> str { + ; ---- convert the (signed) long into decimal string form, without left padding 0's + %ir {{ + loadm.l r99200,conv.str_l.value + load.w r99000,conv.string_out + syscall 60 (r99200.l, r99000.w) : r99000.w + returnr.w r99000 + }} +} + sub internal_str_uw(uword value, str out_ptr) { uword value2 = value/10 ubyte digits = value-value2*10 as ubyte diff --git a/compiler/res/prog8lib/virtual/textio.p8 b/compiler/res/prog8lib/virtual/textio.p8 index d2f2ab309..2d7473d75 100644 --- a/compiler/res/prog8lib/virtual/textio.p8 +++ b/compiler/res/prog8lib/virtual/textio.p8 @@ -151,6 +151,14 @@ sub print_w (word value) { print(conv.str_w(value)) } +sub print_l (long value) { + ; ---- print the (signed) long in decimal form, without left padding 0's + %ir {{ + loadm.l r99200,txt.print_l.value + syscall 59 (r99200.l) + }} +} + sub input_chars (str buffer) -> ubyte { ; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well) ; It assumes the keyboard is selected as I/O channel! diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 2a6416dd7..f4326c374 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -82,7 +82,6 @@ internal class AstChecker(private val program: Program, } } - checkLongType(identifier) val stmt = identifier.targetStatement(program.builtinFunctions) if(stmt==null) { if(identifier.parent is ArrayIndexedExpression) { @@ -363,10 +362,6 @@ internal class AstChecker(private val program: Program, super.visit(label) } - override fun visit(numLiteral: NumericLiteral) { - checkLongType(numLiteral) - } - private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean { class Searcher: IAstVisitor { @@ -813,7 +808,6 @@ internal class AstChecker(private val program: Program, } override fun visit(addressOf: AddressOf) { - checkLongType(addressOf) val variable=addressOf.identifier?.targetVarDecl() if (variable!=null) { if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) @@ -862,8 +856,6 @@ internal class AstChecker(private val program: Program, if(decl.names.size>1) throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls") - if(decl.datatype.isLong && decl.type!=VarDeclType.CONST) - errors.err("cannot use long type for variables; only for constants", decl.position) if(decl.type==VarDeclType.MEMORY) { if (decl.datatype.isString) errors.err("strings cannot be memory-mapped", decl.position) @@ -1329,7 +1321,6 @@ internal class AstChecker(private val program: Program, } } - checkLongType(expr) val dt = expr.expression.inferType(program).getOrUndef() if(!dt.isUndefined) { @@ -1474,8 +1465,6 @@ internal class AstChecker(private val program: Program, return } - checkLongType(expr) - val leftIDt = expr.left.inferType(program) val rightIDt = expr.right.inferType(program) if(!leftIDt.isKnown || !rightIDt.isKnown) { @@ -1614,7 +1603,6 @@ internal class AstChecker(private val program: Program, } override fun visit(typecast: TypecastExpression) { - checkLongType(typecast) if(typecast.type.isPassByRef) errors.err("cannot type cast to string or array type", typecast.position) @@ -1671,7 +1659,6 @@ internal class AstChecker(private val program: Program, } override fun visit(functionCallExpr: FunctionCallExpression) { - checkLongType(functionCallExpr) // this function call is (part of) an expression, which should be in a statement somewhere. val stmtOfExpression = findParentNode(functionCallExpr) ?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}") @@ -1905,7 +1892,6 @@ internal class AstChecker(private val program: Program, } args.forEach{ - checkLongType(it) if(it.inferType(program).isStructInstance) errors.err("structs can only be passed via a pointer", it.position) } @@ -1918,7 +1904,6 @@ internal class AstChecker(private val program: Program, } override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { - checkLongType(arrayIndexedExpression) val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions) if(target is VarDecl) { if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer) @@ -2164,17 +2149,6 @@ internal class AstChecker(private val program: Program, super.visit(deref) } - private fun checkLongType(expression: Expression) { - if(expression.inferType(program) issimpletype BaseDataType.LONG) { - if((expression.parent as? VarDecl)?.type!=VarDeclType.CONST) { - if (expression.parent !is RepeatLoop) { - if (errors.noErrorForLine(expression.position)) - errors.err("integer overflow", expression.position) - } - } - } - } - private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean { return if (targetDt.isString) { when { diff --git a/examples/test.p8 b/examples/test.p8 index 9c6d8aafa..d55a1a203 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,11 +1,39 @@ -main { - sub start() { - func() +%import textio + +main { + long bignum = 12345678 + long bignum2 = -999999 + + struct Node { + ubyte id + str name + long array + bool flag + long counter } - sub func() { - if cx16.r0<10 or cx16.r0>319 { - cx16.r1++ - } + sub start() { + ^^Node test = [] + + bignum++ + bignum2-- + + txt.print_l(bignum) + txt.spc() + txt.print_l(bignum2) + txt.nl() + + str output = "...................." + txt.print(conv.str_l(bignum)) + txt.nl() + + bignum = 999999 + bignum-- ; TODO this works in the current VM... + bignum = -888888 + + test.counter = 0 + test.counter ++ ; TODO ... why doesn't this? (requires plusMinusMultAnyLong routine) + test.counter = bignum2 + test.counter -- } } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index cd7647a4e..d4803d8a6 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -136,8 +136,8 @@ ARITHMETIC ---------- All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte. -exts reg1, reg2 - reg1 = signed extension of reg2 (byte to word, or word to long) (note: unlike M68k, exts.b -> word and exts.w -> long. The latter is not yet implemented yet as we don't have longs yet) -ext reg1, reg2 - reg1 = unsigned extension of reg2 (which in practice just means clearing the MSB / MSW) (note: unlike M68k, ext.b -> word and ext.w -> long. The latter is not yet implemented yet as we don't have longs yet) +exts reg1, reg2 - reg1 = signed extension of reg2 (byte to word, or word to long) (note: unlike M68k, exts.b -> word and exts.w -> long.) +ext reg1, reg2 - reg1 = unsigned extension of reg2 (which in practice just means clearing the MSB / MSW) (note: unlike M68k, ext.b -> word and ext.w -> long. ) inc reg1 - reg1 = reg1+1 incm address - memory at address += 1 dec reg1 - reg1 = reg1-1 @@ -247,9 +247,9 @@ sei - set interrupt disable flag nop - do nothing breakpoint - trigger a breakpoint align alignmentvalue - represents a memory alignment directive -lsig [b, w] reg1, reg2 - reg1 becomes the least significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) -msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) -concat [b, w] reg1, reg2, reg3 - reg1.w = 'concatenate' two registers: lsb/lsw of reg2 (as msb) and lsb/lsw of reg3 (as lsb) into word or int (int not yet implemented; requires 32bits regs) +lsig [b, w] reg1, reg2 - reg1 becomes the least significant byte (or word) of the word (or int) in reg2 +msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 +concat [b, w] reg1, reg2, reg3 - reg1.w/l = 'concatenate' two registers: lsb/lsw of reg2 (as msb) and lsb/lsw of reg3 (as lsb) into word or int) push [b, w, f] reg1 - push value in reg1 on the stack pop [b, w, f] reg1 - pop value from stack into reg1 pushst - push status register bits to stack @@ -559,8 +559,8 @@ val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThat enum class IRDataType { BYTE, WORD, - FLOAT - // TODO add INT (32-bit)? INT24 (24-bit)? + FLOAT, + LONG // 32 bits integer } enum class OperandDirection { @@ -623,6 +623,8 @@ data class InstructionFormat(val datatype: IRDataType?, result[IRDataType.BYTE] = InstructionFormat(IRDataType.BYTE, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) if('W' in typespec) result[IRDataType.WORD] = InstructionFormat(IRDataType.WORD, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) + if('L' in typespec) + result[IRDataType.LONG] = InstructionFormat(IRDataType.LONG, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) if('F' in typespec) result[IRDataType.FLOAT] = InstructionFormat(IRDataType.FLOAT, reg1, reg2, reg3, fpreg1, fpreg2, address, immediate, funcCall, sysCall) } @@ -643,12 +645,12 @@ data class InstructionFormat(val datatype: IRDataType?, */ val instructionFormats = mutableMapOf( Opcode.NOP to InstructionFormat.from("N"), - Opcode.LOAD to InstructionFormat.from("BW,>r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1,fr1,r1"), Opcode.LOADHA to InstructionFormat.from("B,>r1"), Opcode.LOADHX to InstructionFormat.from("B,>r1"), @@ -656,16 +658,16 @@ val instructionFormats = mutableMapOf( Opcode.LOADHAX to InstructionFormat.from("W,>r1"), Opcode.LOADHAY to InstructionFormat.from("W,>r1"), Opcode.LOADHXY to InstructionFormat.from("W,>r1"), - Opcode.LOADFIELD to InstructionFormat.from("BW,>r1,fr1,r1,fr1,fr1"), Opcode.LOADHFACONE to InstructionFormat.from("F,>fr1"), - Opcode.STOREM to InstructionFormat.from("BW,a | F,a"), - Opcode.STOREI to InstructionFormat.from("BW,a | F,a"), - Opcode.STOREIX to InstructionFormat.from("BW,a | F,a"), - Opcode.STOREZM to InstructionFormat.from("BW,>a | F,>a"), - Opcode.STOREZI to InstructionFormat.from("BW,a | F,a"), + Opcode.STOREM to InstructionFormat.from("BWL,a | F,a"), + Opcode.STOREI to InstructionFormat.from("BWL,a | F,a"), + Opcode.STOREIX to InstructionFormat.from("BWL,a | F,a"), + Opcode.STOREZM to InstructionFormat.from("BWL,>a | F,>a"), + Opcode.STOREZI to InstructionFormat.from("BWL,a | F,a"), Opcode.STOREHA to InstructionFormat.from("B,r1 | F,<>fr1"), - Opcode.INCM to InstructionFormat.from("BW,<>a | F,<>a"), - Opcode.DEC to InstructionFormat.from("BW,<>r1 | F,<>fr1"), - Opcode.DECM to InstructionFormat.from("BW,<>a | F,<>a"), - Opcode.NEG to InstructionFormat.from("BW,<>r1 | F,<>fr1"), - Opcode.NEGM to InstructionFormat.from("BW,<>a | F,<>a"), - Opcode.ADDR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), - Opcode.SUBR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), + Opcode.BGTR to InstructionFormat.from("BWL,r1 | F,<>fr1"), + Opcode.INCM to InstructionFormat.from("BWL,<>a | F,<>a"), + Opcode.DEC to InstructionFormat.from("BWL,<>r1 | F,<>fr1"), + Opcode.DECM to InstructionFormat.from("BWL,<>a | F,<>a"), + Opcode.NEG to InstructionFormat.from("BWL,<>r1 | F,<>fr1"), + Opcode.NEGM to InstructionFormat.from("BWL,<>a | F,<>a"), + Opcode.ADDR to InstructionFormat.from("BWL,<>r1,fr1,r1,fr1,a | F,a"), + Opcode.SUBR to InstructionFormat.from("BWL,<>r1,fr1,r1,fr1,a | F,a"), Opcode.MULR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), - Opcode.MULSR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), + Opcode.MULSR to InstructionFormat.from("BWL,<>r1,fr1,r1,fr1,a | F,a"), Opcode.DIVR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), - Opcode.DIVSR to InstructionFormat.from("BW,<>r1,fr1,r1,fr1,a | F,a"), - Opcode.SQRT to InstructionFormat.from("BW,>r1,fr1,r1,fr1,r1,r1,r1,fr1,r1,fr1,a | F,a"), + Opcode.SQRT to InstructionFormat.from("BWL,>r1,fr1,r1,fr1,r1,r1,r1,r1,r1,r1,r1,r1,r1,r1,a"), - Opcode.ORR to InstructionFormat.from("BW,<>r1,r1,a"), - Opcode.XORR to InstructionFormat.from("BW,<>r1,r1,a"), - Opcode.INV to InstructionFormat.from("BW,<>r1"), - Opcode.INVM to InstructionFormat.from("BW,<>a"), - Opcode.ASRN to InstructionFormat.from("BW,<>r1,a"), - Opcode.LSRN to InstructionFormat.from("BW,<>r1,a"), - Opcode.LSLN to InstructionFormat.from("BW,<>r1,a"), - Opcode.ASR to InstructionFormat.from("BW,<>r1"), - Opcode.ASRM to InstructionFormat.from("BW,<>a"), - Opcode.LSR to InstructionFormat.from("BW,<>r1"), - Opcode.LSRM to InstructionFormat.from("BW,<>a"), - Opcode.LSL to InstructionFormat.from("BW,<>r1"), - Opcode.LSLM to InstructionFormat.from("BW,<>a"), - Opcode.ROR to InstructionFormat.from("BW,<>r1"), - Opcode.RORM to InstructionFormat.from("BW,<>a"), - Opcode.ROXR to InstructionFormat.from("BW,<>r1"), - Opcode.ROXRM to InstructionFormat.from("BW,<>a"), - Opcode.ROL to InstructionFormat.from("BW,<>r1"), - Opcode.ROLM to InstructionFormat.from("BW,<>a"), - Opcode.ROXL to InstructionFormat.from("BW,<>r1"), - Opcode.ROXLM to InstructionFormat.from("BW,<>a"), + Opcode.CMP to InstructionFormat.from("BWL,r1,r1,r1,r1,a"), + Opcode.ORR to InstructionFormat.from("BWL,<>r1,r1,a"), + Opcode.XORR to InstructionFormat.from("BWL,<>r1,r1,a"), + Opcode.INV to InstructionFormat.from("BWL,<>r1"), + Opcode.INVM to InstructionFormat.from("BWL,<>a"), + Opcode.ASRN to InstructionFormat.from("BWL,<>r1,a"), + Opcode.LSRN to InstructionFormat.from("BWL,<>r1,a"), + Opcode.LSLN to InstructionFormat.from("BWL,<>r1,a"), + Opcode.ASR to InstructionFormat.from("BWL,<>r1"), + Opcode.ASRM to InstructionFormat.from("BWL,<>a"), + Opcode.LSR to InstructionFormat.from("BWL,<>r1"), + Opcode.LSRM to InstructionFormat.from("BWL,<>a"), + Opcode.LSL to InstructionFormat.from("BWL,<>r1"), + Opcode.LSLM to InstructionFormat.from("BWL,<>a"), + Opcode.ROR to InstructionFormat.from("BWL,<>r1"), + Opcode.RORM to InstructionFormat.from("BWL,<>a"), + Opcode.ROXR to InstructionFormat.from("BWL,<>r1"), + Opcode.ROXRM to InstructionFormat.from("BWL,<>a"), + Opcode.ROL to InstructionFormat.from("BWL,<>r1"), + Opcode.ROLM to InstructionFormat.from("BWL,<>a"), + Opcode.ROXL to InstructionFormat.from("BWL,<>r1"), + Opcode.ROXLM to InstructionFormat.from("BWL,<>a"), Opcode.BIT to InstructionFormat.from("B,fr1,r1,r1,r1 | F,>fr1"), + Opcode.PUSH to InstructionFormat.from("BWL,r1 | F,>fr1"), Opcode.PUSHST to InstructionFormat.from("N"), Opcode.POPST to InstructionFormat.from("N"), Opcode.CONCAT to InstructionFormat.from("BW,<>r1, require(immediate in -128..255) { "immediate value out of range for byte: $immediate" } IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" } + IRDataType.LONG -> require(immediate in -2147483647..2147483647) { "immediate value out of range for long: $immediate" } IRDataType.FLOAT, null -> {} } } @@ -1083,8 +1086,7 @@ data class IRInstruction( // some word instructions have byte reg1 return when (opcode) { Opcode.STOREZX, Opcode.SQRT -> IRDataType.BYTE - Opcode.EXT, Opcode.EXTS -> TODO("ext.w into long type") - Opcode.CONCAT -> TODO("concat.w into long type") + Opcode.EXT, Opcode.EXTS, Opcode.CONCAT -> IRDataType.LONG else -> IRDataType.WORD } } @@ -1107,7 +1109,7 @@ data class IRInstruction( if(opcode==Opcode.MSIG || opcode==Opcode.LSIG) return when(type) { IRDataType.BYTE -> IRDataType.WORD - IRDataType.WORD -> TODO("msig/lsig.w from long type") + IRDataType.WORD -> IRDataType.LONG else -> null } if(opcode==Opcode.ASRN || opcode==Opcode.LSRN || opcode==Opcode.LSLN) @@ -1125,6 +1127,7 @@ data class IRInstruction( when(type) { IRDataType.BYTE -> result.add(".b ") IRDataType.WORD -> result.add(".w ") + IRDataType.LONG -> result.add(".l ") IRDataType.FLOAT -> result.add(".f ") else -> result.add(" ") } @@ -1154,6 +1157,7 @@ data class IRInstruction( when(it.reg.dt) { IRDataType.BYTE -> result.add("${location}r${it.reg.registerNum}.b$cpuReg,") IRDataType.WORD -> result.add("${location}r${it.reg.registerNum}.w$cpuReg,") + IRDataType.LONG -> result.add("${location}r${it.reg.registerNum}.l$cpuReg,") IRDataType.FLOAT -> result.add("${location}fr${it.reg.registerNum}.f$cpuReg,") } } @@ -1175,12 +1179,14 @@ data class IRInstruction( when (returnspec.dt) { IRDataType.BYTE -> "r${returnspec.registerNum}.b" IRDataType.WORD -> "r${returnspec.registerNum}.w" + IRDataType.LONG -> "r${returnspec.registerNum}.l" IRDataType.FLOAT -> "fr${returnspec.registerNum}.f" } } else { when (returnspec.dt) { IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg + IRDataType.LONG -> "r${returnspec.registerNum}.l@" + cpuReg IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg } } diff --git a/intermediate/src/prog8/intermediate/Utils.kt b/intermediate/src/prog8/intermediate/Utils.kt index e4df22bde..6eefe8a6e 100644 --- a/intermediate/src/prog8/intermediate/Utils.kt +++ b/intermediate/src/prog8/intermediate/Utils.kt @@ -53,6 +53,7 @@ fun convertIRType(typestr: String): IRDataType? { "" -> null ".b" -> IRDataType.BYTE ".w" -> IRDataType.WORD + ".l" -> IRDataType.LONG ".f" -> IRDataType.FLOAT else -> throw IRParseException("invalid type $typestr") } @@ -78,7 +79,7 @@ fun parseIRValue(value: String): Double { } -private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE) +private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.l|\.f)?(.*)""", RegexOption.IGNORE_CASE) private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""") fun parseIRCodeLine(line: String): Either { @@ -207,6 +208,10 @@ fun parseIRCodeLine(line: String): Either { if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535)) throw IRParseException("immediate value out of range for word: $immediateInt") } + IRDataType.LONG -> { + if (immediateInt!=null && immediateInt < -2147483647) + throw IRParseException("immediate value out of range for long: $immediateInt") + } IRDataType.FLOAT -> {} null -> {} } @@ -271,6 +276,7 @@ private fun parseCall(rest: String): ParsedCall { val type = when(match.groups[2]!!.value) { "b" -> IRDataType.BYTE "w" -> IRDataType.WORD + "l" -> IRDataType.LONG "f" -> IRDataType.FLOAT else -> throw IRParseException("invalid type spec in $reg") } @@ -359,6 +365,7 @@ fun irType(type: DataType): IRDataType { BaseDataType.UBYTE, BaseDataType.BYTE -> IRDataType.BYTE BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> IRDataType.WORD + BaseDataType.LONG -> IRDataType.LONG BaseDataType.FLOAT -> IRDataType.FLOAT BaseDataType.STRUCT_INSTANCE -> throw AssemblyError("no support for struct instances yet so no IR datatype for $type") else -> throw AssemblyError("no IR datatype for $type") diff --git a/virtualmachine/src/prog8/vm/Memory.kt b/virtualmachine/src/prog8/vm/Memory.kt index 387d3a435..54a146a92 100644 --- a/virtualmachine/src/prog8/vm/Memory.kt +++ b/virtualmachine/src/prog8/vm/Memory.kt @@ -32,6 +32,10 @@ class Memory { return (mem[address] + 256u*mem[address+1]).toUShort() } + fun getSL(address: Int): Int { + return (mem[address] + 256u*mem[address+1] + 65536u*mem[address+2] + 16777216u*mem[address+3]).toInt() + } + fun getSW(address: Int): Short { return (mem[address].toInt() + mem[address+1].toInt()*256).toShort() } @@ -47,6 +51,14 @@ class Memory { mem[address] = uv.toUByte() } + fun setSL(address: Int, value: Int) { + val uv = value.toUInt() + mem[address+3] = (uv shr 24).toUByte() + mem[address+2] = (uv shr 16).toUByte() + mem[address+1] = (uv shr 8).toUByte() + mem[address] = uv.toUByte() + } + fun setFloat(address: Int, value: Double) { var bits = value.toBits() mem[address] = bits.toUByte() diff --git a/virtualmachine/src/prog8/vm/Registers.kt b/virtualmachine/src/prog8/vm/Registers.kt index 57b86b084..9bb9946ac 100644 --- a/virtualmachine/src/prog8/vm/Registers.kt +++ b/virtualmachine/src/prog8/vm/Registers.kt @@ -6,14 +6,14 @@ package prog8.vm * A,X and Y "physical" 6502 registers. */ class Registers { - private val registers = Array(99999) { 0u } + private val registers = Array(99999) { 0 } private val floatRegisters = Array(99999) { 0.0 } var cpuA: UByte = 0u var cpuX: UByte = 0u var cpuY: UByte = 0u fun reset() { - registers.fill(0u) + registers.fill(0) floatRegisters.fill(0.0) cpuA = 0u cpuX = 0u @@ -21,29 +21,35 @@ class Registers { } fun setUB(reg: Int, value: UByte) { - registers[reg] = registers[reg] and 0xff00u or value.toUShort() + registers[reg] = value.toInt() } fun setSB(reg: Int, value: Byte) { - registers[reg] = registers[reg] and 0xff00u or (value.toUShort() and 0x00ffu) + registers[reg] = value.toInt() } fun setUW(reg: Int, value: UShort) { - registers[reg] = value + registers[reg] = value.toInt() } fun setSW(reg: Int, value: Short) { - registers[reg] = value.toUShort() + registers[reg] = value.toInt() + } + + fun setSL(reg: Int, value: Int) { + registers[reg] = value } fun getUB(reg: Int) = registers[reg].toUByte() fun getSB(reg: Int) = registers[reg].toByte() - fun getUW(reg: Int) = registers[reg] + fun getUW(reg: Int) = registers[reg].toUShort() fun getSW(reg: Int) = registers[reg].toShort() + fun getSL(reg: Int) = registers[reg] + fun getFloat(reg:Int) = floatRegisters[reg] fun setFloat(reg:Int, value: Double) { diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 7449e5967..e3062860c 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -68,6 +68,9 @@ SYSCALLS: DO NOT RENUMBER THESE OR YOU WILL BREAK EXISTING CODE 56 = CLOSE_FILE 57 = CLOSE_FILE_WRITE 58 = ncompare strings +59 = print_i32 ; print signed 32 bits integer (prog8 long) +60 = i32 to string ; put string representation of signed 32 bits integer (prog8 long) into memory +61 = decimal string to prog8 long (i32 signed) */ enum class Syscall { @@ -130,6 +133,9 @@ enum class Syscall { CLOSE_FILE, CLOSE_FILE_WRITE, NCOMPARE_STRINGS, + PRINT_I32, + I32_TO_STRING, + STR_TO_LONG, ; companion object { @@ -143,6 +149,7 @@ object SysCalls { when(it.reg.dt) { IRDataType.BYTE -> vm.registers.getUB(it.reg.registerNum) IRDataType.WORD -> vm.registers.getUW(it.reg.registerNum) + IRDataType.LONG -> vm.registers.getSL(it.reg.registerNum) IRDataType.FLOAT -> vm.registers.getFloat(it.reg.registerNum) } } @@ -164,6 +171,7 @@ object SysCalls { when(returns.dt) { IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte()) IRDataType.WORD -> vm.registers.setUW(returns.registerNum, vv.toInt().toUShort()) + IRDataType.LONG -> vm.registers.setSL(returns.registerNum, vv.toInt()) IRDataType.FLOAT -> vm.registers.setFloat(returns.registerNum, vv) } } @@ -200,6 +208,10 @@ object SysCalls { val value = getArgValues(callspec.arguments, vm).single() print(value) } + Syscall.PRINT_I32 -> { + val value = getArgValues(callspec.arguments, vm).single() + print(value) + } Syscall.INPUT -> { val (address, maxlen) = getArgValues(callspec.arguments, vm) var input = readln() @@ -263,6 +275,17 @@ object SysCalls { } return returnValue(callspec.returns.single(), value, vm) } + Syscall.STR_TO_LONG -> { + val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort + val memstring = vm.memory.getString(stringAddr.toInt()) + val match = Regex("^[+-]?\\d+").find(memstring) ?: return returnValue(callspec.returns.single(), 0, vm) + val value = try { + match.value.toInt() + } catch(_: NumberFormatException) { + 0 + } + return returnValue(callspec.returns.single(), value, vm) + } Syscall.STR_TO_FLOAT -> { val stringAddr = getArgValues(callspec.arguments, vm).single() as UShort val memstring = vm.memory.getString(stringAddr.toInt()).replace(" ", "") @@ -634,6 +657,10 @@ object SysCalls { } Syscall.CLOSE_FILE -> vm.close_file_read() Syscall.CLOSE_FILE_WRITE -> vm.close_file_write() + Syscall.I32_TO_STRING -> { + val (number, stringbuffer) = getArgValues(callspec.arguments, vm) + vm.memory.setString((stringbuffer as UShort).toInt(), number.toString(), true) + } } } } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index ea1362678..50183b9a5 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -353,12 +353,17 @@ class VirtualMachine(irProgram: IRProgram) { IRDataType.BYTE -> { registers.setUB(reg, value.toUByte()) statusZero = value==0 - statusNegative = value>=0x80 + statusNegative = value<0 || value>=0x80 } IRDataType.WORD -> { registers.setUW(reg, value.toUShort()) statusZero = value==0 - statusNegative = value>=0x8000 + statusNegative = value<0 || value>=0x8000 + } + IRDataType.LONG -> { + registers.setSL(reg, value) + statusZero = value==0 + statusNegative = value<0 } IRDataType.FLOAT -> throw IllegalArgumentException("attempt to set integer result register but float type") } @@ -377,6 +382,10 @@ class VirtualMachine(irProgram: IRProgram) { val value = registers.getUW(i.reg1!!) valueStack.pushw(value) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!) + valueStack.pushl(value) + } IRDataType.FLOAT -> { val value = registers.getFloat(i.fpReg1!!) valueStack.pushf(value) @@ -389,6 +398,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.removeLast().toInt(), i.type!!) IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().toInt(), i.type!!) + IRDataType.LONG -> setResultReg(i.reg1!!, valueStack.popl(), i.type!!) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf()) } nextPc() @@ -425,6 +435,7 @@ class VirtualMachine(irProgram: IRProgram) { when(value.dt!!) { IRDataType.BYTE -> valueStack.add(value.value as UByte) IRDataType.WORD -> valueStack.pushw(value.value as UShort) + IRDataType.LONG -> valueStack.pushl(value.value as Int) IRDataType.FLOAT -> valueStack.pushf(value.value as Double) } value.dt=null @@ -472,6 +483,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(i.address!!) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!)) } nextPc() @@ -489,6 +505,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(registers.getUW(i.reg2!!).toInt()) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt())) } nextPc() @@ -508,6 +529,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(registers.getUW(i.reg2!!).toInt() + offset) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> { registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt() + offset)) } @@ -527,6 +553,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(i.address!! + registers.getUB(i.reg2!!).toInt()) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUB(i.reg1!!).toInt())) } nextPc() @@ -546,6 +577,12 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!) + val value = memory.getSL(pointer.toInt()) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value.toInt(), i.type!!) + } IRDataType.FLOAT -> { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!) registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt())) @@ -566,6 +603,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg2!!) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!)) } nextPc() @@ -575,6 +617,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> memory.setUB(i.address!!, registers.getUB(i.reg1!!)) IRDataType.WORD -> memory.setUW(i.address!!, registers.getUW(i.reg1!!)) + IRDataType.LONG -> memory.setSL(i.address!!, registers.getSL(i.reg1!!)) IRDataType.FLOAT -> memory.setFloat(i.address!!, registers.getFloat(i.fpReg1!!)) } nextPc() @@ -584,6 +627,7 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), registers.getUB(i.reg1!!)) IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt(), registers.getUW(i.reg1!!)) + IRDataType.LONG -> memory.setSL(registers.getUW(i.reg2!!).toInt(), registers.getSL(i.reg1!!)) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!)) } nextPc() @@ -595,6 +639,7 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + offset, registers.getUB(i.reg1!!)) IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt() + offset, registers.getUW(i.reg1!!)) + IRDataType.LONG -> memory.setSL(registers.getUW(i.reg2!!).toInt() + offset, registers.getSL(i.reg1!!)) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt() + offset, registers.getFloat(i.fpReg1!!)) } nextPc() @@ -604,6 +649,7 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUB(i.reg1!!)) IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUW(i.reg1!!)) + IRDataType.LONG -> memory.setSL(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getSL(i.reg1!!)) IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!)) } nextPc() @@ -619,6 +665,10 @@ class VirtualMachine(irProgram: IRProgram) { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!) memory.setUW(pointer.toInt(), registers.getUW(i.reg1!!)) } + IRDataType.LONG -> { + val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!) + memory.setSL(pointer.toInt(), registers.getSL(i.reg1!!)) + } IRDataType.FLOAT -> { val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!) memory.setFloat(pointer.toInt(), registers.getFloat(i.fpReg1!!)) @@ -631,6 +681,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> memory.setUB(i.address!!, 0u) IRDataType.WORD -> memory.setUW(i.address!!, 0u) + IRDataType.LONG -> memory.setSL(i.address!!, 0) IRDataType.FLOAT -> memory.setFloat(i.address!!, 0.0) } nextPc() @@ -640,6 +691,7 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u) IRDataType.WORD -> memory.setUW(registers.getUW(i.reg1!!).toInt(), 0u) + IRDataType.LONG -> memory.setSL(registers.getUW(i.reg1!!).toInt(), 0) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0.0) } nextPc() @@ -649,6 +701,7 @@ class VirtualMachine(irProgram: IRProgram) { when (i.type!!) { IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u) IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u) + IRDataType.LONG -> memory.setSL(i.address!! + registers.getUB(i.reg1!!).toInt(), 0) IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0.0) } nextPc() @@ -675,6 +728,7 @@ class VirtualMachine(irProgram: IRProgram) { when(arg.reg.dt) { IRDataType.BYTE -> memory.setUB(arg.address!!, registers.getUB(arg.reg.registerNum)) IRDataType.WORD -> memory.setUW(arg.address!!, registers.getUW(arg.reg.registerNum)) + IRDataType.LONG -> memory.setSL(arg.address!!, registers.getSL(arg.reg.registerNum)) IRDataType.FLOAT -> memory.setFloat(arg.address!!, registers.getFloat(arg.reg.registerNum)) } } @@ -719,6 +773,15 @@ class VirtualMachine(irProgram: IRProgram) { throw IllegalArgumentException("missing return value reg") } } + IRDataType.LONG -> { + if(returns.isNotEmpty()) + registers.setSL(returns.single().registerNum, i.immediate!!) + else { + val callInstr = context.returnChunk.instructions[context.returnIndex-1] + if(callInstr.opcode!=Opcode.CALL) + throw IllegalArgumentException("missing return value reg") + } + } IRDataType.FLOAT -> { if(returns.isNotEmpty()) registers.setFloat(returns.single().registerNum, i.immediateFp!!) @@ -759,6 +822,15 @@ class VirtualMachine(irProgram: IRProgram) { throw IllegalArgumentException("missing return value reg") } } + IRDataType.LONG -> { + if(returns.isNotEmpty()) + registers.setSL(returns.single().registerNum, registers.getSL(i.reg1!!)) + else { + val callInstr = context.returnChunk.instructions[context.returnIndex-1] + if(callInstr.opcode!=Opcode.CALL) + throw IllegalArgumentException("missing return value reg") + } + } IRDataType.FLOAT -> { if(returns.isNotEmpty()) registers.setFloat(returns.single().registerNum, registers.getFloat(i.fpReg1!!)) @@ -938,6 +1010,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!)+1 + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)+1f) } nextPc() @@ -956,6 +1033,11 @@ class VirtualMachine(irProgram: IRProgram) { memory.setUW(address, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(address)+1 + memory.setSL(address, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> memory.setFloat(address, memory.getFloat(address)+1f) } nextPc() @@ -973,6 +1055,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!)-1 + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg1!!)-1f) } nextPc() @@ -990,6 +1077,11 @@ class VirtualMachine(irProgram: IRProgram) { memory.setUW(i.address!!, value) statusbitsNZ(value.toInt(), i.type!!) } + IRDataType.LONG -> { + val value = memory.getSL(i.address!!)-1 + memory.setSL(i.address!!, value) + statusbitsNZ(value, i.type!!) + } IRDataType.FLOAT -> memory.setFloat(i.address!!, memory.getFloat(i.address!!)-1f) } nextPc() @@ -1007,6 +1099,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value.toUShort()) statusbitsNZ(value, IRDataType.WORD) } + IRDataType.LONG -> { + val value = -registers.getSL(i.reg1!!) + registers.setSL(i.reg1!!, value) + statusbitsNZ(value, IRDataType.LONG) + } IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, -registers.getFloat(i.fpReg1!!)) } nextPc() @@ -1025,6 +1122,11 @@ class VirtualMachine(irProgram: IRProgram) { memory.setUW(address, value.toUShort()) statusbitsNZ(value, IRDataType.WORD) } + IRDataType.LONG -> { + val value = -memory.getSL(address) + memory.setSL(address, value) + statusbitsNZ(value, IRDataType.LONG) + } IRDataType.FLOAT -> memory.setFloat(address, -memory.getFloat(address)) } nextPc() @@ -1034,6 +1136,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByte("+", i.reg1!!, i.reg2!!) IRDataType.WORD -> plusMinusMultAnyWord("+", i.reg1!!, i.reg2!!) + IRDataType.LONG -> plusMinusMultAnyLong("+", i.reg1!!, i.reg2!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val right = registers.getFloat(i.fpReg2!!) @@ -1048,6 +1151,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultConstByte("+", i.reg1!!, i.immediate!!.toUByte()) IRDataType.WORD -> plusMinusMultConstWord("+", i.reg1!!, i.immediate!!.toUShort()) + IRDataType.LONG -> plusMinusMultConstLong("+", i.reg1!!, i.immediate!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val result = arithFloat(left, "+", i.immediateFp!!) @@ -1062,6 +1166,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByteInplace("+", i.reg1!!, address) IRDataType.WORD -> plusMinusMultAnyWordInplace("+", i.reg1!!, address) + IRDataType.LONG -> plusMinusMultAnyLongInplace("+", i.reg1!!, address) IRDataType.FLOAT -> { val left = memory.getFloat(address) val right = registers.getFloat(i.fpReg1!!) @@ -1076,6 +1181,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByte("-", i.reg1!!, i.reg2!!) IRDataType.WORD -> plusMinusMultAnyWord("-", i.reg1!!, i.reg2!!) + IRDataType.LONG -> plusMinusMultAnyLong("-", i.reg1!!, i.reg2!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val right = registers.getFloat(i.fpReg2!!) @@ -1090,6 +1196,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultConstByte("-", i.reg1!!, i.immediate!!.toUByte()) IRDataType.WORD -> plusMinusMultConstWord("-", i.reg1!!, i.immediate!!.toUShort()) + IRDataType.LONG -> plusMinusMultConstLong("-", i.reg1!!, i.immediate!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val result = arithFloat(left, "-", i.immediateFp!!) @@ -1104,6 +1211,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByteInplace("-", i.reg1!!, address) IRDataType.WORD -> plusMinusMultAnyWordInplace("-", i.reg1!!, address) + IRDataType.LONG -> plusMinusMultAnyLongInplace("-", i.reg1!!, address) IRDataType.FLOAT -> { val left = memory.getFloat(address) val right = registers.getFloat(i.fpReg1!!) @@ -1118,6 +1226,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByte("*", i.reg1!!, i.reg2!!) IRDataType.WORD -> plusMinusMultAnyWord("*", i.reg1!!, i.reg2!!) + IRDataType.LONG -> throw IllegalArgumentException("mulr unsigned long not supported") IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val right = registers.getFloat(i.fpReg2!!) @@ -1132,6 +1241,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultConstByte("*", i.reg1!!, i.immediate!!.toUByte()) IRDataType.WORD -> plusMinusMultConstWord("*", i.reg1!!, i.immediate!!.toUShort()) + IRDataType.LONG -> throw IllegalArgumentException("mul unsigned long not supported") IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val result = arithFloat(left, "*", i.immediateFp!!) @@ -1146,6 +1256,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByteInplace("*", i.reg1!!, address) IRDataType.WORD -> plusMinusMultAnyWordInplace("*", i.reg1!!, address) + IRDataType.LONG -> throw IllegalArgumentException("mulm unsigned long not supported") IRDataType.FLOAT -> { val left = memory.getFloat(address) val right = registers.getFloat(i.fpReg1!!) @@ -1160,6 +1271,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByteSigned("*", i.reg1!!, i.reg2!!) IRDataType.WORD -> plusMinusMultAnyWordSigned("*", i.reg1!!, i.reg2!!) + IRDataType.LONG -> plusMinusMultAnyLongSigned("*", i.reg1!!, i.reg2!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val right = registers.getFloat(i.fpReg2!!) @@ -1174,6 +1286,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultConstByteSigned("*", i.reg1!!, i.immediate!!.toByte()) IRDataType.WORD -> plusMinusMultConstWordSigned("*", i.reg1!!, i.immediate!!.toShort()) + IRDataType.LONG -> plusMinusMultConstLongSigned("*", i.reg1!!, i.immediate!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val result = arithFloat(left, "*", i.immediateFp!!) @@ -1188,6 +1301,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> plusMinusMultAnyByteSignedInplace("*", i.reg1!!, address) IRDataType.WORD -> plusMinusMultAnyWordSignedInplace("*", i.reg1!!, address) + IRDataType.LONG -> plusMinusMultAnyLongSignedInplace("*", i.reg1!!, address) IRDataType.FLOAT -> { val left = memory.getFloat(address) val right = registers.getFloat(i.fpReg1!!) @@ -1202,6 +1316,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divOrModByteUnsigned("/", i.reg1!!, i.reg2!!) IRDataType.WORD -> divOrModWordUnsigned("/", i.reg1!!, i.reg2!!) + IRDataType.LONG -> throw IllegalArgumentException("divr unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1211,6 +1326,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divOrModConstByteUnsigned("/", i.reg1!!, i.immediate!!.toUByte()) IRDataType.WORD -> divOrModConstWordUnsigned("/", i.reg1!!, i.immediate!!.toUShort()) + IRDataType.LONG -> throw IllegalArgumentException("div unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1221,6 +1337,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divModByteUnsignedInplace("/", i.reg1!!, address) IRDataType.WORD -> divModWordUnsignedInplace("/", i.reg1!!, address) + IRDataType.LONG -> throw IllegalArgumentException("divm unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1230,6 +1347,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divModByteSigned("/", i.reg1!!, i.reg2!!) IRDataType.WORD -> divModWordSigned("/", i.reg1!!, i.reg2!!) + IRDataType.LONG -> divModLongSigned("/", i.reg1!!, i.reg2!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val right = registers.getFloat(i.fpReg2!!) @@ -1244,6 +1362,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divModConstByteSigned("/", i.reg1!!, i.immediate!!.toByte()) IRDataType.WORD -> divModConstWordSigned("/", i.reg1!!, i.immediate!!.toShort()) + IRDataType.LONG -> divModConstLongSigned("/", i.reg1!!, i.immediate!!) IRDataType.FLOAT -> { val left = registers.getFloat(i.fpReg1!!) val result = arithFloat(left, "/", i.immediateFp!!) @@ -1258,6 +1377,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divModByteSignedInplace("/", i.reg1!!, address) IRDataType.WORD -> divModWordSignedInplace("/", i.reg1!!, address) + IRDataType.LONG -> divModLongSignedInplace("/", i.reg1!!, address) IRDataType.FLOAT -> { val left = memory.getFloat(address) val right = registers.getFloat(i.fpReg1!!) @@ -1272,6 +1392,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divOrModByteUnsigned("%", i.reg1!!, i.reg2!!) IRDataType.WORD -> divOrModWordUnsigned("%", i.reg1!!, i.reg2!!) + IRDataType.LONG -> throw IllegalArgumentException("modr unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1281,6 +1402,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divOrModConstByteUnsigned("%", i.reg1!!, i.immediate!!.toUByte()) IRDataType.WORD -> divOrModConstWordUnsigned("%", i.reg1!!, i.immediate!!.toUShort()) + IRDataType.LONG -> throw IllegalArgumentException("mod unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1290,6 +1412,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divAndModUByte(i.reg1!!, i.reg2!!) // division+remainder results on value stack IRDataType.WORD -> divAndModUWord(i.reg1!!, i.reg2!!) // division+remainder results on value stack + IRDataType.LONG -> throw IllegalArgumentException("divmodr unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1299,6 +1422,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> divAndModConstUByte(i.reg1!!, i.immediate!!.toUByte()) // division+remainder results on value stack IRDataType.WORD -> divAndModConstUWord(i.reg1!!, i.immediate!!.toUShort()) // division+remainder results on value stack + IRDataType.LONG -> throw IllegalArgumentException("divmod unsigned long not supported") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1308,6 +1432,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setSB(i.reg1!!, registers.getSB(i.reg2!!).toInt().sign.toByte()) IRDataType.WORD -> registers.setSB(i.reg1!!, registers.getSW(i.reg2!!).toInt().sign.toByte()) + IRDataType.LONG -> registers.setSB(i.reg1!!, registers.getSL(i.reg2!!).sign.toByte()) IRDataType.FLOAT -> registers.setSB(i.reg1!!, registers.getFloat(i.fpReg1!!).sign.toInt().toByte()) } nextPc() @@ -1317,6 +1442,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, sqrt(registers.getUB(i.reg2!!).toDouble()).toInt().toUByte()) IRDataType.WORD -> registers.setUB(i.reg1!!, sqrt(registers.getUW(i.reg2!!).toDouble()).toInt().toUByte()) + IRDataType.LONG -> TODO("long sqrt") IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, sqrt(registers.getFloat(i.fpReg2!!))) } nextPc() @@ -1325,13 +1451,17 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsSQUARE(i: IRInstruction) { when(i.type!!) { IRDataType.BYTE -> { - val value = registers.getUB(i.reg2!!).toDouble().toInt() + val value = registers.getUB(i.reg2!!).toInt() registers.setUB(i.reg1!!, (value*value).toUByte()) } IRDataType.WORD -> { - val value = registers.getUW(i.reg2!!).toDouble().toInt() + val value = registers.getUW(i.reg2!!).toInt() registers.setUW(i.reg1!!, (value*value).toUShort()) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg2!!) + registers.setSL(i.reg1!!, value*value) + } IRDataType.FLOAT -> { val value = registers.getFloat(i.fpReg2!!) registers.setFloat(i.fpReg1!!, value*value) @@ -1352,6 +1482,11 @@ class VirtualMachine(irProgram: IRProgram) { val reg2 = registers.getUW(i.reg2!!) reg1.toInt() - reg2.toInt() } + IRDataType.LONG -> { + val reg1 = registers.getSL(i.reg1!!) + val reg2 = registers.getSL(i.reg2!!) + reg1 - reg2 + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsComparison(comparison, i.type!!) @@ -1368,6 +1503,10 @@ class VirtualMachine(irProgram: IRProgram) { val reg1 = registers.getUW(i.reg1!!) reg1.toInt() - (i.immediate!! and 65535) } + IRDataType.LONG -> { + val reg1 = registers.getSL(i.reg1!!) + reg1 - i.immediate!! + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsComparison(comparison, i.type!!) @@ -1400,6 +1539,7 @@ class VirtualMachine(irProgram: IRProgram) { when(type) { IRDataType.BYTE -> statusNegative = (value and 0x80)==0x80 IRDataType.WORD -> statusNegative = (value and 0x8000)==0x8000 + IRDataType.LONG -> statusNegative = value<0 IRDataType.FLOAT -> { /* floats don't change the status bits */ } } } @@ -1418,6 +1558,7 @@ class VirtualMachine(irProgram: IRProgram) { when(type) { IRDataType.BYTE -> statusNegative = (comparison and 0x80)!=0 IRDataType.WORD -> statusNegative = (comparison and 0x8000)!=0 + IRDataType.LONG -> statusNegative = comparison<0 IRDataType.FLOAT -> { /* floats don't change the status bits */ } } // TODO determine statusOverflow in comparison @@ -1850,7 +1991,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsEXT(i: IRInstruction) { when(i.type!!){ IRDataType.BYTE -> registers.setUW(i.reg1!!, registers.getUB(i.reg2!!).toUShort()) - IRDataType.WORD -> throw IllegalArgumentException("ext.w not yet supported, requires 32 bits registers") + IRDataType.WORD -> registers.setSL(i.reg1!!, registers.getUW(i.reg2!!).toInt()) + IRDataType.LONG -> throw IllegalArgumentException("ext.l makes no sense, 32 bits is already the widest you can get") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1859,7 +2001,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsEXTS(i: IRInstruction) { when(i.type!!){ IRDataType.BYTE -> registers.setSW(i.reg1!!, registers.getSB(i.reg2!!).toShort()) - IRDataType.WORD -> throw IllegalArgumentException("exts.w not yet supported, requires 32 bits registers") + IRDataType.WORD -> registers.setSL(i.reg1!!, registers.getSW(i.reg2!!).toInt()) + IRDataType.LONG -> throw IllegalArgumentException("exts.l makes no sense, 32 bits is already the widest you can get") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1871,6 +2014,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte()) IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort()) + IRDataType.LONG -> registers.setSL(i.reg1!!, value) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1888,6 +2032,10 @@ class VirtualMachine(irProgram: IRProgram) { value = registers.getUW(i.reg1!!).toInt() and i.immediate!! registers.setUW(i.reg1!!, value.toUShort()) } + IRDataType.LONG -> { + value = registers.getSL(i.reg1!!) and i.immediate!! + registers.setSL(i.reg1!!, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1910,6 +2058,12 @@ class VirtualMachine(irProgram: IRProgram) { value = left.toInt() and right.toInt() memory.setUW(address, value.toUShort()) } + IRDataType.LONG -> { + val left = memory.getSL(address) + val right = registers.getSL(i.reg1!!) + value = left and right + memory.setSL(address, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1922,6 +2076,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte()) IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort()) + IRDataType.LONG -> registers.setSL(i.reg1!!, value) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1939,6 +2094,10 @@ class VirtualMachine(irProgram: IRProgram) { value = registers.getUW(i.reg1!!).toInt() or i.immediate!! registers.setUW(i.reg1!!, value.toUShort()) } + IRDataType.LONG -> { + value = registers.getSL(i.reg1!!) or i.immediate!! + registers.setSL(i.reg1!!, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1961,6 +2120,12 @@ class VirtualMachine(irProgram: IRProgram) { value = left.toInt() or right.toInt() memory.setUW(address, value.toUShort()) } + IRDataType.LONG -> { + val left = memory.getSL(address) + val right = registers.getSL(i.reg1!!) + value = left or right + memory.setSL(address, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1973,6 +2138,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte()) IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort()) + IRDataType.LONG -> registers.setSL(i.reg1!!, value) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -1990,6 +2156,10 @@ class VirtualMachine(irProgram: IRProgram) { value = registers.getUW(i.reg1!!).toInt() xor i.immediate!! registers.setUW(i.reg1!!, value.toUShort()) } + IRDataType.LONG -> { + value = registers.getSL(i.reg1!!) xor i.immediate!! + registers.setSL(i.reg1!!, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -2012,6 +2182,12 @@ class VirtualMachine(irProgram: IRProgram) { value = left.toInt() xor right.toInt() memory.setUW(address, value.toUShort()) } + IRDataType.LONG -> { + val left = memory.getSL(address) + val right = registers.getSL(i.reg1!!) + value = left xor right + memory.setSL(address, value) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } statusbitsNZ(value, i.type!!) @@ -2022,6 +2198,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1!!).inv()) IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg1!!).inv()) + IRDataType.LONG -> registers.setSL(i.reg1!!, registers.getSL(i.reg1!!).inv()) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2032,6 +2209,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv()) IRDataType.WORD -> memory.setUW(address, memory.getUW(address).inv()) + IRDataType.LONG -> memory.setSL(address, memory.getSL(address).inv()) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2042,6 +2220,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte()) IRDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort()) + IRDataType.LONG -> registers.setSL(i.reg1!!, left shr right) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2059,6 +2238,10 @@ class VirtualMachine(irProgram: IRProgram) { val memvalue = memory.getSW(address).toInt() memory.setSW(address, (memvalue shr operand).toShort()) } + IRDataType.LONG -> { + val memvalue = memory.getSL(address) + memory.setSL(address, memvalue shr operand) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2076,6 +2259,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 1)!=0 registers.setSW(i.reg1!!, (value shr 1).toShort()) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!) + statusCarry = (value and 1)!=0 + registers.setSL(i.reg1!!, value shr 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2094,6 +2282,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 1)!=0 memory.setSW(address, (value shr 1).toShort()) } + IRDataType.LONG -> { + val value = memory.getSL(address) + statusCarry = (value and 1)!=0 + memory.setSL(address, value shr 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2104,6 +2297,7 @@ class VirtualMachine(irProgram: IRProgram) { when(i.type!!) { IRDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte()) IRDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort()) + IRDataType.LONG -> registers.setSL(i.reg1!!, (left shr right.toInt()).toInt()) IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2121,6 +2315,10 @@ class VirtualMachine(irProgram: IRProgram) { val memvalue = memory.getUW(address).toInt() memory.setUW(address, (memvalue shr operand).toUShort()) } + IRDataType.LONG -> { + val memvalue = memory.getSL(address) + memory.setSL(address, memvalue shr operand) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2138,6 +2336,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 1)!=0 registers.setUW(i.reg1!!, (value shr 1).toUShort()) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!) + statusCarry = (value and 1)!=0 + registers.setSL(i.reg1!!, value shr 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2156,6 +2359,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 1)!=0 memory.setUW(address, (value shr 1).toUShort()) } + IRDataType.LONG -> { + val value = memory.getSL(address) + statusCarry = (value and 1)!=0 + memory.setSL(address, value shr 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2170,6 +2378,9 @@ class VirtualMachine(irProgram: IRProgram) { IRDataType.WORD -> { registers.setUW(i.reg1!!, (left shl right.toInt()).toUShort()) } + IRDataType.LONG -> { + registers.setSL(i.reg1!!, (left shl right.toInt()).toInt()) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2187,6 +2398,10 @@ class VirtualMachine(irProgram: IRProgram) { val memvalue = memory.getUW(address).toInt() memory.setUW(address, (memvalue shl operand).toUShort()) } + IRDataType.LONG -> { + val memvalue = memory.getSL(address) + memory.setSL(address, memvalue shl operand) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2204,6 +2419,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 0x8000)!=0 registers.setUW(i.reg1!!, (value shl 1).toUShort()) } + IRDataType.LONG -> { + val value = registers.getSL(i.reg1!!) + statusCarry = value<0 + registers.setSL(i.reg1!!, value shl 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2222,6 +2442,11 @@ class VirtualMachine(irProgram: IRProgram) { statusCarry = (value and 0x8000)!=0 memory.setUW(address, (value shl 1).toUShort()) } + IRDataType.LONG -> { + val value = memory.getSL(address) + statusCarry = value<0 + memory.setSL(address, value shl 1) + } IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2250,6 +2475,16 @@ class VirtualMachine(irProgram: IRProgram) { orig.rotateRight(1) registers.setUW(i.reg1!!, rotated) } + IRDataType.LONG -> { + val orig = registers.getSL(i.reg1!!).toUInt() + newStatusCarry = (orig and 1u) != 0u + val rotated: UInt = if (useCarry) { + val carry = if (statusCarry) 0x80000000u else 0u + (orig.rotateRight(1) or carry) + } else + orig.rotateRight(1) + registers.setSL(i.reg1!!, rotated.toInt()) + } IRDataType.FLOAT -> { throw IllegalArgumentException("can't ROR a float") } @@ -2282,6 +2517,16 @@ class VirtualMachine(irProgram: IRProgram) { orig.rotateRight(1) memory.setUW(address, rotated) } + IRDataType.LONG -> { + val orig = memory.getSL(address).toUInt() + newStatusCarry = (orig and 1u) != 0u + val rotated: UInt = (if (useCarry) { + val carry = if (statusCarry) 0x80000000u else 0u + (orig.rotateRight(1) or carry) + } else + orig.rotateRight(1)) + memory.setSL(address, rotated.toInt()) + } IRDataType.FLOAT -> { throw IllegalArgumentException("can't ROR a float") } @@ -2313,6 +2558,16 @@ class VirtualMachine(irProgram: IRProgram) { orig.rotateLeft(1) registers.setUW(i.reg1!!, rotated) } + IRDataType.LONG -> { + val orig = registers.getSL(i.reg1!!).toUInt() + newStatusCarry = (orig and 0x80000000u) != 0u + val rotated: UInt = (if (useCarry) { + val carry = if (statusCarry) 1u else 0u + (orig.toUInt().rotateLeft(1) or carry) + } else + orig.rotateLeft(1)) + registers.setSL(i.reg1!!, rotated.toInt()) + } IRDataType.FLOAT -> { throw IllegalArgumentException("can't ROL a float") } @@ -2345,6 +2600,16 @@ class VirtualMachine(irProgram: IRProgram) { orig.rotateLeft(1) memory.setUW(address, rotated) } + IRDataType.LONG -> { + val orig = memory.getSL(address).toUInt() + newStatusCarry = (orig and 0x80000000u) != 0u + val rotated: UInt = (if (useCarry) { + val carry = if (statusCarry) 1u else 0u + (orig.rotateLeft(1) or carry) + } else + orig.rotateLeft(1)) + memory.setSL(address, rotated.toInt()) + } IRDataType.FLOAT -> { throw IllegalArgumentException("can't ROL a float") } @@ -2360,7 +2625,11 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUB(i.reg1!!, value.toUByte()) statusbitsNZ(value.toInt(), i.type!!) } - IRDataType.WORD -> throw IllegalArgumentException("lsig.w not yet supported, requires 32-bits registers") + IRDataType.WORD -> { + val value = registers.getSL(i.reg2!!) + registers.setUW(i.reg1!!, value.toUShort()) + } + IRDataType.LONG -> throw IllegalArgumentException("lsig.l makes no sense, 32 bits is already the widest") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2374,7 +2643,12 @@ class VirtualMachine(irProgram: IRProgram) { statusbitsNZ(newValue, i.type!!) registers.setUB(i.reg1!!, newValue.toUByte()) } - IRDataType.WORD -> throw IllegalArgumentException("msig.w not yet supported, requires 32-bits registers") + IRDataType.WORD -> { + val value = registers.getSL(i.reg2!!) + val newValue = value ushr 16 + registers.setUW(i.reg1!!, newValue.toUShort()) + } + IRDataType.LONG -> throw IllegalArgumentException("lsig.l makes no sense, 32 bits is already the widest") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2389,7 +2663,12 @@ class VirtualMachine(irProgram: IRProgram) { registers.setUW(i.reg1!!, value.toUShort()) statusbitsNZ(value.toInt(), i.type!!) } - IRDataType.WORD -> throw IllegalArgumentException("concat.w not yet supported, requires 32-bits registers") + IRDataType.WORD -> { + val msw = registers.getUW(i.reg2!!) + val lsw = registers.getUW(i.reg3!!) + registers.setSL(i.reg1!!, ((msw.toInt() shl 16) or lsw.toInt())) + } + IRDataType.LONG -> throw IllegalArgumentException("concat.l makes no sense, 32 bits is already the widest") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -2586,6 +2865,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt()) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), registers.getSL(i.reg2!!)) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2597,6 +2877,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!) IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), i.immediate!!) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), i.immediate!!) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2608,6 +2889,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt()) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!).toUInt(), registers.getSL(i.reg2!!).toUInt()) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2619,6 +2901,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt()) IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt()) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!).toUInt(), i.immediate!!.toUInt()) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2630,6 +2913,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt()) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!).toUInt(), registers.getSL(i.reg2!!).toUInt()) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2641,6 +2925,7 @@ class VirtualMachine(irProgram: IRProgram) { return when(i.type) { IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt()) + IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), registers.getSL(i.reg2!!)) IRDataType.FLOAT -> { throw IllegalArgumentException("can't use float here") } @@ -2648,6 +2933,43 @@ class VirtualMachine(irProgram: IRProgram) { } } + private fun plusMinusMultAnyLong(operator: String, reg1: Int, reg2: Int) { + TODO("Not yet implemented") + } + + private fun plusMinusMultConstLong(operator: String, reg1: Int, value: Int) { + TODO("Not yet implemented") + } + + private fun plusMinusMultAnyLongInplace(operator: String, reg1: Int, address: Int) { + TODO("Not yet implemented") + } + + private fun plusMinusMultAnyLongSigned(operator: String, reg1: Int, reg2: Int) { + TODO("Not yet implemented") + } + + private fun plusMinusMultConstLongSigned(operator: String, reg1: Int, value: Int) { + TODO("Not yet implemented") + } + + private fun plusMinusMultAnyLongSignedInplace(operator: String, reg1: Int, address: Int) { + TODO("Not yet implemented") + } + + private fun divModLongSigned(operator: String, reg1: Int, reg2: Int) { + TODO("Not yet implemented") + } + + private fun divModConstLongSigned(operator: String, reg1: Int, immediate: Int) { + TODO("Not yet implemented") + } + + private fun divModLongSignedInplace(operator: String, reg1: Int, address: Int) { + TODO("Not yet implemented") + } + + private var window: GraphicsWindow? = null fun gfx_enable(mode: UByte) { @@ -2754,6 +3076,14 @@ internal fun ArrayDeque.pushw(value: UShort) { add((value.toInt() ushr 8).toUByte()) } +internal fun ArrayDeque.pushl(value: Int) { + val uint = value.toUInt() + add((uint and 255u).toUByte()) + add((uint shr 8 and 255u).toUByte()) + add((uint shr 16 and 255u).toUByte()) + add((uint shr 24 and 255u).toUByte()) +} + internal fun ArrayDeque.pushf(value: Double) { // push float; lsb first, msb last var bits = value.toBits() @@ -2780,6 +3110,14 @@ internal fun ArrayDeque.popw(): UShort { return ((msb.toInt() shl 8) + lsb.toInt()).toUShort() } +internal fun ArrayDeque.popl(): Int { + val b0 = removeLast().toUInt() + val b1 = removeLast().toUInt() + val b2 = removeLast().toUInt() + val b3 = removeLast().toUInt() + return (b0 shl 24 or b1 shl 16 or b2 shl 8 or b3).toInt() +} + internal fun ArrayDeque.popf(): Double { // pop float; lsb is on bottom, msb on top val b0 = removeLast().toLong() diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index d342b76de..15151db48 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -236,6 +236,7 @@ class VmProgramLoader { dt.isSignedByte -> memory.setSB(addr, 0) dt.isUnsignedWord || dt.isPointer -> memory.setUW(addr, 0u) dt.isSignedWord -> memory.setSW(addr, 0) + dt.isLong -> memory.setSL(addr, 0) dt.isFloat -> memory.setFloat(addr, 0.0) else -> throw IRParseException("invalid dt") } @@ -248,6 +249,7 @@ class VmProgramLoader { variable.dt.isSignedByte -> memory.setSB(addr, it.toInt().toByte()) variable.dt.isUnsignedWord -> memory.setUW(addr, it.toInt().toUShort()) variable.dt.isSignedWord -> memory.setSW(addr, it.toInt().toShort()) + variable.dt.isLong -> memory.setSL(addr, it.toInt()) variable.dt.isFloat -> memory.setFloat(addr, it) else -> throw IRParseException("invalid dt") }