add an unlimited register mode

master
Anton Lydike 2 years ago
parent 86063d64d7
commit 636e06f243

@ -57,12 +57,19 @@ if __name__ == '__main__':
setattr(namespace, self.dest, d) setattr(namespace, self.dest, d)
parser = argparse.ArgumentParser(description='RISC-V Userspace parser and emulator', prog='riscemu') parser = argparse.ArgumentParser(description='RISC-V Userspace parser and emulator', prog='riscemu',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('files', metavar='file.asm', type=str, nargs='+', parser.add_argument('files', metavar='file.asm', type=str, nargs='+',
help='The assembly files to load, the last one will be run') help='The assembly files to load, the last one will be run')
parser.add_argument('--options', '-o', action=OptionStringAction, parser.add_argument('--options', '-o', action=OptionStringAction,
keys=('disable_debug', 'no_syscall_symbols', 'fail_on_ex', 'add_accept_imm')) keys=('disable_debug', 'no_syscall_symbols', 'fail_on_ex', 'add_accept_imm', 'unlimited_regs'),
help="""Toggle options. Available options are:
disable_debug: Disable ebreak instructions
no_syscall_symbols: Don't add symbols for SCALL_EXIT and others
fail_on_ex: If set, exceptions won't trigger the debugger
add_accept_imm: Accept "add rd, rs, imm" instruction (instead of addi)
unlimited_regs: Allow an unlimited number of registers""")
parser.add_argument('--syscall-opts', '-so', action=OptionStringAction, parser.add_argument('--syscall-opts', '-so', action=OptionStringAction,
keys=('fs_access', 'disable_input')) keys=('fs_access', 'disable_input'))
@ -88,6 +95,7 @@ if __name__ == '__main__':
include_scall_symbols=not args.options['no_syscall_symbols'], include_scall_symbols=not args.options['no_syscall_symbols'],
debug_on_exception=not args.options['fail_on_ex'], debug_on_exception=not args.options['fail_on_ex'],
add_accept_imm=args.options['add_accept_imm'], add_accept_imm=args.options['add_accept_imm'],
unlimited_registers=args.options['unlimited_regs'],
scall_fs=args.syscall_opts['fs_access'], scall_fs=args.syscall_opts['fs_access'],
scall_input=not args.syscall_opts['disable_input'], scall_input=not args.syscall_opts['disable_input'],
verbosity=args.verbose verbosity=args.verbose

@ -20,6 +20,7 @@ class RunConfig:
scall_fs: bool = False scall_fs: bool = False
verbosity: int = 0 verbosity: int = 0
slowdown: float = 1 slowdown: float = 1
unlimited_registers: bool = False
CONFIG = RunConfig() CONFIG = RunConfig()

@ -6,7 +6,7 @@ SPDX-License-Identifier: MIT
This package holds all instruction sets, available to the processor This package holds all instruction sets, available to the processor
""" """
from .instruction_set import InstructionSet from .instruction_set import InstructionSet, Instruction
from .RV32M import RV32M from .RV32M import RV32M
from .RV32I import RV32I from .RV32I import RV32I
from .RV32A import RV32A from .RV32A import RV32A

@ -110,6 +110,9 @@ class AssemblyFileLoader(ProgramLoader):
with open(self.source_path, 'r') as f: with open(self.source_path, 'r') as f:
return parse_tokens(self.filename, tokenize(f)) return parse_tokens(self.filename, tokenize(f))
def parse_io(self, io):
return parse_tokens(self.filename, tokenize(io))
@classmethod @classmethod
def can_parse(cls, source_path: str) -> float: def can_parse(cls, source_path: str) -> float:
""" """

@ -17,11 +17,22 @@ class Registers:
Represents a bunch of registers Represents a bunch of registers
""" """
def __init__(self): valid_regs = {
'zero', 'ra', 'sp', 'gp', 'tp', 's0', 'fp',
't0', 't1', 't2', 't3', 't4', 't5', 't6',
's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11',
'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7',
'ft0', 'ft1', 'ft2', 'ft3', 'ft4', 'ft5', 'ft6', 'ft7',
'fs0', 'fs1', 'fs2', 'fs3', 'fs4', 'fs5', 'fs6', 'fs7', 'fs8', 'fs9', 'fs10', 'fs11',
'fa0', 'fa1', 'fa2', 'fa3', 'fa4', 'fa5', 'fa6', 'fa7'
}
def __init__(self, infinite_regs: bool = False):
from .types import Int32 from .types import Int32
self.vals = defaultdict(lambda: Int32(0)) self.vals = defaultdict(lambda: Int32(0))
self.last_set = None self.last_set = None
self.last_read = None self.last_read = None
self.infinite_regs = infinite_regs
def dump(self, full=False): def dump(self, full=False):
""" """
@ -108,7 +119,10 @@ class Registers:
reg = 's1' reg = 's1'
if mark_set: if mark_set:
self.last_set = reg self.last_set = reg
# check 32 bit signed bounds
if not self.infinite_regs and reg not in self.valid_regs:
raise RuntimeError("Invalid register: {}".format(reg))
self.vals[reg] = val.unsigned() self.vals[reg] = val.unsigned()
return True return True
@ -123,6 +137,10 @@ class Registers:
# raise InvalidRegisterException(reg) # raise InvalidRegisterException(reg)
if reg == 'fp': if reg == 'fp':
reg = 's0' reg = 's0'
if not self.infinite_regs and reg not in self.valid_regs:
raise RuntimeError("Invalid register: {}".format(reg))
if mark_read: if mark_read:
self.last_read = reg self.last_read = reg
return self.vals[reg] return self.vals[reg]

@ -31,7 +31,7 @@ class CPU(ABC):
def __init__(self, mmu: 'MMU', instruction_sets: List[Type['InstructionSet']], conf: RunConfig): def __init__(self, mmu: 'MMU', instruction_sets: List[Type['InstructionSet']], conf: RunConfig):
self.mmu = mmu self.mmu = mmu
self.regs = Registers() self.regs = Registers(conf.unlimited_registers)
self.conf = conf self.conf = conf
self.instruction_sets = set() self.instruction_sets = set()

Loading…
Cancel
Save