more vm opcodes

This commit is contained in:
Irmen de Jong 2018-03-06 21:36:41 +01:00
parent bcc1a6b91f
commit 6696887f0e
2 changed files with 58 additions and 34 deletions

View File

@ -40,10 +40,23 @@ class Opcode(enum.IntEnum):
CMP_GTE = 105 CMP_GTE = 105
CALL = 200 CALL = 200
RETURN = 201 RETURN = 201
JUMP = 202 SYSCALL = 202
JUMP_IF_TRUE = 203 JUMP = 203
JUMP_IF_FALSE = 204 JUMP_IF_TRUE = 204
SYSCALL = 205 JUMP_IF_FALSE = 205
JUMP_IF_STATUS_ZERO = 206
JUMP_IF_STATUS_NE = 207
JUMP_IF_STATUS_EQ = 208
JUMP_IF_STATUS_CC = 209
JUMP_IF_STATUS_CS = 210
JUMP_IF_STATUS_VC = 211
JUMP_IF_STATUS_VS = 212
JUMP_IF_STATUS_GE = 213
JUMP_IF_STATUS_LE = 214
JUMP_IF_STATUS_GT = 215
JUMP_IF_STATUS_LT = 216
JUMP_IF_STATUS_POS = 217
JUMP_IF_STATUS_NEG = 218
class Value: class Value:

View File

@ -52,7 +52,7 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
# various arithmetic operations, logical operations, boolean test and comparison operations # various arithmetic operations, logical operations, boolean test and comparison operations
# jump label # jump label
# jump_if_true label, jump_if_false label # jump_if_true label, jump_if_false label
# @todo jump_if_status_XX label special system dependent status register conditional check such as carry bit or overflow bit) # jump_if_status_XX label special system dependent status register conditional check such as carry bit or overflow bit)
# return (return values on stack) # return (return values on stack)
# syscall function (special system dependent implementation) # syscall function (special system dependent implementation)
# call function (arguments are on stack) # call function (arguments are on stack)
@ -74,7 +74,7 @@ import tkinter
import tkinter.font import tkinter.font
from typing import Dict, List, Tuple, Union, no_type_check from typing import Dict, List, Tuple, Union, no_type_check
from .program import Instruction, Variable, Block, Program, Opcode, Value from .program import Instruction, Variable, Block, Program, Opcode, Value
from .core import Memory, DataType, TerminateExecution from .core import Memory, DataType, TerminateExecution, ExecutionError
class CallFrameMarker: class CallFrameMarker:
@ -167,15 +167,9 @@ class VM:
charin_address = 0xd001 charin_address = 0xd001
def __init__(self, program: Program, timerprogram: Program=None) -> None: def __init__(self, program: Program, timerprogram: Program=None) -> None:
opcode_names = [oc.name for oc in Opcode] for opcode in Opcode:
timerprogram = timerprogram or Program([]) if opcode not in self.dispatch_table:
for ocname in opcode_names: raise NotImplementedError("missing opcode dispatch for " + opcode.name)
if not hasattr(self, "opcode_" + ocname):
raise NotImplementedError("missing opcode method for " + ocname)
for method in dir(self):
if method.startswith("opcode_"):
if not method[7:] in opcode_names:
raise RuntimeError("opcode method for undefined opcode " + method)
for oc in Opcode: for oc in Opcode:
if oc not in self.dispatch_table: if oc not in self.dispatch_table:
raise NotImplementedError("no dispatch entry in table for " + oc.name) raise NotImplementedError("no dispatch entry in table for " + oc.name)
@ -186,7 +180,7 @@ class VM:
self.memory.mark_readonly(start, end) self.memory.mark_readonly(start, end)
self.main_stack = Stack() self.main_stack = Stack()
self.timer_stack = Stack() self.timer_stack = Stack()
self.main_program, self.timer_program, self.variables, self.labels = self.flatten_programs(program, timerprogram) self.main_program, self.timer_program, self.variables, self.labels = self.flatten_programs(program, timerprogram or Program([]))
self.connect_instruction_pointers(self.main_program) self.connect_instruction_pointers(self.main_program)
self.connect_instruction_pointers(self.timer_program) self.connect_instruction_pointers(self.timer_program)
self.program = self.main_program self.program = self.main_program
@ -516,23 +510,6 @@ class VM:
self.pc = callframe.returninstruction self.pc = callframe.returninstruction
return False return False
def opcode_JUMP(self, instruction: Instruction) -> bool:
return True # jump simply points to the next instruction elsewhere
def opcode_JUMP_IF_TRUE(self, instruction: Instruction) -> bool:
result = self.stack.pop()
if result:
self.pc = self.pc.alt_next # alternative next instruction
return False
return True
def opcode_JUMP_IF_FALSE(self, instruction: Instruction) -> bool:
result = self.stack.pop()
if result:
return True
self.pc = self.pc.alt_next # alternative next instruction
return False
def opcode_SYSCALL(self, instruction: Instruction) -> bool: def opcode_SYSCALL(self, instruction: Instruction) -> bool:
syscall = instruction.args[0] syscall = instruction.args[0]
assert isinstance(syscall, str) assert isinstance(syscall, str)
@ -542,6 +519,27 @@ class VM:
else: else:
raise RuntimeError("no syscall method for " + syscall) raise RuntimeError("no syscall method for " + syscall)
def opcode_JUMP(self, instruction: Instruction) -> bool:
return True # jump simply points to the next instruction elsewhere
def opcode_JUMP_IF_TRUE(self, instruction: Instruction) -> bool:
result = self.stack.pop()
assert isinstance(result, Value)
if result.value:
self.pc = self.pc.alt_next # alternative next instruction
return False
return True
def opcode_JUMP_IF_FALSE(self, instruction: Instruction) -> bool:
result = self.stack.pop()
if result.value: # type: ignore
return True
self.pc = self.pc.alt_next # alternative next instruction
return False
def opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG(self, instruction: Instruction) -> bool:
raise ExecutionError("unsupported conditional jump", instruction) # @todo implement hardware specific status register flags
dispatch_table = { dispatch_table = {
Opcode.TERMINATE: opcode_TERMINATE, Opcode.TERMINATE: opcode_TERMINATE,
Opcode.NOP: opcode_NOP, Opcode.NOP: opcode_NOP,
@ -570,10 +568,23 @@ class VM:
Opcode.CMP_GTE: opcode_CMP_GTE, Opcode.CMP_GTE: opcode_CMP_GTE,
Opcode.CALL: opcode_CALL, Opcode.CALL: opcode_CALL,
Opcode.RETURN: opcode_RETURN, Opcode.RETURN: opcode_RETURN,
Opcode.SYSCALL: opcode_SYSCALL,
Opcode.JUMP: opcode_JUMP, Opcode.JUMP: opcode_JUMP,
Opcode.JUMP_IF_TRUE: opcode_JUMP_IF_TRUE, Opcode.JUMP_IF_TRUE: opcode_JUMP_IF_TRUE,
Opcode.JUMP_IF_FALSE: opcode_JUMP_IF_FALSE, Opcode.JUMP_IF_FALSE: opcode_JUMP_IF_FALSE,
Opcode.SYSCALL: opcode_SYSCALL, Opcode.JUMP_IF_STATUS_ZERO: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_NE: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_EQ: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_CC: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_CS: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_VC: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_VS: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_GE: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_LE: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_GT: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_LT: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_POS: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
Opcode.JUMP_IF_STATUS_NEG: opcode_JUMP_IF_STATUS_UNSUPPORTED_FLAG,
} }