Coarse counter and deskew stage

parent 61b5d6ed
......@@ -19,6 +19,7 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.tdc_package.all;
......@@ -32,6 +33,8 @@ entity tdc_channel is
g_RAW_COUNT : positive;
-- Number of fractional part bits.
g_FP_COUNT : positive;
-- Number of coarse counter bits.
g_COARSE_COUNT : positive;
-- Length of the ring oscillator.
g_RO_LENGTH : positive
);
......@@ -39,6 +42,10 @@ entity tdc_channel is
clk_i : in std_logic;
reset_i : in std_logic;
-- Coarse counter and deskew inputs.
coarse_i : in std_logic_vector(g_COARSE_COUNT-1 downto 0);
deskew_i : in std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
-- Signal input.
signal_i : in std_logic;
calib_i : in std_logic;
......@@ -48,7 +55,7 @@ entity tdc_channel is
detect_o : out std_logic;
polarity_o : out std_logic;
raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
fp_o : out std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
-- LUT access.
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
......@@ -63,10 +70,15 @@ entity tdc_channel is
end entity;
architecture rtl of tdc_channel is
signal muxed_signal : std_logic;
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);
signal muxed_signal : std_logic;
signal taps : std_logic_vector(4*g_CARRY4_COUNT-1 downto 0);
signal polarity : std_logic;
signal polarity_d1 : std_logic;
signal polarity_d2 : std_logic;
signal raw : std_logic_vector(g_RAW_COUNT-1 downto 0);
signal raw_d1 : std_logic_vector(g_RAW_COUNT-1 downto 0);
signal raw_d2 : std_logic_vector(g_RAW_COUNT-1 downto 0);
signal lut : std_logic_vector(g_FP_COUNT-1 downto 0);
begin
with calib_sel_i select
muxed_signal <= calib_i when '1', signal_i when others;
......@@ -114,7 +126,7 @@ begin
bwea_i => (others => '0'),
aa_i => raw,
da_i => (others => '0'),
qa_o => fp_o,
qa_o => lut,
web_i => lut_we_i,
bweb_i => (others => '0'),
......@@ -131,20 +143,39 @@ begin
en_i => ro_en_i,
clk_o => ro_clk_o
);
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');
polarity_d2 <= '1';
raw_d1 <= (others => '0');
raw_d2 <= (others => '0');
else
detect_o <= polarity xor polarity_d1;
detect_o <= polarity_d1 xor polarity_d2;
polarity_d1 <= polarity;
raw_o <= raw;
polarity_d2 <= polarity_d1;
raw_d1 <= raw;
raw_d2 <= raw_d1;
end if;
end if;
end process;
polarity_o <= polarity_d2;
raw_o <= raw_d2;
-- Combine coarse counter value and deskew.
process(clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
fp_o <= (others => '0');
else
fp_o <= std_logic_vector(
unsigned(coarse_i & (lut'range => '0'))
- unsigned(lut)
+ unsigned(deskew_i));
end if;
end if;
end process;
......
......@@ -34,40 +34,48 @@ entity tdc_channelbank is
g_RAW_COUNT : positive;
-- Number of fractional part bits.
g_FP_COUNT : positive;
-- Number of coarse counter bits.
g_COARSE_COUNT : positive;
-- Length of each ring oscillator.
g_RO_LENGTH : positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
-- Control.
next_i : in std_logic;
last_o : out std_logic;
calib_sel_i : in std_logic;
-- Per-channel signal inputs.
signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
clk_i : in std_logic;
reset_i : in std_logic;
-- Control.
cc_rst_i : in std_logic;
cc_cy_o : out std_logic;
next_i : in std_logic;
last_o : out std_logic;
calib_sel_i : in std_logic;
-- Per-channel deskew input.
deskew_i : in std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
-- Per-channel signal inputs.
signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
-- Per-channel detection outputs.
detect_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
polarity_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
raw_o : out std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0);
detect_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
polarity_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
raw_o : out std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
-- LUT access.
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0);
lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
-- LUT access.
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0);
lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
-- Online calibration ring oscillator.
ro_clk_o : out std_logic
-- Online calibration ring oscillator.
ro_clk_o : out std_logic
);
end entity;
architecture rtl of tdc_channelbank is
signal coarse_counter : std_logic_vector(g_COARSE_COUNT-1 downto 0);
signal current_channel_onehot : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
signal lut_d_o_s : std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0);
signal ro_clk_o_s : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
......@@ -83,12 +91,17 @@ begin
g_CARRY4_COUNT => g_CARRY4_COUNT,
g_RAW_COUNT => g_RAW_COUNT,
g_FP_COUNT => g_FP_COUNT,
g_COARSE_COUNT => g_COARSE_COUNT,
g_RO_LENGTH => g_RO_LENGTH
)
port map(
clk_i => clk_i,
reset_i => reset_i,
coarse_i => coarse_counter,
deskew_i =>
deskew_i((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
signal_i => signal_i(i),
calib_i => calib_i(i),
calib_sel_i => this_calib_sel,
......@@ -96,7 +109,8 @@ begin
detect_o => detect_o(i),
polarity_o => polarity_o(i),
raw_o => raw_o((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT),
fp_o => fp_o((i+1)*g_FP_COUNT-1 downto i*g_FP_COUNT),
fp_o =>
fp_o((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
lut_a_i => lut_a_i,
lut_we_i => this_lut_we,
......@@ -108,6 +122,24 @@ begin
);
end generate;
-- Coarse counter.
process(clk_i)
begin
if rising_edge(clk_i) then
if (reset_i = '1') or (cc_rst_i = '1') then
coarse_counter <= (coarse_counter'range => '0');
cc_cy_o <= '0';
else
coarse_counter <= std_logic_vector(unsigned(coarse_counter) + 1);
if coarse_counter = (coarse_counter'range => '1') then
cc_cy_o <= '1';
else
cc_cy_o <= '0';
end if;
end if;
end if;
end process;
-- Combine LUT outputs.
process(lut_d_o_s, current_channel_onehot)
variable v_lut_d_o: std_logic_vector(g_FP_COUNT-1 downto 0);
......
......@@ -28,30 +28,35 @@ component tdc_channelbank is
g_CARRY4_COUNT : positive;
g_RAW_COUNT : positive;
g_FP_COUNT : positive;
g_COARSE_COUNT : positive;
g_RO_LENGTH : positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
clk_i : in std_logic;
reset_i : in std_logic;
next_i : in std_logic;
last_o : out std_logic;
calib_sel_i : in std_logic;
cc_rst_i : in std_logic;
cc_cy_o : out std_logic;
next_i : in std_logic;
last_o : out std_logic;
calib_sel_i : in std_logic;
deskew_i : in std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
detect_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
polarity_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
raw_o : out std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0);
detect_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
polarity_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
raw_o : out std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0);
lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0);
lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
ro_clk_o : out std_logic
ro_clk_o : out std_logic
);
end component;
......@@ -60,12 +65,16 @@ component tdc_channel is
g_CARRY4_COUNT : positive;
g_RAW_COUNT : positive;
g_FP_COUNT : positive;
g_COARSE_COUNT : positive;
g_RO_LENGTH : positive
);
port(
clk_i : in std_logic;
reset_i : in std_logic;
coarse_i : in std_logic_vector(g_COARSE_COUNT-1 downto 0);
deskew_i : in std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
signal_i : in std_logic;
calib_i : in std_logic;
calib_sel_i : in std_logic;
......@@ -73,7 +82,7 @@ component tdc_channel is
detect_o : out std_logic;
polarity_o : out std_logic;
raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0);
fp_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
fp_o : out std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic;
......
......@@ -19,7 +19,8 @@
\maketitle{}
\section{Specifications}
\section{Delay line structure}
\section{Architecture details}
\subsection{Delay line structure}
The delay line uses a carry chain. It is made up of \verb!CARRY4! primitives whose \verb!CO! outputs are registered by the dedicated D flip flops of the same slices. The signal is injected at the \verb!CYINIT! pin at the bottom of the carry chain. The \verb!CARRY4! primitives have their \verb!S! inputs hardwired to 1, which means the carry chain becomes a delay line with the signal going unchanged through the \verb!MUXCY! elements (see \cite{s6hdl} for reference). Since each \verb!CARRY4! contains four \verb!MUXCY! elements, the delay line has four times as many taps as there are \verb!CARRY4! primitives.
Using the Xilinx timing model, a surprising observation is that some delay differences between consecutive taps are negative. This probably is at the origin of the ``bubbles'' mentioned in the EPFL paper \cite{epfl}. The schematics given by Xilinx of the \verb!CARRY4! primitive is misleading there, and has probably little to do with the actual transistor-level implementation. The Xilinx documentation \cite{s6hdl} gives a hint by describing the primitive as ``Fast Carry Logic \textit{with Look Ahead}''.
......@@ -30,7 +31,7 @@ To avoid negative differences, we simply reorder the bits at the output of the d
\includegraphics[width=\textwidth]{delaystruct.pdf}
\end{figure}
\section{Calibration mechanism}
\subsection{Calibration mechanism}
In the formulas below:
\begin{itemize}
\item $T_{sys}$ is the system clock period.
......@@ -41,7 +42,7 @@ In the formulas below:
\item $f$ (respectively $f_{0}$) is the current (respectively reference) frequency of the online calibration ring oscillator.
\end{itemize}
\subsection{Offline calibration}
\subsubsection{Offline calibration}
\begin{equation}
W_{0}(N-1) = 0
\end{equation}
......@@ -53,12 +54,14 @@ W_{0}(n) = \frac{H(n+1)}{C} \cdot T_{sys}
R_{0}(n) = \displaystyle\sum\limits_{i=n}^{N-1}{W_{0}(i)} = \frac{T_{sys}}{C} \cdot \displaystyle\sum\limits_{i=n}^{N-1}{H(i)}
\end{equation}
\subsection{Online calibration}
\subsubsection{Online calibration}
\begin{equation}
R(n) = \frac{f_{0}}{f} \cdot R_{0}(n)
\end{equation}
\subsection{Deskew stage}
\begin{thebibliography}{99}
\bibitem{s6hdl} Xilinx, \textsl{Spartan-6 Libraries Guide for HDL Designs}, \url{http://www.xilinx.com/support/documentation/sw_manuals/xilinx12_3/spartan6_hdl.pdf}
\bibitem{epfl} Claudio Favi and Edoardo Charbon, \textsl{A 17ps Time-to-Digital Converter Implemented in 65nm FPGA Technology}, ACM 2009, \url{http://infoscience.epfl.ch/record/139431}
......
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