Compare commits

...

6 Commits

View File

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