Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • da/simudator
1 result
Select Git revision
Show changes
Commits on Source (17)
Showing
with 352 additions and 276 deletions
from __future__ import annotations
from os import error
from typing import Any
from simudator.core.signal import Signal
......@@ -63,7 +65,7 @@ class Module:
"""
raise NotImplementedError
def get_state(self) -> dict:
def get_state(self) -> dict[str, Any]:
"""
Return the state of the module.
......@@ -77,6 +79,23 @@ class Module:
state_dict["name"] = self.name
return state_dict
def get_parameter(self) -> dict[str, Any]:
"""
Return the parameters of the module.
Parameters are immutable attributes of modules that affect how they operate,
such as the bit length of internal registers. They are set once during the initialization
of the modules and assumed to be constant throughout the execution of the program.
Returns
-------
dict[str, Any]
Parameters of the module represented as a dictionary with one key for
each parameter variable.
"""
param_dict = dict()
return param_dict
def get_gui_state(self) -> dict:
"""
Return the state of the module as should be displayed in a GUI.
......
......@@ -84,19 +84,23 @@ class Demux(Module):
def get_state(self) -> dict[str, Any]:
state = super().get_state()
state["value"] = self._value
state["bit_length"] = self._bit_length
return state
def get_parameter(self) -> dict[str, Any]:
parameter = super().get_parameter()
parameter["bit_length"] = self._bit_length
return parameter
def set_state(self, state: dict[str, Any]) -> None:
"""Set the name and value of the demux.
Parameters
----------
state : dict[str, Any]
The state of the demux to load. Should contain the keys "value" and
"bit_length", both with values of type ``int``.
The state of the demux to load. Should contain the key
"value" of type ``int``.
"""
super().set_state(state)
self._value = state["value"]
self._bit_length = state["bit_length"]
......@@ -83,10 +83,15 @@ class Mux(Module):
def get_state(self) -> dict[str, Any]:
state = super().get_state()
state["value"] = self._value
state["bit_length"] = self._bit_length
return state
def get_parameter(self) -> dict[str, Any]:
parameter = super().get_state()
parameter["bit_length"] = self._bit_length
return parameter
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\nvalue: " + str(self._value) + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
......@@ -97,13 +102,11 @@ class Mux(Module):
Parameters
----------
state : dict[str, Any]
The state of the demux to load. Should contain the keys "name",
"value" and "bit_length" with values of type ``str``, ``int`` and
``int`` respectively.
The state of the demux to load. Should contain the keys "name"
and "value" with values of type ``str`` and ``int`` respectively.
"""
super().set_state(state)
self._value = state["value"]
self._bit_length = state["bit_length"]
def print_module(self) -> None:
print(
......
......@@ -26,16 +26,16 @@ class Register(Module):
def __init__(
self,
input_signal: Signal,
output_signal: Signal,
input: Signal,
output: Signal,
value: Any = 0,
name: str = "Register",
) -> None:
# signals
signals = {
"in_content": input_signal,
"out_content": output_signal,
"in_content": input,
"out_content": output,
}
# init the instance
......@@ -58,7 +58,8 @@ class Register(Module):
self.signals["out_content"].update_value(self._value)
def update_logic(self):
"""Do nothing.
"""
Do nothing.
The register has no logic.
"""
......@@ -69,7 +70,7 @@ class Register(Module):
state["value"] = self._value
return state
def get_gui_state(self) -> dict:
def get_gui_state(self) -> dict[str, Any]:
state = self.get_state()
return state
......@@ -93,7 +94,7 @@ class Register(Module):
self._value = 0
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\nvalue:: " + str(self._value) + "\n\n"
content = self.name + ":\n" + "value: " + str(self._value) + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def print_module(self) -> None:
......@@ -136,7 +137,7 @@ class IntegerRegister(Register):
name: str | None = None,
) -> None:
# set the name
# set the register name
if name is None:
name = f"{bit_length}-bit register"
......@@ -152,21 +153,27 @@ class IntegerRegister(Register):
def get_state(self) -> dict[str, Any]:
state = super().get_state()
state["bit_length"] = self._bit_length
return state
def get_parameter(self) -> dict[str, Any]:
"""
Return a dict of the register parameter, i.e. its bit length.
"""
parameter = super().get_parameter()
parameter["bit_length"] = self._bit_length
return parameter
def set_state(self, state: dict[str, Any]) -> None:
super().set_state(state)
if "bit_length" in state:
self._bit_length = state["bit_length"]
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\nvalue: " + hex(self._value)[2:] + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def save_state_to_file(self, file_path: str) -> None:
file = open(file_path, "a")
file.write(self.name + ":\n")
file.write("value: " + hex(self._value)[2:] + "\n\n")
file.close()
def load_from_str(self, state_string) -> None:
def load_from_str(self, state_string):
string_pair = state_string.split(": ")
# TODO: Maybe check if it starts with value: ?
self._value = int(string_pair[1], 16)
......@@ -178,8 +185,8 @@ class Flag(IntegerRegister):
def __init__(
self,
input_signal: Signal,
output_signal: Signal,
input: Signal,
output: Signal,
bit_length=1,
value=0,
name="Flag",
......@@ -187,8 +194,8 @@ class Flag(IntegerRegister):
# set the flags name
super().__init__(
input=input_signal,
output=output_signal,
input=input,
output=output,
bit_length=bit_length,
value=value,
name=name,
......@@ -210,9 +217,14 @@ class Flag(IntegerRegister):
state["value"] = self._value
return state
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\nvalue: " + str(self._value) + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def save_state_to_file(self, file_path: str) -> None:
"""
Tries to save the modules state to a given file.
"""
file = open(file_path, "a")
file.write(self.name + ":\n")
file.write("value: " + str(self._value) + "\n\n")
file.close()
def print_module(self) -> None:
print(
......
import sys
import traceback
from enum import Enum
from qtpy.QtWidgets import QButtonGroup, QHBoxLayout, QHeaderView, QRadioButton
......@@ -40,7 +42,10 @@ class IntegerMemoryWindow(MemoryWindow):
An integer specifying the number of bits of each address.
"""
def __init__(self, memory_module: Memory, bit_length: int):
def __init__(
self,
memory_module: Memory,
):
# Do not let parent create edit/view buttons
super().__init__(memory_module, False)
......@@ -49,11 +54,11 @@ class IntegerMemoryWindow(MemoryWindow):
self.layout.removeWidget(self._memory_table)
# Add our own
self._memory_table = IntegerMemoryTable(memory_module, bit_length)
self._memory_table = IntegerMemoryTable(memory_module)
self.layout.addWidget(self._memory_table)
# Create base buttons, they are exclusive by default
# so need a seperate QButtonGroup since these four
# so need a separate QButtonGroup since these four
# have nothing to do with the edit/view buttons
self.dec_signed_button = QRadioButton("Decimal Signed")
self.dec_unsigned_button = QRadioButton("Decimal Unsigned")
......@@ -136,9 +141,9 @@ class IntegerMemoryTable(MemoryTable):
"""
def __init__(self, memory_module: Memory, bit_length: int, column_size=-1):
def __init__(self, memory_module: Memory, column_size=-1):
self._base = Base.DECIMAL_UNSIGNED
self._bit_length = bit_length
self._bit_length = memory_module.get_parameter()["bit_length"]
super().__init__(memory_module, column_size)
self.update()
......@@ -248,6 +253,6 @@ class IntegerMemoryTable(MemoryTable):
# -7 + 16 % 16 = 9 = 1001 = -7
value = (value + max_value) % max_value
index = row * 4 + col
index = row * self._column_size + col
state['memory'][index] = value
self._memory.set_state(state)
......@@ -35,7 +35,7 @@ class MemoryWindow(QWidget):
An instance of the Memory base class.
edit_buttons: bool
A bool deciding whether or not to add buttons to the widget
for toggling between setting the memory contents to
for toggling between setting the memory contents to
editable or not.
"""
......@@ -196,7 +196,7 @@ class MemoryTable(QTableWidget):
value = item.text()
if value == "":
return
index = row * 4 + col
index = row * self._column_size + col
state['memory'][index] = value
self._memory.set_state(state)
......
......@@ -50,7 +50,8 @@ class IntegerRegisterGraphicsItem(RegisterGraphicsItem):
"""
def update(self):
parameter = self.module.get_parameter()
hex_length = math.ceil(parameter["bit_length"] / 4)
state = self.module.get_state()
hex_length = math.ceil(state["bit_length"] / 4)
full_text = f"{state['name']}: {state['value']:0{hex_length}x}"
self.text.setText(full_text)
......@@ -48,7 +48,9 @@ class IrGraphicsItem(ModuleGraphicsItem):
def update(self):
# Update small text
instr = self.module.instruction
ir_state = self.module.get_state()
instr = ir_state["value"]
self.small_text.setText(f"IR: {instr:04x}")
# Update larg text
......
......@@ -68,8 +68,7 @@ class MiaMemoryGraphicsItem(MemoryGraphicsItem):
Create and show a MemoryWindow that displays the contents
of the memory module associated with this graphics item.
"""
bit_length = 16
self.memory_window = IntegerMemoryWindow(self.module, bit_length)
self.memory_window = IntegerMemoryWindow(self.module)
self.memory_window.show()
def memoryBreakpointDialog(self) -> None:
......
......@@ -35,12 +35,10 @@ class MicroMemoryGraphicsItem(MiaMemoryGraphicsItem):
def update(self):
# get instruction field
current_instr = self.module.curr_instr
instr = self.module.memory[current_instr]
uM_state = self.module.get_state()
instr = uM_state["curr_instr"]
# TODO: why calculate this from the instruction?
# The module already have this data, maybe wewrite get_state?
# mask out specific fields
alu_field = (instr >> 21) & 0b1111
tb_field = (instr >> 18) & 0b111
fb_field = (instr >> 15) & 0b111
......
......@@ -155,6 +155,7 @@ class MIA_CPU(Processor):
pm_size,
pm_bus_id,
name="PM",
bit_length=16,
)
# GRX specific
......@@ -173,6 +174,7 @@ class MIA_CPU(Processor):
k1_size,
always_write_id,
name="K1",
bit_length=7,
)
# K2 specific
......@@ -185,6 +187,7 @@ class MIA_CPU(Processor):
k2_size,
always_write_id,
name="K2",
bit_length=7,
)
# IR specific
......@@ -276,7 +279,7 @@ class MIA_CPU(Processor):
self._lambdas = {}
def is_new_instruction(self) -> bool:
return self.get_module("uPC").value == 0
return self.get_module("uPC").get_state()["value"] == 0
def get_current_instructions(self) -> list[tuple[str, int, int]]:
asm_instr = self.get_asm_instruction()
......@@ -303,8 +306,8 @@ class MIA_CPU(Processor):
If the label doesnt exist, the string is empty.
"""
ir = self.get_module("IR")
op_code = ir.op
ir_state = self.get_module("IR").get_state()
op_code = ir_state["op"]
return self.get_module("K1").get_label(int(op_code))
def get_pipeline_dimensions(self) -> tuple[int, int]:
......
......@@ -8,7 +8,7 @@ class HR(IntegerRegister, MiaBusConnector):
Register for saving large AlU calculations in MIA.
"""
# Python does not allow multiple inherintence if more than one of the
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Thus we also includes the __slots__
# from MiaBusConnector.
__slots__ = ("bus_id", "bus_control_s")
......
......@@ -15,7 +15,7 @@ class IR(Module, MiaBusConnector):
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Thus we also includes the __slots__
# from MiaBusConnector.
__slots__ = ("op", "grx", "m", "a", "bus_id", "instruction", "bus_control_s")
__slots__ = ("_op", "_grx", "_m", "_a", "bus_id", "_instruction", "bus_control_s")
def __init__(
self,
......@@ -40,13 +40,12 @@ class IR(Module, MiaBusConnector):
Module.__init__(self, signals, name)
MiaBusConnector.__init__(self, bus_control, bus_id)
# Internal values
self.op = 0
self.grx = 0
self.m = 0
self.a = 0
self._op = 0
self._grx = 0
self._m = 0
self._a = 0
self._instruction = default_value
self.bus_id = bus_id
self.instruction = default_value
def update_register(self) -> None:
"""
......@@ -54,11 +53,11 @@ class IR(Module, MiaBusConnector):
from the bus and bitshift each part of the instruction.
"""
if self.read_from_bus():
self.instruction = self.signals["in_input"].get_value()
self.op = self.instruction >> 12
self.grx = (self.instruction >> 10) & 0b11
self.m = (self.instruction >> 8) & 0b11
self.a = self.instruction & (2**8 - 1)
self._instruction = self.signals["in_input"].get_value()
self._op = self._instruction >> 12
self._grx = (self._instruction >> 10) & 0b11
self._m = (self._instruction >> 8) & 0b11
self._a = self._instruction & (2**8 - 1)
def output_register(self) -> None:
"""
......@@ -66,12 +65,12 @@ class IR(Module, MiaBusConnector):
and m_s, and output its whole instruction to the bus when
asked to.
"""
self.signals["out_op"].update_value(self.op)
self.signals["out_grx"].update_value(self.grx)
self.signals["out_m"].update_value(self.m)
self.signals["out_op"].update_value(self._op)
self.signals["out_grx"].update_value(self._grx)
self.signals["out_m"].update_value(self._m)
if self.write_to_bus():
self.signals["out_output"].update_value(self.instruction)
self.signals["out_output"].update_value(self._instruction)
else:
self.signals["out_output"].update_value(None)
......@@ -81,40 +80,40 @@ class IR(Module, MiaBusConnector):
def get_state(self) -> dict[str, Any]:
state = {
"name": self.name,
"value": self.instruction,
"op": self.op,
"grx": self.grx,
"m": self.m,
"a": self.a,
"value": self._instruction,
"op": self._op,
"grx": self._grx,
"m": self._m,
"a": self._a,
}
return state
def get_gui_state(self) -> dict:
state = super().get_gui_state()
state["value"] = self.instruction
state["value"] = self._instruction
return state
def set_state(self, state: dict) -> None:
super().set_state(state)
self.instruction = state["value"]
self._instruction = state["value"]
if "op" in state:
self.op = state["op"]
self._op = state["op"]
if "grx" in state:
self.grx = state["grx"]
self._grx = state["grx"]
if "m" in state:
self.m = state["m"]
self._m = state["m"]
if "a" in state:
self.a = state["a"]
self._a = state["a"]
def reset(self) -> None:
"""
Resets the instruction register to 0.
"""
self.instruction = 0
self.op = 0
self.grx = 0
self.m = 0
self.a = 0
self._instruction = 0
self._op = 0
self._grx = 0
self._m = 0
self._a = 0
def print_module(self) -> None:
print(
......@@ -122,23 +121,22 @@ class IR(Module, MiaBusConnector):
self.name,
"\n -----",
"\n value: ",
hex(self.instruction),
hex(self._instruction),
"\n op: ",
bin(self.op),
bin(self._op),
"\n grx: ",
bin(self.grx),
bin(self._grx),
"\n m: ",
bin(self.m),
bin(self._m),
"\n a: ",
bin(self.a),
bin(self._a),
)
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\n"
content += "Instruction: " + hex(self.instruction)[2:] + "\n\n"
content += "Instruction: " + hex(self._instruction)[2:] + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def load_from_str(self, state_string):
string_pair = state_string.split(": ")
# TODO: Maybe check if it starts with instruction: ?
self.instruction = int(string_pair[1], 16)
self._instruction = int(string_pair[1], 16)
......@@ -13,12 +13,11 @@ class LC(Module):
"""
__slots__ = (
"value",
"read_from_bus",
"read_from_uADR",
"decrement_by_one",
"bit_length",
"mask",
"_value",
"_read_from_bus",
"_read_from_uADR",
"_decrement_by_one",
"_bit_length",
)
def __init__(
......@@ -70,16 +69,15 @@ class LC(Module):
super().__init__(signals, name)
# the value of the loop counter
self.value = value
self._value = value
# helper variables
self.read_from_bus = False
self.read_from_uADR = False
self.decrement_by_one = False
self._read_from_bus = False
self._read_from_uADR = False
self._decrement_by_one = False
# bit length and mask
self.bit_length = bit_length
self.mask = 2**self.bit_length - 1
self._bit_length = bit_length
def update_register(self) -> None:
"""Reads bit 12 and 13 from the micro memory and updates the
......@@ -92,39 +90,42 @@ class LC(Module):
match self.signals["in_control"].get_value():
case 0b00: # LC is not effected
self.decrement_by_one = False
self.read_from_bus = False
self.read_from_uADR = False
self._decrement_by_one = False
self._read_from_bus = False
self._read_from_uADR = False
case 0b01: # Decrement by one
self.decrement_by_one = True
self.read_from_bus = False
self.read_from_uADR = False
self._decrement_by_one = True
self._read_from_bus = False
self._read_from_uADR = False
case 0b10: # Load 8 least significant bits from bus
self.decrement_by_one = False
self.read_from_bus = True
self.read_from_uADR = False
self._decrement_by_one = False
self._read_from_bus = True
self._read_from_uADR = False
case 0b11: # LCs 7 least significant bits are loaded from uADR
self.decrement_by_one = False
self.read_from_bus = False
self.read_from_uADR = True
self._decrement_by_one = False
self._read_from_bus = False
self._read_from_uADR = True
if self.read_from_bus:
if self._read_from_bus:
input_value = self.signals["in_input"].get_value()
self.value = input_value & self.mask
mask = 2**self._bit_length - 1
self._value = input_value & mask
if self.read_from_uADR:
if self._read_from_uADR:
input_value = self.signals["in_address"].get_value()
self.value = input_value & self.mask
mask = 2**self._bit_length - 1
self._value = input_value & mask
if self.decrement_by_one:
self.value -= 1
if self._decrement_by_one:
self._value -= 1
# overflow correctly
if self.value < 0:
self.value = self.mask
# underflow correctly
if self._value < 0:
mask = 2**self._bit_length - 1
self._value = mask
def output_register(self) -> None:
"""The loop counter will only output to the L flag, this is
......@@ -136,7 +137,7 @@ class LC(Module):
"""When the loop counter reaches zero, set the l flag to 1.
Otherwise set it to zero.
"""
if self.value == 0:
if self._value == 0:
self.signals["out_flag_l"].update_value(1)
else:
self.signals["out_flag_l"].update_value(0)
......@@ -152,45 +153,53 @@ class LC(Module):
"""
state = dict()
state["name"] = self.name
state["value"] = self.value
state["bit_length"] = self.bit_length
state["mask"] = self.mask
state["read_from_bus"] = self.read_from_bus
state["read_from_uADR"] = self.read_from_uADR
state["decrement_by_one"] = self.decrement_by_one
state["value"] = self._value
state["read_from_bus"] = self._read_from_bus
state["read_from_uADR"] = self._read_from_uADR
state["decrement_by_one"] = self._decrement_by_one
return state
def get_parameter(self) -> dict[str, Any]:
"""Return a dictionary of the parameters of the loop counter,
i.e. the bit length of the counter.
Returns
-------
dict[str, Any]
The parameter of the loop counter.
"""
parameter = super().get_parameter()
parameter["bit_length"] = self._bit_length
return parameter
def set_state(self, state: dict[str, Any]) -> None:
"""Sets the loop counter state to one given in dict."""
self.name = state["name"]
self.value = state["value"]
self._value = state["value"]
if "bit_length" in state:
self.bit_length = state["bit_length"]
if "mask" in state:
self.mask = state["mask"]
self._bit_length = state["bit_length"]
if "read_from_bus" in state:
self.read_from_bus = state["read_from_bus"]
self._read_from_bus = state["read_from_bus"]
if "read_from_uADR" in state:
self.read_from_uADR = state["read_from_uADR"]
self._read_from_uADR = state["read_from_uADR"]
if "decrement_by_one" in state:
self.decrement_by_one = state["decrement_by_one"]
self._decrement_by_one = state["decrement_by_one"]
def reset(self) -> None:
"""Resets the loop counter to 0."""
self.value = 0
self.read_from_bus = False
self.read_from_uADR = False
self.decrement_by_one = False
self._value = 0
self._read_from_bus = False
self._read_from_uADR = False
self._decrement_by_one = False
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\n"
content += "value: " + hex(self.value)[2:] + "\n\n"
content += "value: " + hex(self._value)[2:] + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def load_from_str(self, state_string):
string_pair = state_string.split(": ")
# TODO: Maybe check if it starts with value: ?
self.value = int(string_pair[1], 16)
self._value = int(string_pair[1], 16)
def print_module(self) -> None:
print(
......@@ -198,11 +207,11 @@ class LC(Module):
self.name,
"\n -----",
"\n value: ",
hex(self.value),
hex(self._value),
"\n decrement: ",
self.decrement_by_one,
self._decrement_by_one,
"\n read from uADR: ",
self.read_from_uADR,
self._read_from_uADR,
"\n read from bus: ",
self.read_from_bus,
self._read_from_bus,
)
......@@ -9,7 +9,7 @@ class MiaBusConnector:
Has logic for controlling when to read and write to bus.
"""
# Python does not allow multiple inherintence if more than one of the
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Since the modules that inherit from MiaBusConnector
# also inherits from other classes we leave this class __slots__ empty.
__slots__ = ()
......
......@@ -14,7 +14,7 @@ class GRX(Module, MiaBusConnector):
registers should be indexed by the GRx bits or the M bits.
"""
# Python does not allow multiple inherintence if more than one of the
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Thus we also includes the __slots__
# from MiaBusConnector.
__slots__ = (
......
from typing import Any
from simudator.core.modules.memory import Memory
from simudator.core.signal import Signal
from simudator.processor.mia.modules.mia_bus_connect import MiaBusConnector
......@@ -7,14 +9,14 @@ class MiaMemory(MiaBusConnector, Memory):
"""
A MIA specific memory, functionality from the general memory
and the MiaBusConnector is inherited. The module can be of
arbitrary size and supports opperations that read and write
arbitrary size and supports operations that read and write
to/from the mia bus.
"""
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Thus we also includes the __slots__
# from MiaBusConnector.
__slots__ = ("label_adress_mapping", "bus_id", "bus_control_s")
__slots__ = ("label_address_mapping", "bus_id", "bus_control_s", "_bit_length")
def __init__(
self,
......@@ -25,6 +27,7 @@ class MiaMemory(MiaBusConnector, Memory):
size: int = 1,
bus_id: int = 0,
name: str = "PM",
bit_length: int = 16,
) -> None:
MiaBusConnector.__init__(self, bus_control_s, bus_id)
Memory.__init__(
......@@ -38,7 +41,8 @@ class MiaMemory(MiaBusConnector, Memory):
)
self.bus_control_s.add_destination(self)
self.label_adress_mapping = {}
self.label_address_mapping = {}
self._bit_length = bit_length
def update_register(self) -> None:
"""
......@@ -77,6 +81,11 @@ class MiaMemory(MiaBusConnector, Memory):
size = len(self._memory)
self._memory = [0 for _ in range(size)]
def get_parameter(self) -> dict[str, Any]:
parameter = super().get_parameter()
parameter["bit_length"] = self._bit_length
return parameter
def load_from_str(self, state_string) -> None:
"""
Loads the module from a string, used when loading state from
......@@ -90,20 +99,20 @@ class MiaMemory(MiaBusConnector, Memory):
line_data = line.split()
value = int(line_data[1], 16)
# Last character of the adress is a semicolon
adress = int(line_data[0][:-1], 16)
# Last character of the address is a semicolon
address = int(line_data[0][:-1], 16)
self._memory[adress] = value
self._memory[address] = value
# There is an asm instruction label
if len(line_data) == 3:
instr = line_data[2]
self.label_adress_mapping[adress] = instr
self.label_address_mapping[address] = instr
def get_label(self, adress: int) -> str:
def get_label(self, address: int) -> str:
"""Return the label at the given memory address if it exists, else an empty string"""
if adress in self.label_adress_mapping.keys():
return self.label_adress_mapping[adress]
if address in self.label_address_mapping.keys():
return self.label_address_mapping[address]
return ""
......@@ -18,16 +18,14 @@ class MicroMemory(Module):
"""
__slots__ = (
"curr_instr",
"z_flag_val",
"n_flag_val",
"c_flag_val",
"o_flag_val",
"l_flag_val",
"memory",
"halt",
"adress_padding",
"value_padding",
"_curr_instr",
"_z_flag_val",
"_n_flag_val",
"_c_flag_val",
"_o_flag_val",
"_l_flag_val",
"_memory",
"_halt",
)
MEMORY_ADDRESS_PADDING = 2
......@@ -51,8 +49,6 @@ class MicroMemory(Module):
o_flag: Signal,
l_flag: Signal,
name: str = "uM",
adress_padding: int = 2,
value_padding: int = 7,
) -> None:
"""
Parameters
......@@ -117,19 +113,14 @@ class MicroMemory(Module):
super().__init__(signals, name)
# Internal variables
self.curr_instr = 0
self.z_flag_val = 0
self.n_flag_val = 0
self.c_flag_val = 0
self.o_flag_val = 0
self.l_flag_val = 0
self.memory = [0 for _ in range(128)]
self.halt = False # Used for signalling a HALT
# paddings to ensure saving to file has the correct format
self.adress_padding = adress_padding
self.value_padding = value_padding
self._curr_instr = 0
self._z_flag_val = 0
self._n_flag_val = 0
self._c_flag_val = 0
self._o_flag_val = 0
self._l_flag_val = 0
self._memory = [0 for _ in range(128)]
self._halt = False # Used for signalling a HALT
def update_logic(self) -> None:
"""
......@@ -143,15 +134,15 @@ class MicroMemory(Module):
if instruction is None:
return
self.curr_instr = instruction
self.z_flag_val = self.signals["in_flag_z"].get_value()
self.n_flag_val = self.signals["in_flag_n"].get_value()
self.c_flag_val = self.signals["in_flag_c"].get_value()
self.o_flag_val = self.signals["in_flag_o"].get_value()
self.l_flag_val = self.signals["in_flag_l"].get_value()
self._curr_instr = instruction
self._z_flag_val = self.signals["in_flag_z"].get_value()
self._n_flag_val = self.signals["in_flag_n"].get_value()
self._c_flag_val = self.signals["in_flag_c"].get_value()
self._o_flag_val = self.signals["in_flag_o"].get_value()
self._l_flag_val = self.signals["in_flag_l"].get_value()
# Extract the different fields of the micro instruction
instr = self.memory[self.curr_instr]
instr = self._memory[self._curr_instr]
alu_field = (instr >> 21) & 0b1111
tb_field = (instr >> 18) & 0b111
fb_field = (instr >> 15) & 0b111
......@@ -217,7 +208,7 @@ class MicroMemory(Module):
case 0b0011:
self.signals["out_control_upc"].update_value(0b011)
case 0b0100:
self._conditional_jump(self.z_flag_val, 0, uadr_field)
self._conditional_jump(self._z_flag_val, 0, uadr_field)
case 0b0101:
self.signals["out_control_upc"].update_value(0b100)
self.signals["out_upc"].update_value(uadr_field)
......@@ -227,19 +218,19 @@ class MicroMemory(Module):
case 0b0111:
self.signals["out_control_upc"].update_value(0b101)
case 0b1000:
self._conditional_jump(self.z_flag_val, 1, uadr_field)
self._conditional_jump(self._z_flag_val, 1, uadr_field)
case 0b1001:
self._conditional_jump(self.n_flag_val, 1, uadr_field)
self._conditional_jump(self._n_flag_val, 1, uadr_field)
case 0b1010:
self._conditional_jump(self.c_flag_val, 1, uadr_field)
self._conditional_jump(self._c_flag_val, 1, uadr_field)
case 0b1011:
self._conditional_jump(self.o_flag_val, 1, uadr_field)
self._conditional_jump(self._o_flag_val, 1, uadr_field)
case 0b1100:
self._conditional_jump(self.l_flag_val, 1, uadr_field)
self._conditional_jump(self._l_flag_val, 1, uadr_field)
case 0b1101:
self._conditional_jump(self.c_flag_val, 0, uadr_field)
self._conditional_jump(self._c_flag_val, 0, uadr_field)
case 0b1110:
self._conditional_jump(self.o_flag_val, 0, uadr_field)
self._conditional_jump(self._o_flag_val, 0, uadr_field)
case 0b1111:
# Halt is handled by update_register
self.signals["out_control_upc"].update_value(0b011)
......@@ -257,11 +248,11 @@ class MicroMemory(Module):
were to be done in update_logic, the halt would erroneously be signaled
one cycle to early.
"""
seq_field = (self.memory[self.curr_instr] >> 7) & 0b1111
seq_field = (self._memory[self._curr_instr] >> 7) & 0b1111
if seq_field == 0b1111:
self.halt = True
self._halt = True
else:
self.halt = False
self._halt = False
def _conditional_jump(self, flag, cond_value, uadr):
"""Helper function for executing a conditional jump to the specified uadr
......@@ -281,27 +272,37 @@ class MicroMemory(Module):
value 0 are not printed.
"""
print("", self.name, "\n -----\n")
for adress in range(len(self.memory)):
if self.memory[adress] != 0:
for adress in range(len(self._memory)):
if self._memory[adress] != 0:
print("", str(adress), "", str(self.memory[adress]), "\n")
def get_state(self) -> dict:
state = super().get_state()
state["memory"] = self.memory[:]
state["halt"] = self.halt
state["curr_instr"] = self.curr_instr
state["memory"] = self._memory[:]
state["halt"] = self._halt
state["curr_instr"] = self._curr_instr
return state
def get_gui_state(self) -> dict[str, Any]:
state = super().get_state()
state["memory"] = self.memory[:]
state["memory"] = self._memory[:]
return state
def get_parameter(self) -> dict:
parameter = super().get_parameter()
# Bit length is not used internally within this module.
# The only way the micro memory memory can receive input
# is from the user, and the user is not able to insert values that
# are larger than 25 bits
parameter["bit_length"] = 25
return parameter
def set_state(self, state: dict) -> None:
super().set_state(state)
self.memory = state["memory"]
self._memory = state["memory"]
if "halt" in state:
self.halt = state["halt"]
self._halt = state["halt"]
def output_register(self):
pass
......@@ -310,14 +311,14 @@ class MicroMemory(Module):
return self.signals["in_upc"]
def reset(self) -> None:
self.curr_instr = 0
self.z_flag_val = 0
self.n_flag_val = 0
self.c_flag_val = 0
self.o_flag_val = 0
self.l_flag_val = 0
self.memory = [0 for i in range(128)]
self.halt = False # Used for signalling a HALT
self._curr_instr = 0
self._z_flag_val = 0
self._n_flag_val = 0
self._c_flag_val = 0
self._o_flag_val = 0
self._l_flag_val = 0
self._memory = [0 for _ in range(128)]
self._halt = False # Used for signalling a HALT
def load_from_str(self, state_string) -> None:
"""Load the contents of the micro memory from a string consisting of a
......@@ -335,8 +336,8 @@ class MicroMemory(Module):
b0: ffff
'
"""
for i in range(len(self.memory)):
self.memory[i] = 0
for i in range(len(self._memory)):
self._memory[i] = 0
lines = state_string.split("\n")
for line in lines:
......@@ -344,11 +345,11 @@ class MicroMemory(Module):
line_data = line.split(": ")
adress = int(line_data[0], 16)
value = int(line_data[1], 16)
self.memory[adress] = value
self._memory[adress] = value
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\n"
for index, value in enumerate(self.memory):
for index, value in enumerate(self._memory):
content += (
str(hex(index)[2:].rjust(self.MEMORY_ADDRESS_PADDING, "0")) + ": "
)
......@@ -362,7 +363,7 @@ class MicroMemory(Module):
"""Helper function for pretty_print that returns the length of
the largest adress in the memory to print for a module.
"""
return len(str(len(self.memory)))
return len(str(len(self._memory)))
def get_longest_line_len(self, ignore_keys=None) -> int:
"""Helper function for pretty_print that returns the length of
......@@ -374,7 +375,7 @@ class MicroMemory(Module):
longest_memory_line = 0
for value in self.memory:
for value in self._memory:
value_len = len(str(value))
if value_len > longest_memory_line:
longest_memory_line = value_len
......
......@@ -11,7 +11,7 @@ class MicroPC(Module):
to read from or write to.
"""
__slots__ = ("value", "bit_length")
__slots__ = ("_value", "_bit_length")
def __init__(
self,
......@@ -25,7 +25,7 @@ class MicroPC(Module):
name: str = "uPC",
) -> None:
self.value = 0
self._value = 0
# Signals
signals = {
......@@ -43,50 +43,50 @@ class MicroPC(Module):
def update_register(self) -> None:
match self.signals["in_control"].get_value():
case 0b000:
self.value += 1
self._value += 1
# Overflow
if self.value == 128:
self.value = 0
if self._value == 128:
self._value = 0
case 0b001:
self.value = self.signals["in_k1"].get_value()
self._value = self.signals["in_k1"].get_value()
case 0b010:
self.value = self.signals["in_k2"].get_value()
self._value = self.signals["in_k2"].get_value()
case 0b011:
self.value = 0
self._value = 0
case 0b100:
self.value = self.signals["in_um"].get_value()
self._value = self.signals["in_um"].get_value()
case 0b101:
self.value = self.signals["in_supc"].get_value()
self._value = self.signals["in_supc"].get_value()
case 0b110:
self.signals["out_supc"].update_value(self.value + 1)
self.value = self.signals["in_um"].get_value()
self.signals["out_supc"].update_value(self._value + 1)
self._value = self.signals["in_um"].get_value()
def output_register(self) -> None:
self.signals["out_um"].update_value(self.value)
self.signals["out_um"].update_value(self._value)
def get_state(self) -> dict:
state = super().get_state()
state["value"] = self.value
state["value"] = self._value
return state
def get_gui_state(self) -> dict:
state = {
"name": self.name,
"value": self.value,
"value": self._value,
}
return state
def set_state(self, state: dict) -> None:
super().set_state(state)
self.value = state["value"]
self._value = state["value"]
def reset(self) -> None:
"""
Resets the micro program counter to 0.
"""
self.value = 0
self._value = 0
def update_logic(self) -> None:
"""
......@@ -96,13 +96,12 @@ class MicroPC(Module):
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\n"
content += "value: " + hex(self.value)[2:] + "\n\n"
content += "value: " + hex(self._value)[2:] + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def load_from_str(self, state_string):
string_pair = state_string.split(": ")
# TODO: Maybe check if it starts with value: ?
self.value = int(string_pair[1], 16)
self._value = int(string_pair[1], 16)
def print_module(self) -> None:
print("", self.name, "\n -----", "\n value: ", hex(self.value))
print("", self.name, "\n -----", "\n value: ", hex(self._value))
......@@ -17,10 +17,10 @@ class PC(Module, MiaBusConnector):
value on the bus. If both are true it does nothing.
"""
# Python does not allow multiple inherintence if more than one of the
# Python does not allow multiple inherintence if more than one of the
# parent classes uses __slots__. Thus we also includes the __slots__
# from MiaBusConnector.
__slots__ = ("bus_id", "bus_control_s", "value", "increase_by_one")
__slots__ = ("bus_id", "bus_control_s", "_value", "_increase_by_one", "_bit_length")
def __init__(
self,
......@@ -41,16 +41,14 @@ class PC(Module, MiaBusConnector):
}
Module.__init__(self, signals, name)
# internal state
self.value = value
# help variables
self.increase_by_one = False
self._value = value
self._increase_by_one = False
self._bit_length = 8
def output_register(self) -> None:
"""Output the value of the program counter to the bus."""
if self.write_to_bus():
self.signals["out_content"].update_value(self.value)
self.signals["out_content"].update_value(self._value)
else:
self.signals["out_content"].update_value(None)
......@@ -61,17 +59,22 @@ class PC(Module, MiaBusConnector):
should do nothing and wait for the next cycle.
"""
self.increase_by_one = self.signals["in_control"].get_value()
self._increase_by_one = self.signals["in_control"].get_value()
if self.increase_by_one and self.read_from_bus():
if self._increase_by_one and self.read_from_bus():
return
mask = 2**self._bit_length - 1
if self.read_from_bus():
# Read the 8 lowest bits from the bus
self.value = self.signals["in_input"].get_value() & 0xFF
self._value = self.signals["in_input"].get_value() & mask
if self._increase_by_one:
self._value += 1
if self.increase_by_one:
self.value += 1
# overflow correctly
if self._value > mask:
self._value = 0
def update_logic(self) -> None:
self.output_register()
......@@ -83,44 +86,55 @@ class PC(Module, MiaBusConnector):
Returns
-------
dict[Any]
dict[str, Any]
The state of the program counter.
"""
state = dict()
state["name"] = self.name
state["value"] = self.value
state["increment"] = self.increase_by_one
state["bit_length"] = 8
state["value"] = self._value
state["increment"] = self._increase_by_one
return state
def get_parameter(self) -> dict[str, Any]:
"""Return a dictionary of the parameters of the program counter,
i.e. the bit length of the counter.
Returns
-------
dict[str, Any]
The paramter of the program counter.
"""
paramter = Module.get_parameter(self)
paramter["bit_length"] = self._bit_length
return paramter
def get_gui_state(self) -> dict:
state = {
"name": self.name,
"value": self.value,
"value": self._value,
}
return state
def set_state(self, state: dict[str, Any]) -> None:
"""Sets the program counter state to one given in dict."""
self.name = state["name"]
self.value = state["value"]
self._value = state["value"]
if "increment" in state:
self.increase_by_one = state["increment"]
self._increase_by_one = state["increment"]
def reset(self) -> None:
"""Reset the program counter to 0."""
self.value = 0
self.increase_by_one = False
self._value = 0
self._increase_by_one = False
def save_state_to_file(self, file_path: str) -> bool:
content = self.name + ":\n"
content += "value: " + hex(self.value)[2:] + "\n\n"
content += "value: " + hex(self._value)[2:] + "\n\n"
return super()._helper_save_state_to_file(file_path, content)
def load_from_str(self, state_string):
string_pair = state_string.split(": ")
# TODO: Maybe check if it starts with value: ?
self.value = int(string_pair[1], 16)
self._value = int(string_pair[1], 16)
def print_module(self) -> None:
print("", self.name, "\n -----", "\n value: ", hex(self.value))
print("", self.name, "\n -----", "\n value: ", hex(self._value))