Compare commits

..

1 Commits

Author SHA1 Message Date
Irmen de Jong
df56be32b2 working on long variable type 2025-07-15 20:28:03 +02:00
29 changed files with 176 additions and 440 deletions

View File

@@ -19,7 +19,7 @@ class StatementOptimizer(private val program: Program,
val functionName = functionCallStatement.target.nameInSource[0] val functionName = functionCallStatement.target.nameInSource[0]
if (functionName in functions.purefunctionNames) { if (functionName in functions.purefunctionNames) {
if("ignore_unused" !in parent.definingBlock.options()) if("ignore_unused" !in parent.definingBlock.options())
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position) errors.info("statement has no effect (function return value is discarded)", functionCallStatement.position)
return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer)) return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer))
} }
} }

View File

@@ -376,7 +376,7 @@ hline_filled_right .byte 0, %10000000, %11000000, %11100000, %11110000, %1111
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1 _ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
; note: this can be even faster if we also have a 320 word x-lookup table, but hey, that's a lot of memory. ; note: this can be even faster if we also have a 320 word x-lookup table, but hey, that's a lot of memory.
; see https://codebase64.net/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics ; see http://codebase64.org/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
; the y lookup tables encodes this formula: BITMAP_ADDRESS + 320*(py>>3) + (py & 7) (y from 0..199) ; the y lookup tables encodes this formula: BITMAP_ADDRESS + 320*(py>>3) + (py & 7) (y from 0..199)
; We use the 64tass syntax for range expressions to calculate this table on assembly time. ; We use the 64tass syntax for range expressions to calculate this table on assembly time.

View File

@@ -3,7 +3,7 @@
; ;
; some more interesting routines can be found here: ; some more interesting routines can be found here:
; http://6502org.wikidot.com/software-math ; http://6502org.wikidot.com/software-math
; https://codebase64.net/doku.php?id=base:6502_6510_maths ; http://codebase64.org/doku.php?id=base:6502_6510_maths
; https://github.com/TobyLobster/multiply_test ; https://github.com/TobyLobster/multiply_test
; https://github.com/TobyLobster/sqrt_test ; https://github.com/TobyLobster/sqrt_test
@@ -353,7 +353,7 @@ _divisor .word ?
randword .proc randword .proc
; -- 16 bit pseudo random number generator into AY ; -- 16 bit pseudo random number generator into AY
; default seed = $00c2 $1137. NOTE: uses self-modifying code so won't work in ROM (use randword_rom instead) ; default seed = $00c2 $1137. NOTE: uses self-modifying code so won't work in ROM (use randword_rom instead)
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit ; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
inc x1 inc x1
clc clc
x1=*+1 x1=*+1
@@ -377,7 +377,7 @@ b1=*+1
randword_rom .proc randword_rom .proc
; -- 16 bit pseudo random number generator into AY. Can run from ROM. ; -- 16 bit pseudo random number generator into AY. Can run from ROM.
; NOTE: you have to set the initial seed using randseed_rom! (a good default seed = $00c2 $1137) ; NOTE: you have to set the initial seed using randseed_rom! (a good default seed = $00c2 $1137)
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit ; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
inc _x1 inc _x1
clc clc
lda _x1 lda _x1

View File

@@ -380,7 +380,7 @@ _quadrant_region_to_direction:
asmsub atan2(ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A { asmsub atan2(ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A {
;; Calculate the angle, in a 256-degree circle, between two points into A. ;; Calculate the angle, in a 256-degree circle, between two points into A.
;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane! ;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane!
;; http://codebase64.net/doku.php?id=base:8bit_atan2_8-bit_angle ;; https://www.codebase64.org/doku.php?id=base:8bit_atan2_8-bit_angle
;; This uses 2 large lookup tables so uses a lot of memory but is super fast. ;; This uses 2 large lookup tables so uses a lot of memory but is super fast.
%asm {{ %asm {{

View File

@@ -82,7 +82,6 @@ internal class AstChecker(private val program: Program,
} }
} }
checkLongType(identifier)
val stmt = identifier.targetStatement(program.builtinFunctions) val stmt = identifier.targetStatement(program.builtinFunctions)
if(stmt==null) { if(stmt==null) {
if(identifier.parent is ArrayIndexedExpression) { if(identifier.parent is ArrayIndexedExpression) {
@@ -172,7 +171,9 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(ifElse: IfElse) { override fun visit(ifElse: IfElse) {
checkCondition(ifElse.condition) if(!ifElse.condition.inferType(program).isBool) {
errors.err("condition should be a boolean", ifElse.condition.position)
}
val constvalue = ifElse.condition.constValue(program) val constvalue = ifElse.condition.constValue(program)
if(constvalue!=null) { if(constvalue!=null) {
@@ -360,10 +361,6 @@ internal class AstChecker(private val program: Program,
super.visit(label) super.visit(label)
} }
override fun visit(numLiteral: NumericLiteral) {
checkLongType(numLiteral)
}
private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean { private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean {
class Searcher: IAstVisitor class Searcher: IAstVisitor
{ {
@@ -615,12 +612,18 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(untilLoop: UntilLoop) { override fun visit(untilLoop: UntilLoop) {
checkCondition(untilLoop.condition) if(!untilLoop.condition.inferType(program).isBool) {
errors.err("condition should be a boolean", untilLoop.condition.position)
}
super.visit(untilLoop) super.visit(untilLoop)
} }
override fun visit(whileLoop: WhileLoop) { override fun visit(whileLoop: WhileLoop) {
checkCondition(whileLoop.condition) if(!whileLoop.condition.inferType(program).isBool) {
errors.err("condition should be a boolean", whileLoop.condition.position)
}
super.visit(whileLoop) super.visit(whileLoop)
} }
@@ -799,7 +802,6 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(addressOf: AddressOf) { override fun visit(addressOf: AddressOf) {
checkLongType(addressOf)
val variable=addressOf.identifier?.targetVarDecl() val variable=addressOf.identifier?.targetVarDecl()
if (variable!=null) { if (variable!=null) {
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
@@ -815,7 +817,9 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(ifExpr: IfExpression) { override fun visit(ifExpr: IfExpression) {
checkCondition(ifExpr.condition) if(!ifExpr.condition.inferType(program).isBool)
errors.err("condition should be a boolean", ifExpr.condition.position)
val trueDt = ifExpr.truevalue.inferType(program) val trueDt = ifExpr.truevalue.inferType(program)
val falseDt = ifExpr.falsevalue.inferType(program) val falseDt = ifExpr.falsevalue.inferType(program)
if(trueDt.isUnknown || falseDt.isUnknown) { if(trueDt.isUnknown || falseDt.isUnknown) {
@@ -826,23 +830,10 @@ internal class AstChecker(private val program: Program,
super.visit(ifExpr) super.visit(ifExpr)
} }
private fun checkCondition(condition: Expression) {
if(!condition.inferType(program).isBool)
errors.err("condition should be a boolean", condition.position)
val cast = condition as? TypecastExpression
if(cast!=null && cast.type.isBool) {
if(cast.expression.inferType(program).isPointer) {
errors.err("condition should be a boolean", condition.position)
}
}
}
override fun visit(decl: VarDecl) { override fun visit(decl: VarDecl) {
if(decl.names.size>1) if(decl.names.size>1)
throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls") 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.type==VarDeclType.MEMORY) {
if (decl.datatype.isString) if (decl.datatype.isString)
errors.err("strings cannot be memory-mapped", decl.position) errors.err("strings cannot be memory-mapped", decl.position)
@@ -1284,7 +1275,6 @@ internal class AstChecker(private val program: Program,
} }
} }
checkLongType(expr)
val dt = expr.expression.inferType(program).getOrUndef() val dt = expr.expression.inferType(program).getOrUndef()
if(!dt.isUndefined) { if(!dt.isUndefined) {
@@ -1419,8 +1409,6 @@ internal class AstChecker(private val program: Program,
return return
} }
checkLongType(expr)
val leftIDt = expr.left.inferType(program) val leftIDt = expr.left.inferType(program)
val rightIDt = expr.right.inferType(program) val rightIDt = expr.right.inferType(program)
if(!leftIDt.isKnown || !rightIDt.isKnown) { if(!leftIDt.isKnown || !rightIDt.isKnown) {
@@ -1548,7 +1536,6 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(typecast: TypecastExpression) { override fun visit(typecast: TypecastExpression) {
checkLongType(typecast)
if(typecast.type.isPassByRef) if(typecast.type.isPassByRef)
errors.err("cannot type cast to string or array type", typecast.position) errors.err("cannot type cast to string or array type", typecast.position)
@@ -1605,7 +1592,6 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(functionCallExpr: FunctionCallExpression) { override fun visit(functionCallExpr: FunctionCallExpression) {
checkLongType(functionCallExpr)
// this function call is (part of) an expression, which should be in a statement somewhere. // this function call is (part of) an expression, which should be in a statement somewhere.
val stmtOfExpression = findParentNode<Statement>(functionCallExpr) val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}") ?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
@@ -1666,17 +1652,6 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(functionCallStatement: FunctionCallStatement) { override fun visit(functionCallStatement: FunctionCallStatement) {
if(functionCallStatement.target.nameInSource.size==1) {
val functionName = functionCallStatement.target.nameInSource[0]
if (functionName in program.builtinFunctions.purefunctionNames) {
if("ignore_unused" !in functionCallStatement.parent.definingBlock.options()) {
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
return
}
}
}
// most function calls, even to builtin functions, are still regular FunctionCall nodes here. // most function calls, even to builtin functions, are still regular FunctionCall nodes here.
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner // they get converted to the more specialized node type in BeforeAsmTypecastCleaner
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors) val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)
@@ -1869,7 +1844,6 @@ internal class AstChecker(private val program: Program,
} }
args.forEach{ args.forEach{
checkLongType(it)
if(it.inferType(program).isStructInstance) if(it.inferType(program).isStructInstance)
errors.err("structs can only be passed via a pointer", it.position) errors.err("structs can only be passed via a pointer", it.position)
} }
@@ -1882,7 +1856,6 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
checkLongType(arrayIndexedExpression)
val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions) val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions)
if(target is VarDecl) { if(target is VarDecl) {
if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer) if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer)
@@ -2104,17 +2077,6 @@ internal class AstChecker(private val program: Program,
errors.err("unable to determine type of dereferenced pointer expression", deref.position) errors.err("unable to determine type of dereferenced pointer expression", deref.position)
} }
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 { private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean {
return if (targetDt.isString) { return if (targetDt.isString) {
when { when {

View File

@@ -109,11 +109,6 @@ _loop:
if not CONDITION if not CONDITION
goto _loop goto _loop
*/ */
val error = checkCondition(untilLoop.condition)
if(error!=null) {
errors.err(error, untilLoop.condition.position)
return noModifications
}
val pos = untilLoop.position val pos = untilLoop.position
val loopLabel = program.makeLabel("untilloop", pos) val loopLabel = program.makeLabel("untilloop", pos)
val replacement = AnonymousScope(mutableListOf( val replacement = AnonymousScope(mutableListOf(
@@ -127,27 +122,6 @@ if not CONDITION
return listOf(IAstModification.ReplaceNode(untilLoop, replacement, parent)) return listOf(IAstModification.ReplaceNode(untilLoop, replacement, parent))
} }
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
val dt = expr.expression.inferType(program).getOrUndef()
if(dt.isPointerArray || dt.isPointer) {
errors.err("pointers don't support prefix operators", expr.position)
}
return noModifications
}
private fun checkCondition(condition: Expression): String? {
if(!condition.inferType(program).isBool)
return "condition should be a boolean"
val cast = condition as? TypecastExpression
if(cast!=null && cast.type.isBool) {
if(cast.expression.inferType(program).isPointer) {
return "condition should be a boolean"
}
}
return null
}
override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> { override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> {
/* /*
@@ -155,12 +129,6 @@ if not CONDITION
while false -> discard while false -> discard
*/ */
val error = checkCondition(whileLoop.condition)
if(error!=null) {
errors.err(error, whileLoop.condition.position)
return noModifications
}
val constCondition = whileLoop.condition.constValue(program)?.asBooleanValue val constCondition = whileLoop.condition.constValue(program)?.asBooleanValue
if(constCondition==true) { if(constCondition==true) {
errors.warn("condition is always true", whileLoop.condition.position) errors.warn("condition is always true", whileLoop.condition.position)
@@ -763,18 +731,4 @@ _after:
return noModifications return noModifications
} }
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
val error = checkCondition(ifElse.condition)
if(error!=null)
errors.err(error, ifElse.condition.position)
return noModifications
}
override fun after(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> {
val error = checkCondition(ifExpr.condition)
if(error!=null)
errors.err(error, ifExpr.condition.position)
return noModifications
}
} }

View File

@@ -198,7 +198,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
is PtNumber, is PtNumber,
is PtRange, is PtRange,
is PtString -> true is PtString -> true
is PtIdentifier -> true // actually PtIdentifier IS "complex" this time (it's a variable that might change) but it's kinda annoying to give a warning message for this very common case // note that unlike most other times, PtIdentifier IS "complex" this time (it's a variable that might change)
else -> false else -> false
} }

View File

@@ -501,19 +501,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val trueDt = ifExpr.truevalue.inferType(program) val trueDt = ifExpr.truevalue.inferType(program)
val falseDt = ifExpr.falsevalue.inferType(program) val falseDt = ifExpr.falsevalue.inferType(program)
if (trueDt != falseDt) { if (trueDt != falseDt) {
val modifications = mutableListOf<IAstModification>()
// ubyte or uword combined with a pointer type -> cast BOTH to uword
if((trueDt.isPointer && falseDt.isInteger) || (falseDt.isPointer && trueDt.isInteger)) {
val leftCast = TypecastExpression(ifExpr.truevalue, DataType.UWORD, true, ifExpr.truevalue.position)
val rightCast = TypecastExpression(ifExpr.falsevalue, DataType.UWORD, true, ifExpr.falsevalue.position)
return listOf(
IAstModification.ReplaceNode(ifExpr.truevalue, leftCast, ifExpr),
IAstModification.ReplaceNode(ifExpr.falsevalue, rightCast, ifExpr)
)
}
val (commonDt, toFix) = BinaryExpression.commonDatatype( val (commonDt, toFix) = BinaryExpression.commonDatatype(
trueDt.getOrUndef(), trueDt.getOrUndef(),
falseDt.getOrUndef(), falseDt.getOrUndef(),
@@ -521,11 +508,11 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
ifExpr.falsevalue ifExpr.falsevalue
) )
if (toFix != null) { if (toFix != null) {
val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, toFix, commonDt, ifExpr) addTypecastOrCastedValueModification(modifications, toFix, commonDt, ifExpr)
return modifications return modifications
} }
} }
return noModifications return noModifications
} }

View File

@@ -178,6 +178,11 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
return listOf(IAstModification.ReplaceNode(typecast, cmp, parent)) return listOf(IAstModification.ReplaceNode(typecast, cmp, parent))
} }
} }
else if (et.isPointer) {
val ptrAsUword = TypecastExpression(typecast.expression, DataType.UWORD, true, typecast.position)
val cmp = BinaryExpression(ptrAsUword, "!=", NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, 0.0, typecast.position), typecast.position)
return listOf(IAstModification.ReplaceNode(typecast, cmp, parent))
}
} }
return noModifications return noModifications

View File

@@ -5,7 +5,6 @@ import io.kotest.engine.spec.tempdir
import io.kotest.inspectors.shouldForAll import io.kotest.inspectors.shouldForAll
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.FunctionCallStatement
@@ -14,7 +13,6 @@ import prog8.code.core.BuiltinFunctions
import prog8.code.core.RegisterOrPair import prog8.code.core.RegisterOrPair
import prog8.code.core.isNumeric import prog8.code.core.isNumeric
import prog8.code.target.Cx16Target import prog8.code.target.Cx16Target
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText import prog8tests.helpers.compileText
class TestBuiltinFunctions: FunSpec({ class TestBuiltinFunctions: FunSpec({
@@ -105,31 +103,5 @@ main {
compileText(Cx16Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null compileText(Cx16Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
} }
test("warning for return value discarding of pure functions") {
val src="""
main {
sub start() {
word @shared ww = 2222
abs(ww)
sgn(ww)
sqrt(ww)
min(ww, 0)
max(ww, 0)
clamp(ww, 0, 319)
}
}"""
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
compileText(Cx16Target(), true, src, outputDir, errors=errors, writeAssembly = false) shouldNotBe null
errors.warnings.size shouldBe 6
errors.warnings[0] shouldContain "statement has no effect"
errors.warnings[1] shouldContain "statement has no effect"
errors.warnings[2] shouldContain "statement has no effect"
errors.warnings[3] shouldContain "statement has no effect"
errors.warnings[4] shouldContain "statement has no effect"
errors.warnings[5] shouldContain "statement has no effect"
}
}) })

View File

@@ -240,13 +240,11 @@ class TestCompilerOnExamplesVirtual: FunSpec({
listOf( listOf(
"bouncegfx", "bouncegfx",
"bsieve", "bsieve",
"fountain",
"pixelshader", "pixelshader",
"sincos", "sincos",
"pointers/animalgame", "pointers/animalgame",
"pointers/binarytree", // TODO add to "c64" later as well "pointers/binarytree", // TODO add to "c64" later as well
"pointers/sortedlist", // TODO add to "c64" later as well "pointers/sortedlist" // TODO add to "c64" later as well
"pointers/fountain" // TODO add to "c64" later as well
), ),
listOf(false, true) listOf(false, true)
) )

View File

@@ -1412,57 +1412,4 @@ main {
compileText(VMTarget(), false, src, outputDir) shouldNotBe null compileText(VMTarget(), false, src, outputDir) shouldNotBe null
} }
test("pointer cannot be used in conditional expression in shorthand form") {
val src="""
main {
sub start() {
^^word ptr
if ptr cx16.r0++
if not ptr cx16.r1++
while ptr cx16.r0++
while not ptr cx16.r1++
do cx16.r0++ until ptr
do cx16.r1++ until not ptr
cx16.r0 = if ptr 1 else 0
cx16.r1 = if not ptr 1 else 0
}
}"""
val errors=ErrorReporterForTests()
compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null
errors.errors.size shouldBe 8
errors.errors[0] shouldContain "condition should be a boolean"
errors.errors[1] shouldContain "pointers don't support prefix operators"
errors.errors[2] shouldContain "condition should be a boolean"
errors.errors[3] shouldContain "pointers don't support prefix operators"
errors.errors[4] shouldContain "condition should be a boolean"
errors.errors[5] shouldContain "pointers don't support prefix operators"
errors.errors[6] shouldContain "condition should be a boolean"
errors.errors[7] shouldContain "pointers don't support prefix operators"
}
test("pointers in if expressions") {
val src="""
main {
sub start() {
^^word ptr
if ptr!=0
cx16.r0++
if ptr==0
cx16.r0++
cx16.r0 = if ptr!=0 0 else ptr
cx16.r1 = if ptr==0 0 else ptr
cx16.r2 = if ptr!=0 ptr else 0
cx16.r3 = if ptr==0 ptr else 0
}
}"""
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
}
}) })

View File

@@ -27,7 +27,7 @@ of these library modules automatically as required.
.. note:: .. note::
Several algorithms and math routines in Prog8's assembly library files are adapted from Several algorithms and math routines in Prog8's assembly library files are adapted from
code publicly available on https://www.codebase64.net/ code publicly available on https://www.codebase64.org/
.. _builtinfunctions: .. _builtinfunctions:

View File

@@ -65,11 +65,6 @@ Various things:
and it does it at run time. In this demo a jump table is not only created in the library, and it does it at run time. In this demo a jump table is not only created in the library,
but also in the main program and copied into the library for its use. but also in the main program and copied into the library for its use.
`Additional custom compilation targets (such as VIC-20) <https://github.com/gillham/prog8targets>`_
Various custom targets for Prog8 that are not (yet?) part of the Prog8 examples themselves.
These additional compilation targets may be in varying state of completeness.
Perhaps most recognisable at the time of adding this link, are the various VIC-20 targets.
.. image:: _static/curious.png .. image:: _static/curious.png
:align: center :align: center

View File

@@ -46,6 +46,9 @@ Pointers of different types cannot be assigned to one another, unless you use an
Typed pointers and an 'untyped' uword pointer/value can be assigned to each other without an explicit cast. Typed pointers and an 'untyped' uword pointer/value can be assigned to each other without an explicit cast.
Because it is pretty common to check if a pointer value is zero or not (because zero usually means that the pointer doesn't exist/has no value),
pointers can be implicitly cast to a boolean. This allows you to easily write conditionals such as ``while ptr { ... }``
Dereferencing a pointer, pointer arithmetic Dereferencing a pointer, pointer arithmetic
------------------------------------------- -------------------------------------------

View File

@@ -1,6 +1,7 @@
TODO TODO
==== ====
STRUCTS and TYPED POINTERS STRUCTS and TYPED POINTERS
-------------------------- --------------------------
@@ -22,6 +23,7 @@ STRUCTS and TYPED POINTERS
- DONE: you should be able to get the address of an individual field: ``&structpointer.field`` - DONE: you should be able to get the address of an individual field: ``&structpointer.field``
- DONE: teach sizeof() how to calculate struct sizes (need unit test + doc) - DONE: teach sizeof() how to calculate struct sizes (need unit test + doc)
- DONE: sizeof(ptr^^) works - DONE: sizeof(ptr^^) works
- DONE: implicit cast of pointer to bool, also in loop conditions (while ptr {...})
- DONE: implicit cast of pointer to uword in conditional expressions - DONE: implicit cast of pointer to uword in conditional expressions
- DONE: subroutine parameters and return values should be able to accept pointers as well now - DONE: subroutine parameters and return values should be able to accept pointers as well now
- DONE (for basic types only): allow array syntax on pointers too: ptr[2] means ptr+sizeof()*2, ptr[0] just means ptr^^ . - DONE (for basic types only): allow array syntax on pointers too: ptr[2] means ptr+sizeof()*2, ptr[0] just means ptr^^ .
@@ -61,7 +63,7 @@ STRUCTS and TYPED POINTERS
- DONE: fixed support for (expression) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with peek() - DONE: fixed support for (expression) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with peek()
- DONE: fixed support for (assigntarget) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with poke() - DONE: fixed support for (assigntarget) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with poke()
- write docs in structpointers.rst - write docs in structpointers.rst
- scan through virtual library modules to change untyped uword pointers to typed pointers: compression, conv, diskio, math, sorting, strings, syslib, textio. - scan through virtual library modules to change untyped uword pointers to typed pointers
- add support for array index dereferencing as assign target "array[2]^^.value = 99" where array is struct pointers (currently a 'no support' error) - add support for array index dereferencing as assign target "array[2]^^.value = 99" where array is struct pointers (currently a 'no support' error)
- add support for array index dereferencing as assign target "array[2].value = 99" where array is struct pointers (currently a parser error) - add support for array index dereferencing as assign target "array[2].value = 99" where array is struct pointers (currently a parser error)
- try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly) - try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly)
@@ -144,14 +146,6 @@ Libraries
Optimizations Optimizations
------------- -------------
- if expression generates more instructions than old style if else (IR):
pp.next = if particles!=0 particles else 0
versus:
if particles!=0
pp.next = particles
else
pp.next = 0
- in Identifier: use typedarray of strings instead of listOf? Other places? - in Identifier: use typedarray of strings instead of listOf? Other places?
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time - Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples) - Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)

View File

@@ -69,6 +69,7 @@ main {
sub learn_new_animal() { sub learn_new_animal() {
str new_animal = "?" * 30 str new_animal = "?" * 30
str answer = "?" * 10
; note that we make copies of the animal name and question strings to store them later ; note that we make copies of the animal name and question strings to store them later
txt.print("\nI give up. What is the animal? ") txt.print("\nI give up. What is the animal? ")

View File

@@ -68,14 +68,14 @@ btree {
^^Node parent = root ^^Node parent = root
repeat { repeat {
if parent.value >= value { if parent.value >= value {
if parent.left!=0 if parent.left
parent = parent.left parent = parent.left
else { else {
parent.left = node parent.left = node
return return
} }
} else { } else {
if parent.right!=0 if parent.right
parent = parent.right parent = parent.right
else { else {
parent.right = node parent.right = node
@@ -88,7 +88,7 @@ btree {
sub contains(uword value) -> bool { sub contains(uword value) -> bool {
^^Node r = root ^^Node r = root
while r!=0 { while r {
if r.value==value if r.value==value
return true return true
if r.value>value if r.value>value
@@ -102,19 +102,19 @@ btree {
sub size() -> ubyte { sub size() -> ubyte {
ubyte count ubyte count
if root!=0 if root
count_node(root) count_node(root)
return count return count
sub count_node(^^Node r) { sub count_node(^^Node r) {
count++ count++
if r.left!=0 { if r.left {
sys.pushw(r) sys.pushw(r)
count_node(r.left) count_node(r.left)
r = sys.popw() r = sys.popw()
} }
if r.right!=0 { if r.right {
sys.pushw(r) sys.pushw(r)
count_node(r.right) count_node(r.right)
r = sys.popw() r = sys.popw()
@@ -126,7 +126,7 @@ btree {
; note: we don't deallocate the memory from the node, for simplicity sake ; note: we don't deallocate the memory from the node, for simplicity sake
^^Node n = root ^^Node n = root
^^Node parent = 0 ^^Node parent = 0
while n!=0 { while n {
if n.value==value { if n.value==value {
if n.left==0 if n.left==0
replacechild(parent, n, n.right) replacechild(parent, n, n.right)
@@ -154,7 +154,7 @@ btree {
sub find_successor(^^Node p) -> ^^Node { sub find_successor(^^Node p) -> ^^Node {
^^Node succ = p ^^Node succ = p
p = p.right p = p.right
while p!=0 { while p {
succ = p succ = p
p = p.left p = p.left
} }
@@ -171,19 +171,19 @@ btree {
sub print_tree_inorder() { sub print_tree_inorder() {
if root!=0 if root
print_tree(root) print_tree(root)
txt.nl() txt.nl()
sub print_tree(^^Node r) { sub print_tree(^^Node r) {
if r.left!=0 { if r.left {
sys.pushw(r) sys.pushw(r)
print_tree(r.left) print_tree(r.left)
r = sys.popw() r = sys.popw()
} }
txt.print_uw(r.value) txt.print_uw(r.value)
txt.print(", ") txt.print(", ")
if r.right!=0 { if r.right {
sys.pushw(r) sys.pushw(r)
print_tree(r.right) print_tree(r.right)
r = sys.popw() r = sys.popw()
@@ -193,7 +193,7 @@ btree {
sub print_tree_preorder() { sub print_tree_preorder() {
if root!=0 if root
print_tree(root,0) print_tree(root,0)
txt.nl() txt.nl()
@@ -201,14 +201,14 @@ btree {
repeat depth txt.print(" ") repeat depth txt.print(" ")
txt.print_uw(r.value) txt.print_uw(r.value)
txt.nl() txt.nl()
if r.left!=0 { if r.left {
sys.pushw(r) sys.pushw(r)
sys.push(depth) sys.push(depth)
print_tree(r.left, depth+1) print_tree(r.left, depth+1)
depth = sys.pop() depth = sys.pop()
r = sys.popw() r = sys.popw()
} }
if r.right!=0 { if r.right {
sys.pushw(r) sys.pushw(r)
sys.push(depth) sys.push(depth)
print_tree(r.right, depth+1) print_tree(r.right, depth+1)

View File

@@ -1,94 +0,0 @@
; Particle fountain.
; This is NOT necessarily the most efficient or idiomatic Prog8 way to do this!
; But it is just an example for how you could allocate and use structs dynamically.
; It uses a linked list to store all active particles.
%import math
main {
struct Particle {
word x,y
byte speedx, speedy
ubyte brightness
^^Particle next
}
const uword MAX_PARTICLES = 450
const ubyte GRAVITY = 1
^^Particle particles ; linked list of all active particles
uword active_particles = 0
sub start() {
repeat 4
spawnrandom()
sys.gfx_enable(0) ; enable lo res screen
repeat {
sys.gfx_clear(0)
update_particles()
sys.wait(2)
sys.waitvsync()
}
}
sub spawnrandom() {
if active_particles < MAX_PARTICLES {
^^Particle pp = arena.alloc(sizeof(Particle))
pp.next = if particles!=0 particles else 0
particles = pp
initparticle(pp)
active_particles++
}
}
sub initparticle(^^Particle pp) {
pp.x = 160
pp.y = 238
pp.speedx = math.rnd() % 10 as byte -5
if pp.speedx==0
pp.speedx=1
pp.speedy = -10 - math.rnd() % 12
pp.brightness = 255
}
sub update_particles() {
^^Particle pp = particles
while pp!=0 {
pp.speedy += GRAVITY
pp.x += pp.speedx
pp.y += pp.speedy
if pp.y >= 239 {
; reuse the particle that went off the screen and spawn another one (if allowed)
initparticle(pp)
spawnrandom()
} else {
pp.x = clamp(pp.x, 0, 319)
}
sys.gfx_plot(pp.x as uword, pp.y as uword, pp.brightness)
if pp.brightness>=7
pp.brightness -= 7
pp = pp.next
}
}
}
arena {
; extremely trivial arena allocator (that never frees)
uword buffer = memory("arena", 4000, 0)
uword next = buffer
sub alloc(ubyte size) -> uword {
defer next += size
return next
}
}

View File

@@ -28,7 +28,7 @@ main {
sub printlist() { sub printlist() {
ubyte count = 0 ubyte count = 0
^^slist.Node n = slist.head ^^slist.Node n = slist.head
while n!=0 { while n {
txt.print_uw(n.size) txt.print_uw(n.size)
txt.chrout(':') txt.chrout(':')
txt.chrout(n.letter) txt.chrout(n.letter)
@@ -60,10 +60,10 @@ slist {
uword size = node.size uword size = node.size
^^Node predecessor = 0 ^^Node predecessor = 0
^^Node current = head ^^Node current = head
while current!=0 { while current {
if current.size >= size { if current.size >= size {
node.next = current node.next = current
if predecessor!=0 if predecessor
break break
else { else {
head = node head = node

View File

@@ -1,19 +1,8 @@
%option no_sysinit
%zeropage basicsafe %zeropage basicsafe
%import textio
main { main {
sub start() { sub start() {
^^word ptr long @shared num = 123456789
if ptr!=0
cx16.r0++
if ptr==0
cx16.r0++
cx16.r0 = if ptr!=0 0 else ptr
cx16.r1 = if ptr==0 0 else ptr
cx16.r2 = if ptr!=0 ptr else 0
cx16.r3 = if ptr==0 ptr else 0
} }
} }

View File

@@ -4,16 +4,14 @@
main { main {
const ubyte MAX_PARTICLES = 128
sub start() { sub start() {
word[MAX_PARTICLES] particleX word[128] particleX
word[MAX_PARTICLES] particleY word[128] particleY
byte[MAX_PARTICLES] particleDX byte[128] particleDX
byte[MAX_PARTICLES] particleDY byte[128] particleDY
ubyte pi ubyte pi
for pi in 0 to MAX_PARTICLES-1 { for pi in 0 to 127 {
particleX[pi] = math.rndw() % 319 as word particleX[pi] = math.rndw() % 319 as word
particleY[pi] = math.rndw() % 240 as word particleY[pi] = math.rndw() % 240 as word
particleDX[pi] = (math.rnd() & 1)*2 as byte - 1 particleDX[pi] = (math.rnd() & 1)*2 as byte - 1
@@ -44,7 +42,7 @@ main {
} }
sub plot_particles() { sub plot_particles() {
for pi in 0 to MAX_PARTICLES-1 { for pi in 0 to 127 {
particleX[pi] += particleDX[pi] particleX[pi] += particleDX[pi]
particleY[pi] += particleDY[pi] particleY[pi] += particleDY[pi]
if particleX[pi]<0 or particleX[pi]>319 { if particleX[pi]<0 or particleX[pi]>319 {

View File

@@ -1,72 +0,0 @@
; Particle fountain.
; based on fixed array allocation of arrays of all the particle's properties.
%import math
main {
const ubyte MAX_PARTICLES = 255
const ubyte GRAVITY = 1
word[MAX_PARTICLES] particleX
word[MAX_PARTICLES] particleY
byte[MAX_PARTICLES] particleSpeedX
byte[MAX_PARTICLES] particleSpeedY
ubyte[MAX_PARTICLES] particleBrightness
ubyte active_particles = 0
sub start() {
repeat 4
spawnrandom()
sys.gfx_enable(0) ; enable lo res screen
repeat {
sys.gfx_clear(0)
update_particles()
sys.wait(2)
sys.waitvsync()
}
}
sub spawnrandom() {
if active_particles < MAX_PARTICLES {
initparticle(active_particles)
active_particles++
}
}
sub initparticle(ubyte pi) {
particleX[pi] = 160
particleY[pi] = 238
particleSpeedX[pi] = math.rnd() % 10 as byte -5
if particleSpeedX[pi]==0
particleSpeedX[pi]=1
particleSpeedY[pi] = -10 - math.rnd() % 12
particleBrightness[pi] = 255
}
sub update_particles() {
ubyte pi
for pi in 0 to active_particles-1 {
particleSpeedY[pi] += GRAVITY
particleX[pi] += particleSpeedX[pi]
particleY[pi] += particleSpeedY[pi]
if particleY[pi] >= 239 {
; reuse the particle that went off the screen and spawn another one (if allowed)
initparticle(pi)
spawnrandom()
} else {
particleX[pi] = clamp(particleX[pi], 0, 319)
}
sys.gfx_plot(particleX[pi] as uword, particleY[pi] as uword, particleBrightness[pi])
if particleBrightness[pi]>=7
particleBrightness[pi] -= 7
}
}
}

View File

@@ -23,8 +23,7 @@ Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by t
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly. Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=64 bits). Omitting it defaults to b if the instruction requires a type. Value types: integers (.b=byte=8 bits, .w=word=16 bits, .l=long=32 bits) and float (.f=64 bits). Omitting it defaults to b if the instruction requires a type.
Currently ther is NO support for 24 or 32 bits integers.
There is no distinction between signed and unsigned integers. There is no distinction between signed and unsigned integers.
Instead, a different instruction is used if a distinction should be made (for example div and divs). Instead, a different instruction is used if a distinction should be made (for example div and divs).
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions. Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
@@ -34,7 +33,7 @@ NOTE: Labels in source text should always start with an underscore.
LOAD/STORE LOAD/STORE
---------- ----------
All have type b or w or f. All have type b or w or l or f.
load reg1, value - load immediate value into register. If you supply a symbol, loads the *address* of the symbol! (variable values are loaded from memory via the loadm instruction) load reg1, value - load immediate value into register. If you supply a symbol, loads the *address* of the symbol! (variable values are loaded from memory via the loadm instruction)
loadm reg1, address - load reg1 with value at memory address loadm reg1, address - load reg1 with value at memory address
@@ -518,8 +517,8 @@ val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThat
enum class IRDataType { enum class IRDataType {
BYTE, BYTE,
WORD, WORD,
LONG,
FLOAT FLOAT
// TODO add INT (32-bit)? INT24 (24-bit)?
} }
enum class OperandDirection { enum class OperandDirection {
@@ -862,6 +861,7 @@ data class IRInstruction(
when (type) { when (type) {
IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" } IRDataType.BYTE -> 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.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 -> {} IRDataType.FLOAT, null -> {}
} }
} }
@@ -1115,6 +1115,7 @@ data class IRInstruction(
when(it.reg.dt) { when(it.reg.dt) {
IRDataType.BYTE -> result.add("${location}r${it.reg.registerNum}.b$cpuReg,") IRDataType.BYTE -> result.add("${location}r${it.reg.registerNum}.b$cpuReg,")
IRDataType.WORD -> result.add("${location}r${it.reg.registerNum}.w$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,") IRDataType.FLOAT -> result.add("${location}fr${it.reg.registerNum}.f$cpuReg,")
} }
} }
@@ -1136,12 +1137,14 @@ data class IRInstruction(
when (returnspec.dt) { when (returnspec.dt) {
IRDataType.BYTE -> "r${returnspec.registerNum}.b" IRDataType.BYTE -> "r${returnspec.registerNum}.b"
IRDataType.WORD -> "r${returnspec.registerNum}.w" IRDataType.WORD -> "r${returnspec.registerNum}.w"
IRDataType.LONG -> "r${returnspec.registerNum}.l"
IRDataType.FLOAT -> "fr${returnspec.registerNum}.f" IRDataType.FLOAT -> "fr${returnspec.registerNum}.f"
} }
} else { } else {
when (returnspec.dt) { when (returnspec.dt) {
IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg
IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg
IRDataType.LONG -> "r${returnspec.registerNum}.l@" + cpuReg
IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg
} }
} }

View File

@@ -216,6 +216,7 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535)) if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535))
throw IRParseException("immediate value out of range for word: $immediateInt") throw IRParseException("immediate value out of range for word: $immediateInt")
} }
IRDataType.LONG -> {}
IRDataType.FLOAT -> {} IRDataType.FLOAT -> {}
null -> {} null -> {}
} }
@@ -368,6 +369,7 @@ fun irType(type: DataType): IRDataType {
BaseDataType.UBYTE, BaseDataType.UBYTE,
BaseDataType.BYTE -> IRDataType.BYTE BaseDataType.BYTE -> IRDataType.BYTE
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> IRDataType.WORD BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> IRDataType.WORD
BaseDataType.LONG -> IRDataType.LONG
BaseDataType.FLOAT -> IRDataType.FLOAT BaseDataType.FLOAT -> IRDataType.FLOAT
BaseDataType.STRUCT_INSTANCE -> TODO("IR datatype for struct instances") BaseDataType.STRUCT_INSTANCE -> TODO("IR datatype for struct instances")
else -> throw AssemblyError("no IR datatype for $type") else -> throw AssemblyError("no IR datatype for $type")

View File

@@ -32,19 +32,30 @@ class Memory {
return (mem[address] + 256u*mem[address+1]).toUShort() 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 { fun getSW(address: Int): Short {
return (mem[address].toInt() + mem[address+1].toInt()*256).toShort() return (mem[address].toInt() + mem[address+1].toInt()*256).toShort()
} }
fun setUW(address: Int, value: UShort) { fun setUW(address: Int, value: UShort) {
mem[address+1] = (value.toInt() ushr 8).toUByte()
mem[address] = value.toUByte() mem[address] = value.toUByte()
mem[address+1] = (value.toInt() ushr 8).toUByte()
}
fun setSL(address: Int, value: Int) {
mem[address] = value.toUByte()
mem[address+1] = (value ushr 8).toUByte()
mem[address+2] = (value ushr 16).toUByte()
mem[address+3] = (value ushr 24).toUByte()
} }
fun setSW(address: Int, value: Short) { fun setSW(address: Int, value: Short) {
val uv = value.toUShort() val uv = value.toUShort()
mem[address+1] = (uv.toInt() ushr 8).toUByte()
mem[address] = uv.toUByte() mem[address] = uv.toUByte()
mem[address+1] = (uv.toInt() ushr 8).toUByte()
} }
fun setFloat(address: Int, value: Double) { fun setFloat(address: Int, value: Double) {

View File

@@ -6,14 +6,14 @@ package prog8.vm
* A,X and Y "physical" 6502 registers. * A,X and Y "physical" 6502 registers.
*/ */
class Registers { class Registers {
private val registers = Array<UShort>(99999) { 0u } private val registers = Array<Int>(99999) { 0 }
private val floatRegisters = Array(99999) { 0.0 } private val floatRegisters = Array(99999) { 0.0 }
var cpuA: UByte = 0u var cpuA: UByte = 0u
var cpuX: UByte = 0u var cpuX: UByte = 0u
var cpuY: UByte = 0u var cpuY: UByte = 0u
fun reset() { fun reset() {
registers.fill(0u) registers.fill(0)
floatRegisters.fill(0.0) floatRegisters.fill(0.0)
cpuA = 0u cpuA = 0u
cpuX = 0u cpuX = 0u
@@ -21,26 +21,32 @@ class Registers {
} }
fun setUB(reg: Int, value: UByte) { 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) { 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) { fun setUW(reg: Int, value: UShort) {
registers[reg] = value registers[reg] = value.toInt()
} }
fun setSW(reg: Int, value: Short) { 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 getUB(reg: Int) = registers[reg].toUByte()
fun getSB(reg: Int) = registers[reg].toByte() fun getSB(reg: Int) = registers[reg].toByte()
fun getUW(reg: Int) = registers[reg] fun getUW(reg: Int) = registers[reg].toUShort()
fun getSL(reg: Int) = registers[reg]
fun getSW(reg: Int) = registers[reg].toShort() fun getSW(reg: Int) = registers[reg].toShort()

View File

@@ -143,6 +143,7 @@ object SysCalls {
when(it.reg.dt) { when(it.reg.dt) {
IRDataType.BYTE -> vm.registers.getUB(it.reg.registerNum) IRDataType.BYTE -> vm.registers.getUB(it.reg.registerNum)
IRDataType.WORD -> vm.registers.getUW(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) IRDataType.FLOAT -> vm.registers.getFloat(it.reg.registerNum)
} }
} }
@@ -164,6 +165,7 @@ object SysCalls {
when(returns.dt) { when(returns.dt) {
IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte()) IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte())
IRDataType.WORD -> vm.registers.setUW(returns.registerNum, vv.toInt().toUShort()) 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) IRDataType.FLOAT -> vm.registers.setFloat(returns.registerNum, vv)
} }
} }

View File

@@ -360,6 +360,11 @@ class VirtualMachine(irProgram: IRProgram) {
statusZero = value==0 statusZero = value==0
statusNegative = value>=0x8000 statusNegative = 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") 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!!) val value = registers.getUW(i.reg1!!)
valueStack.pushw(value) valueStack.pushw(value)
} }
IRDataType.LONG -> {
val value = registers.getSL(i.reg1!!)
valueStack.pushl(value)
}
IRDataType.FLOAT -> { IRDataType.FLOAT -> {
val value = registers.getFloat(i.fpReg1!!) val value = registers.getFloat(i.fpReg1!!)
valueStack.pushf(value) valueStack.pushf(value)
@@ -389,6 +398,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.removeLast().toInt(), i.type!!) IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.removeLast().toInt(), i.type!!)
IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().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()) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf())
} }
nextPc() nextPc()
@@ -425,6 +435,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(value.dt!!) { when(value.dt!!) {
IRDataType.BYTE -> valueStack.add(value.value as UByte) IRDataType.BYTE -> valueStack.add(value.value as UByte)
IRDataType.WORD -> valueStack.pushw(value.value as UShort) IRDataType.WORD -> valueStack.pushw(value.value as UShort)
IRDataType.LONG -> valueStack.pushl(value.value as Int)
IRDataType.FLOAT -> valueStack.pushf(value.value as Double) IRDataType.FLOAT -> valueStack.pushf(value.value as Double)
} }
value.dt=null value.dt=null
@@ -472,6 +483,11 @@ class VirtualMachine(irProgram: IRProgram) {
registers.setUW(i.reg1!!, value) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) 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!!)) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!))
} }
nextPc() nextPc()
@@ -489,6 +505,11 @@ class VirtualMachine(irProgram: IRProgram) {
registers.setUW(i.reg1!!, value) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) 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())) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt()))
} }
nextPc() nextPc()
@@ -508,6 +529,11 @@ class VirtualMachine(irProgram: IRProgram) {
registers.setUW(i.reg1!!, value) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) statusbitsNZ(value.toInt(), i.type!!)
} }
IRDataType.LONG -> {
val value = memory.getSL(registers.getUW(i.reg2!!).toInt() + offset)
registers.setSL(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!)
}
IRDataType.FLOAT -> { IRDataType.FLOAT -> {
registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt() + offset)) 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) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) 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())) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUB(i.reg1!!).toInt()))
} }
nextPc() nextPc()
@@ -546,6 +577,12 @@ class VirtualMachine(irProgram: IRProgram) {
registers.setUW(i.reg1!!, value) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) 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, i.type!!)
}
IRDataType.FLOAT -> { IRDataType.FLOAT -> {
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!) val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!)
registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt())) registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt()))
@@ -566,6 +603,11 @@ class VirtualMachine(irProgram: IRProgram) {
registers.setUW(i.reg1!!, value) registers.setUW(i.reg1!!, value)
statusbitsNZ(value.toInt(), i.type!!) 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!!)) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!))
} }
nextPc() nextPc()
@@ -575,6 +617,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!!, registers.getUB(i.reg1!!)) IRDataType.BYTE -> memory.setUB(i.address!!, registers.getUB(i.reg1!!))
IRDataType.WORD -> memory.setUW(i.address!!, registers.getUW(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!!)) IRDataType.FLOAT -> memory.setFloat(i.address!!, registers.getFloat(i.fpReg1!!))
} }
nextPc() nextPc()
@@ -584,6 +627,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), registers.getUB(i.reg1!!)) 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.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!!)) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
} }
nextPc() nextPc()
@@ -595,6 +639,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + offset, registers.getUB(i.reg1!!)) 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.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!!)) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt() + offset, registers.getFloat(i.fpReg1!!))
} }
nextPc() nextPc()
@@ -604,6 +649,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUB(i.reg1!!)) 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.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!!)) IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
} }
nextPc() nextPc()
@@ -631,6 +677,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!!, 0u) IRDataType.BYTE -> memory.setUB(i.address!!, 0u)
IRDataType.WORD -> memory.setUW(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) IRDataType.FLOAT -> memory.setFloat(i.address!!, 0.0)
} }
nextPc() nextPc()
@@ -640,6 +687,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u) IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u)
IRDataType.WORD -> memory.setUW(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) IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0.0)
} }
nextPc() nextPc()
@@ -649,6 +697,7 @@ class VirtualMachine(irProgram: IRProgram) {
when (i.type!!) { when (i.type!!) {
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u) 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.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) IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0.0)
} }
nextPc() nextPc()
@@ -1922,6 +1971,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte()) IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort()) 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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
statusbitsNZ(value, i.type!!) statusbitsNZ(value, i.type!!)
@@ -1973,6 +2023,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte()) IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort()) 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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
statusbitsNZ(value, i.type!!) statusbitsNZ(value, i.type!!)
@@ -2022,6 +2073,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1!!).inv()) IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1!!).inv())
IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
nextPc() nextPc()
@@ -2032,6 +2084,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv()) IRDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv())
IRDataType.WORD -> memory.setUW(address, memory.getUW(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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
nextPc() nextPc()
@@ -2042,6 +2095,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte()) IRDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte())
IRDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort()) 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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
nextPc() nextPc()
@@ -2104,6 +2158,7 @@ class VirtualMachine(irProgram: IRProgram) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte()) IRDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort()) 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") IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
} }
nextPc() nextPc()
@@ -2582,6 +2637,7 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) 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.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 -> { IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use float here")
} }
@@ -2593,6 +2649,7 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!) IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!)
IRDataType.WORD -> Pair(registers.getSW(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 -> { IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use float here")
} }
@@ -2604,8 +2661,8 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) 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.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
IRDataType.FLOAT -> { IRDataType.LONG, IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use long or float here")
} }
null -> throw IllegalArgumentException("need type for branch instruction") null -> throw IllegalArgumentException("need type for branch instruction")
} }
@@ -2615,8 +2672,8 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt()) IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt())
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt()) IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt())
IRDataType.FLOAT -> { IRDataType.LONG, IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use long or float here")
} }
null -> throw IllegalArgumentException("need type for branch instruction") null -> throw IllegalArgumentException("need type for branch instruction")
} }
@@ -2626,8 +2683,8 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) 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.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
IRDataType.FLOAT -> { IRDataType.LONG, IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use long or float here")
} }
null -> throw IllegalArgumentException("need type for logical instruction") null -> throw IllegalArgumentException("need type for logical instruction")
} }
@@ -2637,6 +2694,7 @@ class VirtualMachine(irProgram: IRProgram) {
return when(i.type) { return when(i.type) {
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) 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.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 -> { IRDataType.FLOAT -> {
throw IllegalArgumentException("can't use float here") throw IllegalArgumentException("can't use float here")
} }
@@ -2750,6 +2808,13 @@ internal fun ArrayDeque<UByte>.pushw(value: UShort) {
add((value.toInt() ushr 8).toUByte()) add((value.toInt() ushr 8).toUByte())
} }
internal fun ArrayDeque<UByte>.pushl(value: Int) {
add((value and 255).toUByte())
add((value ushr 8).toUByte())
add((value ushr 16).toUByte())
add((value ushr 24).toUByte())
}
internal fun ArrayDeque<UByte>.pushf(value: Double) { internal fun ArrayDeque<UByte>.pushf(value: Double) {
// push float; lsb first, msb last // push float; lsb first, msb last
var bits = value.toBits() var bits = value.toBits()
@@ -2776,6 +2841,14 @@ internal fun ArrayDeque<UByte>.popw(): UShort {
return ((msb.toInt() shl 8) + lsb.toInt()).toUShort() return ((msb.toInt() shl 8) + lsb.toInt()).toUShort()
} }
internal fun ArrayDeque<UByte>.popl(): Int {
val msb24 = removeLast()
val msb16 = removeLast()
val msb = removeLast()
val lsb = removeLast()
return (msb24.toInt() shl 24) + (msb16.toInt() shl 16) + (msb.toInt() shl 8) + lsb.toInt()
}
internal fun ArrayDeque<UByte>.popf(): Double { internal fun ArrayDeque<UByte>.popf(): Double {
// pop float; lsb is on bottom, msb on top // pop float; lsb is on bottom, msb on top
val b0 = removeLast().toLong() val b0 = removeLast().toLong()