feat: какая-то минимальная система обработки опкодов
This commit is contained in:
BIN
src/__pycache__/optable.cpython-311.pyc
Normal file
BIN
src/__pycache__/optable.cpython-311.pyc
Normal file
Binary file not shown.
6
src/main.py
Normal file
6
src/main.py
Normal file
@ -0,0 +1,6 @@
|
||||
def main():
|
||||
print("Hello from dp32-proto!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
71
src/optable.py
Normal file
71
src/optable.py
Normal file
@ -0,0 +1,71 @@
|
||||
from dataclasses import dataclass
|
||||
from enum import Flag, Enum, auto
|
||||
|
||||
class OpcodeFlags(Flag):
|
||||
QUICK = auto()
|
||||
# Форсирует чтение не более 1 слова
|
||||
# в тех случаях, когда это не требуется
|
||||
# по характеру действия
|
||||
UNEXPANDED = auto()
|
||||
|
||||
OpF = OpcodeFlags
|
||||
|
||||
class OpcodeLayout(Enum):
|
||||
MATH = auto()
|
||||
BRANCH = auto()
|
||||
MEM = auto()
|
||||
|
||||
OpL = OpcodeLayout
|
||||
|
||||
class OpcodeActions(Enum):
|
||||
ADD = auto()
|
||||
SUB = auto()
|
||||
MUL = auto()
|
||||
DIV = auto()
|
||||
AND = auto()
|
||||
OR = auto()
|
||||
XOR = auto()
|
||||
MASK = auto()
|
||||
LOAD = auto()
|
||||
STORE = auto()
|
||||
BRANCH = auto()
|
||||
MEM_BRANCH = auto()
|
||||
|
||||
OpA = OpcodeActions
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OpcodeDescription:
|
||||
flags: OpcodeFlags
|
||||
layout: OpcodeLayout
|
||||
action: OpcodeActions
|
||||
|
||||
OpD = OpcodeDescription
|
||||
|
||||
OPCODES = {
|
||||
# block 1
|
||||
0x00: OpD(OpF(0), OpL.MATH, OpA.ADD),
|
||||
0x10: OpD(OpF.QUICK, OpL.MATH, OpA.ADD),
|
||||
0x01: OpD(OpF(0), OpL.MATH, OpA.SUB),
|
||||
0x11: OpD(OpF.QUICK, OpL.MATH, OpA.SUB),
|
||||
0x02: OpD(OpF(0), OpL.MATH, OpA.MUL),
|
||||
0x12: OpD(OpF.QUICK, OpL.MATH, OpA.MUL),
|
||||
0x03: OpD(OpF(0), OpL.MATH, OpA.DIV),
|
||||
0x13: OpD(OpF.QUICK, OpL.MATH, OpA.DIV),
|
||||
0x04: OpD(OpF.UNEXPANDED, OpL.MATH, OpA.AND),
|
||||
0x05: OpD(OpF.UNEXPANDED, OpL.MATH, OpA.OR),
|
||||
0x06: OpD(OpF.UNEXPANDED, OpL.MATH, OpA.XOR),
|
||||
0x07: OpD(OpF.UNEXPANDED, OpL.MATH, OpA.MASK),
|
||||
# block 2
|
||||
0x20: OpD(OpF(0), OpL.MEM, OpA.LOAD),
|
||||
0x30: OpD(OpF.QUICK, OpL.MEM, OpA.LOAD),
|
||||
0x21: OpD(OpF(0), OpL.MEM, OpA.STORE),
|
||||
0x31: OpD(OpF.QUICK, OpL.MEM, OpA.STORE),
|
||||
# block 3
|
||||
0x40: OpD(OpF(0), OpL.BRANCH, OpA.BRANCH),
|
||||
0x50: OpD(OpF.QUICK, OpL.BRANCH, OpA.BRANCH),
|
||||
0x51: OpD(OpF(0), OpL.BRANCH, OpA.MEM_BRANCH),
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(hex(12))
|
||||
print(~12)
|
||||
172
src/vm.py
Normal file
172
src/vm.py
Normal file
@ -0,0 +1,172 @@
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import ClassVar, Callable, Any
|
||||
from ctypes import c_uint32, c_int32, c_uint8
|
||||
import struct
|
||||
from optable import OPCODES, OpcodeDescription, OpL, OpA, OpF, OpD
|
||||
from enum import IntFlag, auto
|
||||
|
||||
class VMFlags(IntFlag):
|
||||
AFTER_BRANCH = auto()
|
||||
|
||||
class Condition:
|
||||
def __init__(self, cond: int):
|
||||
self.i: bool = bool(cond & (1 << 3))
|
||||
self.v: bool = bool(cond & (1 << 2))
|
||||
self.n: bool = bool(cond & (1 << 1))
|
||||
self.z: bool = bool(cond & (1 << 0))
|
||||
|
||||
@dataclass
|
||||
class VM:
|
||||
instr_callbacks: ClassVar[dict[OpcodeDescription, Callable]]
|
||||
|
||||
def __init__(self, mem):
|
||||
self.mem: bytearray = mem
|
||||
self.cc: c_uint8 = c_uint8(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._vm_flags: VMFlags = VMFlags(0)
|
||||
self.__init_callbacks__()
|
||||
|
||||
def __init_callbacks__(self):
|
||||
VM.instr_callbacks = {
|
||||
# ariphmetic
|
||||
OpD(OpF(0), OpL.MATH, OpA.ADD):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs + rhs),
|
||||
|
||||
OpD(OpF.QUICK, OpL.MATH, OpA.ADD):
|
||||
self._math_quick_callback_gen(lambda lhs, rhs: lhs + rhs),
|
||||
|
||||
OpD(OpF(0), OpL.MATH, OpA.SUB):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs - rhs),
|
||||
|
||||
OpD(OpF.QUICK, OpL.MATH, OpA.SUB):
|
||||
self._math_quick_callback_gen(lambda lhs, rhs: lhs - rhs),
|
||||
|
||||
OpD(OpF(0), OpL.MATH, OpA.MUL):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs * rhs),
|
||||
|
||||
OpD(OpF.QUICK, OpL.MATH, OpA.MUL):
|
||||
self._math_quick_callback_gen(lambda lhs, rhs: lhs * rhs),
|
||||
|
||||
OpD(OpF(0), OpL.MATH, OpA.DIV):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs // rhs),
|
||||
|
||||
OpD(OpF.QUICK, OpL.MATH, OpA.DIV):
|
||||
self._math_quick_callback_gen(lambda lhs, rhs: lhs // rhs),
|
||||
|
||||
# logical ops
|
||||
OpD(OpF.UNEXPANDED, OpL.MATH, OpA.AND):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs & rhs),
|
||||
|
||||
OpD(OpF.UNEXPANDED, OpL.MATH, OpA.OR):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs | rhs),
|
||||
|
||||
OpD(OpF.UNEXPANDED, OpL.MATH, OpA.XOR):
|
||||
self._math_callback_gen(lambda lhs, rhs: lhs ^ rhs),
|
||||
|
||||
OpD(OpF.UNEXPANDED, OpL.MATH, OpA.MASK):
|
||||
self._math_callback_gen(
|
||||
lambda lhs, rhs: lhs & ((~rhs + (1 << 32)) % (1 << 32))
|
||||
),
|
||||
|
||||
# block 2
|
||||
OpD(OpF(0), OpL.MEM, OpA.LOAD):
|
||||
self._load_callback,
|
||||
OpD(OpF.QUICK, OpL.MEM, OpA.LOAD):
|
||||
self._load_callback,
|
||||
OpD(OpF(0), OpL.MEM, OpA.STORE):
|
||||
self._store_callback,
|
||||
OpD(OpF.QUICK, OpL.MEM, OpA.STORE):
|
||||
self._store_callback,
|
||||
|
||||
# block 3
|
||||
OpD(OpF(0), OpL.BRANCH, OpA.BRANCH):
|
||||
self._branch_callback,
|
||||
OpD(OpF.QUICK, OpL.BRANCH, OpA.BRANCH):
|
||||
self._branch_callback,
|
||||
OpD(OpF(0), OpL.BRANCH, OpA.MEM_BRANCH):
|
||||
self._branch_indexed_callback
|
||||
}
|
||||
|
||||
def step(self) -> None:
|
||||
"""
|
||||
Make one step (only step into)
|
||||
"""
|
||||
opcode = self.mem[self.pc.value]
|
||||
opdesc = self._fetch_opcode_desc(opcode)
|
||||
if not VMFlags.AFTER_BRANCH:
|
||||
self.pc = c_uint32(self.cc.value + 1)
|
||||
self._vm_flags
|
||||
|
||||
def continue_(self) -> None:
|
||||
"""
|
||||
Continue from current breakpoint
|
||||
"""
|
||||
pass
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Run from very beginning
|
||||
"""
|
||||
|
||||
def _fetch_opcode_desc(self, opcode: int):
|
||||
return OPCODES[opcode]
|
||||
|
||||
def _math_callback_gen(
|
||||
self,
|
||||
operation: Callable[[int, int], int]
|
||||
) -> Callable[["VM", int, int ,int], None]:
|
||||
"""
|
||||
Поскольку математические операции конструируются
|
||||
по одному шаблону, я завел функцию высшего порядка,
|
||||
которая будет их генерировать
|
||||
"""
|
||||
def callback(self, r3: int, r1: int, r2: int):
|
||||
lhs = self.registers[r1].value
|
||||
rhs = self.registers[r2].value
|
||||
self.registers[r3] = c_int32(operation(lhs, rhs))
|
||||
return callback
|
||||
|
||||
def _math_quick_callback_gen(
|
||||
self,
|
||||
operation: Callable[[int, int], int]
|
||||
) -> Callable[["VM", int, int ,int], None]:
|
||||
"""
|
||||
Поскольку математические операции конструируются
|
||||
по одному шаблону, я завел функцию высшего порядка,
|
||||
которая будет их генерировать.
|
||||
|
||||
В отлиие от _math_callback_gen, эта уже предназначена для
|
||||
операций с пометкой QUICK
|
||||
"""
|
||||
def callback(self, r3: int, r1: int, i8: int) -> None:
|
||||
lhs = self.registers[r1].value
|
||||
self.registers[r3] = c_int32(operation(lhs, i8))
|
||||
return callback
|
||||
|
||||
def _load_callback(self, r3: int, r1: int, disp: int) -> None:
|
||||
addr = (self.registers[r1].value + disp) * 4
|
||||
self.registers[r3] = c_int32(
|
||||
struct.unpack("i", self.mem[addr:addr+4])[0]
|
||||
)
|
||||
|
||||
def _store_callback(self, r3: int, r1: int, disp: int) -> None:
|
||||
addr = (self.registers[r1].value + disp) * 4
|
||||
self.mem[addr:addr+4] = struct.pack("i", self.registers[r3].value)
|
||||
|
||||
def _branch_callback(self, cond: int, disp: int) -> None:
|
||||
c = Condition(cond)
|
||||
vm_c = Condition(self.cc.value)
|
||||
if (c.v & vm_c.v) & (c.n & vm_c.n) & (c.z & vm_c.z) == c.i:
|
||||
self._vm_flags |= VMFlags.AFTER_BRANCH
|
||||
self.pc = c_uint32(self.pc.value + disp)
|
||||
|
||||
def _branch_indexed_callback(self, cond: int, r1: int, disp: int) -> None:
|
||||
c = Condition(cond)
|
||||
vm_c = Condition(self.cc.value)
|
||||
if (c.v & vm_c.v) & (c.n & vm_c.n) & (c.z & vm_c.z) == c.i:
|
||||
self._vm_flags |= VMFlags.AFTER_BRANCH
|
||||
addr = self.registers[r1].value + disp
|
||||
self.pc = c_uint32(addr)
|
||||
Reference in New Issue
Block a user