mirror of
https://github.com/irmen/prog8.git
synced 2025-07-19 02:24:31 +00:00
Compare commits
1 Commits
structs
...
structs-wi
Author | SHA1 | Date | |
---|---|---|---|
|
df56be32b2 |
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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.
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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 {{
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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"
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
)
|
)
|
||||||
|
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
@@ -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:
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
@@ -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)
|
||||||
|
@@ -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? ")
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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
|
||||||
|
@@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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")
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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()
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user