Source code for piel.integration.amaranth_cocotb
from piel.types.digital import TruthTable
from ..file_system import return_path
from ..types import PathTypes
[docs]
def create_cocotb_truth_table_verification_python_script(
module: PathTypes,
truth_table: TruthTable,
test_python_module_name: str = "top_test",
):
"""
Creates a cocotb test script for verifying logic defined by the truth table.
Args:
module (PathTypes): The path to the module where the test script will be placed.
truth_table (TruthTable): A dictionary representing the truth table.
test_python_module_name (str, optional): The name of the test python module. Defaults to "top_test".
Example:
truth_table = {
"A": [0, 0, 1, 1],
"B": [0, 1, 0, 1],
"X": [0, 1, 1, 0] # Expected output (for XOR logic, as an example)
}
create_cocotb_truth_table_verification_python_script(truth_table)
"""
# Extract input and output connection
input_ports = truth_table.input_ports
output_ports = truth_table.output_ports
# Get the implementation dictionary with only the specified connection
truth_table_dict = truth_table.implementation_dictionary
# Resolve the module path and create the tb directory if it doesn't exist
module_path = return_path(module)
tb_directory_path = module_path / "tb"
tb_directory_path.mkdir(parents=True, exist_ok=True)
python_module_test_file_path = tb_directory_path / f"{test_python_module_name}.py"
output_file = tb_directory_path / "out" / "truth_table_test_results.csv"
output_file.parent.mkdir(
parents=True, exist_ok=True
) # Ensure 'out' directory exists
# Create the header for the script
script_content = """
# This file is public domain, it can be freely copied without restrictions.
# SPDX-License-Identifier: CC0-1.0
import cocotb
from cocotb.triggers import Timer
from cocotb.utils import get_sim_time
import pandas as pd
@cocotb.test()
async def truth_table_test(dut):
\"\"\"Test for logic defined by the truth table\"\"\"
"""
# Extract signal names and values from the truth table
signals = list(truth_table_dict.keys())
num_tests = len(truth_table_dict[signals[0]])
# Initialize lists to store signal files for logging
for signal in signals:
script_content += f" {signal.lower()}_data = []\n"
script_content += " time = []\n\n"
# Loop over each row in the truth table to generate test cases
for i in range(num_tests):
script_content += f" # Test case {i + 1}\n"
for signal in input_ports: # Input connection are the inputs to the DUT
value = truth_table_dict[signal][i]
script_content += f' dut.{signal}.value = cocotb.binary.BinaryValue("{value}")\n' # Assign binary string values directly
script_content += " await Timer(2, units='ns')\n\n"
# Check the expected output for each output port
for output_signal in output_ports:
expected_value = truth_table_dict[output_signal][i]
script_content += f' assert dut.{output_signal}.value == cocotb.binary.BinaryValue("{expected_value}"), '
script_content += f'f"Test failed for inputs {input_ports}: expected {expected_value} but got {{dut.{output_signal}.value}}."\n'
# Append files to lists for logging
for signal in signals:
script_content += f" {signal.lower()}_data.append(dut.{signal}.value)\n"
script_content += " time.append(get_sim_time())\n\n"
# Store the results in a CSV file
script_content += " simulation_data = {\n"
for signal in signals:
script_content += f' "{signal.lower()}": {signal.lower()}_data,\n'
script_content += ' "time": time\n'
script_content += " }\n\n"
script_content += (
f' pd.DataFrame(simulation_data).to_csv("{str(output_file)}") \n'
)
# Write the script to a file
with open(python_module_test_file_path, "w") as file:
file.write(script_content)
print(f"Test script written to {python_module_test_file_path}")