-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is part of the ongoing effort of making all cores compatible with open source HDL simulators like GHDL and NVC.
- Loading branch information
Showing
6 changed files
with
360 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,6 @@ | ||
files = [ "cic_dyn.vhd", "cic_decim.v", "log2.v", "decimation_strober.vhd", "cic_dual.vhd" ] | ||
files = [ "cic_dyn.vhd", "log2.v", "decimation_strober.vhd", "cic_dual.vhd" ] | ||
|
||
if use_cic_decim_vhdl: | ||
files.append("cic_decim.vhd") | ||
else: | ||
files.append("cic_decim.v") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
------------------------------------------------------------------------------- | ||
-- Title : CIC decimator with dynamically-adjustable decimator | ||
------------------------------------------------------------------------------- | ||
-- Author : Augusto Fraga Giachero <augusto.fraga@lnls.br> | ||
-- Company : CNPEM LNLS-GIE | ||
-- Platform : Generic | ||
-- Standard : VHDL'93 | ||
------------------------------------------------------------------------------- | ||
-- Description: CIC decimator with dinamically adjustable decimation rate | ||
-- | ||
-- The CIC has a valid signal (act) pipeline that signals when the data is | ||
-- filling integrator and comb pipelines. When the decimation strobe | ||
-- comes (act_out_i), the data in the last integrator register is sampled | ||
-- to the comb stage. However, to allow the decimation strobe to happen in | ||
-- a different clock period from the valid input signal, the valid signal | ||
-- in the last register is marked as invalid during the decimation. The | ||
-- sampling only happens when this register is valid, avoiding data corruption | ||
-- from occasional spurious decimation strobes. | ||
-- | ||
-- Design based on Daniel Tavare's verilog implementation | ||
------------------------------------------------------------------------------- | ||
-- Copyright (c) 2023 CNPEM | ||
-- Licensed under GNU Lesser General Public License (LGPL) v3.0 | ||
------------------------------------------------------------------------------- | ||
-- Revisions : | ||
-- Date Version Author Description | ||
-- 2023-01-20 1.0 augusto.fraga Created | ||
------------------------------------------------------------------------------- | ||
|
||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
entity cic_decim is | ||
generic ( | ||
DATAIN_WIDTH : integer := 16; | ||
DATAOUT_WIDTH : integer := 16; | ||
M : integer := 2; | ||
N : integer := 5; | ||
MAXRATE : integer := 64; | ||
BITGROWTH : integer := 35; | ||
ROUND_CONVERGENT : integer := 0 | ||
); | ||
port ( | ||
clk_i : in std_logic; | ||
rst_i : in std_logic; | ||
en_i : in std_logic; | ||
data_i : in std_logic_vector(DATAIN_WIDTH-1 downto 0); | ||
data_o : out std_logic_vector(DATAOUT_WIDTH-1 downto 0); | ||
act_i : in std_logic; | ||
act_out_i : in std_logic; | ||
val_o : out std_logic | ||
); | ||
end entity; | ||
|
||
architecture cic_decim_arch of cic_decim is | ||
constant c_dataout_full_width : natural := DATAIN_WIDTH + BITGROWTH; | ||
constant c_dataout_extra_bits : integer := c_dataout_full_width - DATAOUT_WIDTH; | ||
type t_signed_array is array (positive range <>) of signed(c_dataout_full_width downto 0); | ||
type t_signed_matrix is array (positive range <>) of t_signed_array(N-1 downto 0); | ||
|
||
function f_replicate(x : std_logic; len : natural) | ||
return std_logic_vector | ||
is | ||
variable v_ret : std_logic_vector(len-1 downto 0) := (others => x); | ||
begin | ||
return v_ret; | ||
end f_replicate; | ||
|
||
-- round using "convergent rounding" method | ||
function f_convergent_round(x : std_logic_vector; x_new_msb : natural) | ||
return std_logic_vector | ||
is | ||
constant x_old_msb : natural := x'left; | ||
constant x_extra_msb : natural := x_old_msb - x_new_msb - 1; | ||
variable v_x_conv : std_logic_vector(x_new_msb downto 0); | ||
begin | ||
-- if it's midscale (tie), converge to even integers | ||
if (unsigned(x(x_extra_msb downto 0)) = | ||
unsigned('1' & f_replicate('0', x_extra_msb))) then | ||
v_x_conv := std_logic_vector(unsigned(x(x_old_msb downto x_extra_msb+1)) + | ||
unsigned'("" & x(x_extra_msb+1))); | ||
-- otherwise, round to nearest integer | ||
else | ||
v_x_conv := std_logic_vector(unsigned(x(x_old_msb downto x_extra_msb+1)) + | ||
unsigned'("" & x(x_extra_msb))); | ||
end if; | ||
|
||
-- overflow, saturate | ||
if v_x_conv(v_x_conv'left) /= x(x_old_msb) then | ||
return x(x_old_msb) & f_replicate(not x(x_old_msb), x_new_msb); | ||
end if; | ||
|
||
return v_x_conv; | ||
end f_convergent_round; | ||
|
||
signal integrator : t_signed_array(N-1 downto 0); | ||
signal pipe : t_signed_array(N-1 downto 0); | ||
signal diff_delay : t_signed_matrix(M-1 downto 0); | ||
signal act_integ : std_logic_vector(N-1 downto 0); | ||
signal act_comb : std_logic_vector(N-1 downto 0); | ||
signal sampler : signed(c_dataout_full_width downto 0); | ||
signal act_samp : std_logic; | ||
signal val_int : std_logic; | ||
begin | ||
process(clk_i) | ||
begin | ||
if rising_edge(clk_i) then | ||
if rst_i = '1' then | ||
diff_delay <= (others => (others => (others => '0'))); | ||
integrator <= (others => (others => '0')); | ||
pipe <= (others => (others => '0')); | ||
act_integ <= (others => '0'); | ||
act_comb <= (others => '0'); | ||
sampler <= (others => '0'); | ||
data_o <= (others => '0'); | ||
act_samp <= '0'; | ||
val_int <= '0'; | ||
val_o <= '0'; | ||
elsif en_i = '1' then | ||
if act_i = '1' then | ||
integrator(0) <= integrator(0) + resize(signed(data_i), N); | ||
act_integ(0) <= '1'; | ||
for i in 1 to N-1 loop | ||
integrator(i) <= integrator(i) + integrator(i-1); | ||
act_integ(i) <= act_integ(i); | ||
end loop; | ||
else | ||
-- Clear the act_integ flag only when the COMB section acknowledges it | ||
if act_out_i = '1' then | ||
act_integ(N-1) <= '0'; | ||
end if; | ||
|
||
if act_out_i = '1' and act_integ(N-1) = '1' then | ||
sampler <= integrator(N-1); | ||
act_samp <= '1'; | ||
diff_delay(0)(0) <= sampler; | ||
|
||
for i in 1 to M-1 loop | ||
diff_delay(0)(i) <= diff_delay(0)(i-1); | ||
end loop; | ||
|
||
pipe(0) <= sampler - diff_delay(0)(M-1); | ||
act_comb(0) <= act_samp; | ||
|
||
for i in 1 to N-1 loop | ||
diff_delay(i)(0) <= pipe(i-1); | ||
for j in 1 to M-1 loop | ||
diff_delay(i)(j) <= diff_delay(i)(j-1); | ||
end loop; | ||
pipe(i) <= pipe(i-1) - diff_delay(i)(M-1); | ||
act_comb(i) <= act_comb(i-1); | ||
end loop; | ||
|
||
if N = 1 then | ||
val_int <= act_samp; | ||
else | ||
val_int <= act_comb(N-2); | ||
end if; | ||
|
||
else | ||
val_int <= '0'; | ||
end if; | ||
|
||
end if; | ||
val_o <= val_int; | ||
if c_dataout_extra_bits = 0 then | ||
data_o <= std_logic_vector(pipe(N-1)); | ||
elsif c_dataout_extra_bits > 0 then | ||
if ROUND_CONVERGENT = 1 then | ||
-- Convergent round | ||
data_o <= f_convergent_round(std_logic_vector(pipe(N-1)), DATAOUT_WIDTH); | ||
else | ||
-- Truncate least significant bits | ||
data_o <= std_logic_vector(pipe(N-1)(c_dataout_full_width-1 downto c_dataout_extra_bits)); | ||
end if; | ||
else | ||
-- Sign-extend bits as selected data output width > computed data output | ||
-- width | ||
data_o <= std_logic_vector(resize(pipe(N-1), DATAOUT_WIDTH)); | ||
end if; | ||
end if; | ||
end if; | ||
end process; | ||
end architecture; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
files = ["cic_decim_tb.vhd"] | ||
modules = {"local" : [ | ||
"../../ip_cores/general-cores", | ||
"../../modules", | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
------------------------------------------------------------------------------- | ||
-- Title : CIC decimator testbench | ||
------------------------------------------------------------------------------- | ||
-- Author : Augusto Fraga Giachero | ||
-- Company : CNPEM LNLS-GIE | ||
-- Platform : Simulation | ||
-- Standard : VHDL 2008 | ||
------------------------------------------------------------------------------- | ||
-- Description: | ||
------------------------------------------------------------------------------- | ||
-- Copyright (c) 2023-01-23 CNPEM | ||
-- Licensed under GNU Lesser General Public License (LGPL) v3.0 | ||
------------------------------------------------------------------------------- | ||
-- Revisions : | ||
-- Date Version Author Description | ||
-- 2023-01-23 1.0 augusto.fraga Created | ||
------------------------------------------------------------------------------- | ||
|
||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
use ieee.math_real.all; | ||
|
||
library work; | ||
use work.dsp_cores_pkg.all; | ||
|
||
entity cic_decim_tb is | ||
generic ( | ||
g_DATAIN_WIDTH : integer := 16; | ||
g_DATAOUT_WIDTH : integer := 32; | ||
g_CIC_DELAY : integer := 1; | ||
g_CIC_STAGES : integer := 1; | ||
g_MAX_RATE : integer := 2048; | ||
g_BITGROWTH : integer := 11; | ||
g_ROUND_CONVERGENT : boolean := false | ||
); | ||
end cic_decim_tb; | ||
|
||
architecture rtl of cic_decim_tb is | ||
function bool_to_int(x : boolean) return integer is | ||
begin | ||
if x then | ||
return 1; | ||
else | ||
return 0; | ||
end if; | ||
end function; | ||
|
||
procedure f_gen_clk(constant freq : in natural; | ||
signal clk : inout std_logic) is | ||
begin | ||
loop | ||
wait for (0.5 / real(freq)) * 1 sec; | ||
clk <= not clk; | ||
end loop; | ||
end procedure f_gen_clk; | ||
|
||
procedure f_wait_cycles(signal clk : in std_logic; | ||
constant cycles : natural) is | ||
begin | ||
for i in 1 to cycles loop | ||
wait until rising_edge(clk); | ||
end loop; | ||
end procedure f_wait_cycles; | ||
|
||
type t_cic_decim_iface is record | ||
en_i : std_logic; | ||
decim_i : std_logic; | ||
valid_i : std_logic; | ||
valid_o : std_logic; | ||
data_i : std_logic_vector(g_DATAIN_WIDTH-1 downto 0); | ||
data_o : std_logic_vector(g_DATAOUT_WIDTH-1 downto 0); | ||
end record; | ||
|
||
procedure f_cic_decim_write(signal cic_if : inout t_cic_decim_iface; | ||
data : signed(g_DATAIN_WIDTH-1 downto 0); | ||
signal clk : in std_logic) is | ||
begin | ||
cic_if.en_i <= '1'; | ||
cic_if.data_i <= std_logic_vector(data); | ||
cic_if.valid_i <= '1'; | ||
wait until rising_edge(clk); | ||
cic_if.valid_i <= '0'; | ||
end procedure; | ||
|
||
procedure f_cic_decim_read(signal cic_if : inout t_cic_decim_iface; | ||
signal data : out signed(g_DATAOUT_WIDTH-1 downto 0); | ||
signal clk : in std_logic) is | ||
begin | ||
cic_if.en_i <= '1'; | ||
cic_if.decim_i <= '1'; | ||
wait until rising_edge(clk); | ||
wait until rising_edge(clk); | ||
cic_if.decim_i <= '0'; | ||
wait until cic_if.valid_o = '1'; | ||
data <= signed(cic_if.data_o); | ||
end procedure; | ||
|
||
signal cic_decim_iface : t_cic_decim_iface := ( | ||
en_i => '0', | ||
decim_i => '0', | ||
valid_i => '0', | ||
valid_o => '0', | ||
data_i => (others => '0'), | ||
data_o => (others => '0') | ||
); | ||
signal result : signed(g_DATAOUT_WIDTH-1 downto 0) := (others => '0'); | ||
signal clk : std_logic := '0'; | ||
signal rst : std_logic := '1'; | ||
begin | ||
|
||
cmp_cic_decim: cic_decim | ||
generic map ( | ||
DATAIN_WIDTH => g_DATAIN_WIDTH, | ||
DATAOUT_WIDTH => g_DATAOUT_WIDTH, | ||
M => g_CIC_DELAY, | ||
N => g_CIC_STAGES, | ||
MAXRATE => g_MAX_RATE, | ||
BITGROWTH => g_BITGROWTH, | ||
ROUND_CONVERGENT => bool_to_int(g_ROUND_CONVERGENT) | ||
) | ||
port map ( | ||
clk_i => clk, | ||
rst_i => rst, | ||
en_i => cic_decim_iface.en_i, | ||
data_i => cic_decim_iface.data_i, | ||
data_o => cic_decim_iface.data_o, | ||
act_i => cic_decim_iface.valid_i, | ||
act_out_i => cic_decim_iface.decim_i, | ||
val_o => cic_decim_iface.valid_o | ||
); | ||
|
||
f_gen_clk(100e6, clk); | ||
process | ||
begin | ||
f_wait_cycles(clk, 5); | ||
rst <= '0'; | ||
f_wait_cycles(clk, 1); | ||
for i in 1 to 20 loop | ||
f_cic_decim_write(cic_decim_iface, to_signed(20, g_DATAIN_WIDTH), clk); | ||
end loop; | ||
f_cic_decim_read(cic_decim_iface, result, clk); | ||
std.env.finish; | ||
end process; | ||
|
||
end architecture rtl; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
cic_decim_tb | ||
cic_decim_tb.ghw | ||
*.cf | ||
*.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
action = "simulation" | ||
target = "xilinx" | ||
syn_device = "xc7a200t" | ||
sim_tool = "ghdl" | ||
top_module = "cic_decim_tb" | ||
|
||
modules = {"local" : ["../"]} | ||
|
||
use_cic_decim_vhdl = True | ||
|
||
ghdl_opt = "--std=08" | ||
|
||
sim_post_cmd = "ghdl -r --std=08 cic_decim_tb --wave=cic_decim_tb.ghw --assert-level=error --stop-time=50us" |