Basic delay line and encoder

parent 0ac60964
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_channel
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Per-channel processing
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
-- 2011-08-03 SB Created file
-------------------------------------------------------------------------------
-- Copyright (C) 2011 Sebastien Bourdeauducq
library ieee;
use ieee.std_logic_1164.all;
use work.tdc_package.all;
entity tdc_channel is
generic(
-- Number of CARRY4 elements.
g_CARRY4_COUNT : positive;
-- Number of raw output bits.
g_RAW_COUNT : positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
signal_i : in std_logic;
detect_o : out std_logic;
polarity_o : out std_logic;
raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0)
);
end entity;
architecture rtl of tdc_channel is
signal taps : std_logic_vector(4*g_CARRY4_COUNT-1 downto 0);
signal polarity, polarity_d1 : std_logic;
signal raw : std_logic_vector(g_RAW_COUNT-1 downto 0);
begin
cmp_delayline: tdc_delayline
generic map(
g_WIDTH => g_CARRY4_COUNT
)
port map(
clk_i => clk_i,
reset_i => reset_i,
signal_i => signal_i,
taps_o => taps
);
cmp_lbc: tdc_lbc
generic map(
g_N => g_RAW_COUNT,
g_NIN => g_CARRY4_COUNT*4
)
port map(
clk_i => clk_i,
reset_i => reset_i,
d_i => taps,
polarity_o => polarity,
count_o => raw
);
polarity_o <= polarity_d1;
process(clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
detect_o <= '0';
polarity_d1 <= '1';
raw_o <= (others => '0');
else
detect_o <= polarity xor polarity_d1;
polarity_d1 <= polarity;
raw_o <= raw;
end if;
end if;
end process;
end architecture;
...@@ -24,11 +24,13 @@ library UNISIM; ...@@ -24,11 +24,13 @@ library UNISIM;
use UNISIM.vcomponents.all; use UNISIM.vcomponents.all;
entity tdc_delayline is entity tdc_delayline is
generic ( generic(
g_WIDTH : positive -- number of CARRY4 elements -- Number of CARRY4 elements.
g_WIDTH : positive
); );
port ( port(
clk_sample_i : in std_logic; clk_i : in std_logic;
reset_i : in std_logic;
signal_i : in std_logic; signal_i : in std_logic;
taps_o : out std_logic_vector(4*g_WIDTH-1 downto 0) taps_o : out std_logic_vector(4*g_WIDTH-1 downto 0)
); );
...@@ -41,7 +43,7 @@ begin ...@@ -41,7 +43,7 @@ begin
-- generate a carry chain -- generate a carry chain
g_carry4: for i in 0 to g_WIDTH-1 generate g_carry4: for i in 0 to g_WIDTH-1 generate
g_firstcarry4: if i = 0 generate g_firstcarry4: if i = 0 generate
CARRY4_inst : CARRY4 port map ( cmp_CARRY4: CARRY4 port map(
CO => unreg(3 downto 0), CO => unreg(3 downto 0),
CI => '0', CI => '0',
CYINIT => signal_i, CYINIT => signal_i,
...@@ -50,7 +52,7 @@ begin ...@@ -50,7 +52,7 @@ begin
); );
end generate; end generate;
g_nextcarry4: if i > 0 generate g_nextcarry4: if i > 0 generate
CARRY4_inst : CARRY4 port map ( cmp_CARRY4: CARRY4 port map(
CO => unreg(4*(i+1)-1 downto 4*i), CO => unreg(4*(i+1)-1 downto 4*i),
CI => unreg(4*i-1), CI => unreg(4*i-1),
CYINIT => '0', CYINIT => '0',
...@@ -62,15 +64,25 @@ begin ...@@ -62,15 +64,25 @@ begin
-- double latch the output -- double latch the output
g_fd: for j in 0 to 4*g_WIDTH-1 generate g_fd: for j in 0 to 4*g_WIDTH-1 generate
FD_inst1 : FD port map ( cmp_FDR_1: FDR
C => clk_sample_i, generic map(
D => unreg(j), INIT => '0'
Q => reg1(j) )
); port map(
FD_inst2 : FD port map ( C => clk_i,
C => clk_sample_i, R => reset_i,
D => reg1(j), D => unreg(j),
Q => taps_o(j) Q => reg1(j)
); );
cmp_FDR_2: FDR
generic map(
INIT => '0'
)
port map(
C => clk_i,
R => reset_i,
D => reg1(j),
Q => taps_o(j)
);
end generate; end generate;
end architecture; end architecture;
...@@ -23,58 +23,82 @@ use ieee.std_logic_1164.all; ...@@ -23,58 +23,82 @@ use ieee.std_logic_1164.all;
entity tdc_lbc is entity tdc_lbc is
generic ( generic (
-- Number of output bits. -- Number of output bits.
-- The number of input bits is 2^g_N-1. g_N : positive;
g_N : positive -- Number of input bits. Maximum is 2^g_N-1.
g_NIN: positive
); );
port ( port(
clk_i : in std_logic; clk_i : in std_logic;
polarity_i : in std_logic; reset_i : in std_logic;
d_i : in std_logic_vector(2**g_N-2 downto 0); d_i : in std_logic_vector(g_NIN-1 downto 0);
polarity_o : out std_logic;
count_o : out std_logic_vector(g_N-1 downto 0) count_o : out std_logic_vector(g_N-1 downto 0)
); );
end entity; end entity;
architecture rtl of tdc_lbc is architecture rtl of tdc_lbc is
-- "Count leading ones" function inspired by the post by Ulf Samuelsson -- "Count leading symbol" function inspired by the post by Ulf Samuelsson
-- http://www.velocityreviews.com/forums/t25846-p4-how-to-count-zeros-in-registers.html -- http://www.velocityreviews.com/forums/t25846-p4-how-to-count-zeros-in-registers.html
-- --
-- The idea is to use a divide-and-conquer approach to process a 2^N bit number. -- The idea is to use a divide-and-conquer approach to process a 2^N bit number.
-- We split the number in two equal halves of 2^(N-1) bits: -- We split the number in two equal halves of 2^(N-1) bits:
-- MMMMLLLL -- MMMMLLLL
-- then, we check if MMMM is all 1's. -- then, we check if all bits of MMMM are of the counted symbol.
-- If it is, -- If it is,
-- then the number of leading ones is 2^(N-1) + CLO(LLLL) -- then the number of leading symbols is 2^(N-1) + CLS(LLLL)
-- If it is not, -- If it is not,
-- then the number of leading ones is CLO(MMMM) -- then the number of leading symbols is CLS(MMMM)
-- Recursion stops with CLO(0)=0 and CLO(1)=1. -- Recursion stops with CLS(0)=0 and CLS(1)=1.
-- --
-- If the input is not all ones, we never propagate a carry and -- If at least one bit of the input is not the symbol, we never propagate a carry
-- the additions can be replaced by OR's, giving the result bit per bit. -- and the additions can be replaced by OR's, giving the result bit per bit.
-- We assume here an implicit LSB with a 0 value, and work with inputs -- We assume here an implicit LSB with a !symbol value, and work with inputs
-- widths that are a power of 2 minus one. -- widths that are a power of 2 minus one.
function f_clo(d: std_logic_vector) return std_logic_vector is function f_cls(d: std_logic_vector; symbol: std_logic) return std_logic_vector is
variable v_d: std_logic_vector(d'length-1 downto 0); variable v_d: std_logic_vector(d'length-1 downto 0);
begin begin
v_d := d; -- fix indices v_d := d; -- fix indices
if v_d'length = 1 then if v_d'length = 1 then
return v_d(0 downto 0); if v_d(0) = symbol then
return "1";
else
return "0";
end if;
else else
if v_d(v_d'length-1 downto v_d'length/2) = (v_d'length-1 downto v_d'length/2 => '1') then if v_d(v_d'length-1 downto v_d'length/2) = (v_d'length-1 downto v_d'length/2 => symbol) then
return "1" & f_clo(v_d(v_d'length/2-1 downto 0)); return "1" & f_cls(v_d(v_d'length/2-1 downto 0), symbol);
else else
return "0" & f_clo(v_d(v_d'length-1 downto v_d'length/2+1)); return "0" & f_cls(v_d(v_d'length-1 downto v_d'length/2+1), symbol);
end if; end if;
end if; end if;
end function; end function;
signal d_x : std_logic_vector(d_i'length-1 downto 0); signal polarity : std_logic;
signal count_reg : std_logic_vector(g_N-1 downto 0);
signal d_completed : std_logic_vector(2**g_N-2 downto 0);
begin begin
d_x <= (d_i'length-1 downto 0 => polarity_i) xor d_i; polarity_o <= polarity;
g_expand: if g_NIN < 2**g_N-1 generate
d_completed <= d_i & (2**g_N-1-g_NIN-1 downto 0 => not polarity);
end generate;
g_dontexpand: if g_NIN = 2**g_N-1 generate
d_completed <= d_i;
end generate;
process(clk_i) process(clk_i)
begin begin
if rising_edge(clk_i) then if rising_edge(clk_i) then
count_o <= f_clo(d_x); if reset_i = '1' then
polarity <= '1';
count_reg <= (others => '0');
count_o <= (others => '0');
else
polarity <= not d_completed(2**g_N-2);
count_reg <= f_cls(d_completed, polarity);
count_o <= count_reg;
end if;
end if; end if;
end process; end process;
end architecture; end architecture;
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_package
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Component declarations for the TDC core
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
-- 2011-08-03 SB Created file
-------------------------------------------------------------------------------
-- Copyright (C) 2011 Sebastien Bourdeauducq
library ieee;
use ieee.std_logic_1164.all;
package tdc_package is
component tdc_lbc is
generic (
g_N : positive;
g_NIN: positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
d_i : in std_logic_vector(g_NIN-1 downto 0);
polarity_o : out std_logic;
count_o : out std_logic_vector(g_N-1 downto 0)
);
end component;
component tdc_delayline is
generic(
g_WIDTH : positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
signal_i : in std_logic;
taps_o : out std_logic_vector(4*g_WIDTH-1 downto 0)
);
end component;
end package;
#!/bin/sh #!/bin/sh
set -e set -e
ghdl -i ../../core/tdc_lbc.vhd tb_lbc.vhd ghdl -i ../../core/tdc_package.vhd ../../core/tdc_lbc.vhd tb_lbc.vhd
ghdl -m tb_lbc ghdl -m tb_lbc
ghdl -r tb_lbc ghdl -r tb_lbc
...@@ -17,10 +17,13 @@ ...@@ -17,10 +17,13 @@
-- Copyright (C) 2011 Sebastien Bourdeauducq -- Copyright (C) 2011 Sebastien Bourdeauducq
-- TODO: test pipelining and polarity inversion
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
use ieee.math_real.all; use ieee.math_real.all;
use work.tdc_package.all;
entity tb_lbc is entity tb_lbc is
generic( generic(
...@@ -60,22 +63,26 @@ begin ...@@ -60,22 +63,26 @@ begin
end function; end function;
signal clk : std_logic; signal clk : std_logic;
signal polarity : std_logic; signal reset : std_logic;
signal d : std_logic_vector(2**g_N-2 downto 0); signal d : std_logic_vector(2**g_N-2 downto 0);
signal d_bak : std_logic_vector(2**g_N-2 downto 0);
signal count : std_logic_vector(g_N-1 downto 0); signal count : std_logic_vector(g_N-1 downto 0);
signal polarity : std_logic;
begin begin
dut: entity work.tdc_lbc cmp_dut: tdc_lbc
generic map( generic map(
g_N => g_N g_N => g_N,
g_NIN => 2**g_N-1
) )
port map( port map(
clk_i => clk, clk_i => clk,
polarity_i => polarity, reset_i => reset,
d_i => d, d_i => d,
count_o => count count_o => count,
polarity_o => polarity
); );
polarity <= '0'; reset <= '0';
process process
variable v_seed1 : positive := 1; variable v_seed1 : positive := 1;
variable v_seed2 : positive := 2; variable v_seed2 : positive := 2;
...@@ -83,6 +90,14 @@ begin ...@@ -83,6 +90,14 @@ begin
variable v_int_rand : integer; variable v_int_rand : integer;
variable v_stim : std_logic_vector(0 downto 0); variable v_stim : std_logic_vector(0 downto 0);
begin begin
-- reset
reset <= '1';
clk <= '0';
wait for 4 ns;
clk <= '1';
wait for 4 ns;
reset <= '0';
for i in 0 to 2**g_N-1 loop for i in 0 to 2**g_N-1 loop
-- generate test vector -- generate test vector
for j in 0 to 2**g_N-2 loop for j in 0 to 2**g_N-2 loop
...@@ -97,12 +112,17 @@ begin ...@@ -97,12 +112,17 @@ begin
d(j) <= v_stim(0); d(j) <= v_stim(0);
end if; end if;
end loop; end loop;
wait for 0 ns;
d_bak <= d;
-- generate, print and verify output -- generate, print and verify output
clk <= '0'; for j in 0 to 1 loop
wait for 4 ns; clk <= '0';
clk <= '1'; wait for 4 ns;
wait for 4 ns; clk <= '1';
report "Vector:" & str(d) & " Expected:" & integer'image(i) & " Result:" & integer'image(to_integer(unsigned(count))); wait for 4 ns;
d <= (others => '0');
end loop;
report "Vector:" & str(d_bak) & " Expected:" & integer'image(i) & " Result:" & integer'image(to_integer(unsigned(count))) & "(" & chr(polarity) & ")";
assert i = to_integer(unsigned(count)) severity failure; assert i = to_integer(unsigned(count)) severity failure;
end loop; end loop;
report "Test passed."; report "Test passed.";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment