Skip to content
Snippets Groups Projects
Commit ab5674b3 authored by Johannes Kung's avatar Johannes Kung
Browse files

Moved printing functionality out from Processor class + minor refactor of...

Moved printing functionality out from Processor class + minor refactor of public processor attributes
parent 72abb33c
No related branches found
No related tags found
1 merge request!39Moved printing functionality out from Processor class + minor refactor of...
...@@ -3,6 +3,7 @@ from __future__ import annotations ...@@ -3,6 +3,7 @@ from __future__ import annotations
import ast import ast
from os.path import exists, isdir from os.path import exists, isdir
from simudator.cli.printing import pretty_print, pretty_print_verbose
from simudator.core.processor import Processor from simudator.core.processor import Processor
HELP_TEXT = """Here is a list of possible commands: HELP_TEXT = """Here is a list of possible commands:
...@@ -195,12 +196,12 @@ class CLI: ...@@ -195,12 +196,12 @@ class CLI:
case ["pp"] | ["pretty print"]: case ["pp"] | ["pretty print"]:
# pretty print the modules of the processor # pretty print the modules of the processor
self._processor.pretty_print() pretty_print(self._processor)
case ["ppv"] | ["pretty print verbose"]: case ["ppv"] | ["pretty print verbose"]:
# pretty print the modules of the processor # pretty print the modules of the processor
# with all available information # with all available information
self._processor.pretty_print_verbose() pretty_print_verbose(self._processor)
# Breakpoints ------------------------------------------------- # Breakpoints -------------------------------------------------
case ["p", "br"] | ["print", "breaks"]: case ["p", "br"] | ["print", "breaks"]:
......
from simudator.core.module import Module
from simudator.core.modules.memory import Memory
from simudator.core.processor import Processor
from simudator.processor.mia.modules.bus import Bus
from simudator.processor.mia.modules.micro_memory import MicroMemory
def pretty_print(processor: Processor) -> None:
"""Print the processor state in a readable and compact format."""
pretty_print_verbose(processor, processor._ignore_keys)
def pretty_print_verbose(
processor: Processor, ignore_keys: list[str] | None = None
) -> None:
"""
Print the most relevant information about each module in a compact and
readable format.
State variables of modules can be ignored with the optional argument.
Parameters
----------
ignore_keys : list[str]
List of names of state variables of modules to exclude when
printing module states.
"""
# TODO: ignore keys per module and not for all modules
memory_modules = []
other_modules = []
if ignore_keys is None:
ignore_keys = []
# TODO: remove isinstance(module, micro_memory)
for module in processor.get_modules():
if not isinstance(module, Bus):
if isinstance(module, Memory) or isinstance(module, MicroMemory):
memory_modules.append(module)
else:
other_modules.append(module)
# sort the modules by name to ensure that they appear in the
# same order
memory_modules.sort(key=lambda x: x.name, reverse=True)
other_modules.sort(key=lambda x: x.name, reverse=True)
# specify which keys to ignore from the modules 'get_state'
# function
# TODO: ignore fields per module, this will ignore 'mask'
# for every module
module_to_line_length = {}
# get the longest line length for all other_modules
for module in other_modules:
# +3 for padding
line_len = module.get_longest_line_len(ignore_keys) + 3
# TODO: what to do if two or more modules has the same name
module_to_line_length[module] = line_len
groups = group_pp_modules(module_to_line_length)
print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
# print each group separate
for group in groups:
pretty_print_names(group)
# Build a new string containing the information to show
# the user
for row in range(get_most_fields(group, ignore_keys)):
string = ""
total_padding = 0
# Get the information from each module
for module in group:
module_state = module.get_state()
keys = fields_to_list(module)
# Get the keys that we want to print to the user
# If this is not done, the keys we want to print
# could end up on an index that is higher than the
# number of rows printed and will therefore be missed
real_keys = [key for key in keys if key not in ignore_keys]
# Dont go out of index
# Needed since one module might want to print 4
# fields and another only 1
if row < len(real_keys) and real_keys[row] not in ignore_keys:
string += real_keys[row] + ": " + str(module_state[real_keys[row]])
# pad the string so each string has the same length
total_padding += module_to_line_length[module]
string = string.ljust(total_padding)
# replace last to chars with a separator and padding
string = string[0:-2] + "| "
print(string)
print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
for memory_module in memory_modules:
pretty_print_memory(memory_module)
def pretty_print_memory(module: Memory) -> None:
"""Print a memory module in a compact and readable format.
Parameters
----------
module : Memory
Memory module to print the state of.
"""
print(module.name)
print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
longest_line_len = module.get_longest_line_len()
# longest_line_len = processor.get_longest_memory_value(module.memory)
string = ""
last_mem_len = module.get_largest_mem_adr()
for i, value in enumerate(module.get_state()["memory"]):
# create a new string containing the address and the value
# of the memory address formatted to fit with the largest
# address and largest memory value
new_row = (str(i).ljust(last_mem_len) + ": " + str(value)).ljust(
longest_line_len + last_mem_len + 3
) + "|"
# only add the string if there is space for it, else
# print the string and start a new
if len(string + new_row) + 1 > Processor.MAX_LINE_LEN:
print(string)
string = new_row
else:
# First iteration string will be
# empty and should not be padded
if string:
string += " " + new_row
else:
string = new_row
print(string)
print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
print()
def pretty_print_names(module_to_line_length: dict[Module, int]) -> None:
"""
Print the name of the modules in one row with formatting.
Adds spacing between the names so that the longest state variable of
each module has space to be printed below the name.
Parameters
----------
module_to_line_length : dict[Module, int]
Mapping from module to length of the longest state variable of
the module.
"""
name_string = ""
total_len = 0
for module in module_to_line_length:
name_string += module.name
total_len += module_to_line_length[module]
name_string = name_string.ljust(total_len)
name_string = name_string[0:-2] + "| "
print(name_string)
def group_pp_modules(
module_to_line_length: dict[Module, int]
) -> list[dict[Module, int]]:
"""Group the modules to be pretty printed into groups with a
total line length lower than 'Processor.MAX_LINE_LEN'.
Parameters
----------
module_to_line_length : dict[Module, int]
Mapping from module to length of the longest state variable of
the module (takes as the line length).
Returns
-------
list[dict[Module, int]]
List of mappings from module to line length, each mapping
representing a group of modules for printing.
"""
groups = [{}]
group_index = 0
line_len = 0
for module in module_to_line_length:
# Make sure the line is not to long
if line_len + module_to_line_length[module] < Processor.MAX_LINE_LEN:
line_len += module_to_line_length[module]
groups[group_index][module] = module_to_line_length[module]
# If it would have been, start a new group
else:
groups.append({})
group_index += 1
groups[group_index][module] = module_to_line_length[module]
line_len = module_to_line_length[module]
return groups
def fields_to_list(module: Module, ignore_keys=[]) -> list[str]:
"""
Return a list containing all state variable names, excluding module
name, for a module.
Optional argument to ignore specific state variables.
Parameters
----------
module : Module
Module to get state variable names from.
ignore_keys : list[str]
List of state variable names to exclude.
Returns
-------
list[str]
List of state variable names, excluding module name, of a module.
"""
return [
key for key in module.get_state() if key != "name" and key not in ignore_keys
]
def get_most_fields(modules: dict[Module, int], ignore_keys=None) -> int:
"""Get the maximum number of state variables among all modules.
Can optionally ignore keys.
Parameters
----------
modules : dict[Module, int]
Mapping from module to length of the longest state variable of
the module. Used as a list of modules to take the maximum over.
ignore_keys : list[str]
State variables to exclude.
Returns
-------
int
The maximum of the number of module state variables among all
modules of the processor.
"""
if ignore_keys is None:
ignore_keys = []
fields = 0
for module in modules:
module_fields = len(fields_to_list(module, ignore_keys))
if module_fields > fields:
fields = module_fields
return fields
This diff is collapsed.
...@@ -53,7 +53,7 @@ class BreakpointWindow(QWidget): ...@@ -53,7 +53,7 @@ class BreakpointWindow(QWidget):
stop_icon = self.style().standardIcon(QStyle.SP_DialogCancelButton) stop_icon = self.style().standardIcon(QStyle.SP_DialogCancelButton)
# Add an list item for each breakpoint in cpu # Add an list item for each breakpoint in cpu
for bp_id, breakpoint in self.cpu.breakpoints.items(): for bp_id, breakpoint in self.cpu.get_breakpoints().items():
bp_str = str(bp_id) + ": " + breakpoint.__str__() bp_str = str(bp_id) + ": " + breakpoint.__str__()
bp_item = QListWidgetItem(bp_str) bp_item = QListWidgetItem(bp_str)
...@@ -95,7 +95,7 @@ class BreakpointWindow(QWidget): ...@@ -95,7 +95,7 @@ class BreakpointWindow(QWidget):
if bp_id is None: if bp_id is None:
return return
del self.cpu.breakpoints[bp_id] self.cpu.remove_breakpoint(bp_id)
self.update() self.update()
def getSelectedItemId(self) -> int: def getSelectedItemId(self) -> int:
...@@ -120,4 +120,4 @@ class BreakpointWindow(QWidget): ...@@ -120,4 +120,4 @@ class BreakpointWindow(QWidget):
# Do nothing if there are no breakpoints or if id is nonetype # Do nothing if there are no breakpoints or if id is nonetype
if bp_id is None or bp_id == -1: if bp_id is None or bp_id == -1:
return return
return self.cpu.breakpoints[bp_id] return self.cpu.get_breakpoints()[bp_id]
...@@ -40,7 +40,16 @@ class MIA_CPU(Processor): ...@@ -40,7 +40,16 @@ class MIA_CPU(Processor):
super().__init__() super().__init__()
# Creating all signals # Creating all signals
# Signals follow the naming convention 'to_from' # Signals follow the naming convention 'to_from'
self.max_line_len = 100
# Add state variable names to skip when pretty printing the MIA
# processor in the CLI
self._ignore_keys += [
"increment",
"read_from_bus",
"read_from_uADR",
"decrement_by_one",
"bus_id",
]
# A signal used by all modules connected to the bus # A signal used by all modules connected to the bus
bus_control = Signal(self, "bus_control", (0, 0)) bus_control = Signal(self, "bus_control", (0, 0))
...@@ -262,9 +271,9 @@ class MIA_CPU(Processor): ...@@ -262,9 +271,9 @@ class MIA_CPU(Processor):
for module in ALLTHEMODULES: for module in ALLTHEMODULES:
self.add_module(module) self.add_module(module)
self.micro_memory = uM self._micro_memory = uM
self.lambdas = {} self._lambdas = {}
def is_new_instruction(self) -> bool: def is_new_instruction(self) -> bool:
return self.get_module("uPC").value == 0 return self.get_module("uPC").value == 0
...@@ -307,7 +316,7 @@ class MIA_CPU(Processor): ...@@ -307,7 +316,7 @@ class MIA_CPU(Processor):
return (2, 2) return (2, 2)
def should_halt(self) -> bool: def should_halt(self) -> bool:
micro_memory_state = self.micro_memory.get_state() micro_memory_state = self._micro_memory.get_state()
return micro_memory_state["halt"] return micro_memory_state["halt"]
def launch_gui(self): def launch_gui(self):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment