Compare commits

...

6 Commits

View File

@ -4,10 +4,12 @@ from typing import ClassVar, Callable
from ctypes import c_uint32, c_int32 from ctypes import c_uint32, c_int32
import struct import struct
from optable import OPCODES, OpcodeDescription, OpL, OpA, OpF, OpD from optable import OPCODES, OpcodeDescription, OpL, OpA, OpF, OpD
from enum import IntFlag, auto from enum import IntFlag, Enum, auto
class VMFlags(IntFlag): class VMFlags(IntFlag):
AFTER_BRANCH = auto() # if last instruction is big, then you should
# skip more memory on step
EXPANDED_INSTR = auto()
class Condition: class Condition:
def __init__(self, cond: int): def __init__(self, cond: int):
@ -21,9 +23,19 @@ class VMCC(IntFlag):
NEGATIVE = 1 << 1 NEGATIVE = 1 << 1
ZERO = 1 << 0 ZERO = 1 << 0
@dataclass
class Breakpoint(Exception): class Breakpoint(Exception):
address: int address: int
class VMExceptionType(Enum):
END_OF_MEM = auto()
INVALID_OPCODE = auto()
@dataclass
class VMException(Exception):
cause: VMExceptionType
pc: int
@dataclass @dataclass
class VM: class VM:
instr_callbacks: ClassVar[dict[OpcodeDescription, Callable]] instr_callbacks: ClassVar[dict[OpcodeDescription, Callable]]
@ -39,7 +51,7 @@ class VM:
self.cc: VMCC = VMCC(0) self.cc: VMCC = VMCC(0)
self.pc: c_uint32 = c_uint32(0) self.pc: c_uint32 = c_uint32(0)
self.registers: list[c_int32] = [c_int32(0) for _ in range(256)] self.registers: list[c_int32] = [c_int32(0) for _ in range(256)]
self.breakpoints: set[int] = field(default_factory=set) self.breakpoints: set[int] = set()
self._vm_flags: VMFlags = VMFlags(0) self._vm_flags: VMFlags = VMFlags(0)
self.__init_callbacks__() self.__init_callbacks__()
@ -108,16 +120,17 @@ class VM:
""" """
Make one step (only step into) Make one step (only step into)
""" """
# По какой-то причине адрессация работает opcode = self.mem[self.pc.value * 4]
# так, будто мы на 1 слово впереди опкода
if not VMFlags.AFTER_BRANCH:
self.pc = c_uint32(self.cc.value + 1)
# сбрасываем флаг AFTER_BRANCH
self._vm_flags &= ~(VMFlags.AFTER_BRANCH)
opcode = self.mem[self.pc.value]
opdesc = self._fetch_opcode_desc(opcode) opdesc = self._fetch_opcode_desc(opcode)
args = self._parse_arguments(opdesc) args = self._parse_arguments(opdesc)
# По какой-то причине адрессация работает
# так, будто мы на 1 слово впереди опкода
self.pc = c_uint32(self.pc.value + 1)
# сбрасываем флаг AFTER_BRANCH
self._vm_flags &= ~(VMFlags.AFTER_BRANCH)
self._run_callback(opdesc, args) self._run_callback(opdesc, args)
if VMFlags.EXPANDED_INSTR in self._vm_flags:
self.pc = c_uint32(self.pc.value + 1)
def continue_(self) -> None: def continue_(self) -> None:
""" """
@ -156,21 +169,24 @@ class VM:
if opdesc.layout == OpL.MATH: if opdesc.layout == OpL.MATH:
assert len(args) == 4 assert len(args) == 4
_, r3, r1, r2_or_i8 = args _, r3, r1, r2_or_i8 = args
# поскольку этот колбэк сгенерирован,
# ему необходимо в явном виде указывать
# аргумент self
self.instr_callbacks[opdesc]( self.instr_callbacks[opdesc](
r3, r1, r2_or_i8 self, r3, r1, r2_or_i8
) )
if opdesc.layout == OpL.MEM: if opdesc.layout == OpL.MEM:
if OpF.QUICK in opdesc.flags: if OpF.QUICK in opdesc.flags:
assert len(args) == 4 assert len(args) == 4
_, r3, r1, i8 = args _, r3, r1, i8 = args
self.instr_callbacks[opdesc]( self.instr_callbacks[opdesc](
r3, r1, i8 self, r3, r1, i8
) )
else: else:
assert len(args) == 5 assert len(args) == 5
_, r3, r1, _, disp = args _, r3, r1, _, disp = args
self.instr_callbacks[opdesc]( self.instr_callbacks[opdesc](
r3, r1, disp self, r3, r1, disp
) )
if opdesc.layout == OpL.BRANCH: if opdesc.layout == OpL.BRANCH: