Source code for piel.tools.amaranth.verify
from typing import Literal, Any
from ...project_structure import get_module_folder_type_location
from ...file_system import return_path
from ...types import PathTypes
from piel.types.digital import TruthTable
__all__ = ["verify_amaranth_truth_table"]
[docs]
def verify_amaranth_truth_table(
truth_table_amaranth_module: Any,
truth_table: TruthTable,
vcd_file_name: str,
target_directory: PathTypes,
implementation_type: Literal[
"combinatorial", "sequential", "memory"
] = "combinatorial",
):
"""
Verifies that the outputs generated by the given Amaranth module match the provided truth table.
This function runs a simulation of the Amaranth module and checks if the outputs for each set of inputs
match the expected outputs as specified in the truth table. It can optionally generate a VCD file for detailed analysis.
Args:
truth_table_amaranth_module (amaranth.Elaboratable): The Amaranth module to be verified.
truth_table (TruthTable): The truth table specifying expected inputs and outputs.
vcd_file_name (str): The name of the VCD file to generate for the simulation.
target_directory (PathTypes): The directory where the VCD file will be saved. Can be a direct path or a module type path.
implementation_type (Literal["combinatorial", "sequential", "memory"], optional):
The type of implementation to simulate. Defaults to "combinatorial".
Returns:
None
Raises:
AttributeError: If the specified connection are not found in the Amaranth module.
Examples:
>>> am_module = MyAmaranthModule() # Assuming this is a defined Amaranth module.
>>> truth_table = TruthTable(
>>> input_ports=["input1"],
>>> output_ports=["output1", "output2"],
>>> input1=["0", "1"],
>>> output1=["1", "0"],
>>> output2=["0", "1"]
>>> )
>>> verify_amaranth_truth_table(am_module, truth_table, "output.vcd", "/path/to/save")
"""
import amaranth as am
from amaranth.sim import Simulator, Delay
import types
if isinstance(truth_table_amaranth_module, am.Elaboratable):
pass
else:
raise AttributeError("Amaranth module should be am.Elaboratable")
inputs = truth_table.input_ports
outputs = truth_table.output_ports
truth_table_df = truth_table.dataframe
def verify_logic():
"""
Implements the logic verification for the Amaranth module.
This generator function sets the input signals and checks the output signals against
the expected values from the truth table in each simulation cycle.
"""
input_port_signal = getattr(truth_table_amaranth_module, inputs[0]).eq
for i, input_value_i in enumerate(truth_table_df[inputs[0]]):
# Apply input value
yield input_port_signal(
int(input_value_i, 2)
) # Convert input value to integer (assuming binary string)
yield Delay(1e-6) # Delay for combinatorial logic simulation
# Check each output signal
for output_port in outputs:
output_port_signal = getattr(truth_table_amaranth_module, output_port)
expected_output_value = int(truth_table_df[output_port].iloc[i], 2)
assert (yield output_port_signal) == expected_output_value, (
f"Expected output {expected_output_value} on {output_port} for input {input_value_i} "
f"but got {(yield output_port_signal)}."
)
# Determine the output files files directory
if isinstance(target_directory, types.ModuleType):
target_directory = get_module_folder_type_location(
module=target_directory, folder_type="digital_testbench"
)
else:
target_directory = return_path(target_directory)
# Ensure the target directory exists
target_directory.mkdir(parents=True, exist_ok=True)
output_vcd_file = target_directory / vcd_file_name
# Set up the simulator for the Amaranth module
simulation = Simulator(truth_table_amaranth_module)
simulation.add_process(verify_logic)
if implementation_type == "sequential":
simulation.add_clock(1e-6) # Add a clock for sequential logic
simulation.add_sync_process(verify_logic) # Sync process for sequential logic
elif implementation_type == "combinatorial":
# No clock is needed for combinatorial logic
pass
elif implementation_type == "memory":
# Add specific handling for memory-based implementations if needed
pass
# Run the simulation and write VCD output for verification
with simulation.write_vcd(str(output_vcd_file)):
simulation.run()
print(f"VCD file generated and written to {output_vcd_file}")