Compare commits
10 Commits
afbe0a5dfe
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ddff443183 | |||
| 99512fa611 | |||
| 89608dcb22 | |||
| 0707a981e1 | |||
| 9a3399a975 | |||
| 7b6b3f73cd | |||
| 6a4a02ffb9 | |||
| 1aade33b48 | |||
| 94160414aa | |||
| 4f1c9286a2 |
10
LICENSE
Normal file
10
LICENSE
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
any purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
||||||
|
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||||
|
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||||
|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
54
README.md
54
README.md
@ -0,0 +1,54 @@
|
|||||||
|
# DP32-proto
|
||||||
|
|
||||||
|
Прототип эмулятора процессора DP32
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Это проект программной эмуляции и отладки процессора DP32 на языке python. В этом проекте можно найти 2 компонента - отладчик dp32dbg и эмулятор dp32emu. Первый полностью опирается на отладочную информацию в следующем формате. Это очень простой отладчик и очень нестабильный, поскольку писался с упором на скорость, а не на качество.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"src": "absolute/path/to/source"
|
||||||
|
"labels" : {
|
||||||
|
"label1": 1
|
||||||
|
"label2": 2
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"instructions" : {
|
||||||
|
"<offset-in-words>" : {
|
||||||
|
"lenght": 2,
|
||||||
|
"srcline": 3
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
Стяните данный репозиторий и выполните в корне проекта команду `pip install .`
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
После установки у вас появятся 2 программы:
|
||||||
|
|
||||||
|
- dp32emu - программный эмулятор процессора dp32. Принимает на вход бинарный файл с командами dp32, выполняет их и в результате своей работы выдает дамп памяти процессора после завершения работы
|
||||||
|
- dp32dbg - отладчик, опирающийся на вышеуказанный эмулятор. Позволяет выполнять действия пошаговой отладки и предоставляет базовую функциональность точек останова (но с ньюансами)
|
||||||
|
|
||||||
|
Посмотреть инструкцию по запуску проще всего передав флаг `-h` каждой из этих программ
|
||||||
|
|
||||||
|
## Использование отладчика
|
||||||
|
|
||||||
|
help не встроен в отладчик, поскольку до этого его функционал не был документирован. Приведу здесь основной набор команд отладчика
|
||||||
|
|
||||||
|
- `step/s` - выполняет одну инструкцию, на которую сейчас указывает регистр pc виртуальной машины
|
||||||
|
- `breakpoint <lineno>` - устанавливает точку останова на определенной строке исходного кода. С точками останова 2 ньюанса:
|
||||||
|
1. Они они не могут быть установлены на комментарии или пустые строки. Если на строке больше одной операции, точка будет установлена на самую раннюю
|
||||||
|
2. Когда виртуальная машина встретит точку останова, временно она не сможет выполнять команду continue, поскольку не предусмотрено ротации точек останова. Если нужно продолжить выполнение программы дальше - выполните одну команду step
|
||||||
|
- `continue/c` - выполняет программу до ближайшей точки останова
|
||||||
|
- `reset` - сбрасывает состояние виртуальной машины и ее память, но не точки останова
|
||||||
|
- `run` - сбрасывает состояние виртуальной машины и запускает выполнение кода
|
||||||
|
- `cbp` - очищает все точки останова
|
||||||
|
- `print/p <reg>` - печатает содержимое регистров. Регистры записываются в формате `r1-r255`, позволяет также посмотреть адреса меток (указав название меток в качестве параметра) и системные регистры: pc, cc
|
||||||
|
- `inspect/i <size> <amount> <place>` - печатает содержимое памяти по определенному адресу в определенном формате (строчная - знаковые, заглавная - беззнаковые): b/B - байт, h/H - полуслова - 16 бит, w/W - слова - 32 бита. `amount` - количество подряд идущих ячеек, содержимое которых нужно прочитать. `place` - место, с которого следует начать печать. Можеть представлять собой либо имя метки, либо полный адрес в десятичной или 16-ричной системе счисления
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,8 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
dp32emu = "main:main"
|
dp32emu = "dp32proto.main:main"
|
||||||
dp32dbg = "dbg_main:main"
|
dp32dbg = "dp32proto.dbg_main:main"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools"]
|
requires = ["setuptools"]
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
# почему так грязно?
|
|
||||||
|
|
||||||
Потому что я заколебался воевать с модульностью питона, чтобы сделать это красиво
|
|
||||||
4
src/dp32proto/README.md
Normal file
4
src/dp32proto/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Почему такая некрасивая структура
|
||||||
|
|
||||||
|
Этот репозиторий нужен был для того, чтобы отладить программу для процессора DP32. Структура проекта сделана такой для того, чтобы сократить время, необходимое на структуризацию и разрешение зависимостей.
|
||||||
|
|
||||||
98
src/dp32proto/dbg.json
Normal file
98
src/dp32proto/dbg.json
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"_start": 0,
|
||||||
|
"_start_return": 9,
|
||||||
|
"f_fibo": 11,
|
||||||
|
"f_fibo_loop": 14,
|
||||||
|
"return": 27,
|
||||||
|
"result": 28,
|
||||||
|
"end": 29
|
||||||
|
},
|
||||||
|
"instructions": {
|
||||||
|
"0": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 6
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 7
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 8
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 9
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 10
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 11
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 13
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 16
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 17
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 18
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 20
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 21
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 22
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 23
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 24
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 25
|
||||||
|
},
|
||||||
|
"21": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 27
|
||||||
|
},
|
||||||
|
"23": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 28
|
||||||
|
},
|
||||||
|
"25": {
|
||||||
|
"length": 2,
|
||||||
|
"srcline": 29
|
||||||
|
},
|
||||||
|
"27": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 31
|
||||||
|
},
|
||||||
|
"28": {
|
||||||
|
"length": 1,
|
||||||
|
"srcline": 32
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"src": "C:\\Users\\etdia\\code\\dp32-proto\\src\\test.dasm"
|
||||||
|
}
|
||||||
@ -4,10 +4,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from dpdebugger import Debugger, DbgDict, DbgInstrDesc
|
from .dpdebugger import Debugger, DbgDict, DbgInstrDesc
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import json
|
import json
|
||||||
import dbg_tui
|
from . import dbg_tui
|
||||||
|
|
||||||
def parse_dbg(dbg_json_dict: dict) -> DbgDict:
|
def parse_dbg(dbg_json_dict: dict) -> DbgDict:
|
||||||
"""
|
"""
|
||||||
@ -51,7 +51,7 @@ def main():
|
|||||||
dbg_dict: DbgDict = parse_dbg(json.load(f))
|
dbg_dict: DbgDict = parse_dbg(json.load(f))
|
||||||
|
|
||||||
dbg = Debugger(mem, dbg_dict)
|
dbg = Debugger(mem, dbg_dict)
|
||||||
with open (dbg_dict["src"], 'r') as f:
|
with open (dbg_dict["src"], 'r', encoding="utf8") as f:
|
||||||
src = f.read()
|
src = f.read()
|
||||||
|
|
||||||
dbg_tui.run_tui(dbg, src)
|
dbg_tui.run_tui(dbg, src)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
from dpdebugger import Debugger
|
from .dpdebugger import Debugger
|
||||||
from vm import VMException, VMExceptionType, VMStatus
|
from .vm import VMException, VMExceptionType, VMStatus
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import cast
|
from typing import cast
|
||||||
import math
|
import math
|
||||||
@ -3,7 +3,7 @@
|
|||||||
хоть как-то помочь
|
хоть как-то помочь
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from vm import VM, VMException, Breakpoint, Condition, WORD_SIZE
|
from .vm import VM, VMException, Breakpoint, Condition, WORD_SIZE
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import TypedDict, Callable, cast
|
from typing import TypedDict, Callable, cast
|
||||||
@ -55,12 +55,13 @@ class Debugger:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mem: bytearray, dbg_dict: DbgDict):
|
def __init__(self, mem: bytearray, dbg_dict: DbgDict):
|
||||||
with open(dbg_dict["src"], 'r') as f:
|
with open(dbg_dict["src"], 'r', encoding="utf8") as f:
|
||||||
self._source_lines = f.readlines()
|
self._source_lines = f.readlines()
|
||||||
self._vm = VM(mem)
|
self._vm = VM(mem)
|
||||||
self._dbg_dict = dbg_dict
|
self._dbg_dict = dbg_dict
|
||||||
self._breakpoints = set()
|
self._breakpoints = set()
|
||||||
self.__init_callbacks__()
|
self.__init_callbacks__()
|
||||||
|
self.last_breakpoint: Breakpoint | None = None
|
||||||
|
|
||||||
def __init_callbacks__(self):
|
def __init_callbacks__(self):
|
||||||
self._callbacks_table = {
|
self._callbacks_table = {
|
||||||
@ -70,6 +71,8 @@ class Debugger:
|
|||||||
"c": self._continue,
|
"c": self._continue,
|
||||||
"breakpoint": self._breakpoint,
|
"breakpoint": self._breakpoint,
|
||||||
"b": self._breakpoint,
|
"b": self._breakpoint,
|
||||||
|
"clearbreakpoints": self._breakpointsclear,
|
||||||
|
"cbp": self._breakpointsclear,
|
||||||
"print": self._print,
|
"print": self._print,
|
||||||
"p": self._print,
|
"p": self._print,
|
||||||
"run": self._run,
|
"run": self._run,
|
||||||
@ -118,15 +121,21 @@ class Debugger:
|
|||||||
addr = -1
|
addr = -1
|
||||||
# находим за линейное время. Плохая практика, но так как
|
# находим за линейное время. Плохая практика, но так как
|
||||||
# сходные коды вряд ли будут длиннее 1000 строк - приемлемо
|
# сходные коды вряд ли будут длиннее 1000 строк - приемлемо
|
||||||
for addr, desc in self._dbg_dict.items():
|
for addr, desc in self._dbg_dict["instructions"].items():
|
||||||
desc = cast(DbgInstrDesc, desc)
|
desc = cast(DbgInstrDesc, desc)
|
||||||
if not desc["srcline"] == desired_addr:
|
if not desc["srcline"] == desired_addr:
|
||||||
continue
|
continue
|
||||||
self._breakpoints.add(int(addr))
|
self._breakpoints.add(int(addr))
|
||||||
|
self._vm.breakpoints.add(int(addr))
|
||||||
return f"Breakpoint succesfully set on line {desired_addr}"
|
return f"Breakpoint succesfully set on line {desired_addr}"
|
||||||
|
|
||||||
return f"Couldn't place breakpoint on src line {desired_addr}"
|
return f"Couldn't place breakpoint on src line {desired_addr}"
|
||||||
|
|
||||||
|
def _breakpointsclear(self, args: list[str]):
|
||||||
|
self._breakpoints.clear()
|
||||||
|
self._vm.breakpoints.clear()
|
||||||
|
return "Cleared all breakpoints"
|
||||||
|
|
||||||
def _print(self, args: list[str]) -> str:
|
def _print(self, args: list[str]) -> str:
|
||||||
to_print = args[0]
|
to_print = args[0]
|
||||||
if to_print == "pc":
|
if to_print == "pc":
|
||||||
@ -154,8 +163,9 @@ class Debugger:
|
|||||||
def _run(self, args: list[str]) -> str:
|
def _run(self, args: list[str]) -> str:
|
||||||
try:
|
try:
|
||||||
self._vm.run()
|
self._vm.run()
|
||||||
except Breakpoint:
|
except Breakpoint as b:
|
||||||
return ""
|
return (f'breakpoint on line '
|
||||||
|
f'{self._dbg_dict["instructions"][b.address]["srcline"]}')
|
||||||
return "Program finished"
|
return "Program finished"
|
||||||
|
|
||||||
def _inspect(self, args: list[str]) -> str:
|
def _inspect(self, args: list[str]) -> str:
|
||||||
@ -173,6 +183,7 @@ class Debugger:
|
|||||||
return ("You passed wrong offset parameter. It should be either "
|
return ("You passed wrong offset parameter. It should be either "
|
||||||
"name of some label or explicit decimal or hexdecimal "
|
"name of some label or explicit decimal or hexdecimal "
|
||||||
"number, in the second case it should start with 0x")
|
"number, in the second case it should start with 0x")
|
||||||
|
offset = self._vm._to_raw_bytes_offset(offset)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sym = self.UNPACK_SYMBOL_TABLE[size_arg]
|
sym = self.UNPACK_SYMBOL_TABLE[size_arg]
|
||||||
@ -182,8 +193,20 @@ class Debugger:
|
|||||||
"options as size: b/B - byte, h/H - 2 bytes, "
|
"options as size: b/B - byte, h/H - 2 bytes, "
|
||||||
"w/W - 4 bytes. Big - unsigned, small - signed")
|
"w/W - 4 bytes. Big - unsigned, small - signed")
|
||||||
contents = struct.unpack(
|
contents = struct.unpack(
|
||||||
sym*amount,
|
">"+sym*amount,
|
||||||
self._vm.mem[offset:offset+size*amount]
|
self._vm.mem[offset:offset+size*amount]
|
||||||
)
|
)
|
||||||
return f"{mem_location}:" + " ".join(map(str, contents))
|
return f"{mem_location}:" + " ".join(map(str, contents))
|
||||||
|
|
||||||
|
def _recover_from_breakpoint(self, cur_bp: Breakpoint):
|
||||||
|
"""
|
||||||
|
Когда виртуальная машина сталкивается с точкой останова, она на
|
||||||
|
ней зависает навечно. Для продолжения работы надо текущую точку
|
||||||
|
останова убрать, сделать шаг, а потом добавить. Предыдущая точка
|
||||||
|
остановка как раз хранится в дебаггере
|
||||||
|
"""
|
||||||
|
if not self.last_breakpoint:
|
||||||
|
return
|
||||||
|
if cur_bp.address != self.last_breakpoint.address:
|
||||||
|
return
|
||||||
|
self._vm.breakpoints.remove(cur_bp.address)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from vm import VM
|
from .vm import VM
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = ArgumentParser(
|
parser = ArgumentParser(
|
||||||
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
|||||||
from typing import ClassVar, Callable
|
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, Enum, auto
|
from enum import IntFlag, Enum, auto
|
||||||
|
|
||||||
WORD_SIZE: int = 4
|
WORD_SIZE: int = 4
|
||||||
@ -59,6 +59,7 @@ class VM:
|
|||||||
self._initial_mem = mem.copy()
|
self._initial_mem = mem.copy()
|
||||||
self.__init_callbacks__()
|
self.__init_callbacks__()
|
||||||
self.reset()
|
self.reset()
|
||||||
|
self.breakpoints: set[int] = set()
|
||||||
|
|
||||||
def __init_callbacks__(self):
|
def __init_callbacks__(self):
|
||||||
VM.instr_callbacks = {
|
VM.instr_callbacks = {
|
||||||
@ -126,7 +127,6 @@ 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] = set()
|
|
||||||
self._vm_flags: VMFlags = VMFlags(0)
|
self._vm_flags: VMFlags = VMFlags(0)
|
||||||
self.status = VMStatus.INITED
|
self.status = VMStatus.INITED
|
||||||
|
|
||||||
@ -262,6 +262,25 @@ class VM:
|
|||||||
cond, disp
|
cond, disp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _perform_ariphmetic_operation(
|
||||||
|
lhs: int,
|
||||||
|
rhs: int,
|
||||||
|
op: Callable[[int, int], int]
|
||||||
|
) -> tuple[int, VMCC]:
|
||||||
|
cc = VMCC(0)
|
||||||
|
result = op(lhs, rhs)
|
||||||
|
if result < 0:
|
||||||
|
cc |= VMCC.NEGATIVE
|
||||||
|
elif result == 0:
|
||||||
|
cc |= VMCC.ZERO
|
||||||
|
# самая дорогая проверка на переполнение)
|
||||||
|
try:
|
||||||
|
struct.pack('i', result)
|
||||||
|
except struct.error:
|
||||||
|
cc |= VMCC.OVERFLOW
|
||||||
|
return result, cc
|
||||||
|
|
||||||
def _math_callback_gen(
|
def _math_callback_gen(
|
||||||
self,
|
self,
|
||||||
operation: Callable[[int, int], int]
|
operation: Callable[[int, int], int]
|
||||||
@ -274,10 +293,16 @@ class VM:
|
|||||||
def callback(self, r3: int, r1: int, r2: int):
|
def callback(self, r3: int, r1: int, r2: int):
|
||||||
lhs = self.registers[r1].value
|
lhs = self.registers[r1].value
|
||||||
rhs = self.registers[r2].value
|
rhs = self.registers[r2].value
|
||||||
self.registers[r3] = c_int32(operation(lhs, rhs))
|
result, cc = self._perform_ariphmetic_operation(
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
operation)
|
||||||
|
self.registers[r3] = c_int32(result)
|
||||||
|
self.cc = cc
|
||||||
|
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
|
|
||||||
def _math_quick_callback_gen(
|
def _math_quick_callback_gen(
|
||||||
self,
|
self,
|
||||||
operation: Callable[[int, int], int]
|
operation: Callable[[int, int], int]
|
||||||
@ -293,24 +318,21 @@ class VM:
|
|||||||
def callback(self, r3: int, r1: int, i8: int) -> None:
|
def callback(self, r3: int, r1: int, i8: int) -> None:
|
||||||
self.cc = VMCC(0)
|
self.cc = VMCC(0)
|
||||||
lhs = self.registers[r1].value
|
lhs = self.registers[r1].value
|
||||||
result = operation(lhs, i8)
|
result, flags = self._perform_ariphmetic_operation(
|
||||||
if result < 0:
|
lhs,
|
||||||
self.cc |= VMCC.NEGATIVE
|
i8,
|
||||||
elif result == 0:
|
operation)
|
||||||
self.cc |= VMCC.ZERO
|
|
||||||
# самая дорогая проверка на переполнение)
|
|
||||||
try:
|
|
||||||
struct.pack('i', result)
|
|
||||||
except struct.error:
|
|
||||||
self.cc |= VMCC.OVERFLOW
|
|
||||||
self.registers[r3] = c_int32(result)
|
self.registers[r3] = c_int32(result)
|
||||||
|
self.cc = flags
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
def _load_callback(self, r3: int, r1: int, disp: int) -> None:
|
def _load_callback(self, r3: int, r1: int, disp: int) -> None:
|
||||||
addr = self._to_raw_bytes_offset(self.registers[r1].value + disp)
|
addr = self._to_raw_bytes_offset(self.registers[r1].value + disp)
|
||||||
|
raw_bytes = self.mem[addr:addr+WORD_SIZE]
|
||||||
self.registers[r3] = c_int32(
|
self.registers[r3] = c_int32(
|
||||||
struct.unpack(
|
struct.unpack(
|
||||||
">i", self.mem[addr:addr+WORD_SIZE])[0]
|
">i", raw_bytes
|
||||||
|
)[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
def _store_callback(self, r3: int, r1: int, disp: int) -> None:
|
def _store_callback(self, r3: int, r1: int, disp: int) -> None:
|
||||||
Reference in New Issue
Block a user