Skip to content

Commit

Permalink
fix: remove need for csv in testbench
Browse files Browse the repository at this point in the history
  • Loading branch information
glencoe committed Sep 4, 2023
1 parent 3f7e05f commit f905bbf
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 146 deletions.
7 changes: 4 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ repos:
- id: no-commit-to-branch
stages: [ commit, manual ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.1.1
rev: v1.5.1
hooks:
- id: mypy
stages: [ manual ]
- repo: https://github.com/asottile/dead
rev: v1.5.0
rev: v1.5.2
hooks:
- id: dead
stages: [ manual ]
Expand All @@ -36,13 +36,14 @@ repos:
hooks:
- id: isort
stages: [ commit, manual ]
args: ["--profile=black"]
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
stages: [ commit, manual ]
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.4.0
rev: v9.5.0
hooks:
- id: commitlint
stages: [commit-msg, manual]
7 changes: 4 additions & 3 deletions elasticai/creator/nn/fixed_point/mac/_hw_test_integ.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import glob

import torch
from fixed_point.mac._signal_number_converter import SignalNumberConverter
from fixed_point.mac.sw_function import MacLayer
from fixed_point.mac.testbench import TestBench

from elasticai.creator.file_generation.on_disk_path import OnDiskPath
from elasticai.creator.file_generation.template import InProjectTemplate
from elasticai.creator.vhdl.test_bench_runner import TestBenchRunner

from ._signal_number_converter import SignalNumberConverter
from .sw_function import MacLayer
from .testbench import TestBench

"""
Notes:
- The software layer knows the correct result for an input
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from functools import partial
from typing import Iterable

from fixed_point.mac.number_conversion import (
bits_to_rational,
integer_to_bits,
rational_to_bits,
)
from .number_conversion import bits_to_rational, integer_to_bits, rational_to_bits


class SignalNumberConverter:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import math

from fixed_point.mac._signal_number_converter import SignalNumberConverter
from ._signal_number_converter import SignalNumberConverter


def test_reset_two_times_without_input():
Expand Down
7 changes: 4 additions & 3 deletions elasticai/creator/nn/fixed_point/mac/design.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from creator.file_generation.savable import Path, Savable
from creator.file_generation.template import InProjectTemplate
from fixed_point.mac._signal_number_converter import SignalNumberConverter
from elasticai.creator.file_generation.savable import Path, Savable
from elasticai.creator.file_generation.template import InProjectTemplate

from ._signal_number_converter import SignalNumberConverter


class MacDesign(Savable):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fixed_point.mac.number_conversion import (
from .number_conversion import (
bits_to_rational,
integer_to_bits,
max_rational,
Expand Down
9 changes: 5 additions & 4 deletions elasticai/creator/nn/fixed_point/mac/sw_function.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from creator.file_generation.savable import Savable
from fixed_point._math_operations import MathOperations
from fixed_point._two_complement_fixed_point_config import FixedPointConfig
from fixed_point.mac.design import MacDesign
from elasticai.creator.file_generation.savable import Savable

from .._math_operations import MathOperations
from .._two_complement_fixed_point_config import FixedPointConfig
from .design import MacDesign


class MacLayer:
Expand Down
20 changes: 16 additions & 4 deletions elasticai/creator/nn/fixed_point/mac/testbench.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from creator.file_generation.savable import Path
from creator.file_generation.template import InProjectTemplate
from fixed_point.mac._signal_number_converter import SignalNumberConverter
from elasticai.creator.file_generation.savable import Path
from elasticai.creator.file_generation.template import InProjectTemplate

from ._signal_number_converter import SignalNumberConverter


class InputsFile:
Expand All @@ -21,6 +22,17 @@ def parameters(self):


class TestBench:
"""
The testbench aims to provide an interface between hw and sw engineer for
generating hw/sw tests for a hw/sw module pair.
The use case is as follows:
- Given a translatable software module and some input data `X`, we
- call the software module with the provided data and record the outputs
- generate the hw design (unit under test UUT) for the sw equivalent
- generate a testbench, that feeds the same input data `X` to the UUT and writes the output data to a file or stdout
- compare the output observed by the testbench to the output of the sw module
"""

def __init__(self, total_bits, frac_bits, inputs, name):
self._number_converter = SignalNumberConverter(
total_bits=total_bits, frac_bits=frac_bits
Expand All @@ -36,6 +48,6 @@ def save_to(self, destination: Path):
test_bench = InProjectTemplate(
package="elasticai.creator.nn.fixed_point.mac",
file_name="testbench.tpl.vhd",
parameters={"input_file": f"inputs.csv", "output_file": f"outputs.csv"},
parameters={},
)
destination.create_subpath(self._name).as_file(".vhd").write(test_bench)
143 changes: 45 additions & 98 deletions elasticai/creator/nn/fixed_point/mac/testbench.tpl.vhd
Original file line number Diff line number Diff line change
@@ -1,125 +1,72 @@
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 08/21/2023 09:45:40 AM
-- Design Name:
-- Module Name: test_fxp_mac - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use ieee.std_logic_textio.all;
use std.env.finish;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity testbench_fxp_mac is
generic(
VECTOR_WIDTH : integer := 2;
TOTAL_WIDTH : integer := 4;
FRAC_WIDTH : integer := 2
);
-- Port ( );

end testbench_fxp_mac;

architecture Behavioral of testbench_fxp_mac is
constant VECTOR_WIDTH : integer := 2;
constant TOTAL_WIDTH : integer := 4;
constant FRAC_WIDTH : integer := 2;
constant total_clock_cycles: integer := 4;
signal clock_period : time := 2 ps;
signal clock : std_logic;
signal reset : std_logic;
signal next_sample : std_logic;
signal x1 : signed (TOTAL_WIDTH-1 downto 0);
signal x2 : signed (TOTAL_WIDTH-1 downto 0);
signal x1 : signed (TOTAL_WIDTH-1 downto 0) := (others => '0');
signal x2 : signed (TOTAL_WIDTH-1 downto 0) := (others => '0');
signal sum : signed(TOTAL_WIDTH-1 downto 0);
signal done : std_logic;

file input_buf : text; -- text is keyword
file output_buf : text; -- text is keyword
type input_array_t is array (0 to 1) of signed(TOTAL_WIDTH-1 downto 0);
signal x1_values : input_array_t := (b"0000", b"0010");
signal x2_values : input_array_t := (b"0000", b"0010");



begin
UUT : entity work.fxp_MAC_RoundToEven generic map(VECTOR_WIDTH => VECTOR_WIDTH, TOTAL_WIDTH=>TOTAL_WIDTH, FRAC_WIDTH => FRAC_WIDTH)
port map (reset => reset, next_sample => next_sample, x1 => x1, x2 => x2, sum => sum, done => done);




testbench_1 : process
variable read_col_from_input_buf : line; -- read lines one by one from input_buf
variable write_col_to_output_buf : line; -- line is keyword
variable reset_val, next_sample_val : std_logic; -- to save col1 and col2 values of 1 bit
variable x1_val, x2_val : std_logic_vector(TOTAL_WIDTH-1 downto 0); -- to save col3 value of 2 bit
variable val_SPACE : character; -- for spaces between data in file
variable delimiter : string(1 to 1) := ",";

clock_process: process
begin
file_open(input_buf, "${input_file}", read_mode);
file_open(output_buf, "${output_file}", write_mode);


write(write_col_to_output_buf, string'("START_SIM"));
writeline(output_buf, write_col_to_output_buf);
write(write_col_to_output_buf, string'("reset,next_sample,x1,x2,sum,done"));
writeline(output_buf, write_col_to_output_buf);

readline(input_buf, read_col_from_input_buf); --read headerrow and throw away

while not endfile(input_buf) loop

-- reading input
readline(input_buf, read_col_from_input_buf);
read(read_col_from_input_buf, reset_val);
read(read_col_from_input_buf, val_SPACE); -- read in the space character
read(read_col_from_input_buf, next_sample_val);
read(read_col_from_input_buf, val_SPACE); -- read in the space character
read(read_col_from_input_buf, x1_val);
read(read_col_from_input_buf, val_SPACE); -- read in the space character
read(read_col_from_input_buf, x2_val);

--connect input to signals
reset <= reset_val;
next_sample <= next_sample_val;
x1 <= signed(x1_val);
x2 <= signed(x2_val);
clock <= '0';
wait for clock_period/2;
clock <= '1';
wait for clock_period/2;
end process;

-- writing output
write(write_col_to_output_buf, reset_val);
write(write_col_to_output_buf, delimiter);
write(write_col_to_output_buf, next_sample_val);
write(write_col_to_output_buf, delimiter);
write(write_col_to_output_buf, x1_val);
write(write_col_to_output_buf, delimiter);
write(write_col_to_output_buf, x2_val);
write(write_col_to_output_buf, delimiter);
write(write_col_to_output_buf, std_logic_vector(sum));
write(write_col_to_output_buf, delimiter);
write(write_col_to_output_buf, done);
writeline(output_buf, write_col_to_output_buf);
next_sample <= clock;

wait for 20 ns;
end loop;
write(write_col_to_output_buf, string'("END_SIM"));
writeline(output_buf, write_col_to_output_buf);
file_close(output_buf);
file_close(input_buf);
wait;
testbench_1 : process(clock)
variable iteration_id : integer := 1;
variable reset_performed : std_logic := '0';
begin
if rising_edge(clock) and reset_performed = '0' then
reset <= '0';
reset_performed := '1';
end if;
if falling_edge(clock) then
if reset_performed = '0' then
reset <= '1';
elsif iteration_id < 2 then
x1 <= x1_values(iteration_id);
x2 <= x2_values(iteration_id);
iteration_id := iteration_id + 1;
elsif done = '1' then
report "sum: " & to_bstring(sum);
report "iterations: " & to_string(iteration_id);
finish;
else
iteration_id := iteration_id + 1;
end if;
end if;
end process;

end Behavioral;
53 changes: 29 additions & 24 deletions elasticai/creator/vhdl/test_bench_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,39 @@ def __init__(self, workdir, files, test_bench_name):
self._root = workdir
self._ghdl_dir = "ghdl_build"
self._files = files
self._standard = "08"
self._test_bench_name = test_bench_name

@property
def _workdir_flag(self):
return f"--workdir={self._ghdl_dir}"

def initialize(self):
os.makedirs(f"{self._root}/{self._ghdl_dir}", exist_ok=True)
subprocess.run(["ghdl", "-i", self._workdir_flag] + self._files, cwd=self._root)
subprocess.run(
[
"ghdl",
"-m",
self._workdir_flag,
"-fsynopsys",
f"{self._test_bench_name}",
],
cwd=self._root,
)
self._load_files()
self._compile()

def run(self):
subprocess.run(
[
"ghdl",
"-r",
self._workdir_flag,
"-fsynopsys",
f"{self._test_bench_name}",
],
cwd=self._root,
self._run()

def _load_files(self):
self._execute_command(self._assemble_command("-i") + self._files)

def _compile(self):
self._execute_command(
self._assemble_command("-m") + ["-fsynopsys", self._test_bench_name]
)

def _run(self):
output = self._execute_command_and_return_stdout(
self._assemble_command("-r") + [self._test_bench_name]
)

def _execute_command(self, command):
return subprocess.run(command, cwd=self._root)

def _execute_command_and_return_stdout(self, command):
return subprocess.run(command, cwd=self._root, capture_output=True).stdout

def _assemble_command(self, command_flag):
return ["ghdl", command_flag, f"--std={self._standard}", self._workdir_flag]

@property
def _workdir_flag(self):
return f"--workdir={self._ghdl_dir}"

0 comments on commit f905bbf

Please sign in to comment.