Coarse counter and deskew stage

parent 61b5d6ed
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work; library work;
use work.tdc_package.all; use work.tdc_package.all;
...@@ -32,6 +33,8 @@ entity tdc_channel is ...@@ -32,6 +33,8 @@ entity tdc_channel is
g_RAW_COUNT : positive; g_RAW_COUNT : positive;
-- Number of fractional part bits. -- Number of fractional part bits.
g_FP_COUNT : positive; g_FP_COUNT : positive;
-- Number of coarse counter bits.
g_COARSE_COUNT : positive;
-- Length of the ring oscillator. -- Length of the ring oscillator.
g_RO_LENGTH : positive g_RO_LENGTH : positive
); );
...@@ -39,6 +42,10 @@ entity tdc_channel is ...@@ -39,6 +42,10 @@ entity tdc_channel is
clk_i : in std_logic; clk_i : in std_logic;
reset_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 input.
signal_i : in std_logic; signal_i : in std_logic;
calib_i : in std_logic; calib_i : in std_logic;
...@@ -48,7 +55,7 @@ entity tdc_channel is ...@@ -48,7 +55,7 @@ entity tdc_channel is
detect_o : out std_logic; detect_o : out std_logic;
polarity_o : out std_logic; polarity_o : out std_logic;
raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0); 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 access.
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
...@@ -63,10 +70,15 @@ entity tdc_channel is ...@@ -63,10 +70,15 @@ entity tdc_channel is
end entity; end entity;
architecture rtl of tdc_channel is architecture rtl of tdc_channel is
signal muxed_signal : std_logic; signal muxed_signal : std_logic;
signal taps : std_logic_vector(4*g_CARRY4_COUNT-1 downto 0); signal taps : std_logic_vector(4*g_CARRY4_COUNT-1 downto 0);
signal polarity, polarity_d1 : std_logic; signal polarity : std_logic;
signal raw : std_logic_vector(g_RAW_COUNT-1 downto 0); 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 begin
with calib_sel_i select with calib_sel_i select
muxed_signal <= calib_i when '1', signal_i when others; muxed_signal <= calib_i when '1', signal_i when others;
...@@ -114,7 +126,7 @@ begin ...@@ -114,7 +126,7 @@ begin
bwea_i => (others => '0'), bwea_i => (others => '0'),
aa_i => raw, aa_i => raw,
da_i => (others => '0'), da_i => (others => '0'),
qa_o => fp_o, qa_o => lut,
web_i => lut_we_i, web_i => lut_we_i,
bweb_i => (others => '0'), bweb_i => (others => '0'),
...@@ -131,20 +143,39 @@ begin ...@@ -131,20 +143,39 @@ begin
en_i => ro_en_i, en_i => ro_en_i,
clk_o => ro_clk_o clk_o => ro_clk_o
); );
polarity_o <= polarity_d1;
process(clk_i) process(clk_i)
begin begin
if rising_edge(clk_i) then if rising_edge(clk_i) then
if reset_i = '1' then if reset_i = '1' then
detect_o <= '0'; detect_o <= '0';
polarity_d1 <= '1'; polarity_d1 <= '1';
raw_o <= (others => '0'); polarity_d2 <= '1';
raw_d1 <= (others => '0');
raw_d2 <= (others => '0');
else else
detect_o <= polarity xor polarity_d1; detect_o <= polarity_d1 xor polarity_d2;
polarity_d1 <= polarity; 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 if; end if;
end process; end process;
......
...@@ -34,40 +34,48 @@ entity tdc_channelbank is ...@@ -34,40 +34,48 @@ entity tdc_channelbank is
g_RAW_COUNT : positive; g_RAW_COUNT : positive;
-- Number of fractional part bits. -- Number of fractional part bits.
g_FP_COUNT : positive; g_FP_COUNT : positive;
-- Number of coarse counter bits.
g_COARSE_COUNT : positive;
-- Length of each ring oscillator. -- Length of each ring oscillator.
g_RO_LENGTH : positive g_RO_LENGTH : positive
); );
port( port(
clk_i : in std_logic; clk_i : in std_logic;
reset_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);
-- 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. -- Per-channel detection outputs.
detect_o : out 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); 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); 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); fp_o : out std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
-- LUT access. -- LUT access.
lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic; lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0); 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_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0);
-- Online calibration ring oscillator. -- Online calibration ring oscillator.
ro_clk_o : out std_logic ro_clk_o : out std_logic
); );
end entity; end entity;
architecture rtl of tdc_channelbank is 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 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 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); signal ro_clk_o_s : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
...@@ -83,12 +91,17 @@ begin ...@@ -83,12 +91,17 @@ begin
g_CARRY4_COUNT => g_CARRY4_COUNT, g_CARRY4_COUNT => g_CARRY4_COUNT,
g_RAW_COUNT => g_RAW_COUNT, g_RAW_COUNT => g_RAW_COUNT,
g_FP_COUNT => g_FP_COUNT, g_FP_COUNT => g_FP_COUNT,
g_COARSE_COUNT => g_COARSE_COUNT,
g_RO_LENGTH => g_RO_LENGTH g_RO_LENGTH => g_RO_LENGTH
) )
port map( port map(
clk_i => clk_i, clk_i => clk_i,
reset_i => reset_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), signal_i => signal_i(i),
calib_i => calib_i(i), calib_i => calib_i(i),
calib_sel_i => this_calib_sel, calib_sel_i => this_calib_sel,
...@@ -96,7 +109,8 @@ begin ...@@ -96,7 +109,8 @@ begin
detect_o => detect_o(i), detect_o => detect_o(i),
polarity_o => polarity_o(i), polarity_o => polarity_o(i),
raw_o => raw_o((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT), 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_a_i => lut_a_i,
lut_we_i => this_lut_we, lut_we_i => this_lut_we,
...@@ -108,6 +122,24 @@ begin ...@@ -108,6 +122,24 @@ begin
); );
end generate; 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. -- Combine LUT outputs.
process(lut_d_o_s, current_channel_onehot) process(lut_d_o_s, current_channel_onehot)
variable v_lut_d_o: std_logic_vector(g_FP_COUNT-1 downto 0); variable v_lut_d_o: std_logic_vector(g_FP_COUNT-1 downto 0);
......
...@@ -28,30 +28,35 @@ component tdc_channelbank is ...@@ -28,30 +28,35 @@ component tdc_channelbank is
g_CARRY4_COUNT : positive; g_CARRY4_COUNT : positive;
g_RAW_COUNT : positive; g_RAW_COUNT : positive;
g_FP_COUNT : positive; g_FP_COUNT : positive;
g_COARSE_COUNT : positive;
g_RO_LENGTH : positive g_RO_LENGTH : positive
); );
port( port(
clk_i : in std_logic; clk_i : in std_logic;
reset_i : in std_logic; reset_i : in std_logic;
next_i : in std_logic; cc_rst_i : in std_logic;
last_o : out std_logic; cc_cy_o : out std_logic;
calib_sel_i : in 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); signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
calib_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); detect_o : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
polarity_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); 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); 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_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic; lut_we_i : in std_logic;
lut_d_i : in std_logic_vector(g_FP_COUNT-1 downto 0); 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_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; end component;
...@@ -60,12 +65,16 @@ component tdc_channel is ...@@ -60,12 +65,16 @@ component tdc_channel is
g_CARRY4_COUNT : positive; g_CARRY4_COUNT : positive;
g_RAW_COUNT : positive; g_RAW_COUNT : positive;
g_FP_COUNT : positive; g_FP_COUNT : positive;
g_COARSE_COUNT : positive;
g_RO_LENGTH : positive g_RO_LENGTH : positive
); );
port( port(
clk_i : in std_logic; clk_i : in std_logic;
reset_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; signal_i : in std_logic;
calib_i : in std_logic; calib_i : in std_logic;
calib_sel_i : in std_logic; calib_sel_i : in std_logic;
...@@ -73,7 +82,7 @@ component tdc_channel is ...@@ -73,7 +82,7 @@ component tdc_channel is
detect_o : out std_logic; detect_o : out std_logic;
polarity_o : out std_logic; polarity_o : out std_logic;
raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0); 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_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0);
lut_we_i : in std_logic; lut_we_i : in std_logic;
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
\maketitle{} \maketitle{}
\section{Specifications} \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. 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}''. 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 ...@@ -30,7 +31,7 @@ To avoid negative differences, we simply reorder the bits at the output of the d
\includegraphics[width=\textwidth]{delaystruct.pdf} \includegraphics[width=\textwidth]{delaystruct.pdf}
\end{figure} \end{figure}
\section{Calibration mechanism} \subsection{Calibration mechanism}
In the formulas below: In the formulas below:
\begin{itemize} \begin{itemize}
\item $T_{sys}$ is the system clock period. \item $T_{sys}$ is the system clock period.
...@@ -41,7 +42,7 @@ In the formulas below: ...@@ -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. \item $f$ (respectively $f_{0}$) is the current (respectively reference) frequency of the online calibration ring oscillator.
\end{itemize} \end{itemize}
\subsection{Offline calibration} \subsubsection{Offline calibration}
\begin{equation} \begin{equation}
W_{0}(N-1) = 0 W_{0}(N-1) = 0
\end{equation} \end{equation}
...@@ -53,12 +54,14 @@ W_{0}(n) = \frac{H(n+1)}{C} \cdot T_{sys} ...@@ -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)} 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} \end{equation}
\subsection{Online calibration} \subsubsection{Online calibration}
\begin{equation} \begin{equation}
R(n) = \frac{f_{0}}{f} \cdot R_{0}(n) R(n) = \frac{f_{0}}{f} \cdot R_{0}(n)
\end{equation} \end{equation}
\subsection{Deskew stage}
\begin{thebibliography}{99} \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{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} \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