Compare commits

...

7 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:
""" """
@ -143,21 +156,26 @@ class VM:
addr = self.pc.value * 4 addr = self.pc.value * 4
main_part = struct.unpack(">BBBb", self.mem[addr:addr+4]) main_part = struct.unpack(">BBBb", self.mem[addr:addr+4])
if not OpF.UNEXPANDED in opdesc.flags or OpF.QUICK in opdesc.flags: if OpF.UNEXPANDED in opdesc.flags or OpF.QUICK in opdesc.flags:
upper_part = struct.unpack(">i", self.mem[addr+4:addr+8]) return main_part
return (*main_part, *upper_part) upper_part = struct.unpack(">i", self.mem[addr+4:addr+8])
return main_part return (*main_part, *upper_part)
def _run_callback( def _run_callback(
self, self,
opdesc: OpcodeDescription, opdesc: OpcodeDescription,
args: tuple[int, ...] args: tuple[int, ...]
) -> None: ) -> None:
if not (OpF.QUICK in opdesc.flags or OpF.UNEXPANDED in opdesc.flags):
self._vm_flags |= VMFlags.EXPANDED_INSTR
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: