mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
60hz irq implemented in stackvm
This commit is contained in:
parent
99d63b13a8
commit
7f28f8be11
13
compiler/examples/irq.p8
Normal file
13
compiler/examples/irq.p8
Normal file
@ -0,0 +1,13 @@
|
||||
~ main {
|
||||
|
||||
sub start() -> () {
|
||||
|
||||
byte jiffyclockHi = $a0
|
||||
byte jiffyclockMid = $a1
|
||||
byte jiffyclockLo = $a2
|
||||
|
||||
_vm_gfx_pixel(2,2,jiffyclockHi)
|
||||
_vm_gfx_pixel(4,2,jiffyclockMid)
|
||||
_vm_gfx_pixel(6,2,jiffyclockLo)
|
||||
}
|
||||
}
|
@ -17,9 +17,11 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
val program = Program.load(args.first())
|
||||
//val irqProgram = Program("irq", mutableListOf(), emptyMap(), emptyMap(), emptyMap())
|
||||
val irqProgram = Program.load("irq_stackvm.txt")
|
||||
val vm = StackVm(traceOutputFile = null)
|
||||
val dialog = ScreenDialog()
|
||||
vm.load(program, dialog.canvas)
|
||||
vm.load(program, irqProgram, dialog.canvas)
|
||||
EventQueue.invokeLater {
|
||||
dialog.pack()
|
||||
dialog.isVisible = true
|
||||
@ -36,6 +38,10 @@ fun main(args: Array<String>) {
|
||||
(a.source as Timer).stop()
|
||||
}
|
||||
}
|
||||
|
||||
val irqTimer = Timer(1000/60) { a -> vm.irq(a.`when`) }
|
||||
|
||||
programTimer.start()
|
||||
irqTimer.start()
|
||||
}
|
||||
}
|
||||
|
64
compiler/src/prog8/stackvm/Memory.kt
Normal file
64
compiler/src/prog8/stackvm/Memory.kt
Normal file
@ -0,0 +1,64 @@
|
||||
package prog8.stackvm
|
||||
|
||||
import prog8.compiler.target.c64.Mflpt5
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
|
||||
class Memory {
|
||||
private val mem = ShortArray(65536) // shorts because byte is signed and we store values 0..255
|
||||
|
||||
fun getByte(address: Int): Short {
|
||||
return mem[address]
|
||||
}
|
||||
|
||||
fun setByte(address: Int, value: Short) {
|
||||
if(value<0 || value>255) throw VmExecutionException("byte value not 0..255")
|
||||
mem[address] = value
|
||||
}
|
||||
|
||||
fun getWord(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")
|
||||
mem[address] = value.and(255).toShort()
|
||||
mem[address+1] = (value / 256).toShort()
|
||||
}
|
||||
|
||||
fun setFloat(address: Int, value: Double) {
|
||||
val mflpt5 = Mflpt5.fromNumber(value)
|
||||
mem[address] = mflpt5.b0
|
||||
mem[address+1] = mflpt5.b1
|
||||
mem[address+2] = mflpt5.b2
|
||||
mem[address+3] = mflpt5.b3
|
||||
mem[address+4] = mflpt5.b4
|
||||
}
|
||||
|
||||
fun getFloat(address: Int): Double {
|
||||
return Mflpt5(mem[address], mem[address + 1], mem[address + 2], mem[address + 3], mem[address + 4]).toDouble()
|
||||
}
|
||||
|
||||
fun setString(address: Int, str: String) {
|
||||
// lowercase PETSCII
|
||||
val petscii = Petscii.encodePetscii(str, true)
|
||||
var addr = address
|
||||
for (c in petscii) mem[addr++] = c
|
||||
mem[addr] = 0
|
||||
}
|
||||
|
||||
fun getString(strAddress: Int): String {
|
||||
// lowercase PETSCII
|
||||
val petscii = mutableListOf<Short>()
|
||||
var addr = strAddress
|
||||
while(true) {
|
||||
val byte = mem[addr++]
|
||||
if(byte==0.toShort()) break
|
||||
petscii.add(byte)
|
||||
}
|
||||
return Petscii.decodePetscii(petscii, true)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
for(i in 0..65535) mem[i]=0
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ class BitmapScreenPanel : JPanel() {
|
||||
|
||||
companion object {
|
||||
const val SCREENWIDTH = 320
|
||||
const val SCREENHEIGHT = 256
|
||||
const val SCREENHEIGHT = 200
|
||||
const val SCALING = 3
|
||||
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
|
||||
Color(0x000000), // 0 = black
|
||||
|
@ -1,7 +1,6 @@
|
||||
package prog8.stackvm
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.compiler.target.c64.Mflpt5
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
@ -165,66 +164,6 @@ enum class Syscall(val callNr: Short) {
|
||||
// some of them are straight opcodes (such as MSB, LSB, LSL, LSR, ROL, ROR, ROL2, ROR2, and FLT)!
|
||||
}
|
||||
|
||||
class Memory {
|
||||
private val mem = ShortArray(65536) // shorts because byte is signed and we store values 0..255
|
||||
|
||||
fun getByte(address: Int): Short {
|
||||
return mem[address]
|
||||
}
|
||||
|
||||
fun setByte(address: Int, value: Short) {
|
||||
if(value<0 || value>255) throw VmExecutionException("byte value not 0..255")
|
||||
mem[address] = value
|
||||
}
|
||||
|
||||
fun getWord(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")
|
||||
mem[address] = value.and(255).toShort()
|
||||
mem[address+1] = (value / 256).toShort()
|
||||
}
|
||||
|
||||
fun setFloat(address: Int, value: Double) {
|
||||
val mflpt5 = Mflpt5.fromNumber(value)
|
||||
mem[address] = mflpt5.b0
|
||||
mem[address+1] = mflpt5.b1
|
||||
mem[address+2] = mflpt5.b2
|
||||
mem[address+3] = mflpt5.b3
|
||||
mem[address+4] = mflpt5.b4
|
||||
}
|
||||
|
||||
fun getFloat(address: Int): Double {
|
||||
return Mflpt5(mem[address], mem[address+1], mem[address+2], mem[address+3], mem[address+4]).toDouble()
|
||||
}
|
||||
|
||||
fun setString(address: Int, str: String) {
|
||||
// lowercase PETSCII
|
||||
val petscii = Petscii.encodePetscii(str, true)
|
||||
var addr = address
|
||||
for (c in petscii) mem[addr++] = c
|
||||
mem[addr] = 0
|
||||
}
|
||||
|
||||
fun getString(strAddress: Int): String {
|
||||
// lowercase PETSCII
|
||||
val petscii = mutableListOf<Short>()
|
||||
var addr = strAddress
|
||||
while(true) {
|
||||
val byte = mem[addr++]
|
||||
if(byte==0.toShort()) break
|
||||
petscii.add(byte)
|
||||
}
|
||||
return Petscii.decodePetscii(petscii, true)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
for(i in 0..65535) mem[i]=0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Value(val type: DataType, numericvalue: Number?, val stringvalue: String?=null, val arrayvalue: IntArray?=null) {
|
||||
private var byteval: Short? = null
|
||||
@ -912,10 +851,6 @@ class Program (val name: String,
|
||||
|
||||
class StackVm(val traceOutputFile: String?) {
|
||||
val mem = Memory()
|
||||
val evalstack = MyStack<Value>() // evaluation stack
|
||||
val callstack = MyStack<Instruction>() // subroutine call stack
|
||||
var sourceLine = "" // meta info about current line in source file
|
||||
private set
|
||||
var P_carry: Boolean = false
|
||||
private set
|
||||
var P_irqd: Boolean = false
|
||||
@ -923,22 +858,39 @@ class StackVm(val traceOutputFile: String?) {
|
||||
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 irqProgram = listOf<Instruction>()
|
||||
var evalstack = MyStack<Value>()
|
||||
private set
|
||||
var callstack = MyStack<Instruction>()
|
||||
private set
|
||||
private var traceOutput = if(traceOutputFile!=null) PrintStream(File(traceOutputFile), "utf-8") else null
|
||||
private lateinit var currentIns: Instruction
|
||||
private var canvas: BitmapScreenPanel? = null
|
||||
private val rnd = Random()
|
||||
private val bootTime = System.currentTimeMillis()
|
||||
private lateinit var currentIns: Instruction
|
||||
var sourceLine: String = ""
|
||||
private set
|
||||
|
||||
fun load(program: Program, canvas: BitmapScreenPanel?) {
|
||||
fun load(program: Program, irqProgram: Program?, canvas: BitmapScreenPanel?) {
|
||||
this.program = program.program
|
||||
this.irqProgram = irqProgram?.program ?: mutableListOf(Instruction(Opcode.NOP))
|
||||
this.canvas = canvas
|
||||
variables = program.variables.toMutableMap()
|
||||
if(this.variables.contains("A") ||
|
||||
irqCurrentVariables = irqProgram?.variables?.toMutableMap() ?: mutableMapOf()
|
||||
if(variables.contains("A") ||
|
||||
variables.contains("X") ||
|
||||
variables.contains("Y") ||
|
||||
variables.contains("XY") ||
|
||||
variables.contains("AX") ||
|
||||
variables.contains("AY"))
|
||||
throw VmExecutionException("program contains variable(s) for the reserved registers A,X,...")
|
||||
if(irqCurrentVariables.contains("A") ||
|
||||
irqCurrentVariables.contains("X") ||
|
||||
irqCurrentVariables.contains("Y") ||
|
||||
irqCurrentVariables.contains("XY") ||
|
||||
irqCurrentVariables.contains("AX") ||
|
||||
irqCurrentVariables.contains("AY"))
|
||||
throw VmExecutionException("irqProgram contains variable(s) for the reserved registers A,X,...")
|
||||
// define the 'registers'
|
||||
variables["A"] = Value(DataType.BYTE, 0)
|
||||
variables["X"] = Value(DataType.BYTE, 0)
|
||||
@ -946,14 +898,24 @@ class StackVm(val traceOutputFile: String?) {
|
||||
variables["AX"] = Value(DataType.WORD, 0)
|
||||
variables["AY"] = Value(DataType.WORD, 0)
|
||||
variables["XY"] = Value(DataType.WORD, 0)
|
||||
irqCurrentVariables["A"] = Value(DataType.BYTE, 0)
|
||||
irqCurrentVariables["X"] = Value(DataType.BYTE, 0)
|
||||
irqCurrentVariables["Y"] = Value(DataType.BYTE, 0)
|
||||
irqCurrentVariables["AX"] = Value(DataType.WORD, 0)
|
||||
irqCurrentVariables["AY"] = Value(DataType.WORD, 0)
|
||||
irqCurrentVariables["XY"] = Value(DataType.WORD, 0)
|
||||
|
||||
initMemory(program.memory)
|
||||
evalstack.clear()
|
||||
callstack.clear()
|
||||
irqEvalStack.clear()
|
||||
irqCallStack.clear()
|
||||
P_carry = false
|
||||
P_irqd = false
|
||||
sourceLine = ""
|
||||
irqCurrentLine = ""
|
||||
currentIns = this.program[0]
|
||||
irqCurrentIns = this.irqProgram[0]
|
||||
}
|
||||
|
||||
fun step(instructionCount: Int = 10000) {
|
||||
@ -1568,4 +1530,55 @@ class StackVm(val traceOutputFile: String?) {
|
||||
|
||||
return ins.next
|
||||
}
|
||||
|
||||
fun irq(timestamp: Long) {
|
||||
// 60hz IRQ handling
|
||||
if(P_irqd)
|
||||
return // interrupt is disabled
|
||||
|
||||
P_irqd=true
|
||||
swapIrqExecutionContexts(true)
|
||||
|
||||
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())
|
||||
|
||||
try {
|
||||
// execute the irq routine
|
||||
this.step(Int.MAX_VALUE)
|
||||
} catch(vmt: VmTerminationException) {
|
||||
// irq routine ended
|
||||
}
|
||||
|
||||
if(evalstack.isNotEmpty())
|
||||
throw VmExecutionException("irq: eval stack is not empty at exit from irq program")
|
||||
if(callstack.isNotEmpty())
|
||||
throw VmExecutionException("irq: call stack is not empty at exit from irq program")
|
||||
swapIrqExecutionContexts(false)
|
||||
P_irqd=false
|
||||
}
|
||||
|
||||
private lateinit var irqCurrentIns: Instruction
|
||||
private var irqCurrentVariables = mutableMapOf<String, Value>()
|
||||
private var irqCurrentLine: String = ""
|
||||
private var irqEvalStack = MyStack<Value>()
|
||||
private var irqCallStack = MyStack<Instruction>()
|
||||
private var irqCarry = false
|
||||
|
||||
private fun swapIrqExecutionContexts(startingIrq: Boolean) {
|
||||
irqCarry = P_carry.also { P_carry = irqCarry }
|
||||
irqProgram = program.also { program = irqProgram }
|
||||
irqCurrentIns = currentIns.also { currentIns = irqCurrentIns }
|
||||
irqCurrentVariables = variables.also {variables = irqCurrentVariables }
|
||||
irqCurrentLine = sourceLine.also { sourceLine = irqCurrentLine }
|
||||
irqEvalStack = evalstack.also { evalstack = irqEvalStack }
|
||||
irqCallStack = callstack.also { callstack = irqCallStack }
|
||||
if(startingIrq) {
|
||||
currentIns = program.first()
|
||||
sourceLine = ""
|
||||
P_carry = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testInitAndNop() {
|
||||
val ins = mutableListOf(Instruction(Opcode.NOP))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertEquals(6, vm.variables.size)
|
||||
assertTrue(vm.variables.containsKey("XY"))
|
||||
assertTrue(vm.variables.containsKey("A"))
|
||||
@ -65,7 +65,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testBreakpoint() {
|
||||
val ins = mutableListOf(Instruction(Opcode.BREAKPOINT))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertFailsWith<VmBreakpointException> {
|
||||
vm.step()
|
||||
}
|
||||
@ -76,7 +76,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testLine() {
|
||||
val ins = mutableListOf(Instruction(Opcode.LINE, Value(DataType.STR, null, "line 99")))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(1)
|
||||
assertEquals("line 99", vm.sourceLine)
|
||||
@ -85,7 +85,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testSECandSEIandCLCandCLI() {
|
||||
val ins = mutableListOf(Instruction(Opcode.SEC), Instruction(Opcode.SEI), Instruction(Opcode.CLC), Instruction(Opcode.CLI))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertFalse(vm.P_carry)
|
||||
assertFalse(vm.P_irqd)
|
||||
vm.step(1)
|
||||
@ -105,7 +105,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testPush() {
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(1)
|
||||
assertEquals(1, vm.evalstack.size)
|
||||
@ -122,7 +122,7 @@ class TestStackVmOpcodes {
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.WORD, 0x42ea)),
|
||||
0x3000 to listOf(Value(DataType.WORD, 0x42ea)),
|
||||
0x4000 to listOf(Value(DataType.FLOAT, 42.25)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
vm.load(makeProg(ins, mem=mem), null, null)
|
||||
assertEquals(0xea, vm.mem.getByte(0x2000))
|
||||
assertEquals(0x42, vm.mem.getByte(0x2001))
|
||||
assertEquals(0xea, vm.mem.getByte(0x3000))
|
||||
@ -141,7 +141,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testPushVar() {
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH_VAR, Value(DataType.STR, null, "varname")))
|
||||
vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null)
|
||||
vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null, null)
|
||||
assertEquals(7, vm.variables.size)
|
||||
assertTrue(vm.variables.containsKey("varname"))
|
||||
assertTrue(vm.variables.containsKey("XY"))
|
||||
@ -159,7 +159,7 @@ class TestStackVmOpcodes {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)),
|
||||
Instruction(Opcode.DUP))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(2)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -174,7 +174,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 9999)),
|
||||
Instruction(Opcode.SWAP)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(3)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -188,7 +188,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 3.1415)),
|
||||
Instruction(Opcode.DISCARD))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(2)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -204,7 +204,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 222)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 333)),
|
||||
Instruction(Opcode.ARRAY, Value(DataType.WORD, 2)))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(4)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -218,7 +218,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 22)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 33)),
|
||||
Instruction(Opcode.ARRAY, Value(DataType.WORD, 2)))
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(4)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -232,7 +232,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 222)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 333.33)),
|
||||
Instruction(Opcode.ARRAY, Value(DataType.WORD, 2)))
|
||||
vm.load(makeProg(ins3), null)
|
||||
vm.load(makeProg(ins3), null, null)
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(4)
|
||||
}
|
||||
@ -247,7 +247,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x4000)))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertEquals(0, vm.mem.getWord(0x2000))
|
||||
assertEquals(0, vm.mem.getWord(0x3000))
|
||||
assertEquals(0.0, vm.mem.getFloat(0x4000))
|
||||
@ -274,7 +274,7 @@ class TestStackVmOpcodes {
|
||||
"var2" to Value(DataType.WORD, 0),
|
||||
"var3" to Value(DataType.FLOAT, 0)
|
||||
)
|
||||
vm.load(makeProg(ins, vars), null)
|
||||
vm.load(makeProg(ins, vars), null, null)
|
||||
assertEquals(9, vm.variables.size)
|
||||
vm.step(6)
|
||||
assertEquals(Value(DataType.BYTE, 123), vm.variables["var1"])
|
||||
@ -287,7 +287,7 @@ class TestStackVmOpcodes {
|
||||
val vars2 = mapOf(
|
||||
"var1" to Value(DataType.BYTE, 0)
|
||||
)
|
||||
vm.load(makeProg(ins2, vars2), null)
|
||||
vm.load(makeProg(ins2, vars2), null, null)
|
||||
assertEquals(7, vm.variables.size)
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(2)
|
||||
@ -597,7 +597,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.NEG),
|
||||
Instruction(Opcode.NEG)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(2)
|
||||
assertEquals(1, vm.evalstack.size)
|
||||
@ -610,7 +610,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 1234)),
|
||||
Instruction(Opcode.NEG)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.WORD, 64302), vm.evalstack.pop())
|
||||
|
||||
@ -618,7 +618,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 12)),
|
||||
Instruction(Opcode.NEG)
|
||||
)
|
||||
vm.load(makeProg(ins3), null)
|
||||
vm.load(makeProg(ins3), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.BYTE, 244), vm.evalstack.pop())
|
||||
}
|
||||
@ -632,7 +632,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.INV),
|
||||
Instruction(Opcode.INV)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(3)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
@ -645,7 +645,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1234.33)),
|
||||
Instruction(Opcode.INV)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(2)
|
||||
}
|
||||
@ -661,7 +661,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.LSB),
|
||||
Instruction(Opcode.LSB)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(4)
|
||||
assertEquals(Value(DataType.BYTE, 0x31), vm.evalstack.pop())
|
||||
vm.step(1)
|
||||
@ -681,7 +681,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.MSB),
|
||||
Instruction(Opcode.MSB)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(4)
|
||||
assertEquals(Value(DataType.BYTE, 0xea), vm.evalstack.pop())
|
||||
vm.step(1)
|
||||
@ -699,7 +699,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.B2WORD),
|
||||
Instruction(Opcode.B2WORD)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0x0045), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
@ -715,7 +715,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.MSB2WORD),
|
||||
Instruction(Opcode.MSB2WORD)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0x4500), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
@ -731,7 +731,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.B2FLOAT),
|
||||
Instruction(Opcode.B2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 123.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
@ -747,7 +747,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.W2FLOAT),
|
||||
Instruction(Opcode.W2FLOAT)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.FLOAT, 12345.0), vm.evalstack.pop())
|
||||
assertFailsWith<VmExecutionException> {
|
||||
@ -765,7 +765,7 @@ class TestStackVmOpcodes {
|
||||
)
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 255)),
|
||||
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0xffff)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
vm.load(makeProg(ins, mem=mem), null, null)
|
||||
vm.step(4)
|
||||
assertEquals(101, vm.mem.getByte(0x2000))
|
||||
assertEquals(0, vm.mem.getByte(0x2001))
|
||||
@ -782,7 +782,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.INC_VAR, Value(DataType.STR, null, "var2")))
|
||||
val vars = mapOf("var1" to Value(DataType.WORD, 65534),
|
||||
"var2" to Value(DataType.BYTE, 254))
|
||||
vm.load(makeProg(ins, vars = vars), null)
|
||||
vm.load(makeProg(ins, vars = vars), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"])
|
||||
@ -800,7 +800,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.DEC_VAR, Value(DataType.STR, null, "var2")))
|
||||
val vars = mapOf("var1" to Value(DataType.WORD,1),
|
||||
"var2" to Value(DataType.BYTE, 1))
|
||||
vm.load(makeProg(ins, vars = vars), null)
|
||||
vm.load(makeProg(ins, vars = vars), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.WORD, 0), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"])
|
||||
@ -819,7 +819,7 @@ class TestStackVmOpcodes {
|
||||
)
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 0)),
|
||||
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
vm.load(makeProg(ins, mem=mem), null, null)
|
||||
vm.step(4)
|
||||
assertEquals(99, vm.mem.getByte(0x2000))
|
||||
assertEquals(255, vm.mem.getByte(0x2001))
|
||||
@ -838,7 +838,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 25544)),
|
||||
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_SIN.callNr))
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(4)
|
||||
|
||||
val rndb1 = vm.evalstack.pop()
|
||||
@ -1047,7 +1047,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
@ -1067,7 +1067,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
assertFalse(vm.P_carry)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
@ -1088,7 +1088,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
@ -1108,7 +1108,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
@ -1130,7 +1130,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(2)
|
||||
@ -1152,7 +1152,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("", vm.sourceLine)
|
||||
vm.step(3)
|
||||
@ -1169,7 +1169,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string2")))
|
||||
val labels = mapOf("label" to ins.last()) // points to the second LINE instruction
|
||||
vm.load(makeProg(ins, labels=labels), null)
|
||||
vm.load(makeProg(ins, labels=labels), null, null)
|
||||
vm.step(2)
|
||||
assertEquals("string2", vm.sourceLine)
|
||||
assertEquals(0, vm.callstack.size)
|
||||
@ -1184,7 +1184,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.TERMINATE),
|
||||
Instruction(Opcode.LINE, Value(DataType.STR, null, stringvalue = "string1"))
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
assertFailsWith<VmTerminationException> {
|
||||
vm.step(1)
|
||||
}
|
||||
@ -1208,7 +1208,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.RETURN)
|
||||
)
|
||||
val labels = mapOf("label" to ins[3]) // points to the LINE instruction
|
||||
vm.load(makeProg(ins, labels = labels), null)
|
||||
vm.load(makeProg(ins, labels = labels), null, null)
|
||||
vm.step(1)
|
||||
assertEquals("", vm.sourceLine)
|
||||
assertEquals(1, vm.callstack.size)
|
||||
@ -1244,7 +1244,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHR) // error
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(6)
|
||||
assertEquals(Value(DataType.BYTE, 124), vm.evalstack.peek())
|
||||
vm.step(2)
|
||||
@ -1282,7 +1282,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHL) // error
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(6)
|
||||
assertEquals(Value(DataType.BYTE, 242), vm.evalstack.peek())
|
||||
vm.step(2)
|
||||
@ -1313,7 +1313,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROR), // 0b00100110 c=1
|
||||
Instruction(Opcode.ROR) // 0b10010011 c=0 (original value after 9 rors)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.BYTE, 0b01001001), vm.evalstack.peek())
|
||||
assertTrue(vm.P_carry)
|
||||
@ -1351,7 +1351,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROR),
|
||||
Instruction(Opcode.ROR) // 0b1001001100001101 c=0 (original value after 17 rors)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0b0100100110000110), vm.evalstack.peek())
|
||||
assertTrue(vm.P_carry)
|
||||
@ -1378,7 +1378,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROL), // 0b01001001 c=1
|
||||
Instruction(Opcode.ROL) // 0b10010011 c=0 (original value after 9 rors)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.BYTE, 0b00100110), vm.evalstack.peek())
|
||||
assertTrue(vm.P_carry)
|
||||
@ -1416,7 +1416,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROL),
|
||||
Instruction(Opcode.ROL) // 0b1001001100001101 c=0 (original value after 17 rors)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0b0010011000011010), vm.evalstack.peek())
|
||||
assertTrue(vm.P_carry)
|
||||
@ -1442,7 +1442,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROR2),
|
||||
Instruction(Opcode.ROR2) // 0b10010011 (original value after 8 rors)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.BYTE, 0b11001001), vm.evalstack.peek())
|
||||
assertFalse(vm.P_carry)
|
||||
@ -1472,7 +1472,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROR2),
|
||||
Instruction(Opcode.ROR2) // 0b1001001100001101 (original value after 16 rors)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.WORD, 0b1100100110000110), vm.evalstack.peek())
|
||||
assertFalse(vm.P_carry)
|
||||
@ -1496,7 +1496,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROL2),
|
||||
Instruction(Opcode.ROL2) // 0b10010011 (original value after 8 rols)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.BYTE, 0b00100111), vm.evalstack.peek())
|
||||
assertFalse(vm.P_carry)
|
||||
@ -1524,7 +1524,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.ROL2),
|
||||
Instruction(Opcode.ROL2) // 0b1001001100001101 (original value after 16 rols)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
vm.load(makeProg(ins2), null, null)
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.WORD, 0b0010011000011011), vm.evalstack.peek())
|
||||
assertFalse(vm.P_carry)
|
||||
@ -1544,7 +1544,7 @@ class TestStackVmOpcodes {
|
||||
ins.add(Instruction(Opcode.PUSH, vars.next()))
|
||||
ins.add(Instruction(operator))
|
||||
}
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
for(expectedValue in expected) {
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.BYTE, expectedValue), vm.evalstack.pop())
|
||||
@ -1558,7 +1558,7 @@ class TestStackVmOpcodes {
|
||||
ins.add(Instruction(Opcode.PUSH, value))
|
||||
for (i in 1 until values.size)
|
||||
ins.add(Instruction(operator))
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(values.size)
|
||||
assertEquals(values.size, vm.evalstack.size)
|
||||
for (expectedVal in expected) {
|
||||
@ -1579,7 +1579,7 @@ class TestStackVmOpcodes {
|
||||
ins.add(Instruction(operator))
|
||||
ins.add(Instruction(Opcode.DISCARD))
|
||||
}
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.load(makeProg(ins), null, null)
|
||||
vm.step(values.size)
|
||||
assertEquals(values.size, vm.evalstack.size)
|
||||
for (expectedVal in expected) {
|
||||
|
Loading…
Reference in New Issue
Block a user