unit tests for most of the StackVM opcodes. Fixed some opcode behaviors.

This commit is contained in:
Irmen de Jong 2018-09-21 02:20:37 +02:00
parent 455f60fb84
commit 2f48406aad
6 changed files with 1349 additions and 75 deletions

View File

@ -430,7 +430,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
val to = range.to.constValue(namespace) val to = range.to.constValue(namespace)
var step = 1 var step = 1
if(range.step!=null) { if(range.step!=null) {
val stepLv = range.step?.constValue(namespace) ?: LiteralValue(DataType.BYTE, 1, position = range.position) val stepLv = range.step.constValue(namespace) ?: LiteralValue(DataType.BYTE, 1, position = range.position)
if (stepLv.asIntegerValue == null || stepLv.asIntegerValue == 0) { if (stepLv.asIntegerValue == null || stepLv.asIntegerValue == 0) {
err("range step must be an integer != 0") err("range step must be an integer != 0")
return range return range

View File

@ -1,6 +1,5 @@
package prog8.compiler package prog8.compiler
import jdk.nashorn.internal.ir.JumpStatement
import prog8.ast.* import prog8.ast.*
import prog8.stackvm.* import prog8.stackvm.*
import java.io.PrintStream import java.io.PrintStream

View File

@ -195,7 +195,7 @@ class ConstantFolding(private val namespace: INameScope) : IAstProcessor {
override fun process(range: RangeExpr): IExpression { override fun process(range: RangeExpr): IExpression {
range.from = range.from.process(this) range.from = range.from.process(this)
range.to = range.to.process(this) range.to = range.to.process(this)
range.step = range.step?.process(this) range.step = range.step.process(this)
return super.process(range) return super.process(range)
} }

View File

@ -10,12 +10,12 @@ import javax.swing.Timer
class BitmapScreenPanel : JPanel() { class BitmapScreenPanel : JPanel() {
private val image = BufferedImage(ScreenWidth, ScreenHeight, BufferedImage.TYPE_INT_ARGB) private val image = BufferedImage(SCREENWIDTH, SCREENHEIGHT, BufferedImage.TYPE_INT_ARGB)
private val g2d = image.graphics as Graphics2D private val g2d = image.graphics as Graphics2D
init { init {
val size = Dimension(image.width * Scaling, image.height * Scaling) val size = Dimension(image.width * SCALING, image.height * SCALING)
minimumSize = size minimumSize = size
maximumSize = size maximumSize = size
preferredSize = size preferredSize = size
@ -32,7 +32,7 @@ class BitmapScreenPanel : JPanel() {
fun clearScreen(color: Int) { fun clearScreen(color: Int) {
g2d.background = palette[color and 15] g2d.background = palette[color and 15]
g2d.clearRect(0, 0, BitmapScreenPanel.ScreenWidth, BitmapScreenPanel.ScreenHeight) g2d.clearRect(0, 0, BitmapScreenPanel.SCREENWIDTH, BitmapScreenPanel.SCREENHEIGHT)
} }
fun setPixel(x: Int, y: Int, color: Int) { fun setPixel(x: Int, y: Int, color: Int) {
image.setRGB(x, y, palette[color and 15].rgb) image.setRGB(x, y, palette[color and 15].rgb)
@ -44,9 +44,9 @@ class BitmapScreenPanel : JPanel() {
} }
companion object { companion object {
const val ScreenWidth = 320 const val SCREENWIDTH = 320
const val ScreenHeight = 256 const val SCREENHEIGHT = 256
const val Scaling = 3 const val SCALING = 3
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/ val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white Color(0xFFFFFF), // 1 = white
@ -93,19 +93,19 @@ class ScreenDialog : JFrame() {
// the borders (top, left, right, bottom) // the borders (top, left, right, bottom)
val borderTop = JPanel().apply { val borderTop = JPanel().apply {
preferredSize = Dimension(BitmapScreenPanel.Scaling * (BitmapScreenPanel.ScreenWidth+2*borderWidth), BitmapScreenPanel.Scaling * borderWidth) preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14] background = BitmapScreenPanel.palette[14]
} }
val borderBottom = JPanel().apply { val borderBottom = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.Scaling * (BitmapScreenPanel.ScreenWidth+2*borderWidth), BitmapScreenPanel.Scaling * borderWidth) preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14] background = BitmapScreenPanel.palette[14]
} }
val borderLeft = JPanel().apply { val borderLeft = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.Scaling * borderWidth, BitmapScreenPanel.Scaling * BitmapScreenPanel.ScreenHeight) preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14] background = BitmapScreenPanel.palette[14]
} }
val borderRight = JPanel().apply { val borderRight = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.Scaling * borderWidth, BitmapScreenPanel.Scaling * BitmapScreenPanel.ScreenHeight) preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14] background = BitmapScreenPanel.palette[14]
} }
c = GridBagConstraints() c = GridBagConstraints()

View File

@ -117,6 +117,8 @@ enum class Opcode {
SWAP, SWAP,
SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations CLC, // clear carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations
SEI, // set irq-disable status flag
CLI, // clear irq-disable status flag
NOP, NOP,
BREAKPOINT, // breakpoint BREAKPOINT, // breakpoint
TERMINATE, // end the program TERMINATE, // end the program
@ -134,8 +136,6 @@ enum class Syscall(val callNr: Short) {
GFX_CLEARSCR(17), // clear the screen with color pushed on stack GFX_CLEARSCR(17), // clear the screen with color pushed on stack
GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order
FUNC_P_CARRY(64),
FUNC_P_IRQD(65),
FUNC_SIN(66), FUNC_SIN(66),
FUNC_COS(67), FUNC_COS(67),
FUNC_ABS(68), FUNC_ABS(68),
@ -162,10 +162,9 @@ enum class Syscall(val callNr: Short) {
FUNC_RND(89), // push a random byte on the stack FUNC_RND(89), // push a random byte on the stack
FUNC_RNDW(90), // push a random word on the stack FUNC_RNDW(90), // push a random word on the stack
FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0) FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0)
FUNC_FLT(92)
// note: not all builtin functions of the Prog8 language are present as functions: // note: not all builtin functions of the Prog8 language are present as functions:
// some of them are already opcodes (such as MSB and ROL)! // some of them are already opcodes (such as MSB and ROL and FLT)!
} }
class Memory { class Memory {
@ -181,13 +180,13 @@ class Memory {
} }
fun getWord(address: Int): Int { fun getWord(address: Int): Int {
return 256*mem[address] + mem[address+1] return mem[address] + 256*mem[address+1]
} }
fun setWord(address: Int, value: Int) { fun setWord(address: Int, value: Int) {
if(value<0 || value>65535) throw VmExecutionException("word value not 0..65535") if(value<0 || value>65535) throw VmExecutionException("word value not 0..65535")
mem[address] = (value / 256).toShort() mem[address] = value.and(255).toShort()
mem[address+1] = value.and(255).toShort() mem[address+1] = (value / 256).toShort()
} }
fun setFloat(address: Int, value: Double) { fun setFloat(address: Int, value: Double) {
@ -222,6 +221,10 @@ class Memory {
} }
return Petscii.decodePetscii(petscii, true) return Petscii.decodePetscii(petscii, true)
} }
fun clear() {
for(i in 0..65535) mem[i]=0
}
} }
@ -234,18 +237,22 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
init { init {
when(type) { when(type) {
DataType.BYTE -> { DataType.BYTE -> {
byteval = (numericvalue!!.toInt() and 255).toShort() byteval = numericvalue!!.toShort()
if(byteval!! <0 || byteval!! > 255)
throw VmExecutionException("byte value overflow: $byteval")
asBooleanValue = byteval != (0.toShort()) asBooleanValue = byteval != (0.toShort())
} }
DataType.WORD -> { DataType.WORD -> {
wordval = numericvalue!!.toInt() and 65535 wordval = numericvalue!!.toInt()
if(wordval!! <0 || wordval!! > 65535)
throw VmExecutionException("word value overflow: $wordval")
asBooleanValue = wordval != 0 asBooleanValue = wordval != 0
} }
DataType.FLOAT -> { DataType.FLOAT -> {
floatval = numericvalue!!.toDouble() floatval = numericvalue!!.toDouble()
asBooleanValue = floatval != 0.0 asBooleanValue = floatval != 0.0
} }
DataType.ARRAY -> { DataType.ARRAY, DataType.ARRAY_W -> {
asBooleanValue = arrayvalue!!.isNotEmpty() asBooleanValue = arrayvalue!!.isNotEmpty()
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
@ -262,9 +269,9 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
DataType.WORD -> "w:%04x".format(wordval) DataType.WORD -> "w:%04x".format(wordval)
DataType.FLOAT -> "f:$floatval" DataType.FLOAT -> "f:$floatval"
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> "\"$stringvalue\"" DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> "\"$stringvalue\""
DataType.ARRAY -> TODO("array") DataType.ARRAY -> TODO("tostring array")
DataType.ARRAY_W -> TODO("word array") DataType.ARRAY_W -> TODO("tostring word array")
DataType.MATRIX -> TODO("matrix") DataType.MATRIX -> TODO("tostring matrix")
} }
} }
@ -286,13 +293,23 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
} }
} }
override fun hashCode(): Int {
val bh = byteval?.hashCode() ?: 0x10001234
val wh = wordval?.hashCode() ?: 0x01002345
val fh = floatval?.hashCode() ?: 0x00103456
val ah = arrayvalue?.hashCode() ?: 0x11119876
return bh xor wh xor fh xor ah xor type.hashCode()
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if(other==null || other !is Value) if(other==null || other !is Value)
return false return false
return compareTo(other)==0 return compareTo(other)==0 // note: datatype doesn't matter
} }
operator fun compareTo(other: Value): Int { operator fun compareTo(other: Value): Int {
if(stringvalue!=null && other.stringvalue!=null)
return stringvalue.compareTo(other.stringvalue)
return numericValue().toDouble().compareTo(other.numericValue().toDouble()) return numericValue().toDouble().compareTo(other.numericValue().toDouble())
} }
@ -446,21 +463,21 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
fun bitand(other: Value): Value { fun bitand(other: Value): Value {
val v1 = integerValue() val v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1.and(v2) val result = v1 and v2
return Value(type, result) return Value(type, result)
} }
fun bitor(other: Value): Value { fun bitor(other: Value): Value {
val v1 = integerValue() val v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1.or(v2) val result = v1 or v2
return Value(type, result) return Value(type, result)
} }
fun bitxor(other: Value): Value { fun bitxor(other: Value): Value {
val v1 = integerValue() val v1 = integerValue()
val v2 = other.integerValue() val v2 = other.integerValue()
val result = v1.xor(v2) val result = v1 xor v2
return Value(type, result) return Value(type, result)
} }
@ -470,16 +487,16 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
fun inv(): Value { fun inv(): Value {
return when(type) { return when(type) {
DataType.BYTE -> Value(DataType.BYTE, byteval!!.toInt().inv()) DataType.BYTE -> Value(DataType.BYTE, byteval!!.toInt().inv() and 255)
DataType.WORD -> Value(DataType.WORD, wordval!!.inv()) DataType.WORD -> Value(DataType.WORD, wordval!!.inv() and 65535)
else -> throw VmExecutionException("not can only work on byte/word") else -> throw VmExecutionException("inv can only work on byte/word")
} }
} }
fun inc(): Value { fun inc(): Value {
return when(type) { return when(type) {
DataType.BYTE -> Value(DataType.BYTE, (byteval!! + 1).and(255)) DataType.BYTE -> Value(DataType.BYTE, (byteval!! + 1) and 255)
DataType.WORD -> Value(DataType.WORD, (wordval!! + 1).and(65535)) DataType.WORD -> Value(DataType.WORD, (wordval!! + 1) and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, floatval!! + 1) DataType.FLOAT -> Value(DataType.FLOAT, floatval!! + 1)
else -> throw VmExecutionException("inc can only work on byte/word/float") else -> throw VmExecutionException("inc can only work on byte/word/float")
} }
@ -487,8 +504,8 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
fun dec(): Value { fun dec(): Value {
return when(type) { return when(type) {
DataType.BYTE -> Value(DataType.BYTE, (byteval!! - 1).and(255)) DataType.BYTE -> Value(DataType.BYTE, (byteval!! - 1) and 255)
DataType.WORD -> Value(DataType.WORD, (wordval!! - 1).and(65535)) DataType.WORD -> Value(DataType.WORD, (wordval!! - 1) and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, floatval!! - 1) DataType.FLOAT -> Value(DataType.FLOAT, floatval!! - 1)
else -> throw VmExecutionException("dec can only work on byte/word/float") else -> throw VmExecutionException("dec can only work on byte/word/float")
} }
@ -496,7 +513,7 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
fun lsb(): Value { fun lsb(): Value {
return when(type) { return when(type) {
DataType.BYTE -> Value(DataType.BYTE, byteval!!.toInt() and 255) DataType.BYTE -> Value(DataType.BYTE, byteval!!)
DataType.WORD -> Value(DataType.WORD, wordval!! and 255) DataType.WORD -> Value(DataType.WORD, wordval!! and 255)
else -> throw VmExecutionException("not can only work on byte/word") else -> throw VmExecutionException("not can only work on byte/word")
} }
@ -504,7 +521,7 @@ class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=
fun msb(): Value { fun msb(): Value {
return when(type) { return when(type) {
DataType.BYTE -> Value(DataType.BYTE, byteval!!.toInt() ushr 8 and 255) DataType.BYTE -> Value(DataType.BYTE, 0)
DataType.WORD -> Value(DataType.WORD, wordval!! ushr 8 and 255) DataType.WORD -> Value(DataType.WORD, wordval!! ushr 8 and 255)
else -> throw VmExecutionException("not can only work on byte/word") else -> throw VmExecutionException("not can only work on byte/word")
} }
@ -543,13 +560,13 @@ class LabelInstr(val name: String) : Instruction(opcode = Opcode.NOP) {
} }
} }
private class VmExecutionException(msg: String?) : Exception(msg) class VmExecutionException(msg: String?) : Exception(msg)
private class VmTerminationException(msg: String?) : Exception(msg) class VmTerminationException(msg: String?) : Exception(msg)
private class VmBreakpointException : Exception("breakpoint") class VmBreakpointException : Exception("breakpoint")
private class MyStack<T> : Stack<T>() { class MyStack<T> : Stack<T>() {
fun peek(amount: Int) : List<T> { fun peek(amount: Int) : List<T> {
return this.toList().subList(max(0, size-amount), size) return this.toList().subList(max(0, size-amount), size)
} }
@ -822,48 +839,56 @@ class Program (val name: String,
class StackVm(val traceOutputFile: String?) { class StackVm(val traceOutputFile: String?) {
private val mem = Memory() val mem = Memory()
private val evalstack = MyStack<Value>() // evaluation stack val evalstack = MyStack<Value>() // evaluation stack
private val callstack = MyStack<Instruction>() // subroutine call stack val callstack = MyStack<Instruction>() // subroutine call stack
private var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name var sourceLine = "" // meta info about current line in source file
private var P_carry: Boolean = false private set
private var P_irqd: Boolean = false var P_carry: Boolean = false
private set
var P_irqd: Boolean = false
private set
var variables = mutableMapOf<String, Value>() // all variables (set of all vars used by all blocks/subroutines) key = their fully scoped name
private set
private var program = listOf<Instruction>() private var program = listOf<Instruction>()
private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null
private lateinit var currentIns: Instruction private lateinit var currentIns: Instruction
private lateinit var canvas: BitmapScreenPanel private var canvas: BitmapScreenPanel? = null
private val rnd = Random() private val rnd = Random()
private var sourceLine = ""
fun load(program: Program, canvas: BitmapScreenPanel) { fun load(program: Program, canvas: BitmapScreenPanel?) {
this.program = program.program this.program = program.program
this.canvas = canvas this.canvas = canvas
this.variables = program.variables.toMutableMap() variables = program.variables.toMutableMap()
if(this.variables.contains("A") || if(this.variables.contains("A") ||
this.variables.contains("X") || variables.contains("X") ||
this.variables.contains("Y") || variables.contains("Y") ||
this.variables.contains("XY") || variables.contains("XY") ||
this.variables.contains("AX") || variables.contains("AX") ||
this.variables.contains("AY")) variables.contains("AY"))
throw VmExecutionException("program contains variable(s) for the reserved registers A,X,...") throw VmExecutionException("program contains variable(s) for the reserved registers A,X,...")
// define the 'registers' // define the 'registers'
this.variables["A"] = Value(DataType.BYTE, 0) variables["A"] = Value(DataType.BYTE, 0)
this.variables["X"] = Value(DataType.BYTE, 0) variables["X"] = Value(DataType.BYTE, 0)
this.variables["Y"] = Value(DataType.BYTE, 0) variables["Y"] = Value(DataType.BYTE, 0)
this.variables["AX"] = Value(DataType.WORD, 0) variables["AX"] = Value(DataType.WORD, 0)
this.variables["AY"] = Value(DataType.WORD, 0) variables["AY"] = Value(DataType.WORD, 0)
this.variables["XY"] = Value(DataType.WORD, 0) variables["XY"] = Value(DataType.WORD, 0)
initMemory(program.memory) initMemory(program.memory)
evalstack.clear()
callstack.clear()
P_carry = false
P_irqd = false
sourceLine = ""
currentIns = this.program[0] currentIns = this.program[0]
} }
fun step() { fun step(instructionCount: Int = 10000) {
// step is invoked every 1/100 sec // step is invoked every 1/100 sec
// we execute 10k instructions in one go so we end up doing 1 million vm instructions per second // we execute 10k instructions in one go so we end up doing 1 million vm instructions per second
val instructionsPerStep = 10000
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
for(i:Int in 0..instructionsPerStep) { for(i:Int in 1..instructionCount) {
try { try {
currentIns = dispatch(currentIns) currentIns = dispatch(currentIns)
@ -890,6 +915,7 @@ class StackVm(val traceOutputFile: String?) {
} }
private fun initMemory(memory: Map<Int, List<Value>>) { private fun initMemory(memory: Map<Int, List<Value>>) {
mem.clear()
for (meminit in memory) { for (meminit in memory) {
var address = meminit.key var address = meminit.key
for (value in meminit.value) { for (value in meminit.value) {
@ -936,14 +962,19 @@ class StackVm(val traceOutputFile: String?) {
Opcode.DUP -> evalstack.push(evalstack.peek()) Opcode.DUP -> evalstack.push(evalstack.peek())
Opcode.ARRAY -> { Opcode.ARRAY -> {
val amount = ins.arg!!.integerValue() val amount = ins.arg!!.integerValue()
if(amount<=0)
throw VmExecutionException("array size must be > 0")
val array = mutableListOf<Int>() val array = mutableListOf<Int>()
var arrayDt = DataType.ARRAY
for (i in 1..amount) { for (i in 1..amount) {
val value = evalstack.pop() val value = evalstack.pop()
if(value.type!=DataType.BYTE && value.type!=DataType.WORD) if(value.type!=DataType.BYTE && value.type!=DataType.WORD)
throw VmExecutionException("array requires values to be all byte/word") throw VmExecutionException("array requires values to be all byte/word")
array.add(value.integerValue()) if(value.type==DataType.WORD)
arrayDt = DataType.ARRAY_W
array.add(0, value.integerValue())
} }
evalstack.push(Value(DataType.ARRAY, null, arrayvalue = array.toIntArray())) evalstack.push(Value(arrayDt, null, arrayvalue = array.toIntArray()))
} }
Opcode.DISCARD -> evalstack.pop() Opcode.DISCARD -> evalstack.pop()
Opcode.SWAP -> { Opcode.SWAP -> {
@ -1080,17 +1111,17 @@ class StackVm(val traceOutputFile: String?) {
// plot pixel at (x, y, color) from stack // plot pixel at (x, y, color) from stack
val color = evalstack.pop() val color = evalstack.pop()
val (y, x) = evalstack.pop2() val (y, x) = evalstack.pop2()
canvas.setPixel(x.integerValue(), y.integerValue(), color.integerValue()) canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue())
} }
Syscall.GFX_CLEARSCR -> { Syscall.GFX_CLEARSCR -> {
val color = evalstack.pop() val color = evalstack.pop()
canvas.clearScreen(color.integerValue()) canvas?.clearScreen(color.integerValue())
} }
Syscall.GFX_TEXT -> { Syscall.GFX_TEXT -> {
val text = evalstack.pop() val text = evalstack.pop()
val color = evalstack.pop() val color = evalstack.pop()
val (y, x) = evalstack.pop2() val (y, x) = evalstack.pop2()
canvas.writeText(x.integerValue(), y.integerValue(), text.stringvalue!!, color.integerValue()) canvas?.writeText(x.integerValue(), y.integerValue(), text.stringvalue!!, color.integerValue())
} }
Syscall.FUNC_RND -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255)) Syscall.FUNC_RND -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255))
Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535)) Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535))
@ -1108,8 +1139,6 @@ class StackVm(val traceOutputFile: String?) {
Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble()))) 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_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt())) Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))
Syscall.FUNC_P_CARRY -> P_carry = evalstack.pop().asBooleanValue
Syscall.FUNC_P_IRQD -> P_irqd = evalstack.pop().asBooleanValue
Syscall.FUNC_ABS -> { Syscall.FUNC_ABS -> {
val value = evalstack.pop() val value = evalstack.pop()
val absValue= val absValue=
@ -1131,7 +1160,6 @@ class StackVm(val traceOutputFile: String?) {
Syscall.FUNC_SQRT -> evalstack.push(Value(DataType.FLOAT, sqrt(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_SQRT -> evalstack.push(Value(DataType.FLOAT, sqrt(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_RAD -> evalstack.push(Value(DataType.FLOAT, Math.toRadians(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_RAD -> evalstack.push(Value(DataType.FLOAT, Math.toRadians(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_DEG -> evalstack.push(Value(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_DEG -> evalstack.push(Value(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_FLT -> evalstack.push(Value(DataType.FLOAT, evalstack.pop().numericValue().toDouble()))
Syscall.FUNC_FLOOR -> { Syscall.FUNC_FLOOR -> {
val value = evalstack.pop() val value = evalstack.pop()
val result = val result =
@ -1196,6 +1224,8 @@ class StackVm(val traceOutputFile: String?) {
Opcode.SEC -> P_carry = true Opcode.SEC -> P_carry = true
Opcode.CLC -> P_carry = false Opcode.CLC -> P_carry = false
Opcode.SEI -> P_irqd = true
Opcode.CLI -> P_irqd = false
Opcode.TERMINATE -> throw VmTerminationException("terminate instruction") Opcode.TERMINATE -> throw VmTerminationException("terminate instruction")
Opcode.BREAKPOINT -> throw VmBreakpointException() Opcode.BREAKPOINT -> throw VmBreakpointException()

File diff suppressed because it is too large Load Diff