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;
use UNISIM.vcomponents.all;
entity tdc_delayline is
generic (
g_WIDTH : positive -- number of CARRY4 elements
generic(
-- Number of CARRY4 elements.
g_WIDTH : positive
);
port (
clk_sample_i : in std_logic;
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)
);
......@@ -41,7 +43,7 @@ begin
-- generate a carry chain
g_carry4: for i in 0 to g_WIDTH-1 generate
g_firstcarry4: if i = 0 generate
CARRY4_inst : CARRY4 port map (
cmp_CARRY4: CARRY4 port map(
CO => unreg(3 downto 0),
CI => '0',
CYINIT => signal_i,
......@@ -50,7 +52,7 @@ begin
);
end 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),
CI => unreg(4*i-1),
CYINIT => '0',
......@@ -62,15 +64,25 @@ begin
-- double latch the output
g_fd: for j in 0 to 4*g_WIDTH-1 generate
FD_inst1 : FD port map (
C => clk_sample_i,
D => unreg(j),
Q => reg1(j)
);
FD_inst2 : FD port map (
C => clk_sample_i,
D => reg1(j),
Q => taps_o(j)
);
cmp_FDR_1: FDR
generic map(
INIT => '0'
)
port map(
C => clk_i,
R => reset_i,
D => unreg(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 architecture;
......@@ -23,58 +23,82 @@ use ieee.std_logic_1164.all;
entity tdc_lbc is
generic (
-- 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;
polarity_i : in std_logic;
d_i : in std_logic_vector(2**g_N-2 downto 0);
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 entity;
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
--
-- 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:
-- 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,
-- 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,
-- then the number of leading ones is CLO(MMMM)
-- Recursion stops with CLO(0)=0 and CLO(1)=1.
-- then the number of leading symbols is CLS(MMMM)
-- Recursion stops with CLS(0)=0 and CLS(1)=1.
--
-- If the input is not all ones, we never propagate a carry 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
-- If at least one bit of the input is not the symbol, we never propagate a carry
-- and the additions can be replaced by OR's, giving the result bit per bit.
-- We assume here an implicit LSB with a !symbol value, and work with inputs
-- 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);
begin
v_d := d; -- fix indices
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
if v_d(v_d'length-1 downto v_d'length/2) = (v_d'length-1 downto v_d'length/2 => '1') then
return "1" & f_clo(v_d(v_d'length/2-1 downto 0));
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_cls(v_d(v_d'length/2-1 downto 0), symbol);
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 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
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)
begin
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 process;
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
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 -r tb_lbc
......@@ -17,10 +17,13 @@
-- Copyright (C) 2011 Sebastien Bourdeauducq
-- TODO: test pipelining and polarity inversion
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.tdc_package.all;
entity tb_lbc is
generic(
......@@ -60,22 +63,26 @@ begin
end function;
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_bak : std_logic_vector(2**g_N-2 downto 0);
signal count : std_logic_vector(g_N-1 downto 0);
signal polarity : std_logic;
begin
dut: entity work.tdc_lbc
cmp_dut: tdc_lbc
generic map(
g_N => g_N
g_N => g_N,
g_NIN => 2**g_N-1
)
port map(
clk_i => clk,
polarity_i => polarity,
reset_i => reset,
d_i => d,
count_o => count
count_o => count,
polarity_o => polarity
);
polarity <= '0';
reset <= '0';
process
variable v_seed1 : positive := 1;
variable v_seed2 : positive := 2;
......@@ -83,6 +90,14 @@ begin
variable v_int_rand : integer;
variable v_stim : std_logic_vector(0 downto 0);
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
-- generate test vector
for j in 0 to 2**g_N-2 loop
......@@ -97,12 +112,17 @@ begin
d(j) <= v_stim(0);
end if;
end loop;
wait for 0 ns;
d_bak <= d;
-- generate, print and verify output
clk <= '0';
wait for 4 ns;
clk <= '1';
wait for 4 ns;
report "Vector:" & str(d) & " Expected:" & integer'image(i) & " Result:" & integer'image(to_integer(unsigned(count)));
for j in 0 to 1 loop
clk <= '0';
wait for 4 ns;
clk <= '1';
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;
end loop;
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