added lots of documentation in pydoc style

float_support
Anton Lydike 4 years ago
parent 8c1714116e
commit 2a68f16e99

@ -1,15 +1,23 @@
"""
RiscEmu (c) 2021 Anton Lydike
SPDX-License-Identifier: BSD-2-Clause
This file contains the CPU logic (not the individual instruction sets). See instructions/InstructionSet.py for more info
on them.
"""
import sys
import traceback
from typing import Tuple, List, Dict, Callable, Type
from .Tokenizer import RiscVTokenizer
from .Syscall import *
from .Exceptions import *
from .Syscall import SyscallInterface
from .Exceptions import RiscemuBaseException, LaunchDebuggerException
from .MMU import MMU
from .Config import RunConfig
from .Registers import Registers
from .debug import launch_debug_session
from .colors import FMT_CPU, FMT_NONE, FMT_ERROR
import typing
@ -19,7 +27,18 @@ if typing.TYPE_CHECKING:
class CPU:
"""
This class represents a single CPU. It holds references to it's mmu, registers and syscall interrupt handler.
It is initialized with a configuration and a list of instruction sets.
"""
def __init__(self, conf: RunConfig, instruction_sets: List[Type['InstructionSet']]):
"""
Creates a CPU instance.
:param conf: An instance of the current RunConfiguration
:param instruction_sets: A list of instruction set classes. These must inherit from the InstructionSet class
"""
# setup CPU states
self.pc = 0
self.cycle = 0
@ -48,6 +67,8 @@ class CPU:
def get_tokenizer(self, tokenizer_input):
"""
Returns a tokenizer that respects the language of the CPU
:param tokenizer_input: an instance of the RiscVTokenizerInput class
"""
return RiscVTokenizer(tokenizer_input, self.all_instructions())
@ -70,11 +91,16 @@ class CPU:
def continue_from_debugger(self, verbose=True):
"""
dalled from the debugger to continue running
called from the debugger to continue running
:param verbose: If True, will print each executed instruction to STDOUT
"""
self.__run(verbose)
def step(self):
"""
Execute a single instruction, then return.
"""
if self.exit:
print(FMT_CPU + "[CPU] Program exited with code {}".format(self.exit_code) + FMT_NONE)
else:
@ -131,11 +157,18 @@ class CPU:
raise RuntimeError("Unknown instruction: {}".format(ins))
def all_instructions(self) -> List[str]:
"""
Return a list of all instructions this CPU can execute.
"""
return list(self.instructions.keys())
def __repr__(self):
return "CPU(pc=0x{:08X}, cycle={}, instructions={})".format(
"""
Returns a representation of the CPU and some of its state.
"""
return "CPU(pc=0x{:08X}, cycle={}, exit={}, instructions={})".format(
self.pc,
self.cycle,
self.exit,
" ".join(s.name for s in self.instruction_sets)
)

@ -1,15 +1,15 @@
from .Exceptions import *
from .Exceptions import RiscemuBaseException, LaunchDebuggerException, InvalidSyscallException, LinkerException, \
ParseException, NumberFormatException, InvalidRegisterException, MemoryAccessException, OutOfMemoryException
from .Tokenizer import RiscVToken, RiscVInput, RiscVTokenizer, RiscVInstructionToken, RiscVSymbolToken, \
RiscVPseudoOpToken, TokenType
from .Tokenizer import RiscVInput, RiscVTokenizer
from .Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction
from .Executable import Executable, LoadedExecutable
from .ExecutableParser import ExecutableParser
from .MMU import MMU
from .Registers import Registers
from .Syscall import SyscallInterface, Syscall
from .CPU import CPU
from .CPU import CPU, Registers, Syscall, SyscallInterface
from .Config import RunConfig
from .Config import RunConfig

@ -1,3 +1,11 @@
"""
RiscEmu (c) 2021 Anton Lydike
SPDX-License-Identifier: MIT
This file holds the logic for starting the emulator from the CLI
"""
if __name__ == '__main__':
from . import *
from .helpers import *

@ -1,12 +1,25 @@
import typing
"""
RiscEmu (c) 2021 Anton Lydike
from abc import ABC, abstractmethod
from ..CPU import *
SPDX-License-Identifier: BSD-2-Clause
"""
from typing import Tuple, Callable, Dict
from abc import ABC
from ..CPU import CPU
from ..helpers import ASSERT_LEN, ASSERT_IN, to_unsigned
class InstructionSet(ABC):
"""
Represents a collection of instructions
Each instruction set has to inherit from this class. Each instruction should be it's own method:
instruction_<name>(self, ins: LoadedInstruction)
instructions containing a dot '.' should replace it with an underscore.
"""
def __init__(self, cpu: 'CPU'):
@ -15,7 +28,7 @@ class InstructionSet(ABC):
self.mmu = cpu.mmu
self.regs = cpu.regs
def load(self) -> typing.Dict[str, typing.Callable[['LoadedInstruction'], None]]:
def load(self) -> Dict[str, Callable[['LoadedInstruction'], None]]:
"""
This is called by the CPU once it instantiates this instruction set
@ -27,13 +40,18 @@ class InstructionSet(ABC):
}
def get_instructions(self):
"""
Returns a list of all valid instruction names included in this instruction set
converts underscores in names to dots
"""
for member in dir(self):
if member.startswith('instruction_'):
yield member[12:].replace('_', '.'), getattr(self, member)
def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
"""
parses both rd, rs, imm and rd, imm(rs) arguments and returns (rd, imm+rs1)
parses both rd, rs, imm and rd, imm(rs) argument format and returns (rd, imm+rs1)
(so a register and address tuple for memory instructions)
"""
if len(ins.args) == 3:
@ -101,6 +119,9 @@ class InstructionSet(ABC):
@property
def pc(self):
"""
shorthand for self.cpu.pc
"""
return self.cpu.pc
@pc.setter

@ -1,10 +1,27 @@
"""
RiscEmu (c) 2021 Anton Lydike
SPDX-License-Identifier: BSD-2-Clause
"""
from .InstructionSet import *
from ..helpers import int_from_bytes, int_to_bytes, to_unsigned, to_signed
from ..colors import FMT_DEBUG, FMT_NONE
from ..debug import launch_debug_session
from ..Exceptions import LaunchDebuggerException
from ..Syscall import Syscall
class RV32I(InstructionSet):
"""
The RV32I instruction set. Some instructions are missing, such as
fence, fence.i, rdcycle, rdcycleh, rdtime, rdtimeh, rdinstret, rdinstreth
All atomic read/writes are also not implemented yet
See https://maxvytech.com/images/RV32I-11-2018.pdf for a more detailed overview
"""
def instruction_lb(self, ins: 'LoadedInstruction'):
rd, addr = self.parse_mem_ins(ins)
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 1)))
@ -281,13 +298,13 @@ class RV32I(InstructionSet):
def instruction_sbreak(self, ins: 'LoadedInstruction'):
ASSERT_LEN(ins.args, 0)
if self.cpu.active_debug:
print(FMT_DEBUG + "Debug instruction encountered at 0x{:08X}".format(self.pc-1) + FMT_NONE)
print(FMT_DEBUG + "Debug instruction encountered at 0x{:08X}".format(self.pc - 1) + FMT_NONE)
raise LaunchDebuggerException()
launch_debug_session(
self.cpu,
self.mmu,
self.regs,
"Debug instruction encountered at 0x{:08X}".format(self.pc-1)
"Debug instruction encountered at 0x{:08X}".format(self.pc - 1)
)
def instruction_nop(self, ins: 'LoadedInstruction'):

@ -1,8 +1,17 @@
"""
RiscEmu (c) 2021 Anton Lydike
SPDX-License-Identifier: BSD-2-Clause
"""
from .InstructionSet import *
from ..helpers import int_from_bytes, int_to_bytes, to_unsigned, to_signed
from ..Exceptions import INS_NOT_IMPLEMENTED
class RV32M(InstructionSet):
"""
The RV32M Instruction set, containing multiplication and division instructions
"""
def instruction_mul(self, ins: 'LoadedInstruction'):
rd, rs1, rs2 = self.parse_rd_rs_rs(ins)
self.regs.set(

@ -1,3 +1,11 @@
"""
RiscEmu (c) 2021 Anton Lydike
SPDX-License-Identifier: BSD-2-Clause
This package holds all instruction sets, available to the processor
"""
from .InstructionSet import InstructionSet
from .RV32M import RV32M
from .RV32I import RV32I

Loading…
Cancel
Save