Compare commits

..

4 Commits

Author SHA1 Message Date
Anton Lydike 4d19738072 release 2.1.1 1 year ago
Anton Lydike 47fef8c99f update changelog 1 year ago
Anton Lydike d508e01a6b misc: test python 3.8 in CI, add cfg arg to RiscemuRunner 1 year ago
Anton Lydike 47a9b12263 misc: improve typing and structure 1 year ago

@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10']
python-version: ['3.8','3.10']
steps:
- uses: actions/checkout@v3

10
.gitignore vendored

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

@ -1,14 +1,18 @@
# Changelog
## Upcoming 2.0.6
## 2.1.1
- Bugfix: Allow infinite registers with more than two digits in load/store ins
- Bugfix: Fix how floating point registers are displayed in the debugger
- Bugfix: Various semantic problems in RV32F
## 2.1.0
- Added a very basic libc containing a `crt0.s`, and a few functions
such as `malloc`, `rand`, and `memcpy`.
- Added a subset of the `mmap2` syscall (code 192) to allocate new memory
- Refactored the launching code to improve using riscemu from code
**Planned:**
- Add a floating point unit
- Added floating point support (enabled by default). The RV32F extension is now available
## 2.0.5

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

@ -34,4 +34,4 @@ from .parser import tokenize, parse_tokens, AssemblyFileLoader
__author__ = "Anton Lydike <Anton@Lydike.com>"
__copyright__ = "Copyright 2023 Anton Lydike"
__version__ = "2.0.5"
__version__ = "2.1.1"

@ -12,7 +12,7 @@ from riscemu.riscemu_main import RiscemuMain
try:
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)
except RiscemuBaseException as e:

@ -2,7 +2,7 @@ import argparse
import glob
import os
import sys
from typing import List, Type
from typing import Type, Dict, List, Optional
from riscemu import AssemblyFileLoader, __version__, __copyright__
from riscemu.types import CPU, ProgramLoader, Program
@ -17,21 +17,21 @@ class RiscemuMain:
interoperability.
"""
available_ins_sets: dict[str, type[InstructionSet]]
available_file_loaders: list[type[ProgramLoader]]
available_ins_sets: Dict[str, Type[InstructionSet]]
available_file_loaders: List[Type[ProgramLoader]]
cfg: RunConfig | None
cpu: CPU | None
cfg: Optional[RunConfig]
cpu: Optional[CPU]
input_files: list[str]
selected_ins_sets: list[Type[InstructionSet]]
input_files: List[str]
selected_ins_sets: List[Type[InstructionSet]]
def __init__(self):
def __init__(self, cfg: Optional[RunConfig] = None):
self.available_ins_sets = dict()
self.selected_ins_sets = []
self.available_file_loaders = []
self.cfg: RunConfig | None = None
self.cpu: CPU | None = None
self.cfg: Optional[RunConfig] = cfg
self.cpu: Optional[CPU] = None
self.input_files = []
self.selected_ins_sets = []
@ -129,7 +129,7 @@ class RiscemuMain:
def register_all_program_loaders(self):
self.available_file_loaders.append(AssemblyFileLoader)
def parse_argv(self, argv: list[str]):
def parse_argv(self, argv: List[str]):
parser = argparse.ArgumentParser(
description="RISC-V Userspace emulator",
prog="riscemu",
@ -153,7 +153,7 @@ class RiscemuMain:
setattr(args, "ins", {k: True for k in self.available_ins_sets})
# create RunConfig
self.cfg = self.config_from_parsed_args(args)
self.cfg = self.create_config(args)
# set input files
self.input_files = args.files
@ -167,16 +167,23 @@ class RiscemuMain:
# if use_libc is given, attach libc to path
if self.cfg.use_libc:
libc_path = os.path.join(
os.path.dirname(__file__),
"..",
"libc",
"*.s",
)
for path in glob.iglob(libc_path):
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(
os.path.dirname(__file__),
"..",
"libc",
"*.s",
)
for path in glob.iglob(libc_path):
if path not in self.input_files:
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
cfg_dict = dict(
stack_size=args.stack_size,
@ -208,7 +215,7 @@ class RiscemuMain:
for p in programs:
self.cpu.mmu.load_program(p)
def run(self, argv: list[str]):
def run_from_cli(self, argv: List[str]):
# register everything
self.register_all_isas()
self.register_all_program_loaders()
@ -221,6 +228,29 @@ class RiscemuMain:
# run the program
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):
def __init__(self, option_strings, dest, keys=None, omit_empty=False, **kwargs):

@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT
import sys
from dataclasses import dataclass
from math import log2, ceil
from typing import Dict, IO
from typing import Dict, IO, Union
from .types import BinaryDataMemorySection, MemoryFlags
from .colors import FMT_SYSCALL, FMT_NONE
@ -70,7 +70,7 @@ class Syscall:
def __repr__(self):
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))

Loading…
Cancel
Save