Compare commits
7 Commits
3dd281a424
...
aaa0a95657
| Author | SHA1 | Date | |
|---|---|---|---|
| aaa0a95657 | |||
| becdd26311 | |||
| f543952637 | |||
| 9c4b80bf68 | |||
| 33b56fec71 | |||
| 304a28c1b2 | |||
| 76cf62d6c4 |
48
src/vm.py
48
src/vm.py
@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user