Source code for piel.tools.amaranth.construct

"""
This module provides a function to construct an Amaranth module from a truth table. It converts a truth table
into a digital logic module using the Amaranth framework.

The supported implementation measurement are:
- "combinatorial"
- "sequential"
- "memory"
"""

from piel.types.digital import TruthTable, LogicImplementationType


[docs] def construct_amaranth_module_from_truth_table( truth_table: TruthTable, logic_implementation_type: LogicImplementationType = "combinatorial", ): """ Constructs an Amaranth module based on the provided truth table. # TODO implementation type Args: truth_table (TruthTable): The truth table to be implemented as a TruthTable object. logic_implementation_type (Literal["combinatorial", "sequential", "memory"], optional): The type of implementation. - "combinatorial": Implements the truth table as combinational logic. - "sequential": Implements the truth table as sequential logic. - "memory": Implements the truth table using memory elements. Defaults to "combinatorial". Returns: am.Module: An Amaranth module implementing the given truth table. Examples: >>> detector_phase_truth_table = { >>> "detector_in": ["00", "01", "10", "11"], >>> "phase_map_out": ["00", "10", "11", "11"], >>> } >>> my_truth_table = TruthTable( >>> input_ports=["detector_in"], >>> output_ports=["phase_map_out"], >>> **detector_phase_truth_table >>> ) >>> am_module = construct_amaranth_module_from_truth_table(my_truth_table) """ import amaranth as am # Extract inputs and outputs from the truth table inputs = truth_table.input_ports outputs = truth_table.output_ports truth_table_dict = truth_table.implementation_dictionary if logic_implementation_type == "combinatorial": class TruthTableModule(am.Elaboratable): """ A class representing an Amaranth module generated from a truth table. Attributes: input_signal (am.Signal): The signal corresponding to the input port of the truth table. output_signals (dict): A dictionary mapping output port names to their corresponding signals. inputs_names (list): A list of input port names. outputs_names (list): A list of output port names. truth_table (dict): The truth table dictionary with inputs and outputs. """ def __init__(self, truth_table_dict: dict, inputs: list, outputs: list): """ Initializes the TruthTableModule with the given truth table, inputs, and outputs. Args: truth_table_dict (dict): The dictionary representing the truth table. inputs (list): A list of input port names. outputs (list): A list of output port names. """ super(TruthTableModule, self).__init__() # Ensure that the truth table has entries if len(truth_table_dict[inputs[0]]) == 0: raise ValueError("No truth table inputs provided: " + str(inputs)) # Initialize signals for input and output connection and assign them as attributes self.input_signal = am.Signal( len(truth_table_dict[inputs[0]][0]), name=inputs[0] ) self.output_signals = { output: am.Signal(len(truth_table_dict[output][0]), name=output) for output in outputs } # Assign input and output signals as class attributes for external access setattr(self, inputs[0], self.input_signal) for output in outputs: setattr(self, output, self.output_signals[output]) self.inputs_names = inputs self.outputs_names = outputs self.truth_table = truth_table_dict def elaborate(self, platform): """ Elaborates the Amaranth module to implement the logic based on the truth table. Args: platform: The platform on which the module is to be implemented. TODO Returns: am.Module: The elaborated Amaranth module. """ m = am.Module() # Assume the truth table entries are consistent and iterate over them with m.Switch(self.input_signal): for i in range(len(self.truth_table[self.inputs_names[0]])): input_case = str(self.truth_table[self.inputs_names[0]][i]) with m.Case(input_case): # Assign values to each output signal for the current case for output in self.outputs_names: output_signal_value = self.output_signals[output].eq m.d.comb += output_signal_value( int(self.truth_table[output][i], 2) ) # Default case: set all outputs to 0 with m.Case(): for output in self.outputs_names: m.d.comb += self.output_signals[output].eq(0) return m elif logic_implementation_type == "sequential": class TruthTableModule(am.Elaboratable): def __init__(self, truth_table_dict: dict, inputs: list, outputs: list): super(TruthTableModule, self).__init__() if len(truth_table_dict[inputs[0]]) == 0: raise ValueError("No truth table inputs provided: " + str(inputs)) self.input_signal = am.Signal( len(truth_table_dict[inputs[0]][0]), name=inputs[0] ) self.output_signals = { output: am.Signal(len(truth_table_dict[output][0]), name=output) for output in outputs } setattr(self, inputs[0], self.input_signal) for output in outputs: setattr(self, output, self.output_signals[output]) self.inputs_names = inputs self.outputs_names = outputs self.truth_table = truth_table_dict # State register for sequential implementation self.state = am.Signal( len(truth_table_dict[inputs[0]][0]), name="state" ) def elaborate(self, platform): m = am.Module() # Register to hold the state next_state = am.Signal.like(self.state) m.d.sync += self.state.eq(next_state) # State transition logic based on input signal with m.Switch(self.input_signal): for i in range(len(self.truth_table[self.inputs_names[0]])): input_case = int(self.truth_table[self.inputs_names[0]][i], 2) with m.Case(input_case): m.d.sync += next_state.eq(input_case) for output in self.outputs_names: output_value = int(self.truth_table[output][i], 2) m.d.sync += self.output_signals[output].eq(output_value) # Default case: retain current state with m.Case(): m.d.sync += next_state.eq(self.state) return m return TruthTableModule(truth_table_dict, inputs, outputs)