Source code for addition_layer_model
"""
Library for the AddLayerModel class.
It contains the Python model used to verify the Additional Layer module.
@author: Timothée Charrier
"""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from cocotb.handle import HierarchyObject
[docs]
class AddLayerModel:
"""
Model for the AdderConst module.
This class defines the model used to verify the AdderConst module.
"""
def __init__(
self,
*,
inputs: dict | None = None,
) -> None:
"""
Initialize the model.
Parameters
----------
inputs : dict, optional
The initial input dictionary
Default is None.
"""
if inputs is None:
inputs = {
"i_state": [0] * 5,
}
# Inputs parameters
self.i_state: list[int] = inputs["i_state"]
[docs]
def compute(
self,
*,
i_state: list[int] | None = None,
i_round: int | None = None,
) -> list[int]:
"""
Compute the output state based on the current input state and round.
Parameters
----------
i_state : list[int], optional
The input state
Default is None.
i_round : int, optional
The current round
Default is None.
Returns
-------
Nothing, only updates the state array.
"""
self.i_round: int = i_round if i_round is not None else 0
self.i_state = i_state if i_state is not None else [0] * 5
self.o_state: list[int] = self.i_state.copy()
# Add the round constant to the state
self.o_state[2] ^= 0xF0 - i_round * 0x10 + i_round * 0x1
self.o_state[2] &= 0xFFFFFFFFFFFFFFFF
[docs]
def assert_output(
self,
dut: HierarchyObject,
inputs: dict | None = None,
) -> None:
"""
Assert the output of the DUT and log the input and output values.
Parameters
----------
dut : HierarchyObject
The device under test (DUT).
inputs : dict, optional
The input dictionary.
"""
# Compute the expected output
self.compute(i_state=inputs["i_state"], i_round=inputs["i_round"])
# Get the output state from the DUT
o_state: list[int] = [int(x) for x in dut.o_state.value]
# Convert the output to a list of integers
round_str: str = f"{self.i_round:02X}"
input_str: str = "{:016X} {:016X} {:016X} {:016X} {:016X}".format(
*tuple(x & 0xFFFFFFFFFFFFFFFF for x in self.i_state),
)
expected_str: str = "{:016X} {:016X} {:016X} {:016X} {:016X}".format(
*tuple(x & 0xFFFFFFFFFFFFFFFF for x in self.o_state),
)
output_dut_str: str = "{:016X} {:016X} {:016X} {:016X} {:016X}".format(
*tuple(x & 0xFFFFFFFFFFFFFFFF for x in o_state),
)
dut._log.info("Round :" + round_str)
dut._log.info("Input state :" + input_str)
dut._log.info("Expected state :" + expected_str)
dut._log.info("Output state :" + output_dut_str)
dut._log.info("")
# Define the error message
error_msg: str = f"Output mismatch for round {round_str}\n"
error_msg += f"Expected: {expected_str}\n"
error_msg += f"Received: {output_dut_str}"
# Check if the output is correct
if expected_str != output_dut_str:
error_msg = (
f"Output mismatch for round {round_str}\n"
f"Expected: {expected_str}\n"
f"Received: {output_dut_str}"
)
raise ValueError(error_msg)