Source code for elasticai.creator.vhdl.shared_designs.precomputed_scalar_function.design
from collections.abc import Callable
from elasticai.creator.file_generation.savable import Path
from elasticai.creator.file_generation.template import (
InProjectTemplate,
module_to_package,
)
from elasticai.creator.vhdl.auto_wire_protocols.port_definitions import create_port
from elasticai.creator.vhdl.design.design import Design
from elasticai.creator.vhdl.design.ports import Port
[docs]
class PrecomputedScalarFunction(Design):
_template_package = module_to_package(__name__)
def __init__(
self,
name: str,
input_width: int,
output_width: int,
function: Callable[[int], int],
inputs: list[int],
) -> None:
super().__init__(name)
self._input_width = input_width
self._output_width = output_width
self._function = function
self._inputs = inputs
self._template = InProjectTemplate(
file_name="precomputed_scalar_function.tpl.vhd",
package=self._template_package,
parameters=dict(
name=self.name,
input_data_width=str(self._input_width),
output_data_width=str(self._output_width),
),
)
def _compute_io_pairs(self) -> list[tuple[int, int]]:
ascending_unique_inputs = sorted(set(self._inputs))
io_pairs = []
for input_value in ascending_unique_inputs:
_assert_value_is_representable_with_n_bits(input_value, self._input_width)
output_value = self._function(input_value)
_assert_value_is_representable_with_n_bits(output_value, self._output_width)
io_pairs.append((input_value, output_value))
return io_pairs
@property
def port(self) -> Port:
return create_port(x_width=self._input_width, y_width=self._output_width)
[docs]
def save_to(self, destination: Path) -> None:
process_content = []
pairs = self._compute_io_pairs()
input_value, output_value = pairs[0]
process_content.append(
f"if signed_x <= to_signed({input_value}, BITWIDTH_OUTPUT) then "
f"signed_y <= to_signed({output_value}, BITWIDTH_OUTPUT);"
)
for input_value, output_value in pairs[1:-1]:
process_content.append(
f"elsif signed_x <= to_signed({input_value}, BITWIDTH_OUTPUT) then "
f"signed_y <= to_signed({output_value}, BITWIDTH_OUTPUT);"
)
_, output = pairs[-1]
process_content.append(
f"else signed_y <= to_signed({output}, BITWIDTH_OUTPUT);"
)
process_content.append("end if;")
self._template.parameters.update(process_content=process_content)
destination.create_subpath(self.name).as_file(".vhd").write(self._template)
def _assert_value_is_representable_with_n_bits(value: int, n_bits: int) -> None:
min_value = 2 ** (n_bits - 1) * (-1)
max_value = 2 ** (n_bits - 1) - 1
if value < min_value or value > max_value:
raise ValueError(
f"The value '{value}' cannot be represented "
f"with {n_bits} in two's complement representation."
)