Delay line based Time to digital converter

A time to digital converter is a circuit that digitizes time; i.e., it converts time into digital number. In other words, a time-to-digital converter measures the time interval between two events and represents that interval in the form of a digital number.

TDCs are used in places where the time interval between two events needs to be determined. These two events may, for example, be represented by rising edges of two signals. Some applications of TDCs include time-of-flight measurement circuits and All-Digital PLLs.

Delay line based time-to-digital converter: This is a very primitive TDC and involves a delay-line which is used to delay the reference signal. The other signal is used to sample the state of delay chain. Each stage of delay chain outputs to a flip-flop or a latch which is clocked by the sample signal. Thus, the output of the TDC forms a thermometer code as the stage will show a ‘1’ if the reference signal has passed it, otherwise it will show a zero. The schematic diagram of delay line based time-to-digital converter is shown in figure 1 below:

his is a very primitive TDC and involves a delay-line which is used to delay the reference signal. The other signal is used to sample the state of delay chain. Each stage of delay chain outputs to a flip-flop or a latch which is clocked by the sample signal. Thus, the output of the TDC forms a thermometer code as the stage will show a ‘1’ if the reference signal has passed it, otherwise it will show a zero.
Figure 1: Delay line based Time-to-digital converter


The VHDL code for delay line based time-to-digital converter is given below:
-- This is the module definition of delay line based time to digital converter.
library ieee;
use ieee.std_logic_1164.all;        
entity tdc is
                generic (
                                number_of_bits : integer := 64
                );
                port (
                                retimed_clk : in std_logic;
                                variable_clk : in std_logic;
                                tdc_out : out std_logic_vector (number_of_bits-1 downto 0);
                                reset : in std_logic
                );
end entity;
architecture behavior of tdc is
                component buffd4 is port (
                                I : in std_logic;
                                Z : out std_logic
                );
                end component;
                signal buf_inst_out : std_logic_vector (number_of_bits downto 0);
begin
--buffd4
                buf_inst_out(0) <= variable_clk;
                tdc_loop : for i in 1 to (number_of_bits) generate
                begin
                                buf_inst : buffd4 port map (
                                                I => buf_inst_out(i-1),
                                                Z => buf_inst_out(i)
                                );
                end generate;

                process (reset,retimed_clk)
                begin
                                if reset = '1' then
                                                tdc_out <= (others => '0');
                                elsif retimed_clk'event and retimed_clk = '1' then
                                                tdc_out <= buf_inst_out(number_of_bits downto 1);
                                end if;
                end process;
end architecture;

References:

Hope you’ve found this post useful. Let us know what you think in the comments.

Integer to string conversion and vice-versa in c++

While programming, we often need to convert an integer into string and vice-versa. Some of the examples scenarios to do so are as follows:
  • One may want to concatenate a string and integer number 
  • Read input from a file that contains multiple integers and report the sum. 

There are multiple ways to do it. C provides inbuilt functions stoi (read as string to integer) and sprintf to do this task. C++ provides an object-oriented approach for the same. It provides better methods to do it via sstream library. 

Concatenation of a string and an integer: The following piece of code concatenates a string and an integer and returns the result as a string. It first declares an object of class stringstream and simply reads in a number into the object. There is nothing special that we need to do for the same.
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
string concatenate(const string &str,int num) {
    stringstream s; // stringstream class is defined in sstream
    s<<num;      //integer num is assigned to string s
    string ret = str + s.str(); // s.str() return string object from s
    return ret;
}

String to integer conversion: Following piece of code (function) takes two strings as input, converts them into integers by assigning to objects of istringstream type, and returns their sum.
int sum(const string &str1,const string &str2) {    istringstream s1(str1); // istringstream is defined in sstream    istringstream s2(str2);    int in1,in2;    s1>>in1;    s2>>in2;    return in1+in2;}
The following piece of code calls the above two functions to perform concatenation and calculations:
int main() {   cout << concatenate("my birthday is on this month of ", 25)<<endl;   cout<<"sum = "<<sum("1","2")<<endl;   cout << concatenate("sum is ",sum("1","2") );}

Also read:

Thermometer code

What is thermometer code: Thermometer code resembles the output produced by a thermometer. In thermometer code, a value representing number ‘N’ has the lowermost ‘N’ bits as ‘1’; others as 0. So, to move from N to ‘N+1’, just change the rightmost ‘0’ to ‘1’. Figure 1 below shows graphically the thermometer codes for values from ‘0’ to ‘7’. As is evident, each value resembles a reading in thermometer. This is how, thermometer code got its name. Flash ADCs, time-to-digital converters (TDC) are some of the circuits that utilize thermometer code.

A thermometer code is a series of zeroes followed by a series of ones. A 8-symbol thermometer code will have 7 bits that need to represent all symbols.
Thermometer code with 7 symbols







Characteristics of thermometer code:
  • Each symbol in thermometer code is a sequence of 0s followed by a sequence of 1s
  • There cannot be 0s in-between two 1s. For example, a symbol 01011 is invalid in thermometer code
  • For an n-bit binary code, the corresponding thermometer code will have 2n – 1 symbols; hence, as many bits will be needed to represent thermometer code for the same.

How to convert from binary to thermometer code: Given below is the VHDL code for a 3-bit binary to thermometer converter. A simple case statement can be utilized for the same.
                                  
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity bin2therm2bit is
                port (
                                binary_input : in std_logic_vector (1 downto 0);
                                therm_output : out std_logic_vector (6 downto 0)
                );
end bin2therm6bit;

architecture Behavioral of bin2therm6bit is
begin
                process (binary_input)
                begin
                                label1 : case binary_input is
                                                when "000" => therm_output <= "0000000";
                                                when "001" => therm_output <= "0000001";
                                                when "010" => therm_output <= "0000011";
                                                when "011" => therm_output <= "0000111";
                                                when "100" => therm_output <= "0001111";
                                                when "101" => therm_output <= "0011111";
                                                when "110" => therm_output <= "0111111";
                                                when "111" => therm_output <= "1111111";
                                                when others => therm_output <= “xxxxxxx”;
                                end case;
                end process;
end Behavioral;

Hope you’ve found this post useful. Let us know what you think in the comments.

Also read:

Virtual clock - purpose and timing

What is a virtual clock: By definition, a virtual clock is a clock without any source. Stating more clearly, a virtual clock is a clock that has been defined, but has not been associated with any pin/port. A virtual clock is used as a reference to constrain the interface pins by relating the arrivals at input/output ports with respect to it with the help of input and output delays.

How to define a virtual clock: The most simple sdc command syntax to define a virtual clock is as follows:
                create_clock –name VCLK –period 10
The above SDC command will define a virtual clock “VCLK” with period 10 ns.

Purpose of defining a virtual clock: The advantage of defining a virtual clock is that we can specify desired latency for virtual clock. As mentioned above, virtual clock is used to time interface paths. Figure 1 shows a scenario where it helps to define a virtual clock. Reg-A is flop inside block that is sending data through PORT outside the block. Since, it is a synchronous signal, we can assume it to be captured by a flop (Reg-B) sitting outside the block. Now, within the block, the path to PORT can be timed by specifying output delay for this port with a clock synchronous to clock_in. We can specify a delay with respect to clock_in itself, but there lies the difficulty of specifying the clock latency. If we specify the latency for clock_in, it will be applied to Reg-A also. Applying output delay with respect to a real clock causes input ports to get relaxed and output ports to get tightened after clock tree has been built. Let us elaborate it in some detail below. Let us assume clock period to be 10 ns and the budget allocated to be 3 ns inside; thus, having a "set_output_delay" of 7 ns.



 virtual clock is used to time interface paths. Figure 1 shows a scenario where it helps to define a virtual clock. Reg-A is flop inside block that is sending data through PORT outside the block. Since, it is a synchronous signal, we can assume it to be captured by a flop (Reg-B) sitting outside the block. Now, within the block, the path to PORT can be timed by specifying output delay for this port with a clock synchronous to clock_in. We can specify a delay with respect to clock_in itself, but there lies the difficulty of specifying the clock latency. If we specify the latency for clock_in, it will be applied to Reg-A also. Applying output delay with respect to a real clock causes input ports to get relaxed and output ports to get tightened after clock tree has been built.
Figure 1: Figure to illustrate virtual clock

Case 1: Applying "set_output_delay" with respect to real clock (R_CLK)
Pre-CTS scenario: Here, if we apply any latency to the clock, it will be applied both to launch as well as capture registers (capture register is imaginary here). So, we unltimately get a full cycle to time the path. In other words, applying or not applying a latency to the clock will time the path as needed.
Post-CTS scenario: Post-CTS, we need to "set_propagate_clock RCLK" in order for clock latencies to come into effect. Doing so, the launch register's actual clock latency will come into picture. However, since, capture register is imaginary, there is no clock built onto it and its latency will be zero. So, we get (clock_period - RCLK_latency) as the actual phase shift to time the path. Thus, timing path gets tightened by "RCLK_latency".
Case 2:  Applying set_output_delay with respect to virtual clock (VCLK)
Pre-CTS scenario: In this case, in order to provide full cycle for the path to be timed; if we have applied any latency to RCLK, we will have to apply the same latency for VCLK as well.
Post-CTS scenario: After CTS is built and clocks are propagated, network latency of RCLK will be overridden by actual latency. But VCLK will not be propagated and its source + network latencies will still be reflected as applied in constraints. If (VCLK_source_latency + VCLK_network_latency_user) is equal to (RCLK_source_latency + RCLK_network_latency_CTS), we will still see the same timing path as we see pre-CTS.
Thus, the solution to the problem is to define a virtual clock and apply output delay with respect to it. Making the source latency of virtual clock equal to network latency of real clock will solve the problem.

Can you think of any other method that can serve the purpose of a virtual clock?

Interesting problem – Latches in series


Problem: 100 latches (either all positive or all negative) are placed in series (figure 1). How many cycles of latency will it introduce?

This figure shows 100 negative level-sensitive latches connected together in a chain
Figure 1 : 100 negative level-sensitive latches in series
As we know, setup check between latches of same polarity (both positive or negative) is zero cycle with half cycle of time borrow allowed as shown in figure 2 below for negative level-sensitive latches:

Setup check between two latches of same polarity is zero cycle with half cycle of time borrow allowed.
Figure 2: Setup check between two negative level-sensitive latches

So, if there are a number of same polarity latches, all will form zero cycle setup check with the next latch; resulting in overall zero cycle phase shift.

As is shown in figure 3, all the latches in series are borrowing time, but allowing any actual phase shift to happen. If we have a design with all latches, there cannot be a next state calculation if all the latches are either positive level-sensitive or negative level-sensitive. In other words, for state-machine implementation, there should not be latches of same polarity in series.

Each latch will form a zero cycle setup check with the following latch, resulting in overall zero cycle phase shift.
Figure 3 : Timing for 100 latches in series


Hope you’ve found this post useful. Let us know what you think in the comments.

Also read:

STA

Static timing analysis (STA) is a vast domain involving many sub-fields. It involves computing the limits of delay of elements in the circuit without actually simulating it. In this post, we have tried to list down all the posts that an STA engineer cannot do without. Please add your feedback in comments to make reading it a more meaningful experience.

  • Metastability - This post discusses the basics of metastability and how to avoid it.
  • Lockup latch - The basics of lockup latch, both from timing and DFT perspective have been discussed in this post.

  • Clock latency - Read this if you wish to get acquainted with the terminology related to clock latency

  • Data checks - Non-sequential setup and hold checks have been discussed, very useful for beginners

  • Synchronizers - Different types of synchronizers have been discussed in detail

  • On-chip variations - Describes on-chip variations and the methods undertaken to deal with these
  • Temperature inversion - Discusses the concept of temperature inversion and conductivity trends with temperature

  • Timing arcs - Discusses the basics of timing arcs, positive and negative unateness, cell arcs and net arcs etc.

  • Basics of latch timing - Definition of latch, setup time and hold timing of a latch, latch timing arcs are discussed