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?