Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

++ add in cross mult block #49

Merged
merged 19 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions casper_correlator/correlator_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
library ieee;
use ieee.std_logic_1164.all;

package correlator_pkg is

CONSTANT c_cross_mult_nof_input_streams : NATURAL := 12;
CONSTANT c_cross_mult_aggregation_per_stream : NATURAL := 3;
CONSTANT c_cross_mult_input_bit_width : NATURAL := 5;
CONSTANT c_cross_mult_output_bit_width : NATURAL := 11;

CONSTANT c_cross_mult_input_cbit_width : NATURAL := c_cross_mult_input_bit_width * 2; --COMPLEX
CONSTANT c_cross_mult_output_cbit_width : NATURAL := c_cross_mult_output_bit_width * 2; --COMPLEX
CONSTANT c_cross_mult_total_streams : NATURAL := c_cross_mult_nof_input_streams * c_cross_mult_aggregation_per_stream;
CONSTANT c_cross_mult_nof_output_streams :NATURAL := (c_cross_mult_nof_input_streams+1)*c_cross_mult_nof_input_streams / 2;
CONSTANT c_cross_mult_nof_cmults : NATURAL := c_cross_mult_nof_output_streams * c_cross_mult_aggregation_per_stream;

TYPE s_cross_mult_din is ARRAY (0 TO c_cross_mult_nof_input_streams - 1) OF std_logic_vector((c_cross_mult_aggregation_per_stream * c_cross_mult_input_cbit_width) - 1 downto 0);
TYPE s_cross_mult_out_bus_expand is ARRAY (0 TO (c_cross_mult_total_streams) - 1) OF std_logic_vector(c_cross_mult_input_cbit_width - 1 downto 0);
TYPE s_cross_mult_cmult_in is ARRAY(0 TO (c_cross_mult_nof_cmults - 1)) OF std_logic_vector(c_cross_mult_input_cbit_width - 1 downto 0);
TYPE s_cross_mult_out is ARRAY (0 TO c_cross_mult_nof_output_streams - 1) OF std_logic_vector((c_cross_mult_aggregation_per_stream * c_cross_mult_output_cbit_width) - 1 downto 0);
TYPE s_cross_mult_cmult_out is ARRAY (0 TO c_cross_mult_nof_cmults - 1) OF std_logic_vector(c_cross_mult_output_cbit_width - 1 DOWNTO 0);
TYPE s_cmult_inpt is ARRAY(0 TO 1) OF INTEGER RANGE 0 TO c_cross_mult_total_streams - 1;
TYPE s_cmult_map is ARRAY(0 TO c_cross_mult_nof_cmults - 1) OF s_cmult_inpt;

FUNCTION gen_inpt_to_mult_mapping(nof_aggregation : NATURAL; nof_streams : NATURAL) return s_cmult_map;

end package correlator_pkg;

package body correlator_pkg is

function gen_inpt_to_mult_mapping(nof_aggregation : NATURAL; nof_streams : NATURAL)
return s_cmult_map is
variable mapping : s_cmult_map;
variable mult : INTEGER := 0;
variable aa : INTEGER := 0;
begin
mult := 0;
FOR a IN 0 TO nof_aggregation - 1 LOOP
aa := a * nof_streams;
FOR s IN aa TO (aa + nof_streams - 1) LOOP
FOR ss IN s TO (aa + nof_streams - 1) LOOP
mapping(mult) := (s, ss);
mult := mult + 1;
END LOOP;
END LOOP;
END LOOP;
return mapping;
end function gen_inpt_to_mult_mapping;

end package body correlator_pkg;
85 changes: 85 additions & 0 deletions casper_correlator/cross_multiplier.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
library ieee, common_pkg_lib, casper_multiplier_lib;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use common_pkg_lib.common_pkg.all;
use work.correlator_pkg.all;

entity cross_multiplier is
generic(
g_use_gauss : BOOLEAN := FALSE;
g_use_dsp : BOOLEAN := TRUE;
g_pipeline_input : NATURAL := 1; --! 0 or 1
g_pipeline_product : NATURAL := 1; --! 0 or 1
g_pipeline_adder : NATURAL := 1; --! 0 or 1
g_pipeline_round : NATURAL := 1; --! 0 or 1
g_pipeline_output : NATURAL := 0; --! >= 0
ovflw_behav : BOOLEAN := FALSE;
quant_behav : NATURAL := 0
);
port(
clk : in std_logic;
ce : in std_logic;
sync_in : in std_logic;
sync_out : out std_logic;
din : in s_cross_mult_din;
dout : out s_cross_mult_out
);
end entity cross_multiplier;

architecture RTL of cross_multiplier is

signal s_out_bus_expand : s_cross_mult_out_bus_expand := (others => (others => '0'));
signal s_out_cmults : s_cross_mult_cmult_out := (others => (others => '0'));
signal s_a_cmult_in, s_b_cmult_in : s_cross_mult_cmult_in := (others => (others => '0'));
signal s_out : s_cross_mult_out := (others=>(others=>'0'));

signal s_cmult_input_map : s_cmult_map := gen_inpt_to_mult_mapping(c_cross_mult_aggregation_per_stream, c_cross_mult_nof_input_streams);

begin

gen_expand : FOR j IN 0 TO c_cross_mult_aggregation_per_stream - 1 GENERATE --SPLIT the aggregation
gen_bus_expand : FOR i IN 0 TO c_cross_mult_nof_input_streams - 1 GENERATE -- FOR each stream
s_out_bus_expand(c_cross_mult_nof_input_streams*j + i) <= din(i)((j + 1) * c_cross_mult_input_cbit_width - 1 DOWNTO j * c_cross_mult_input_cbit_width);
END GENERATE;
END GENERATE;

gen_cmult : FOR m IN 0 TO c_cross_mult_nof_cmults - 1 GENERATE
s_a_cmult_in(m) <= s_out_bus_expand(s_cmult_input_map(m)(0));
s_b_cmult_in(m) <= s_out_bus_expand(s_cmult_input_map(m)(1));
cmult_inst : entity casper_multiplier_lib.cmult
generic map(
g_use_ip => FALSE,
g_a_bw => c_cross_mult_input_bit_width,
g_b_bw => c_cross_mult_input_bit_width,
g_ab_bw => c_cross_mult_output_bit_width,
g_conjugate_b => TRUE,
g_use_gauss => g_use_gauss,
g_use_dsp => g_use_dsp,
g_round_method => quant_behav,
g_ovflw_method => ovflw_behav,
g_pipeline_input => g_pipeline_input,
g_pipeline_product => g_pipeline_product,
g_pipeline_adder => g_pipeline_adder,
g_pipeline_round => g_pipeline_round,
g_pipeline_output => g_pipeline_output
)
port map(
clk => clk,
ce => ce,
rst => '0',
in_a => s_a_cmult_in(m),
in_b => s_b_cmult_in(m),
in_val => '1',
out_ab => s_out_cmults(m),
out_val => open
);

END GENERATE;

gen_pack : FOR n IN 0 TO c_cross_mult_nof_output_streams - 1 GENERATE
gen_per_aggregation : FOR p IN 0 TO c_cross_mult_aggregation_per_stream - 1 GENERATE
s_out(n)((p+1)*c_cross_mult_output_cbit_width - 1 DOWNTO p*c_cross_mult_output_cbit_width) <= s_out_cmults(2*n + p)(c_cross_mult_output_cbit_width -1 DOWNTO 0);
END GENERATE;
END GENERATE;
dout <= s_out;
end architecture RTL;
195 changes: 195 additions & 0 deletions casper_correlator/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#Author: Talon Myburgh
#Company: Mydon Solutions

from vunit import VUnit
import numpy as np
import itertools
import glob
from os.path import dirname, join, abspath

# Function for package mangling.
def manglePkg(file_name, line_number, new_line):
with open(file_name, 'r') as file:
lines = file.readlines()
lines[line_number] = new_line
with open(file_name, 'w') as file:
lines = file.writelines(lines)


def mapping(aggre, inpts):
mult_map = {}
mult = 0
for a in range(aggre):
aa = a * inpts
for s in range(aa, aa + inpts):
for ss in range(s, aa + inpts):
mult_map[mult] = (s, ss)
mult += 1
return mult_map

def cross_mult(c_val_dict):
ans_dict = {}
for test, val in c_val_dict.items():
tests = test.split(':')
aggregations = int(tests[1])
streams = int(tests[0])
nof_cmults = aggregations * int(((streams +1)*streams)/2)
answers = np.zeros(nof_cmults,dtype=np.complex64)
mult_map = mapping(aggregations,streams)
for ans in range(nof_cmults):
a = val[mult_map[ans][0]]
b = np.conj(val[mult_map[ans][1]])
answers[ans] = a * b
ans_dict[test] = answers
return ans_dict

def turn_cint_to_int(number:complex, cin_bwidth:int):
if number.real >= 0:
real = int(number.real)
else:
real = int(number.real) + 2**32

if number.imag >= 0:
imag = int(number.imag)
else:
imag = int(number.imag) + 2**32
real_binary = bin(real & (2**cin_bwidth - 1))[2:].zfill(cin_bwidth)
imag_binary = bin(imag & (2**cin_bwidth - 1))[2:].zfill(cin_bwidth)
binary = real_binary + imag_binary
return int(binary, 2)

def split_int_gen_complexint(number, bitwidth):
if number < 0:
number += 2**32
binary = bin(number & (2**bitwidth-1))[2:].zfill(bitwidth)
first_half = binary[:bitwidth//2]
second_half = binary[bitwidth//2:]
if first_half:
first_int = int(first_half, 2)
if first_int >= 2**(bitwidth//2-1):
first_int -= 2**(bitwidth//2)
else:
first_int = 0
if second_half:
second_int = int(second_half, 2)
if second_int >= 2**(bitwidth//2-1):
second_int -= 2**(bitwidth//2)
else:
second_int = 0
return first_int + second_int*1j

# Create VUnit instance by parsing command line arguments
vu = VUnit.from_argv()
vu.add_vhdl_builtins()
script_dir = abspath(dirname(__file__))

aggregations = np.random.randint(2 , 8, 1)
streams = np.random.randint(2, 20, 1)
inpt_bitwidths = int(np.random.randint(2, 10, 1))

package_vals = [f' CONSTANT c_cross_mult_nof_input_streams : NATURAL := {int(streams)};\n',
f' CONSTANT c_cross_mult_aggregation_per_stream : NATURAL := {int(aggregations)};\n',
f' CONSTANT c_cross_mult_input_bit_width : NATURAL := {int(inpt_bitwidths)};\n',
f' CONSTANT c_cross_mult_output_bit_width : NATURAL := {2*int(inpt_bitwidths)+1};\n']

manglePkg(join(script_dir,'correlator_pkg.vhd'), slice(5,9),package_vals)

# COMMON COMPONENTS Library
common_components_lib = vu.add_library("common_components_lib",allow_duplicate=True)
common_components_lib.add_source_files(script_dir + "/../common_components/common_pipeline.vhd")
common_components_lib.add_source_files(script_dir + "/../common_components/common_pipeline_sl.vhd")

# COMMON PACKAGE Library
common_pkg_lib = vu.add_library("common_pkg_lib",allow_duplicate = True)
common_pkg_lib.add_source_files(script_dir + "/../common_pkg/*.vhd")
common_pkg_lib.add_source_files(script_dir + "/../common_pkg/tb_common_pkg.vhd")

# TECHNOLOGY Library
technology_lib = vu.add_library("technology_lib",allow_duplicate = True)
technology_lib.add_source_files(script_dir + "/../technology/technology_select_pkg.vhd")

# XPM Multiplier library
ip_xpm_mult_lib = vu.add_library("ip_xpm_mult_lib", allow_duplicate=True)
ip_xpm_mult_lib.add_source_files(script_dir + "/../ip_xpm/mult/*.vhd")

# STRATIXIV Multiplier library
ip_stratixiv_mult_lib = vu.add_library("ip_stratixiv_mult_lib", allow_duplicate=True)
ip_stratixiv_mult_lib.add_source_files(script_dir + "/../ip_stratixiv/mult/*rtl.vhd")

# CASPER MUlTIPLIER Library
casper_multiplier_lib = vu.add_library("casper_multiplier_lib")
casper_multiplier_lib.add_source_file(join(script_dir, "../casper_multiplier/tech_mult_component.vhd"))
tech_complex_mult = casper_multiplier_lib.add_source_file(join(script_dir, "../casper_multiplier/tech_complex_mult.vhd"))
casper_multiplier_lib.add_source_file(join(script_dir, "../casper_multiplier/tech_agilex_versal_cmult.vhd"))
casper_multiplier_lib.add_source_file(join(script_dir, "../casper_multiplier/common_complex_mult.vhd"))
casper_multiplier_lib.add_source_file(join(script_dir, "../casper_multiplier/cmult.vhd"))

# CASPER CORRELATOR Library
casper_correlator_lib = vu.add_library("casper_correlator_lib",allow_duplicate=True)
casper_correlator_lib.add_source_files(join(script_dir,'*.vhd'))

TB_GENERATED = casper_correlator_lib.test_bench("tb_tb_vu_cross_multiplier")

value_dict = {}
# Here we generate the test values. Note that these values are all taken as complex where real and imag are join (i.e. 85 = 5+5j)
for s, a in itertools.product(streams, aggregations):
print(f"""
Generating test for values:
bitwidth = {inpt_bitwidths}
nof streams = {s}
nof aggregations = {a}""")
max_val = int(2**(2*inpt_bitwidths) -1)
min_val = 0
value_dict[f"{s}:{a}"] = np.random.randint(min_val, max_val, size=(s,a))

generics_dict = {}
#Turn this into strings so they can be passed to generic g_values
for key,val in value_dict.items():
strval = ', '.join(map(str, val.flatten(order = 'F')))
generics_dict[key] = strval

#Here we must construct the complex values for testing
c_dict = {}
for key,val in value_dict.items():
values = val.flatten(order = 'F') #now we've flattened across aggregations which is how the module works and what the mapping expects
# print(values)
c_val = np.zeros(values.shape, dtype=np.complex64)
for i,v in enumerate(values):
c_val[i] = split_int_gen_complexint(int(v),2*int(inpt_bitwidths))
c_dict[key] = c_val

cross_mult_result = cross_mult(c_dict)

result_dict = {}
for test, val in cross_mult_result.items():
tests = test.split(':')
stream = int(tests[0])
aggre = int(tests[1])
int_val = np.zeros(val.shape,dtype=np.int64)
for i,v in enumerate(val):
int_val[i] = turn_cint_to_int(v ,2*int(inpt_bitwidths) + 1)
result_dict[test] = int_val#.reshape(int_val.size//aggre,aggre,order='F')

generics_result = {}
#convert result dict to set of strings for generics:
for key, result in result_dict.items():
strval = ', '.join(map(str, result))#.flatten()))
generics_result[key] = strval

for key, val in generics_dict.items():
vals = key.split(':')
streams = int(vals[0])
aggregations = int(vals[1])
config_name = f"Streams={streams},Aggregations={aggregations},inputbitwidth={inpt_bitwidths}"
TB_GENERATED.add_config(
name = config_name,
generics = {
'g_values' : val,
'g_results' : generics_result[key]
}
)

# RUN
vu.set_compile_option("ghdl.a_flags", ["-frelaxed", "-Wno-hide"])
vu.set_sim_option("ghdl.elab_flags", ["-frelaxed","--syn-binding"])
vu.main()
Loading
Loading