mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
adding singed integer datatypes
This commit is contained in:
parent
2f7d03b6ab
commit
1fe5c943fd
@ -1,15 +1,39 @@
|
||||
%zeropage full
|
||||
%zpreserved $40,200
|
||||
%zpreserved 100,250
|
||||
%option enable_floats
|
||||
|
||||
|
||||
~ main {
|
||||
|
||||
const uword width=320
|
||||
const uword height=200
|
||||
|
||||
sub start() {
|
||||
|
||||
byte[3] barr1 = [-2,-1,2]
|
||||
byte[3] barr2 = [-22,-1, 3]
|
||||
ubyte[3] barr3 = [-2,-1,2] ; @ todo error
|
||||
ubyte[3] barr4 = [1,2,33]
|
||||
ubyte[3] barr5 = [1,2,-33] ; @todo error
|
||||
word[3] warr1 = [-2,-1,2]
|
||||
;word[3] warr2 = [-2,-1,2, 3453] ; @todo ok
|
||||
uword[3] warr3 = [-2,-1,2]
|
||||
uword[3] warr4 = [1,2,33.w]
|
||||
uword[3] warr5 = [1,2,-33] ; @todo error
|
||||
|
||||
byte b1 = 50 * 2
|
||||
byte b2 = -50 * 2
|
||||
ubyte ub1 = 50 * 2
|
||||
word w1 = 999 * 2
|
||||
word w2 = -999 * 2
|
||||
uword uw1 = 999 * 2
|
||||
float f1 = 999*2
|
||||
float f2 = -999*2
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
sub toscreenx(x: float, z: float) -> word {
|
||||
return floor(x/(4.2+z) * flt(height)) + width // 2
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1062,6 +1062,70 @@ class LiteralValue(val type: DataType,
|
||||
|
||||
throw ExpressionError("cannot compare type $type with ${other.type}", other.position)
|
||||
}
|
||||
|
||||
fun intoDatatype(targettype: DataType): LiteralValue {
|
||||
if(type==targettype)
|
||||
return this
|
||||
when(type) {
|
||||
DataType.UBYTE -> {
|
||||
if(targettype==DataType.BYTE && bytevalue!! <= 127)
|
||||
return LiteralValue(targettype, bytevalue=bytevalue, position=position)
|
||||
if(targettype==DataType.WORD || targettype==DataType.UWORD)
|
||||
return LiteralValue(targettype, wordvalue=bytevalue!!.toInt(), position=position)
|
||||
if(targettype==DataType.FLOAT)
|
||||
return LiteralValue(targettype, floatvalue=bytevalue!!.toDouble(), position=position)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
if(targettype==DataType.UBYTE && bytevalue!! >= 0)
|
||||
return LiteralValue(targettype, bytevalue=bytevalue, position=position)
|
||||
if(targettype==DataType.UWORD && bytevalue!! >= 0)
|
||||
return LiteralValue(targettype, wordvalue=bytevalue.toInt(), position=position)
|
||||
if(targettype==DataType.WORD)
|
||||
return LiteralValue(targettype, wordvalue=bytevalue!!.toInt(), position=position)
|
||||
if(targettype==DataType.FLOAT)
|
||||
return LiteralValue(targettype, floatvalue=bytevalue!!.toDouble(), position=position)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
if(targettype==DataType.BYTE && wordvalue!! <= 127)
|
||||
return LiteralValue(targettype, bytevalue=wordvalue.toShort(), position=position)
|
||||
if(targettype==DataType.UBYTE && wordvalue!! <= 255)
|
||||
return LiteralValue(targettype, bytevalue=wordvalue.toShort(), position=position)
|
||||
if(targettype==DataType.WORD && wordvalue!! <= 32767)
|
||||
return LiteralValue(targettype, wordvalue=wordvalue, position=position)
|
||||
if(targettype==DataType.FLOAT)
|
||||
return LiteralValue(targettype, floatvalue=wordvalue!!.toDouble(), position=position)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(targettype==DataType.BYTE && wordvalue!! in -128..127)
|
||||
return LiteralValue(targettype, bytevalue=wordvalue.toShort(), position=position)
|
||||
if(targettype==DataType.UBYTE && wordvalue!! in 0..255)
|
||||
return LiteralValue(targettype, bytevalue=wordvalue.toShort(), position=position)
|
||||
if(targettype==DataType.UWORD && wordvalue!! >=0)
|
||||
return LiteralValue(targettype, wordvalue=wordvalue, position=position)
|
||||
if(targettype==DataType.FLOAT)
|
||||
return LiteralValue(targettype, floatvalue=wordvalue!!.toDouble(), position=position)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
if(floor(floatvalue!!)==floatvalue) {
|
||||
val value = floatvalue.toInt()
|
||||
if (targettype == DataType.BYTE && value in -128..127)
|
||||
return LiteralValue(targettype, bytevalue = value.toShort(), position = position)
|
||||
if (targettype == DataType.UBYTE && value in 0..255)
|
||||
return LiteralValue(targettype, bytevalue = value.toShort(), position = position)
|
||||
if (targettype == DataType.WORD && value in -32768..32767)
|
||||
return LiteralValue(targettype, wordvalue = value, position = position)
|
||||
if (targettype == DataType.UWORD && value in 0..65535)
|
||||
return LiteralValue(targettype, wordvalue = value, position = position)
|
||||
}
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
if(targettype in StringDatatypes)
|
||||
return this
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
throw FatalAstException("invalid type conversion from $this to $targettype")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,10 +105,16 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
||||
if(scope !in vardeclsToAdd)
|
||||
vardeclsToAdd[scope] = mutableListOf()
|
||||
vardeclsToAdd[scope]!!.add(decl.asDefaultValueDecl())
|
||||
val declvalue = decl.value!!
|
||||
val value =
|
||||
if(declvalue is LiteralValue)
|
||||
declvalue.intoDatatype(decl.datatype)
|
||||
else
|
||||
declvalue
|
||||
return VariableInitializationAssignment(
|
||||
AssignTarget(null, IdentifierReference(decl.scopedname.split("."), decl.position), null, decl.position),
|
||||
null,
|
||||
decl.value!!,
|
||||
value,
|
||||
decl.position
|
||||
)
|
||||
}
|
||||
|
@ -200,102 +200,126 @@ class StackVmProgram(val name: String, val heap: HeapValues) {
|
||||
private fun optimizeDataConversionAndUselessDiscards() {
|
||||
// - push value followed by a data type conversion -> push the value in the correct type and remove the conversion
|
||||
// - push something followed by a discard -> remove both
|
||||
val instructionsToReplace = mutableMapOf<Int, Instruction>()
|
||||
|
||||
fun optimizeDiscardAfterPush(index0: Int, index1: Int, ins1: Instruction) {
|
||||
if (ins1.opcode == Opcode.DISCARD_FLOAT || ins1.opcode == Opcode.DISCARD_WORD || ins1.opcode == Opcode.DISCARD_BYTE) {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeFloatConversion(index0: Int, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB,
|
||||
Opcode.MSB,
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT,
|
||||
Opcode.UW2FLOAT,
|
||||
Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a float")
|
||||
Opcode.DISCARD_FLOAT -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_WORD -> throw CompilerException("invalid discard type following a float")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeWordConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() and 255))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, ins0.arg!!.integerValue() ushr 8 and 255))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT -> throw CompilerException("invalid conversion following a word")
|
||||
Opcode.W2FLOAT, Opcode.UW2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
fun optimizeByteConversion(index0: Int, ins0: Instruction, index1: Int, ins1: Instruction) {
|
||||
when (ins1.opcode) {
|
||||
Opcode.LSB -> instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
Opcode.MSB -> throw CompilerException("msb of a byte")
|
||||
Opcode.UB2UWORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 256 * ins0.arg!!.integerValue()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2FLOAT, Opcode.UB2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, ins0.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[index0] = ins
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.W2FLOAT, Opcode.UW2FLOAT -> throw CompilerException("invalid conversion following a byte")
|
||||
Opcode.DISCARD_BYTE -> {
|
||||
instructionsToReplace[index0] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[index1] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
|
||||
}
|
||||
}
|
||||
|
||||
val typeConversionOpcodes = setOf(
|
||||
Opcode.LSB,
|
||||
Opcode.MSB,
|
||||
Opcode.B2WORD,
|
||||
Opcode.UB2UWORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.UB2FLOAT,
|
||||
Opcode.W2FLOAT,
|
||||
Opcode.UW2FLOAT,
|
||||
Opcode.DISCARD_BYTE,
|
||||
Opcode.DISCARD_WORD,
|
||||
Opcode.DISCARD_FLOAT
|
||||
)
|
||||
|
||||
val instructionsToReplace = mutableMapOf<Int, Instruction>()
|
||||
|
||||
this.instructions.asSequence().withIndex().windowed(2).toList().forEach {
|
||||
if(it[1].value.opcode in typeConversionOpcodes) {
|
||||
when(it[0].value.opcode) {
|
||||
Opcode.PUSH_BYTE -> when (it[1].value.opcode) {
|
||||
Opcode.LSB -> instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
Opcode.MSB -> throw CompilerException("msb of a byte")
|
||||
Opcode.B2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, it[0].value.arg!!.integerValue()))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB2WORD -> {
|
||||
val ins = Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 256 * it[0].value.arg!!.integerValue()))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, it[0].value.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a byte")
|
||||
Opcode.DISCARD_BYTE -> {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> {}
|
||||
}
|
||||
Opcode.PUSH_WORD -> when (it[1].value.opcode) {
|
||||
Opcode.LSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, it[0].value.arg!!.integerValue() and 255))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.MSB -> {
|
||||
val ins = Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, it[0].value.arg!!.integerValue() ushr 8 and 255))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.B2WORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT -> throw CompilerException("invalid conversion following a word")
|
||||
Opcode.W2FLOAT -> {
|
||||
val ins = Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, it[0].value.arg!!.integerValue().toDouble()))
|
||||
instructionsToReplace[it[0].index] = ins
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_WORD -> {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
|
||||
else -> {}
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> when (it[1].value.opcode) {
|
||||
Opcode.LSB,
|
||||
Opcode.MSB,
|
||||
Opcode.B2WORD,
|
||||
Opcode.MSB2WORD,
|
||||
Opcode.B2FLOAT,
|
||||
Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a float")
|
||||
Opcode.DISCARD_FLOAT -> {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
Opcode.DISCARD_BYTE, Opcode.DISCARD_WORD -> throw CompilerException("invalid discard type following a float")
|
||||
else -> {}
|
||||
}
|
||||
Opcode.PUSH_BYTE -> optimizeByteConversion(it[0].index, it[0].value, it[1].index, it[1].value)
|
||||
Opcode.PUSH_WORD -> optimizeWordConversion(it[0].index, it[0].value, it[1].index, it[1].value)
|
||||
Opcode.PUSH_FLOAT -> optimizeFloatConversion(it[0].index, it[1].index, it[1].value)
|
||||
Opcode.PUSH_VAR_FLOAT,
|
||||
Opcode.PUSH_VAR_WORD,
|
||||
Opcode.PUSH_VAR_BYTE,
|
||||
Opcode.PUSH_MEM_BYTE,
|
||||
Opcode.PUSH_MEM_WORD,
|
||||
Opcode.PUSH_MEM_FLOAT -> when (it[1].value.opcode) {
|
||||
Opcode.DISCARD_FLOAT, Opcode.DISCARD_WORD, Opcode.DISCARD_BYTE -> {
|
||||
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
|
||||
instructionsToReplace[it[1].index] = Instruction(Opcode.NOP)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB,
|
||||
Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW,
|
||||
Opcode.PUSH_MEM_FLOAT -> optimizeDiscardAfterPush(it[0].index, it[1].index, it[1].value)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -817,9 +841,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
else -> {
|
||||
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
|
||||
when(lv.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> stackvmProg.instr(Opcode.PUSH_BYTE, Value(DataType.UBYTE, lv.bytevalue!!))
|
||||
DataType.UWORD, DataType.WORD -> stackvmProg.instr(Opcode.PUSH_WORD, Value(DataType.UWORD, lv.wordvalue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, lv.floatvalue!!))
|
||||
DataType.UBYTE, DataType.BYTE -> stackvmProg.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!))
|
||||
DataType.UWORD, DataType.WORD -> stackvmProg.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||
@ -847,7 +871,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
when(givenDt) {
|
||||
DataType.UBYTE -> when(targetDt) {
|
||||
DataType.UWORD, DataType.WORD -> stackvmProg.instr(Opcode.UB2UWORD)
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.B2FLOAT)
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.UB2FLOAT)
|
||||
else -> {}
|
||||
}
|
||||
DataType.BYTE -> when(targetDt) {
|
||||
@ -883,8 +907,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
throw CompilerException("const ref should have been const-folded away")
|
||||
VarDeclType.MEMORY -> {
|
||||
when (target.datatype) {
|
||||
DataType.UBYTE -> stackvmProg.instr(Opcode.PUSH_MEM_BYTE, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.UWORD -> stackvmProg.instr(Opcode.PUSH_MEM_WORD, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.UBYTE -> stackvmProg.instr(Opcode.PUSH_MEM_UB, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.BYTE-> stackvmProg.instr(Opcode.PUSH_MEM_B, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.UWORD -> stackvmProg.instr(Opcode.PUSH_MEM_UW, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.WORD -> stackvmProg.instr(Opcode.PUSH_MEM_W, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, (target.value as LiteralValue).asNumericValue!!))
|
||||
else -> TODO("invalid datatype for memory variable expression: $target")
|
||||
}
|
||||
@ -929,8 +955,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
// 1 argument, type determines the exact opcode to use
|
||||
val arg = args.single()
|
||||
when (arg.resultingDatatype(namespace, heap)) {
|
||||
DataType.UBYTE -> stackvmProg.instr(Opcode.B2FLOAT)
|
||||
DataType.UWORD -> stackvmProg.instr(Opcode.W2FLOAT)
|
||||
DataType.UBYTE -> stackvmProg.instr(Opcode.UB2FLOAT)
|
||||
DataType.BYTE -> stackvmProg.instr(Opcode.B2FLOAT)
|
||||
DataType.UWORD -> stackvmProg.instr(Opcode.UW2FLOAT)
|
||||
DataType.WORD -> stackvmProg.instr(Opcode.W2FLOAT)
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.NOP)
|
||||
else -> throw CompilerException("wrong datatype for flt()")
|
||||
}
|
||||
|
@ -35,13 +35,13 @@ val BuiltinFunctions = mapOf(
|
||||
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },
|
||||
"avg" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), DataType.FLOAT, ::builtinAvg),
|
||||
"abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT, ::builtinAbs),
|
||||
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::round) }, // type depends on arg
|
||||
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::floor) }, // type depends on arg
|
||||
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::ceil) }, // type depends on arg
|
||||
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::round) },
|
||||
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::floor) },
|
||||
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.WORD) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::ceil) },
|
||||
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args
|
||||
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
|
||||
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
|
||||
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes.toList())), null, ::builtinLen), // type depends on args
|
||||
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes.toList())), DataType.UWORD, ::builtinLen),
|
||||
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
|
||||
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes.toList())), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
|
||||
"lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }},
|
||||
@ -142,17 +142,6 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
DataType.MATRIX_B -> DataType.BYTE
|
||||
}
|
||||
}
|
||||
"round", "floor", "ceil" -> {
|
||||
val dt=args.single().resultingDatatype(namespace, heap)
|
||||
when(dt) {
|
||||
DataType.UBYTE -> DataType.UBYTE
|
||||
DataType.BYTE -> DataType.BYTE
|
||||
DataType.UWORD -> DataType.UWORD
|
||||
DataType.WORD -> DataType.WORD
|
||||
DataType.FLOAT -> DataType.WORD
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
"sum" -> {
|
||||
val dt=datatypeFromListArg(args.single())
|
||||
when(dt) {
|
||||
@ -167,27 +156,6 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UWORD
|
||||
}
|
||||
}
|
||||
"len" -> {
|
||||
// len of a str is always 0..255 so always a byte,
|
||||
// len of other things is assumed to need a word (even though the actual length could be less than 256)
|
||||
val arg = args.single()
|
||||
when(arg) {
|
||||
is IdentifierReference -> {
|
||||
val stmt = arg.targetStatement(namespace)
|
||||
when(stmt) {
|
||||
is VarDecl -> {
|
||||
val value = stmt.value
|
||||
if(value is LiteralValue) {
|
||||
if(value.isString) return DataType.UBYTE // strings are 0..255
|
||||
}
|
||||
}
|
||||
}
|
||||
DataType.UWORD // assume other lengths are words for now.
|
||||
}
|
||||
is LiteralValue -> throw FatalAstException("len of literalvalue should have been const-folded away already")
|
||||
else -> DataType.UWORD
|
||||
}
|
||||
}
|
||||
else -> throw FatalAstException("unknown result type for builtin function $function")
|
||||
}
|
||||
}
|
||||
@ -207,15 +175,13 @@ private fun oneDoubleArg(args: List<IExpression>, position: Position, namespace:
|
||||
return numericLiteral(function(float), args[0].position)
|
||||
}
|
||||
|
||||
private fun oneDoubleArgOutputInt(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues, function: (arg: Double)->Number): LiteralValue {
|
||||
private fun oneDoubleArgOutputWord(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues, function: (arg: Double)->Number): LiteralValue {
|
||||
if(args.size!=1)
|
||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||
val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||
val float: Double = when(constval.type) {
|
||||
DataType.UBYTE, DataType.UWORD, DataType.FLOAT -> constval.asNumericValue!!.toDouble()
|
||||
else -> throw SyntaxError("built-in function requires one floating point argument", position)
|
||||
}
|
||||
return numericLiteral(function(float).toInt(), args[0].position)
|
||||
if(constval.type!=DataType.FLOAT)
|
||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||
return LiteralValue(DataType.WORD, wordvalue=function(constval.asNumericValue!!.toDouble()).toInt(), position=args[0].position)
|
||||
}
|
||||
|
||||
private fun oneIntArgOutputInt(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues, function: (arg: Int)->Number): LiteralValue {
|
||||
@ -384,15 +350,15 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
|
||||
return when(argument.type) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.MATRIX_UB, DataType.MATRIX_B -> {
|
||||
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).array!!.size
|
||||
numericLiteral(arraySize, args[0].position)
|
||||
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).doubleArray!!.size
|
||||
numericLiteral(arraySize, args[0].position)
|
||||
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position)
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val str = argument.strvalue ?: heap.get(argument.heapId!!).str!!
|
||||
numericLiteral(str.length, args[0].position)
|
||||
LiteralValue(DataType.UWORD, wordvalue=str.length, position=args[0].position)
|
||||
}
|
||||
DataType.UBYTE, DataType.BYTE,
|
||||
DataType.UWORD, DataType.WORD,
|
||||
|
@ -44,7 +44,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
}
|
||||
in IntegerDatatypes -> {
|
||||
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to integer
|
||||
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to ubyte integer
|
||||
val literal = decl.value as? LiteralValue
|
||||
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
|
||||
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
|
||||
@ -426,7 +426,6 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
return super.process(range)
|
||||
}
|
||||
|
||||
// todo datatypes
|
||||
override fun process(literalValue: LiteralValue): LiteralValue {
|
||||
if(literalValue.strvalue!=null) {
|
||||
// intern the string; move it into the heap
|
||||
@ -439,11 +438,23 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
} else if(literalValue.arrayvalue!=null) {
|
||||
val newArray = literalValue.arrayvalue.map { it.process(this) }.toTypedArray()
|
||||
var arrayDt = DataType.ARRAY_UB
|
||||
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.UWORD })
|
||||
arrayDt = DataType.ARRAY_UW
|
||||
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.FLOAT })
|
||||
arrayDt = DataType.ARRAY_F
|
||||
val arrayDt =
|
||||
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.FLOAT })
|
||||
DataType.ARRAY_F
|
||||
else {
|
||||
if (newArray.any { it.resultingDatatype(namespace, heap) in setOf(DataType.BYTE, DataType.WORD) }) {
|
||||
// we have signed values
|
||||
if (newArray.any { it.resultingDatatype(namespace, heap) == DataType.WORD })
|
||||
DataType.ARRAY_W
|
||||
else
|
||||
DataType.ARRAY_B
|
||||
} else {
|
||||
// only unsigned values
|
||||
if (newArray.any { it.resultingDatatype(namespace, heap) == DataType.UWORD })
|
||||
DataType.ARRAY_UW
|
||||
else DataType.ARRAY_UB
|
||||
}
|
||||
}
|
||||
|
||||
// if the values are all constants, the array is moved to the heap
|
||||
val allElementsAreConstant = newArray.fold(true) { c, expr-> c and (expr is LiteralValue)}
|
||||
@ -454,10 +465,21 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
return super.process(literalValue)
|
||||
}
|
||||
if(arrayDt==DataType.ARRAY_UB || arrayDt==DataType.MATRIX_UB) {
|
||||
// all values should be ubytes
|
||||
val integerArray = litArray.map { (it as LiteralValue).bytevalue }
|
||||
if (integerArray.any { it == null || it.toInt() !in 0..255 }) {
|
||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
val array = integerArray.mapNotNull { it?.toInt() }.toIntArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(arrayDt, heapId = heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else if(arrayDt==DataType.ARRAY_B || arrayDt==DataType.MATRIX_B) {
|
||||
// all values should be bytes
|
||||
val integerArray = litArray.map { (it as LiteralValue).bytevalue }
|
||||
if(integerArray.any { it==null || it.toInt() !in 0..255 }) {
|
||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
||||
if(integerArray.any { it==null || it.toInt() !in -128..127 }) {
|
||||
addError(ExpressionError("byte array elements must all be integers -128..127", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
val array = integerArray.mapNotNull { it?.toInt() }.toIntArray()
|
||||
@ -475,6 +497,17 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(DataType.ARRAY_UW, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else if(arrayDt==DataType.ARRAY_W) {
|
||||
// all values should be bytes or words
|
||||
val integerArray = litArray.map { (it as LiteralValue).asIntegerValue }
|
||||
if(integerArray.any {it==null || it !in -32768..32767 }) {
|
||||
addError(ExpressionError("word array elements must all be integers -32768..32767", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
val array = integerArray.filterNotNull().toIntArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(DataType.ARRAY_W, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else if(arrayDt==DataType.ARRAY_F) {
|
||||
// all values should be bytes, words or floats
|
||||
val doubleArray = litArray.map { (it as LiteralValue).asNumericValue?.toDouble() }
|
||||
|
@ -2,29 +2,62 @@ package prog8.stackvm
|
||||
|
||||
import prog8.compiler.target.c64.Mflpt5
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import kotlin.math.abs
|
||||
|
||||
class Memory {
|
||||
private val mem = ShortArray(65536) // shorts because byte is signed and we store values 0..255
|
||||
|
||||
fun getByte(address: Int): Short {
|
||||
fun getUByte(address: Int): Short {
|
||||
return mem[address]
|
||||
}
|
||||
|
||||
fun setByte(address: Int, value: Short) {
|
||||
if(value<0 || value>255) throw VmExecutionException("byte value not 0..255")
|
||||
fun getSByte(address: Int): Short {
|
||||
val ubyte = getUByte(address)
|
||||
if(ubyte <= 127)
|
||||
return ubyte
|
||||
return (-((ubyte.toInt() xor 255)+1)).toShort() // 2's complement
|
||||
}
|
||||
|
||||
fun setUByte(address: Int, value: Short) {
|
||||
if(value !in 0..255)
|
||||
throw VmExecutionException("ubyte value out of range")
|
||||
mem[address] = value
|
||||
}
|
||||
|
||||
fun getWord(address: Int): Int {
|
||||
fun setSByte(address: Int, value: Short) {
|
||||
if(value !in -128..127) throw VmExecutionException("byte value out of range")
|
||||
if(value>=0)
|
||||
setUByte(address, value)
|
||||
else
|
||||
setUByte(address, ((abs(value.toInt()) xor 255)+1).toShort()) // 2's complement
|
||||
}
|
||||
|
||||
fun getUWord(address: Int): Int {
|
||||
return mem[address] + 256*mem[address+1]
|
||||
}
|
||||
|
||||
fun setWord(address: Int, value: Int) {
|
||||
if(value<0 || value>65535) throw VmExecutionException("word value not 0..65535")
|
||||
fun getSWord(address: Int): Int {
|
||||
val uword = getUWord(address)
|
||||
if(uword <= 32767)
|
||||
return uword
|
||||
return -((uword xor 65535)+1) // 2's complement
|
||||
}
|
||||
|
||||
fun setUWord(address: Int, value: Int) {
|
||||
if(value !in 0..65535)
|
||||
throw VmExecutionException("uword value out of range")
|
||||
mem[address] = value.and(255).toShort()
|
||||
mem[address+1] = (value / 256).toShort()
|
||||
}
|
||||
|
||||
fun setSWord(address: Int, value: Int) {
|
||||
if(value !in -32768..32767) throw VmExecutionException("word value out of range")
|
||||
if(value>=0)
|
||||
setUWord(address, value)
|
||||
else
|
||||
setUWord(address, (abs(value) xor 65535)+1) // 2's complement
|
||||
}
|
||||
|
||||
fun setFloat(address: Int, value: Double) {
|
||||
val mflpt5 = Mflpt5.fromNumber(value)
|
||||
mem[address] = mflpt5.b0
|
||||
|
@ -142,8 +142,10 @@ class Program (val name: String,
|
||||
}
|
||||
val (type, valueStr) = args.split(':')
|
||||
return when(type) {
|
||||
"b" -> Value(DataType.UBYTE, valueStr.toShort(16))
|
||||
"w" -> Value(DataType.UWORD, valueStr.toInt(16))
|
||||
"b" -> Value(DataType.BYTE, valueStr.toShort(16))
|
||||
"ub" -> Value(DataType.UBYTE, valueStr.toShort(16))
|
||||
"w" -> Value(DataType.WORD, valueStr.toInt(16))
|
||||
"uw" -> Value(DataType.UWORD, valueStr.toInt(16))
|
||||
"f" -> Value(DataType.FLOAT, valueStr.toDouble())
|
||||
"heap" -> {
|
||||
val heapId = valueStr.toInt()
|
||||
@ -165,9 +167,9 @@ class Program (val name: String,
|
||||
throw VmExecutionException("missing value type character")
|
||||
val type = DataType.valueOf(typeStr.toUpperCase())
|
||||
val value = when(type) {
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, valueStr.substring(2).toShort(16))
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, valueStr.substring(3).toShort(16))
|
||||
DataType.BYTE -> Value(DataType.BYTE, valueStr.substring(2).toShort(16))
|
||||
DataType.UWORD -> Value(DataType.UWORD, valueStr.substring(2).toInt(16))
|
||||
DataType.UWORD -> Value(DataType.UWORD, valueStr.substring(3).toInt(16))
|
||||
DataType.WORD -> Value(DataType.WORD, valueStr.substring(2).toInt(16))
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, valueStr.substring(2).toDouble())
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package prog8.stackvm
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.ast.*
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import java.io.File
|
||||
@ -14,22 +14,26 @@ enum class Opcode {
|
||||
PUSH_BYTE, // push byte value
|
||||
PUSH_WORD, // push word value (or 'address' of string / array / matrix)
|
||||
PUSH_FLOAT, // push float value
|
||||
PUSH_MEM_BYTE, // push byte value from memory to stack
|
||||
PUSH_MEM_WORD, // push word value from memory to stack
|
||||
PUSH_MEM_B, // push byte value from memory to stack
|
||||
PUSH_MEM_UB, // push byte value from memory to stack
|
||||
PUSH_MEM_W, // push word value from memory to stack
|
||||
PUSH_MEM_UW, // push word value from memory to stack
|
||||
PUSH_MEM_FLOAT, // push float value from memory to stack
|
||||
PUSH_VAR_BYTE, // push byte variable
|
||||
PUSH_VAR_WORD, // push word variable
|
||||
PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
|
||||
PUSH_VAR_WORD, // push word variable (uword, word)
|
||||
PUSH_VAR_FLOAT, // push float variable
|
||||
|
||||
// popping values off the (evaluation) stack, possibly storing them in another location
|
||||
DISCARD_BYTE, // discard top byte value
|
||||
DISCARD_WORD, // discard top word value
|
||||
DISCARD_FLOAT, // discard top float value
|
||||
POP_MEM_BYTE, // pop byte value into destination memory address
|
||||
POP_MEM_WORD, // pop word value into destination memory address
|
||||
POP_MEM_B, // pop byte value into destination memory address
|
||||
POP_MEM_UB, // pop byte value into destination memory address
|
||||
POP_MEM_W, // pop word value into destination memory address
|
||||
POP_MEM_UW, // pop word value into destination memory address
|
||||
POP_MEM_FLOAT, // pop float value into destination memory address
|
||||
POP_VAR_BYTE, // pop byte value into variable
|
||||
POP_VAR_WORD, // pop word value into variable
|
||||
POP_VAR_BYTE, // pop byte value into variable (byte, ubyte)
|
||||
POP_VAR_WORD, // pop word value into variable (word, uword)
|
||||
POP_VAR_FLOAT, // pop float value into variable
|
||||
|
||||
// optimized copying of one var to another (replaces push+pop)
|
||||
@ -433,11 +437,19 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
for (value in meminit.value) {
|
||||
when(value.type) {
|
||||
DataType.UBYTE -> {
|
||||
mem.setByte(address, value.integerValue().toShort())
|
||||
mem.setUByte(address, value.integerValue().toShort())
|
||||
address += 1
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
address += 1
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
mem.setWord(address, value.integerValue())
|
||||
mem.setUWord(address, value.integerValue())
|
||||
address += 2
|
||||
}
|
||||
DataType.WORD -> {
|
||||
mem.setSWord(address, value.integerValue())
|
||||
address += 2
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
@ -474,24 +486,32 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
when (ins.opcode) {
|
||||
Opcode.NOP -> {}
|
||||
Opcode.PUSH_BYTE -> {
|
||||
checkDt(ins.arg, DataType.UBYTE)
|
||||
checkDt(ins.arg, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_WORD -> {
|
||||
checkDt(ins.arg, setOf(DataType.UWORD, DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.MATRIX_UB))
|
||||
checkDt(ins.arg, setOf(DataType.UWORD, DataType.WORD) + IterableDatatypes)
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_FLOAT -> {
|
||||
checkDt(ins.arg, DataType.FLOAT)
|
||||
evalstack.push(ins.arg)
|
||||
}
|
||||
Opcode.PUSH_MEM_BYTE -> {
|
||||
Opcode.PUSH_MEM_UB -> {
|
||||
val address = ins.arg!!.integerValue()
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getByte(address)))
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getUByte(address)))
|
||||
}
|
||||
Opcode.PUSH_MEM_WORD -> {
|
||||
Opcode.PUSH_MEM_B -> {
|
||||
val address = ins.arg!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, mem.getWord(address)))
|
||||
evalstack.push(Value(DataType.BYTE, mem.getSByte(address)))
|
||||
}
|
||||
Opcode.PUSH_MEM_UW -> {
|
||||
val address = ins.arg!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, mem.getUWord(address)))
|
||||
}
|
||||
Opcode.PUSH_MEM_W -> {
|
||||
val address = ins.arg!!.integerValue()
|
||||
evalstack.push(Value(DataType.WORD, mem.getSWord(address)))
|
||||
}
|
||||
Opcode.PUSH_MEM_FLOAT -> {
|
||||
val address = ins.arg!!.integerValue()
|
||||
@ -509,17 +529,29 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.FLOAT)
|
||||
}
|
||||
Opcode.POP_MEM_BYTE -> {
|
||||
Opcode.POP_MEM_UB -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setByte(address, value.integerValue().toShort())
|
||||
mem.setUByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_WORD -> {
|
||||
Opcode.POP_MEM_B -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.BYTE)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setSByte(address, value.integerValue().toShort())
|
||||
}
|
||||
Opcode.POP_MEM_UW -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UWORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setWord(address, value.integerValue())
|
||||
mem.setUWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_W -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.WORD)
|
||||
val address = ins.arg!!.integerValue()
|
||||
mem.setSWord(address, value.integerValue())
|
||||
}
|
||||
Opcode.POP_MEM_FLOAT -> {
|
||||
val value = evalstack.pop()
|
||||
@ -539,6 +571,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.add(top))
|
||||
}
|
||||
Opcode.ADD_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.add(top))
|
||||
}
|
||||
Opcode.ADD_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.add(top))
|
||||
}
|
||||
Opcode.ADD_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -557,6 +601,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.sub(top))
|
||||
}
|
||||
Opcode.SUB_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.sub(top))
|
||||
}
|
||||
Opcode.SUB_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.sub(top))
|
||||
}
|
||||
Opcode.SUB_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -575,6 +631,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.mul(top))
|
||||
}
|
||||
Opcode.MUL_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.mul(top))
|
||||
}
|
||||
Opcode.MUL_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.mul(top))
|
||||
}
|
||||
Opcode.MUL_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -593,6 +661,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.div(top))
|
||||
}
|
||||
Opcode.DIV_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.div(top))
|
||||
}
|
||||
Opcode.DIV_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.div(top))
|
||||
}
|
||||
Opcode.DIV_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -611,6 +691,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.floordiv(top))
|
||||
}
|
||||
Opcode.FLOORDIV_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.floordiv(top))
|
||||
}
|
||||
Opcode.FLOORDIV_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.floordiv(top))
|
||||
}
|
||||
Opcode.FLOORDIV_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -629,6 +721,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.remainder(top))
|
||||
}
|
||||
Opcode.REMAINDER_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.remainder(top))
|
||||
}
|
||||
Opcode.REMAINDER_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.remainder(top))
|
||||
}
|
||||
Opcode.REMAINDER_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -647,6 +751,18 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(second, DataType.UWORD)
|
||||
evalstack.push(second.pow(top))
|
||||
}
|
||||
Opcode.POW_B -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.BYTE)
|
||||
checkDt(second, DataType.BYTE)
|
||||
evalstack.push(second.pow(top))
|
||||
}
|
||||
Opcode.POW_W -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.WORD)
|
||||
checkDt(second, DataType.WORD)
|
||||
evalstack.push(second.pow(top))
|
||||
}
|
||||
Opcode.POW_F -> {
|
||||
val (top, second) = evalstack.pop2()
|
||||
checkDt(top, DataType.FLOAT)
|
||||
@ -655,12 +771,12 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.NEG_B -> {
|
||||
val v = evalstack.pop()
|
||||
checkDt(v, DataType.UBYTE)
|
||||
checkDt(v, DataType.BYTE)
|
||||
evalstack.push(v.neg())
|
||||
}
|
||||
Opcode.NEG_W -> {
|
||||
val v = evalstack.pop()
|
||||
checkDt(v, DataType.UWORD)
|
||||
checkDt(v, DataType.WORD)
|
||||
evalstack.push(v.neg())
|
||||
}
|
||||
Opcode.NEG_F -> {
|
||||
@ -839,82 +955,85 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Opcode.CLI -> P_irqd = false
|
||||
Opcode.TERMINATE -> throw VmTerminationException("terminate instruction")
|
||||
Opcode.BREAKPOINT -> throw VmBreakpointException()
|
||||
Opcode.LINE -> {
|
||||
sourceLine = ins.callLabel!!
|
||||
}
|
||||
|
||||
Opcode.SHL_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val newValue = value.shl()
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
}
|
||||
Opcode.SHL_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val newValue = value.shl()
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
}
|
||||
Opcode.SHR_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val newValue = value.shr()
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
}
|
||||
Opcode.SHR_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val newValue = value.shr()
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
}
|
||||
Opcode.ROL_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val (newValue, newCarry) = value.rol(P_carry)
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROL_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val (newValue, newCarry) = value.rol(P_carry)
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROR_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val (newValue, newCarry) = value.ror(P_carry)
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROR_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val (newValue, newCarry) = value.ror(P_carry)
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
P_carry = newCarry
|
||||
}
|
||||
Opcode.ROL2_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val newValue = value.rol2()
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
}
|
||||
Opcode.ROL2_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val newValue = value.rol2()
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
}
|
||||
Opcode.ROR2_MEM_BYTE -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UBYTE, mem.getByte(addr))
|
||||
val value = Value(DataType.UBYTE, mem.getUByte(addr))
|
||||
val newValue = value.ror2()
|
||||
mem.setByte(addr, newValue.integerValue().toShort())
|
||||
mem.setUByte(addr, newValue.integerValue().toShort())
|
||||
}
|
||||
Opcode.ROR2_MEM_WORD -> {
|
||||
val addr = ins.arg!!.integerValue()
|
||||
val value = Value(DataType.UWORD, mem.getWord(addr))
|
||||
val value = Value(DataType.UWORD, mem.getUWord(addr))
|
||||
val newValue = value.ror2()
|
||||
mem.setWord(addr, newValue.integerValue())
|
||||
mem.setUWord(addr, newValue.integerValue())
|
||||
}
|
||||
|
||||
Opcode.JUMP -> {} // do nothing; the next instruction is wired up already to the jump target
|
||||
@ -940,7 +1059,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.PUSH_VAR_BYTE -> {
|
||||
val value = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(value, DataType.UBYTE)
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
@ -955,30 +1074,38 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.POP_VAR_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE)
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, DataType.UBYTE)
|
||||
checkDt(variable, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.POP_VAR_WORD -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
checkDt(variable, setOf(DataType.UWORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(variable, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
if(value.type!=variable.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel!!] = value
|
||||
}
|
||||
Opcode.COPY_VAR_BYTE -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, DataType.UBYTE)
|
||||
checkDt(dest, DataType.UBYTE)
|
||||
checkDt(source, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
checkDt(dest, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_WORD -> {
|
||||
val source = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
val dest = variables[ins.callLabel2] ?: throw VmExecutionException("unknown variable: ${ins.callLabel2}")
|
||||
checkDt(source, setOf(DataType.UWORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(dest, setOf(DataType.UWORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(source, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
checkDt(dest, setOf(DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))
|
||||
if(dest.type!=source.type)
|
||||
throw VmExecutionException("datatype mismatch")
|
||||
variables[ins.callLabel2!!] = source
|
||||
}
|
||||
Opcode.COPY_VAR_FLOAT -> {
|
||||
@ -1327,8 +1454,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
}
|
||||
Opcode.B2WORD -> {
|
||||
val byte = evalstack.pop()
|
||||
checkDt(byte, DataType.UBYTE)
|
||||
evalstack.push(Value(DataType.UWORD, byte.integerValue()))
|
||||
checkDt(byte, DataType.BYTE)
|
||||
evalstack.push(Value(DataType.WORD, byte.integerValue()))
|
||||
}
|
||||
Opcode.UB2UWORD -> {
|
||||
val ubyte = evalstack.pop()
|
||||
checkDt(ubyte, DataType.UBYTE)
|
||||
evalstack.push(Value(DataType.UWORD, ubyte.integerValue()))
|
||||
}
|
||||
Opcode.MSB2WORD -> {
|
||||
val byte = evalstack.pop()
|
||||
@ -1336,30 +1468,38 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
evalstack.push(Value(DataType.UWORD, byte.integerValue() * 256))
|
||||
}
|
||||
Opcode.B2FLOAT -> {
|
||||
val byte = evalstack.pop()
|
||||
checkDt(byte, DataType.BYTE)
|
||||
evalstack.push(Value(DataType.FLOAT, byte.integerValue()))
|
||||
}
|
||||
Opcode.UB2FLOAT -> {
|
||||
val byte = evalstack.pop()
|
||||
checkDt(byte, DataType.UBYTE)
|
||||
evalstack.push(Value(DataType.FLOAT, byte.integerValue()))
|
||||
}
|
||||
Opcode.W2FLOAT -> {
|
||||
val byte = evalstack.pop()
|
||||
checkDt(byte, DataType.UWORD)
|
||||
evalstack.push(Value(DataType.FLOAT, byte.integerValue()))
|
||||
val wrd = evalstack.pop()
|
||||
checkDt(wrd, DataType.UWORD)
|
||||
evalstack.push(Value(DataType.FLOAT, wrd.integerValue()))
|
||||
}
|
||||
Opcode.LINE -> {
|
||||
sourceLine = ins.callLabel!!
|
||||
Opcode.UW2FLOAT -> {
|
||||
val uwrd = evalstack.pop()
|
||||
checkDt(uwrd, DataType.UWORD)
|
||||
evalstack.push(Value(DataType.FLOAT, uwrd.integerValue()))
|
||||
}
|
||||
Opcode.READ_INDEXED_VAR_BYTE -> {
|
||||
// put the byte value of variable[index] onto the stack
|
||||
val index = evalstack.pop().integerValue()
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the byte value from that memory location
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getByte(variable.integerValue())))
|
||||
// assume the variable is a pointer (address) and get the ubyte value from that memory location
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed byte element from the array
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index]))
|
||||
DataType.ARRAY_B, DataType.MATRIX_B -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
|
||||
else -> throw VmExecutionException("not a proper array/matrix/string variable with byte elements")
|
||||
}
|
||||
@ -1371,13 +1511,15 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the word value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getWord(variable.integerValue())))
|
||||
evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed word element from the array
|
||||
val array = heap.get(variable.heapId)
|
||||
if(array.type!=DataType.ARRAY_UW)
|
||||
throw VmExecutionException("not a proper array var with word elements")
|
||||
evalstack.push(Value(DataType.UWORD, array.array!![index]))
|
||||
when(array.type){
|
||||
DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
else -> throw VmExecutionException("not a proper array var with word elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.READ_INDEXED_VAR_FLOAT -> {
|
||||
@ -1399,18 +1541,17 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store byte value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE)
|
||||
checkDt(value, setOf(DataType.UBYTE, DataType.BYTE))
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the byte value to that memory location
|
||||
mem.setByte(variable.integerValue(), value.integerValue().toShort())
|
||||
mem.setUByte(variable.integerValue(), value.integerValue().toShort())
|
||||
} else {
|
||||
// set indexed byte element in the array
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> {
|
||||
array.array!![index] = value.integerValue()
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.MATRIX_UB -> array.array!![index] = value.integerValue()
|
||||
DataType.ARRAY_B, DataType.MATRIX_B -> array.array!![index] = value.integerValue()
|
||||
DataType.STR,
|
||||
DataType.STR_P,
|
||||
DataType.STR_S,
|
||||
@ -1427,17 +1568,20 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// store word value on the stack in variable[index] (index is on the stack as well)
|
||||
val index = evalstack.pop().integerValue()
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UWORD)
|
||||
checkDt(value, setOf(DataType.UWORD, DataType.WORD))
|
||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the word value to that memory location
|
||||
mem.setWord(variable.integerValue(), value.integerValue())
|
||||
mem.setUWord(variable.integerValue(), value.integerValue())
|
||||
} else {
|
||||
// set indexed word element in the array
|
||||
val array = heap.get(variable.heapId)
|
||||
if(array.type!=DataType.ARRAY_UW)
|
||||
throw VmExecutionException("not a proper array var with word elements")
|
||||
array.array!![index] = value.integerValue()
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UW -> array.array!![index] = value.integerValue()
|
||||
DataType.ARRAY_W -> array.array!![index] = value.integerValue()
|
||||
else -> throw VmExecutionException("not a proper array var with word elements")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Opcode.WRITE_INDEXED_VAR_FLOAT -> {
|
||||
@ -1457,24 +1601,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
array.doubleArray!![index] = value.numericValue().toDouble()
|
||||
}
|
||||
}
|
||||
Opcode.ADD_B -> TODO()
|
||||
Opcode.ADD_W -> TODO()
|
||||
Opcode.SUB_B -> TODO()
|
||||
Opcode.SUB_W -> TODO()
|
||||
Opcode.MUL_B -> TODO()
|
||||
Opcode.MUL_W -> TODO()
|
||||
Opcode.DIV_B -> TODO()
|
||||
Opcode.DIV_W -> TODO()
|
||||
Opcode.FLOORDIV_B -> TODO()
|
||||
Opcode.FLOORDIV_W -> TODO()
|
||||
Opcode.REMAINDER_B -> TODO()
|
||||
Opcode.REMAINDER_W -> TODO()
|
||||
Opcode.POW_B -> TODO()
|
||||
Opcode.POW_W -> TODO()
|
||||
Opcode.UB2UWORD -> TODO()
|
||||
Opcode.UB2FLOAT -> TODO()
|
||||
Opcode.UW2FLOAT -> TODO()
|
||||
else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
|
||||
//else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
|
||||
}
|
||||
|
||||
if(traceOutput!=null) {
|
||||
@ -1491,7 +1618,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
when (syscall) {
|
||||
Syscall.WRITE_MEMCHR -> {
|
||||
val address = evalstack.pop().integerValue()
|
||||
print(Petscii.decodePetscii(listOf(mem.getByte(address)), true))
|
||||
print(Petscii.decodePetscii(listOf(mem.getUByte(address)), true))
|
||||
}
|
||||
Syscall.WRITE_MEMSTR -> {
|
||||
val address = evalstack.pop().integerValue()
|
||||
@ -1550,7 +1677,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Syscall.FUNC_LEN -> throw VmExecutionException("len() should have been const-folded away everywhere (it's not possible on non-const values)")
|
||||
Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.UWORD, evalstack.pop().numericValue().toDouble().roundToInt()))
|
||||
Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))
|
||||
Syscall.FUNC_ABS -> {
|
||||
val value = evalstack.pop()
|
||||
val absValue=
|
||||
@ -1574,25 +1701,15 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Syscall.FUNC_DEG -> evalstack.push(Value(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_FLOOR -> {
|
||||
val value = evalstack.pop()
|
||||
val result =
|
||||
when(value.type) {
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, value.numericValue())
|
||||
DataType.UWORD -> Value(DataType.UWORD, value.numericValue())
|
||||
DataType.FLOAT -> Value(DataType.UWORD, floor(value.numericValue().toDouble()))
|
||||
else -> throw VmExecutionException("cannot get floor of $value")
|
||||
}
|
||||
evalstack.push(result)
|
||||
if(value.type in NumericDatatypes)
|
||||
evalstack.push(Value(DataType.WORD, floor(value.numericValue().toDouble()).toInt()))
|
||||
else throw VmExecutionException("cannot get floor of $value")
|
||||
}
|
||||
Syscall.FUNC_CEIL -> {
|
||||
val value = evalstack.pop()
|
||||
val result =
|
||||
when(value.type) {
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, value.numericValue())
|
||||
DataType.UWORD -> Value(DataType.UWORD, value.numericValue())
|
||||
DataType.FLOAT -> Value(DataType.UWORD, ceil(value.numericValue().toDouble()))
|
||||
else -> throw VmExecutionException("cannot get ceil of $value")
|
||||
}
|
||||
evalstack.push(result)
|
||||
if(value.type in NumericDatatypes)
|
||||
evalstack.push(Value(DataType.WORD, ceil(value.numericValue().toDouble()).toInt()))
|
||||
else throw VmExecutionException("cannot get ceil of $value")
|
||||
}
|
||||
Syscall.FUNC_MAX -> {
|
||||
val iterable = evalstack.pop()
|
||||
@ -1697,9 +1814,9 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
|
||||
val jiffies = min((timestamp-bootTime)*60/1000, 24*3600*60-1)
|
||||
// update the C-64 60hz jiffy clock in the ZP addresses:
|
||||
mem.setByte(0x00a0, (jiffies ushr 16).toShort())
|
||||
mem.setByte(0x00a1, (jiffies ushr 8 and 255).toShort())
|
||||
mem.setByte(0x00a2, (jiffies and 255).toShort())
|
||||
mem.setUByte(0x00a0, (jiffies ushr 16).toShort())
|
||||
mem.setUByte(0x00a1, (jiffies ushr 8 and 255).toShort())
|
||||
mem.setUByte(0x00a2, (jiffies and 255).toShort())
|
||||
|
||||
if(irqStartInstruction!=null) {
|
||||
try {
|
||||
|
@ -18,19 +18,27 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
init {
|
||||
when(type) {
|
||||
DataType.UBYTE -> {
|
||||
byteval = (numericvalueOrHeapId.toInt() and 255).toShort() // ubyte wrap around 0..255
|
||||
if(numericvalueOrHeapId.toInt() !in 0..255)
|
||||
throw VmExecutionException("value out of range: $numericvalueOrHeapId")
|
||||
byteval = numericvalueOrHeapId.toShort()
|
||||
asBooleanValue = byteval != (0.toShort())
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
byteval = limitByte(numericvalueOrHeapId.toInt())
|
||||
if(numericvalueOrHeapId.toInt() !in -128..127)
|
||||
throw VmExecutionException("value out of range: $numericvalueOrHeapId")
|
||||
byteval = numericvalueOrHeapId.toShort()
|
||||
asBooleanValue = byteval != (0.toShort())
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
wordval = numericvalueOrHeapId.toInt() and 65535 // uword wrap around 0..65535
|
||||
if(numericvalueOrHeapId.toInt() !in 0..65535)
|
||||
throw VmExecutionException("value out of range: $numericvalueOrHeapId")
|
||||
wordval = numericvalueOrHeapId.toInt()
|
||||
asBooleanValue = wordval != 0
|
||||
}
|
||||
DataType.WORD -> {
|
||||
wordval = limitWord(numericvalueOrHeapId.toInt())
|
||||
if(numericvalueOrHeapId.toInt() !in -32768..32767)
|
||||
throw VmExecutionException("value out of range: $numericvalueOrHeapId")
|
||||
wordval = numericvalueOrHeapId.toInt()
|
||||
asBooleanValue = wordval != 0
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
@ -46,35 +54,22 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun limitByte(value: Int): Short {
|
||||
var bval: Int
|
||||
if(value < 0) {
|
||||
bval = -(abs(value) and 127)
|
||||
if(bval==0) bval=-128
|
||||
}
|
||||
else
|
||||
bval = value and 127
|
||||
return bval.toShort()
|
||||
}
|
||||
fun limitWord(value: Int): Int {
|
||||
var bval: Int
|
||||
if(value < 0) {
|
||||
bval = -(abs(value) and 32767)
|
||||
if(bval==0) bval=-32768
|
||||
}
|
||||
else
|
||||
bval = value and 32767
|
||||
return bval
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return when(type) {
|
||||
DataType.UBYTE -> "ub:%02x".format(byteval)
|
||||
DataType.BYTE -> "b:%02x".format(byteval)
|
||||
DataType.BYTE -> {
|
||||
if(byteval!!<0)
|
||||
"b:-%02x".format(abs(byteval!!.toInt()))
|
||||
else
|
||||
"b:%02x".format(byteval)
|
||||
}
|
||||
DataType.UWORD -> "uw:%04x".format(wordval)
|
||||
DataType.WORD -> "w:%04x".format(wordval)
|
||||
DataType.WORD -> {
|
||||
if(wordval!!<0)
|
||||
"w:-%04x".format(abs(wordval!!))
|
||||
else
|
||||
"w:%04x".format(wordval)
|
||||
}
|
||||
DataType.FLOAT -> "f:$floatval"
|
||||
else -> "heap:$heapId"
|
||||
}
|
||||
@ -125,8 +120,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
if(result.toDouble() < 0 ) {
|
||||
return when(leftDt) {
|
||||
DataType.UBYTE, DataType.UWORD -> throw VmExecutionException("arithmetic error: cannot store a negative value in a $leftDt")
|
||||
DataType.BYTE -> Value(DataType.BYTE, limitByte(result.toInt()))
|
||||
DataType.WORD -> Value(DataType.WORD, limitWord(result.toInt()))
|
||||
DataType.BYTE -> Value(DataType.BYTE, result.toInt())
|
||||
DataType.WORD -> Value(DataType.WORD, result.toInt())
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
||||
else -> throw VmExecutionException("$op on non-numeric type")
|
||||
}
|
||||
@ -134,9 +129,9 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
|
||||
return when(leftDt) {
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, result.toInt() and 255)
|
||||
DataType.BYTE -> Value(DataType.BYTE, limitByte(result.toInt()))
|
||||
DataType.BYTE -> Value(DataType.BYTE, result.toInt())
|
||||
DataType.UWORD -> Value(DataType.UWORD, result.toInt() and 65535)
|
||||
DataType.WORD -> Value(DataType.WORD, limitWord(result.toInt()))
|
||||
DataType.WORD -> Value(DataType.WORD, result.toInt())
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
||||
else -> throw VmExecutionException("$op on non-numeric type")
|
||||
}
|
||||
@ -221,12 +216,20 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
|
||||
fun shl(): Value {
|
||||
val v = integerValue()
|
||||
return Value(type, v shl 1)
|
||||
if(type==DataType.UBYTE)
|
||||
return Value(type, (v shl 1) and 255)
|
||||
if(type==DataType.UWORD)
|
||||
return Value(type, (v shl 1) and 65535)
|
||||
throw VmExecutionException("invalid type for shl: $type")
|
||||
}
|
||||
|
||||
fun shr(): Value {
|
||||
val v = integerValue()
|
||||
return Value(type, v ushr 1)
|
||||
if(type==DataType.UBYTE)
|
||||
return Value(type, (v ushr 1) and 255)
|
||||
if(type==DataType.UWORD)
|
||||
return Value(type, (v ushr 1) and 65535)
|
||||
throw VmExecutionException("invalid type for shr: $type")
|
||||
}
|
||||
|
||||
fun rol(carry: Boolean): Pair<Value, Boolean> {
|
||||
@ -307,8 +310,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
|
||||
fun neg(): Value {
|
||||
return when(type) {
|
||||
DataType.UBYTE -> Value(DataType.UBYTE, -(byteval!!))
|
||||
DataType.UWORD -> Value(DataType.UWORD, -(wordval!!))
|
||||
DataType.BYTE -> Value(DataType.BYTE, -(byteval!!))
|
||||
DataType.WORD -> Value(DataType.WORD, -(wordval!!))
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, -(floatval)!!)
|
||||
else -> throw VmExecutionException("neg can only work on byte/word/float")
|
||||
}
|
||||
|
@ -141,27 +141,51 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testPushMem() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_MEM_BYTE, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.PUSH_MEM_WORD, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, 0x4000))
|
||||
Instruction(Opcode.PUSH_MEM_B, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.PUSH_MEM_UB, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.PUSH_MEM_W, Value(DataType.UWORD, 0x4000)),
|
||||
Instruction(Opcode.PUSH_MEM_UW, Value(DataType.UWORD, 0x5000)),
|
||||
Instruction(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, 0x6000))
|
||||
)
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.UWORD, 0x42ea)),
|
||||
0x3000 to listOf(Value(DataType.UWORD, 0x42ea)),
|
||||
0x4000 to listOf(Value(DataType.FLOAT, 42.25)))
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0x3000 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0x4000 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0x5000 to listOf(Value(DataType.UWORD, 0xc2ca)),
|
||||
0x6000 to listOf(Value(DataType.FLOAT, 42.25)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
assertEquals(0xea, vm.mem.getByte(0x2000))
|
||||
assertEquals(0x42, vm.mem.getByte(0x2001))
|
||||
assertEquals(0xea, vm.mem.getByte(0x3000))
|
||||
assertEquals(0x42, vm.mem.getByte(0x3001))
|
||||
assertEquals(0x42ea, vm.mem.getWord(0x2000))
|
||||
assertEquals(0x42ea, vm.mem.getWord(0x3000))
|
||||
assertEquals(42.25, vm.mem.getFloat(0x4000))
|
||||
assertEquals(0xca, vm.mem.getUByte(0x2000))
|
||||
assertEquals(0xc2, vm.mem.getUByte(0x2001))
|
||||
assertEquals(0xca, vm.mem.getUByte(0x3000))
|
||||
assertEquals(0xc2, vm.mem.getUByte(0x3001))
|
||||
assertEquals(0xca, vm.mem.getUByte(0x4000))
|
||||
assertEquals(0xc2, vm.mem.getUByte(0x4001))
|
||||
assertEquals(0xca, vm.mem.getUByte(0x5000))
|
||||
assertEquals(0xc2, vm.mem.getUByte(0x5001))
|
||||
assertEquals(-54, vm.mem.getSByte(0x2000))
|
||||
assertEquals(-62, vm.mem.getSByte(0x2001))
|
||||
assertEquals(-54, vm.mem.getSByte(0x3000))
|
||||
assertEquals(-62, vm.mem.getSByte(0x3001))
|
||||
assertEquals(-54, vm.mem.getSByte(0x4000))
|
||||
assertEquals(-62, vm.mem.getSByte(0x4001))
|
||||
assertEquals(-54, vm.mem.getSByte(0x5000))
|
||||
assertEquals(-62, vm.mem.getSByte(0x5001))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0x2000))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0x3000))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0x4000))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0x5000))
|
||||
assertEquals(-15670, vm.mem.getSWord(0x2000))
|
||||
assertEquals(-15670, vm.mem.getSWord(0x3000))
|
||||
assertEquals(-15670, vm.mem.getSWord(0x4000))
|
||||
assertEquals(-15670, vm.mem.getSWord(0x5000))
|
||||
assertEquals(42.25, vm.mem.getFloat(0x6000))
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(3)
|
||||
assertEquals(3, vm.evalstack.size)
|
||||
vm.step(5)
|
||||
assertEquals(5, vm.evalstack.size)
|
||||
assertEquals(Value(DataType.FLOAT, 42.25), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.UWORD, 0x42ea), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.UBYTE, 0xea), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.UWORD, 0xc2ca), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.WORD, -15670), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.UBYTE, 0xca), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.BYTE, -54), vm.evalstack.pop())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -199,20 +223,32 @@ class TestStackVmOpcodes {
|
||||
fun testPopMem() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 42.25)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0x42ea)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 123)),
|
||||
Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xc2ca)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)),
|
||||
Instruction(Opcode.POP_MEM_B, Value(DataType.UWORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM_UB, Value(DataType.UWORD, 0x2001)),
|
||||
Instruction(Opcode.POP_MEM_W, Value(DataType.UWORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_UW, Value(DataType.UWORD, 0x3002)),
|
||||
Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertEquals(0, vm.mem.getWord(0x2000))
|
||||
assertEquals(0, vm.mem.getWord(0x3000))
|
||||
assertEquals(0, vm.mem.getUWord(0x2000))
|
||||
assertEquals(0, vm.mem.getUWord(0x2001))
|
||||
assertEquals(0, vm.mem.getUWord(0x3000))
|
||||
assertEquals(0, vm.mem.getUWord(0x3002))
|
||||
assertEquals(0.0, vm.mem.getFloat(0x4000))
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(6)
|
||||
vm.step(11)
|
||||
assertThat(vm.evalstack, empty())
|
||||
assertEquals(123, vm.mem.getByte(0x2000))
|
||||
assertEquals(0x42ea, vm.mem.getWord(0x3000))
|
||||
assertEquals(201, vm.mem.getUByte(0x2000))
|
||||
assertEquals(177, vm.mem.getUByte(0x2001))
|
||||
assertEquals(-55, vm.mem.getSByte(0x2000))
|
||||
assertEquals(-79, vm.mem.getSByte(0x2001))
|
||||
assertEquals(42080, vm.mem.getUWord(0x3000))
|
||||
assertEquals(0xc2ca, vm.mem.getUWord(0x3002))
|
||||
assertEquals(-23456, vm.mem.getSWord(0x3000))
|
||||
assertEquals(-15670, vm.mem.getSWord(0x3002))
|
||||
assertEquals(42.25, vm.mem.getFloat(0x4000))
|
||||
}
|
||||
|
||||
@ -418,15 +454,27 @@ class TestStackVmOpcodes {
|
||||
|
||||
@Test
|
||||
fun testNeg() {
|
||||
testUnaryOperator(Value(DataType.UBYTE, 12), Opcode.NEG_B, Value(DataType.UBYTE, 244))
|
||||
testUnaryOperator(Value(DataType.UWORD, 1234), Opcode.NEG_W, Value(DataType.UWORD, 64302))
|
||||
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, -12))
|
||||
testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG_W, Value(DataType.WORD, -1234))
|
||||
testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG_F, Value(DataType.FLOAT, -123.456))
|
||||
assertFailsWith<VmExecutionException> {
|
||||
testUnaryOperator(Value(DataType.UBYTE, 12), Opcode.NEG_B, Value(DataType.UBYTE, 244))
|
||||
}
|
||||
assertFailsWith<VmExecutionException> {
|
||||
testUnaryOperator(Value(DataType.UWORD, 1234), Opcode.NEG_W, Value(DataType.UWORD, 64302))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInv() {
|
||||
testUnaryOperator(Value(DataType.UBYTE, 123), Opcode.INV_BYTE, Value(DataType.UBYTE, 0x84))
|
||||
testUnaryOperator(Value(DataType.UWORD, 4044), Opcode.INV_WORD, Value(DataType.UWORD, 0xf033))
|
||||
assertFailsWith<VmExecutionException> {
|
||||
testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV_BYTE, Value(DataType.BYTE, 0x84))
|
||||
}
|
||||
assertFailsWith<VmExecutionException> {
|
||||
testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_WORD, Value(DataType.WORD, 0xf033))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -464,13 +512,29 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testB2Word() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0x45)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, 0x7a31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, 127)),
|
||||
Instruction(Opcode.B2WORD),
|
||||
Instruction(Opcode.B2WORD)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 127), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUB2Uword() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0x45)),
|
||||
Instruction(Opcode.UB2UWORD),
|
||||
Instruction(Opcode.UB2UWORD)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.UWORD, 0x0045), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
@ -496,14 +560,30 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testB2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 123)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, 0x7a31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, 127)),
|
||||
Instruction(Opcode.B2FLOAT),
|
||||
Instruction(Opcode.B2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 123.0), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.FLOAT, 127.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUB2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.UB2FLOAT),
|
||||
Instruction(Opcode.UB2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 177.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
@ -512,14 +592,30 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testW2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 11)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 12345)),
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 52345)),
|
||||
Instruction(Opcode.W2FLOAT),
|
||||
Instruction(Opcode.W2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 12345.0), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.FLOAT, 52345.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUW2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)),
|
||||
Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 52345)),
|
||||
Instruction(Opcode.UW2FLOAT),
|
||||
Instruction(Opcode.UW2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 52345.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user