lots more documentation cleanup

float_support
Anton Lydike 4 years ago
parent fdcb3a71be
commit 0574766a81

@ -17,32 +17,37 @@ class MMU:
The MemoryManagementUnit (handles loading binaries, and reading/writing data) The MemoryManagementUnit (handles loading binaries, and reading/writing data)
""" """
max_size = 0xFFFFFFFF
""" """
The maximum size of the memory in bytes The maximum size of the memory in bytes
""" """
max_size = 0xFFFFFFFF
sections: List[LoadedMemorySection]
""" """
A list of all loaded memory sections A list of all loaded memory sections
""" """
sections: List[LoadedMemorySection]
binaries: List[LoadedExecutable]
""" """
A list of all loaded executables A list of all loaded executables
""" """
binaries: List[LoadedExecutable]
last_bin: Optional[LoadedExecutable] = None
""" """
The last loaded executable (the next executable is inserted directly after this one) The last loaded executable (the next executable is inserted directly after this one)
""" """
last_bin: Optional[LoadedExecutable] = None
global_symbols: Dict[str, int]
""" """
The global symbol table The global symbol table
""" """
global_symbols: Dict[str, int]
def __init__(self, conf: RunConfig): def __init__(self, conf: RunConfig):
"""
Create a new MMU, respeccting the active RunConfiguration
:param conf: The config to respect
"""
self.sections = list() self.sections = list()
self.binaries = list() self.binaries = list()
self.last_bin = None self.last_bin = None
@ -52,6 +57,7 @@ class MMU:
def load_bin(self, bin: Executable) -> LoadedExecutable: def load_bin(self, bin: Executable) -> LoadedExecutable:
""" """
Load an executable into memory Load an executable into memory
:param bin: the executable to load :param bin: the executable to load
:return: A LoadedExecutable :return: A LoadedExecutable
:raises OutOfMemoryException: When all memory is used :raises OutOfMemoryException: When all memory is used
@ -88,6 +94,7 @@ class MMU:
def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]: def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]:
""" """
Returns the section that contains the address addr Returns the section that contains the address addr
:param addr: the Address to look for :param addr: the Address to look for
:return: The LoadedMemorySection or None :return: The LoadedMemorySection or None
""" """
@ -99,6 +106,7 @@ class MMU:
def read_ins(self, addr: int) -> LoadedInstruction: def read_ins(self, addr: int) -> LoadedInstruction:
""" """
Read a single instruction located at addr Read a single instruction located at addr
:param addr: The location :param addr: The location
:return: The Instruction :return: The Instruction
""" """
@ -108,6 +116,7 @@ class MMU:
def read(self, addr: int, size: int) -> bytearray: def read(self, addr: int, size: int) -> bytearray:
""" """
Read size bytes of memory at addr Read size bytes of memory at addr
:param addr: The addres at which to start reading :param addr: The addres at which to start reading
:param size: The number of bytes to read :param size: The number of bytes to read
:return: The bytearray at addr :return: The bytearray at addr
@ -118,6 +127,7 @@ class MMU:
def write(self, addr: int, size: int, data): def write(self, addr: int, size: int, data):
""" """
Write bytes into memory Write bytes into memory
:param addr: The address at which to write :param addr: The address at which to write
:param size: The number of bytes to write :param size: The number of bytes to write
:param data: The bytearray to write (only first size bytes are written) :param data: The bytearray to write (only first size bytes are written)
@ -141,6 +151,7 @@ class MMU:
def symbol(self, symb: str): def symbol(self, symb: str):
""" """
Look up the symbol symb in all local symbol tables (and the global one) Look up the symbol symb in all local symbol tables (and the global one)
:param symb: The symbol name to look up :param symb: The symbol name to look up
""" """
print(FMT_MEM + "[MMU] Lookup for symbol {}:".format(symb) + FMT_NONE) print(FMT_MEM + "[MMU] Lookup for symbol {}:".format(symb) + FMT_NONE)

@ -8,18 +8,15 @@ from dataclasses import dataclass
from typing import Dict, IO from typing import Dict, IO
import sys import sys
from .Registers import Registers
from .Exceptions import InvalidSyscallException
from .helpers import * from .helpers import *
import riscemu
import typing import typing
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from . import CPU from . import CPU
"""
All available syscalls (mapped id->name)
"""
SYSCALLS = { SYSCALLS = {
63: 'read', 63: 'read',
64: 'write', 64: 'write',
@ -27,10 +24,8 @@ SYSCALLS = {
1024: 'open', 1024: 'open',
1025: 'close', 1025: 'close',
} }
"""All available syscalls (mapped id->name)"""
"""
All available file open modes
"""
OPEN_MODES = { OPEN_MODES = {
0: 'rb', 0: 'rb',
1: 'wb', 1: 'wb',
@ -38,7 +33,7 @@ OPEN_MODES = {
3: 'x', 3: 'x',
4: 'ab', 4: 'ab',
} }
"""All available file open modes"""
@dataclass(frozen=True) @dataclass(frozen=True)
class Syscall: class Syscall:
@ -46,8 +41,9 @@ class Syscall:
Represents a syscall Represents a syscall
""" """
id: int id: int
registers: Registers """The syscall number (e.g. 64 - write)"""
cpu: 'CPU' cpu: 'riscemu.CPU'
"""The CPU object that created the syscall"""
@property @property
def name(self): def name(self):
@ -59,13 +55,14 @@ class Syscall:
) )
def ret(self, code): def ret(self, code):
self.registers.set('a0', code) self.cpu.regs.set('a0', code)
def get_syscall_symbols(): def get_syscall_symbols():
""" """
Retuns a dictionary of all syscall symbols (SCALL_<name> -> id) Generate global syscall symbols (such as SCALL_READ, SCALL_EXIT etc)
:return:
:return: dictionary of all syscall symbols (SCALL_<name> -> id)
""" """
return { return {
('SCALL_' + name.upper()): num for num, name in SYSCALLS.items() ('SCALL_' + name.upper()): num for num, name in SYSCALLS.items()
@ -97,11 +94,11 @@ class SyscallInterface:
read syscall (63): read from file no a0, into addr a1, at most a2 bytes read syscall (63): read from file no a0, into addr a1, at most a2 bytes
on return a0 will be the number of read bytes or -1 if an error occured on return a0 will be the number of read bytes or -1 if an error occured
""" """
fileno = scall.registers.get('a0') fileno = scall.cpu.regs.get('a0')
addr = scall.registers.get('a1') addr = scall.cpu.regs.get('a1')
size = scall.registers.get('a2') size = scall.cpu.regs.get('a2')
if fileno not in self.open_files: if fileno not in self.open_files:
scall.registers.set('a0', -1) scall.cpu.regs.set('a0', -1)
return return
chars = self.open_files[fileno].readline(size) chars = self.open_files[fileno].readline(size)
@ -119,9 +116,9 @@ class SyscallInterface:
write syscall (64): write a2 bytes from addr a1 into fileno a0 write syscall (64): write a2 bytes from addr a1 into fileno a0
on return a0 will hold the number of bytes written or -1 if an error occured on return a0 will hold the number of bytes written or -1 if an error occured
""" """
fileno = scall.registers.get('a0') fileno = scall.cpu.regs.get('a0')
addr = scall.registers.get('a1') addr = scall.cpu.regs.get('a1')
size = scall.registers.get('a2') size = scall.cpu.regs.get('a2')
if fileno not in self.open_files: if fileno not in self.open_files:
return scall.ret(-1) return scall.ret(-1)
@ -152,9 +149,9 @@ class SyscallInterface:
print(FMT_SYSCALL + '[Syscall] open: opening files not supported without scall-fs flag!' + FMT_NONE) print(FMT_SYSCALL + '[Syscall] open: opening files not supported without scall-fs flag!' + FMT_NONE)
return scall.ret(-1) return scall.ret(-1)
mode = scall.registers.get('a0') mode = scall.cpu.regs.get('a0')
addr = scall.registers.get('a1') addr = scall.cpu.regs.get('a1')
size = scall.registers.get('a2') size = scall.cpu.regs.get('a2')
mode_st = OPEN_MODES.get(mode, ) mode_st = OPEN_MODES.get(mode, )
if mode_st == -1: if mode_st == -1:
@ -181,7 +178,7 @@ class SyscallInterface:
return -1 if an error was encountered, otherwise returns 0 return -1 if an error was encountered, otherwise returns 0
""" """
fileno = scall.registers.get('a0') fileno = scall.cpu.regs.get('a0')
if fileno not in self.open_files: if fileno not in self.open_files:
print(FMT_SYSCALL + '[Syscall] close: unknown fileno {}!'.format(fileno) + FMT_NONE) print(FMT_SYSCALL + '[Syscall] close: unknown fileno {}!'.format(fileno) + FMT_NONE)
return scall.ret(-1) return scall.ret(-1)
@ -196,7 +193,7 @@ class SyscallInterface:
Exit syscall. Exits the system with status code a0 Exit syscall. Exits the system with status code a0
""" """
scall.cpu.exit = True scall.cpu.exit = True
scall.cpu.exit_code = scall.registers.get('a0') scall.cpu.exit_code = scall.cpu.regs.get('a0')
def __repr__(self): def __repr__(self):
return "{}(\n\tfiles={}\n)".format( return "{}(\n\tfiles={}\n)".format(

@ -25,3 +25,6 @@ from .Syscall import SyscallInterface, Syscall
from .CPU import CPU from .CPU import CPU
from .Config import RunConfig from .Config import RunConfig
__author__ = "Anton Lydike <Anton@Lydike.com"
__copyright__ = "Copyright 2021 Anton Lydike"

@ -8,14 +8,14 @@ from math import log10, ceil
from .Exceptions import * from .Exceptions import *
def align_addr(addr: int, to_bytes: int = 8): def align_addr(addr: int, to_bytes: int = 8) -> int:
""" """
align an address to `to_bytes` (meaning addr & to_bytes = 0) align an address to `to_bytes` (meaning addr & to_bytes = 0)
""" """
return addr + (-addr % to_bytes) return addr + (-addr % to_bytes)
def parse_numeric_argument(arg: str): def parse_numeric_argument(arg: str) -> int:
""" """
parse hex or int strings parse hex or int strings
""" """
@ -27,7 +27,7 @@ def parse_numeric_argument(arg: str):
raise ParseException('Invalid immediate argument \"{}\", maybe missing symbol?'.format(arg), (arg, ex)) raise ParseException('Invalid immediate argument \"{}\", maybe missing symbol?'.format(arg), (arg, ex))
def int_to_bytes(val, bytes=4, unsigned=False): def int_to_bytes(val, bytes=4, unsigned=False) -> bytearray:
""" """
int -> byte (two's complement) int -> byte (two's complement)
""" """
@ -38,7 +38,7 @@ def int_to_bytes(val, bytes=4, unsigned=False):
]) ])
def int_from_bytes(bytes, unsigned=False): def int_from_bytes(bytes, unsigned=False) -> int:
""" """
byte -> int (two's complement) byte -> int (two's complement)
""" """
@ -53,19 +53,20 @@ def int_from_bytes(bytes, unsigned=False):
return to_signed(num) return to_signed(num)
def to_unsigned(num: int, bytes=4): def to_unsigned(num: int, bytes=4) -> int:
if num < 0: if num < 0:
return 2 ** (bytes * 8) + num return 2 ** (bytes * 8) + num
return num return num
def to_signed(num: int, bytes=4): def to_signed(num: int, bytes=4) -> int:
if num >> (bytes * 8 - 1): if num >> (bytes * 8 - 1):
return num - 2 ** (8 * bytes) return num - 2 ** (8 * bytes)
return num return num
def create_chunks(my_list, chunk_size): def create_chunks(my_list, chunk_size):
"""Split a list like [a,b,c,d,e,f,g,h,i,j,k,l,m] into e.g. [[a,b,c,d],[e,f,g,h],[i,j,k,l],[m]]"""
return [my_list[i:i + chunk_size] for i in range(0, len(my_list), chunk_size)] return [my_list[i:i + chunk_size] for i in range(0, len(my_list), chunk_size)]
@ -83,6 +84,7 @@ def highlight_in_list(items, hi_ind):
def format_bytes(byte_arr: bytearray, fmt: str, group: int = 1, highlight: int = -1): def format_bytes(byte_arr: bytearray, fmt: str, group: int = 1, highlight: int = -1):
"""Format byte array as per fmt. Group into groups of size `group`, and highlight index `highlight`."""
chunks = create_chunks(byte_arr, group) chunks = create_chunks(byte_arr, group)
if fmt == 'hex': if fmt == 'hex':
return highlight_in_list(['0x{}'.format(ch.hex()) for ch in chunks], highlight) return highlight_in_list(['0x{}'.format(ch.hex()) for ch in chunks], highlight)

@ -24,6 +24,9 @@ class InstructionSet(ABC):
""" """
def __init__(self, cpu: 'CPU'): def __init__(self, cpu: 'CPU'):
"""Create a new instance of the Instruction set. This requires access to a CPU, and grabs vertain things
from it such as access to the MMU and registers.
"""
self.name = self.__class__.__name__ self.name = self.__class__.__name__
self.cpu = cpu self.cpu = cpu
self.mmu = cpu.mmu self.mmu = cpu.mmu

@ -293,7 +293,7 @@ class RV32I(InstructionSet):
def instruction_scall(self, ins: 'LoadedInstruction'): def instruction_scall(self, ins: 'LoadedInstruction'):
ASSERT_LEN(ins.args, 0) ASSERT_LEN(ins.args, 0)
syscall = Syscall(self.regs.get('a7'), self.regs, self.cpu) syscall = Syscall(self.regs.get('a7'), self.cpu)
self.cpu.syscall_int.handle_syscall(syscall) self.cpu.syscall_int.handle_syscall(syscall)
def instruction_sbreak(self, ins: 'LoadedInstruction'): def instruction_sbreak(self, ins: 'LoadedInstruction'):

Loading…
Cancel
Save