misc: improve typing and structure

master
Anton Lydike 1 year ago
parent 1c2dad94e2
commit 47a9b12263

10
.gitignore vendored

@ -1,6 +1,8 @@
venv
__pycache__ __pycache__
.mypy_cache .mypy_cache
dist/ .pytest_cache
riscemu.egg-info
build/ /venv*
/dist
/riscemu.egg-info
/build

@ -348,7 +348,7 @@ class MMU:
return InstructionContext() return InstructionContext()
def find_entrypoint(self) -> int | None: def find_entrypoint(self) -> Optional[int]:
# try to find the global entrypoint # try to find the global entrypoint
if "_start" in self.global_symbols: if "_start" in self.global_symbols:
return self.global_symbols["_start"] return self.global_symbols["_start"]

@ -12,7 +12,7 @@ from riscemu.riscemu_main import RiscemuMain
try: try:
main = RiscemuMain() main = RiscemuMain()
main.run(sys.argv[1:]) main.run_from_cli(sys.argv[1:])
sys.exit(main.cpu.exit_code if not main.cfg.ignore_exit_code else 0) sys.exit(main.cpu.exit_code if not main.cfg.ignore_exit_code else 0)
except RiscemuBaseException as e: except RiscemuBaseException as e:

@ -2,7 +2,7 @@ import argparse
import glob import glob
import os import os
import sys import sys
from typing import List, Type from typing import Type, Dict, List, Optional
from riscemu import AssemblyFileLoader, __version__, __copyright__ from riscemu import AssemblyFileLoader, __version__, __copyright__
from riscemu.types import CPU, ProgramLoader, Program from riscemu.types import CPU, ProgramLoader, Program
@ -17,21 +17,21 @@ class RiscemuMain:
interoperability. interoperability.
""" """
available_ins_sets: dict[str, type[InstructionSet]] available_ins_sets: Dict[str, Type[InstructionSet]]
available_file_loaders: list[type[ProgramLoader]] available_file_loaders: List[Type[ProgramLoader]]
cfg: RunConfig | None cfg: Optional[RunConfig]
cpu: CPU | None cpu: Optional[CPU]
input_files: list[str] input_files: List[str]
selected_ins_sets: list[Type[InstructionSet]] selected_ins_sets: List[Type[InstructionSet]]
def __init__(self): def __init__(self):
self.available_ins_sets = dict() self.available_ins_sets = dict()
self.selected_ins_sets = [] self.selected_ins_sets = []
self.available_file_loaders = [] self.available_file_loaders = []
self.cfg: RunConfig | None = None self.cfg: Optional[RunConfig] = None
self.cpu: CPU | None = None self.cpu: Optional[CPU] = None
self.input_files = [] self.input_files = []
self.selected_ins_sets = [] self.selected_ins_sets = []
@ -129,7 +129,7 @@ class RiscemuMain:
def register_all_program_loaders(self): def register_all_program_loaders(self):
self.available_file_loaders.append(AssemblyFileLoader) self.available_file_loaders.append(AssemblyFileLoader)
def parse_argv(self, argv: list[str]): def parse_argv(self, argv: List[str]):
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="RISC-V Userspace emulator", description="RISC-V Userspace emulator",
prog="riscemu", prog="riscemu",
@ -153,7 +153,7 @@ class RiscemuMain:
setattr(args, "ins", {k: True for k in self.available_ins_sets}) setattr(args, "ins", {k: True for k in self.available_ins_sets})
# create RunConfig # create RunConfig
self.cfg = self.config_from_parsed_args(args) self.cfg = self.create_config(args)
# set input files # set input files
self.input_files = args.files self.input_files = args.files
@ -167,6 +167,12 @@ class RiscemuMain:
# if use_libc is given, attach libc to path # if use_libc is given, attach libc to path
if self.cfg.use_libc: if self.cfg.use_libc:
self.add_libc_to_input_files()
def add_libc_to_input_files(self):
"""
This adds the provided riscemu libc to the programs runtime.
"""
libc_path = os.path.join( libc_path = os.path.join(
os.path.dirname(__file__), os.path.dirname(__file__),
"..", "..",
@ -174,9 +180,10 @@ class RiscemuMain:
"*.s", "*.s",
) )
for path in glob.iglob(libc_path): for path in glob.iglob(libc_path):
if path not in self.input_files:
self.input_files.append(path) self.input_files.append(path)
def config_from_parsed_args(self, args: argparse.Namespace) -> RunConfig: def create_config(self, args: argparse.Namespace) -> RunConfig:
# create a RunConfig from the cli args # create a RunConfig from the cli args
cfg_dict = dict( cfg_dict = dict(
stack_size=args.stack_size, stack_size=args.stack_size,
@ -208,7 +215,7 @@ class RiscemuMain:
for p in programs: for p in programs:
self.cpu.mmu.load_program(p) self.cpu.mmu.load_program(p)
def run(self, argv: list[str]): def run_from_cli(self, argv: List[str]):
# register everything # register everything
self.register_all_isas() self.register_all_isas()
self.register_all_program_loaders() self.register_all_program_loaders()
@ -221,6 +228,29 @@ class RiscemuMain:
# run the program # run the program
self.cpu.launch(self.cfg.verbosity > 1) self.cpu.launch(self.cfg.verbosity > 1)
def run(self):
"""
This assumes that these values were set externally:
- available_file_loaders: A list of available file loaders.
Can be set using .register_all_program_loaders()
- cfg: The RunConfig object. Can be directly assigned to the attribute
- input_files: A list of assembly files to load.
- selected_ins_sets: A list of instruction sets the CPU should support.
"""
assert self.cfg is not None, "self.cfg must be set before calling run()"
assert self.selected_ins_sets, "self.selected_ins_sets cannot be empty"
assert self.input_files, "self.input_files cannot be empty"
if self.cfg.use_libc:
self.add_libc_to_input_files()
self.instantiate_cpu()
self.load_programs()
# run the program
self.cpu.launch(self.cfg.verbosity > 1)
class OptionStringAction(argparse.Action): class OptionStringAction(argparse.Action):
def __init__(self, option_strings, dest, keys=None, omit_empty=False, **kwargs): def __init__(self, option_strings, dest, keys=None, omit_empty=False, **kwargs):

@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass
from math import log2, ceil from math import log2, ceil
from typing import Dict, IO from typing import Dict, IO, Union
from .types import BinaryDataMemorySection, MemoryFlags from .types import BinaryDataMemorySection, MemoryFlags
from .colors import FMT_SYSCALL, FMT_NONE from .colors import FMT_SYSCALL, FMT_NONE
@ -70,7 +70,7 @@ class Syscall:
def __repr__(self): def __repr__(self):
return "Syscall(id={}, name={})".format(self.id, self.name) return "Syscall(id={}, name={})".format(self.id, self.name)
def ret(self, code: int | Int32): def ret(self, code: Union[int, Int32]):
self.cpu.regs.set("a0", Int32(code)) self.cpu.regs.set("a0", Int32(code))

Loading…
Cancel
Save