diff --git a/riscemu/MMU.py b/riscemu/MMU.py index 93f7612..ff806f2 100644 --- a/riscemu/MMU.py +++ b/riscemu/MMU.py @@ -72,7 +72,7 @@ class MMU: return sec return None - def get_bin_containing(self, addr: T_AbsoluteAddress) -> Optional[Program]: + def get_program_at_addr(self, addr: T_AbsoluteAddress) -> Optional[Program]: for program in self.programs: if program.base <= addr < program.base + program.size: return program @@ -192,7 +192,7 @@ class MMU: if not sec: return "unknown at 0x{:0x}".format(address) - bin = self.get_bin_containing(address) + bin = self.get_program_at_addr(address) secs = set(sec.name for sec in bin.sections) if bin else [] elf_markers = { "__global_pointer$", @@ -347,3 +347,13 @@ class MMU: return sec.context return InstructionContext() + + def find_entrypoint(self) -> int | None: + # try to find the global entrypoint + if "_start" in self.global_symbols: + return self.global_symbols["_start"] + # otherwise find a main (that's not necessarily global) + for p in self.programs: + if "main" in p.context.labels: + return p.context.resolve_label("main") + return None diff --git a/riscemu/__main__.py b/riscemu/__main__.py index ee8fd02..8387e0e 100644 --- a/riscemu/__main__.py +++ b/riscemu/__main__.py @@ -176,7 +176,7 @@ unlimited_regs: Allow an unlimited number of registers""", cpu.setup_stack(cfg.stack_size) # launch the last loaded program - cpu.launch(cpu.mmu.programs[-1], verbose=cfg.verbosity > 1) + cpu.launch(verbose=cfg.verbosity > 1) sys.exit(cpu.exit_code if not args.ignore_exit_code else 0) except RiscemuBaseException as e: diff --git a/riscemu/interactive.py b/riscemu/interactive.py index 0d10ee9..038ffb7 100644 --- a/riscemu/interactive.py +++ b/riscemu/interactive.py @@ -31,6 +31,6 @@ if __name__ == "__main__": cpu.setup_stack() - cpu.launch(program) + cpu.launch() sys.exit(cpu.exit_code) diff --git a/riscemu/types/cpu.py b/riscemu/types/cpu.py index 5a1fc21..4dd7bc4 100644 --- a/riscemu/types/cpu.py +++ b/riscemu/types/cpu.py @@ -1,13 +1,12 @@ -import typing from abc import ABC, abstractmethod -from typing import List, Type, Callable, Set, Dict, TYPE_CHECKING +from typing import List, Type, Callable, Set, Dict, TYPE_CHECKING, Iterable from ..registers import Registers from ..config import RunConfig -from ..colors import FMT_RED, FMT_NONE, FMT_ERROR, FMT_CPU +from ..colors import FMT_NONE, FMT_CPU from . import T_AbsoluteAddress, Instruction, Program, ProgramLoader -if typing.TYPE_CHECKING: +if TYPE_CHECKING: from ..MMU import MMU from ..instructions import InstructionSet @@ -91,27 +90,26 @@ class CPU(ABC): def run(self, verbose: bool = False): pass - def launch(self, program: Program, verbose: bool = False): - if program not in self.mmu.programs: - print( - FMT_ERROR + "[CPU] Cannot launch program that's not loaded!" + FMT_NONE - ) - return + def launch(self, verbose: bool = False): + entrypoint = self.mmu.find_entrypoint() + + if entrypoint is None: + entrypoint = self.mmu.programs[0].entrypoint + if self.conf.verbosity > 0: print( FMT_CPU + "[CPU] Started running from {}".format( - self.mmu.translate_address(program.entrypoint) + self.mmu.translate_address(entrypoint) ) + FMT_NONE ) - print(program) - self.pc = program.entrypoint + self.pc = entrypoint self.run(verbose) @classmethod @abstractmethod - def get_loaders(cls) -> typing.Iterable[Type[ProgramLoader]]: + def get_loaders(cls) -> Iterable[Type[ProgramLoader]]: pass def get_best_loader_for(self, file_name: str) -> Type[ProgramLoader]: