# Read decimal value of a 4-bit binary input

I am quite a rookie in the VHDL world, but I seem to have hold of the basics. Atm I am working on a project, which involves me to take a 4-bit binary input (switches), read this value and convert it to decimal values.

This far I have variables (count_ones, count_tens) which are supposed to contain the decimal value of the input.

My current code is as following:

architecture Behavioral of Seven_Seg_Counter is

signal      count_ones      :   integer range 0 to 9 := 0;
signal      count_tens      :   integer range 0 to 9 := 0;
signal      count_hundreds  :   integer range 0 to 9 := 0;
signal      count_thousands :   integer range 0 to 9 := 0;
signal      prescaler       :   integer := 0;
signal      anode           :   integer range 1 to 4 := 1;
signal      digit           :   STD_LOGIC_VECTOR(3 downto 0) := "1110";

begin
Calculate: process (CLK)
variable        countings           :   integer range 0 to 9 := 0;

begin
if rising_edge(CLK) then
if INPUT(3) = '1' then
countings := 8;
else
countings := 0;
end if;
if INPUT(2) = '1' then
countings := countings + 4;
else
countings := 0;
end if;
if INPUT(1) = '1' then
countings := countings + 2;
else
countings := 0;
end if;
if INPUT(0) = '1' then
countings := countings + 1;
else
countings := 0;
end if;

for I in 1 to 9 loop
if countings > 9 then
countings := countings  - 10;
count_tens <= count_tens + 1;
else
count_tens <= 0;
end if;
end loop;

for G in 1 to 9 loop
if countings > 0 then
countings := countings - 1;
count_ones <= count_ones + 1;
else
count_ones <= 0;
end if;
end loop;
end if;
end process;

process (anode, count_thousands, count_hundreds, count_tens, count_ones) -- Bestemmer output som funktion signalerne anode (segmentvælger) og count_XX (den decimale værdi)
begin
case anode is
when 1 =>
case count_ones is
--abcdefg
when 0 => sseg <= "0000001"; -- 0
when 1 => sseg <= "1001111"; -- 1
when 2 => sseg <= "0010010"; -- 2
when 3 => sseg <= "0000110"; -- 3
when 4 => sseg <= "1001100"; -- 4
when 5 => sseg <= "0100100"; -- 5
when 6 => sseg <= "0100000"; -- 6
when 7 => sseg <= "0001111"; -- 7
when 8 => sseg <= "0000000"; -- 8
when 9 => sseg <= "0000100"; -- 9
end case;
when 2 => case count_tens is
--abcdefg
when 0 => sseg <= "0000001"; -- 0
when 1 => sseg <= "1001111"; -- 1
when 2 => sseg <= "0010010"; -- 2
when 3 => sseg <= "0000110"; -- 3
when 4 => sseg <= "1001100"; -- 4
when 5 => sseg <= "0100100"; -- 5
when 6 => sseg <= "0100000"; -- 6
when 7 => sseg <= "0001111"; -- 7
when 8 => sseg <= "0000000"; -- 8
when 9 => sseg <= "0000100"; -- 9
end case;
when 3 => case count_hundreds is
--abcdefg
when 0 => sseg <= "0000001"; -- 0
when 1 => sseg <= "1001111"; -- 1
when 2 => sseg <= "0010010"; -- 2
when 3 => sseg <= "0000110"; -- 3
when 4 => sseg <= "1001100"; -- 4
when 5 => sseg <= "0100100"; -- 5
when 6 => sseg <= "0100000"; -- 6
when 7 => sseg <= "0001111"; -- 7
when 8 => sseg <= "0000000"; -- 8
when 9 => sseg <= "0000100"; -- 9
end case;
when 4 =>  case count_thousands is
--abcdefg
when 0 => sseg <= "0000001"; -- 0
when 1 => sseg <= "1001111"; -- 1
when 2 => sseg <= "0010010"; -- 2
when 3 => sseg <= "0000110"; -- 3
when 4 => sseg <= "1001100"; -- 4
when 5 => sseg <= "0100100"; -- 5
when 6 => sseg <= "0100000"; -- 6
when 7 => sseg <= "0001111"; -- 7
when 8 => sseg <= "0000000"; -- 8
when 9 => sseg <= "0000100"; -- 9
end case;
end case;
end process;

process (anode)
begin
case anode is
when 1 => digit <= "1110";
when 2 => digit <= "1101";
when 3 => digit <= "1011";
when 4 => digit <= "0111";
end case;
end process;

segmentselect <= digit;
LED_OUT <= INPUT;
end Behavioral;


My idea is, I store the binary value (looking aside 1's and 2's complement) in the variable countings (which works fine in a simulation). The next part is, where I actually find the value of countings, and store it's rightmost digit in the signal count_ones (ones), and the leftmost digit (tens) in the signal count_tens. For some unknown reason, my way of finding the ones and tens does not work well with those loops. Maybe I totally misunderstood how to use for loops.

Could any of you maybe help me out? I would really appreciate it.

Loops are tricky indeed. The thing is, a 4-bit input is only the beginning, I'd like to be able to read more, so if I can learn the basic method with just 4 bits, that'd be awesome.

Well, the count_ones signal is for the ones, and the count_tens is for the tens of the input, so I am not quite sure I get, how to_integer(unsigned(INPUT)); is gonna work out, so I get a decimal value from 0 to 9 in count_ones or count_tens.

The subtraction method you are referencing to, I believe, I have tried to implement that in my loops, which do not work out as expected.

Loops in HDL are a tricky thing to use in a synthesizable manner. I would recommend simply reading in the input bits as a binary number, compare with 9, if it is greater subtract 10.

Solution 1:
The Double Dabble Algorithm. Electronics.StackExchange lists many Q&A for this topic:

StackOverflow is also full of results.

Solution 2
Using a systolic array of digit converts.

Let's convert a n-bit binary input into m digits. Each systolic element has a Clock and Reset input as well as a 1-bit Shift_in signal. It generates a 4-bit BCD encoded Digit and a Shift_out signal (aka overflow).

This is the element's port declaration:

subtype T_BCD : UNSIGNED(3 downto 0);

entity arith_convert_bin2bcd_element is
port (
Clock      : IN  STD_LOGIC;
Reset      : IN  STD_LOGIC;

Shift_en   : IN  STD_LOGIC;
Shift_in   : IN  STD_LOGIC;
Shift_out  : OUT STD_LOGIC;
BCD        : OUT T_BCD
);
end;


How does it work?

On every shift operation, it calculates:
$Digit = Digit * 2 + Shift_{in}$

$Shift_{out} = \begin{cases} 1 &\text{when}\,\, (Digit \ge 10) \\ 0 & else\end{cases}$

$Digit = \begin{cases} Digit-10 &\text{when}\,\, (Digit \ge 10) \\ Digit & else\end{cases}$

architecture rtl of arith_convert_bin2bcd_element is
signal Digit_ext  : UNSIGNED(T_BCD'length downto 0);
signal Digit_ov   : STD_LOGIC;
signal Digit_d    : T_BCD        := "0000";
begin

Digit_ext  <= Digit_d & Shift_in;
Digit_ov  <= to_sl(Digit_ext > 9);
Shift_out  <= Digit_ov;-- when rising_edge(Clock);    -- register overflow

process(Clock)
begin
if rising_edge(Clock) then
if (Reset = '1') then
Digit_d    <= "0000";
elsif (Shift_en = '1') then
if (Digit_ov = '0') then
Digit_d  <= Digit_ext(Digit_d'range);
else
Digit_d  <= resize(Digit_ext - 10, Digit_d'length);
end if;
end if;
end if;
end process;

BCD <= Digit_d;
end;


Now you can combine as many element as needed to convert a binary number. What's needed for this task?

• a FSM with 3-4 states: idle, [complement], convert, complete
complement is only needed if you input can be negative
• a counter that counts for n shift operations
• a parallel-in/serial-out register, that shifts or rotates left (to the highest bit)
• a generate statement, that generates m element instances

And here is the systolic array wiring and control logic:

entity arith_convert_bin2bcd is
generic (
IS_SIGNED     : BOOLEAN     := FALSE;
BITS          : POSITIVE    := 8;
DIGITS        : POSITIVE    := 3
);
port (
Clock         : IN  STD_LOGIC;
Reset         : IN  STD_LOGIC;

Start         : IN  STD_LOGIC;
Complete      : OUT STD_LOGIC;

Binary        : IN  STD_LOGIC_VECTOR(BITS - 1 DOWNTO 0);
BCDDigits     : OUT T_BCD_VECTOR(DIGITS - 1 DOWNTO 0);
Sign          : OUT STD_LOGIC
);
end;

architecture rtl of arith_convert_bin2bcd is
type T_STATE is (ST_IDLE, ST_CPL, ST_CONVERT, ST_COMPLETE);

signal State      : T_STATE    := ST_IDLE;
signal NextState  : T_STATE;

signal Digit_Shift_en   : STD_LOGIC;
signal Digit_Shift_in   : STD_LOGIC_VECTOR(DIGITS downto 0);

signal Binary_en        : STD_LOGIC;
signal Binary_cpl       : STD_LOGIC;
signal Binary_rl        : STD_LOGIC;
signal Binary_d         : STD_LOGIC_VECTOR(BITS - 1 downto 0)      := (others => '0');
signal Binary_Sign      : STD_LOGIC;

signal Sign_d           : STD_LOGIC                                := '0';

signal ShiftCounter_rst : STD_LOGIC;
signal ShiftCounter_eq  : STD_LOGIC;
signal ShiftCounter_s   : SIGNED(log2ceilnz(BITS - 1) downto 0)    := (others => '0');
begin

process(Clock)
begin
if rising_edge(Clock) then
if (Reset = '1') then
State    <= ST_IDLE;
else
State    <= NextState;
end if;
end if;
end process;

process(State, Start, Binary_Sign, ShiftCounter_eq)
begin
NextState         <= State;
Complete          <= '0';

Binary_en         <= '0';
Binary_cpl        <= '0';
Binary_rl         <= '0';

Digit_Shift_en    <= '0';
ShiftCounter_rst  <= '1';

case State is
when ST_IDLE =>
if (Start = '1') then
Binary_en       <= '1';

if (Binary_Sign = '1') then
NextState     <= ST_CPL;
else
NextState     <= ST_CONVERT;
end if;
end if;

when ST_CPL =>
Binary_cpl        <= '1';
NextState         <= ST_CONVERT;

when ST_CONVERT =>
Binary_rl         <= '1';
Digit_Shift_en    <= '1';
ShiftCounter_rst  <= '0';

if (ShiftCounter_eq = '1') then
NextState       <= ST_COMPLETE;
end if;

when ST_COMPLETE =>
Complete          <= '1';
NextState         <= ST_IDLE;

end case;
end process;

process(Clock)
begin
if rising_edge(Clock) then
if (Reset = '1') then
Binary_d  <= (others => '0');
elsif (Binary_en = '1') then
Binary_d  <= Binary;
Sign_d    <= '0';
elsif (Binary_cpl = '1') then
Binary_d  <= cpl(Binary_d);    -- 2's component
Sign_d    <= '1';
elsif (Binary_rl = '1') then
Binary_d  <= Binary_d(Binary_d'high - 1 downto 0) & Binary_d(Binary_d'high);
end if;
end if;
end process;

Sign              <= Sign_d;

Binary_Sign       <= Binary_d(Binary_d'high);
Digit_Shift_in(0) <= Binary_d(Binary_d'high);

-- count shift operations from BITS-2 downto -1
ShiftCounter_s    <= counter_dec(ShiftCounter_s, ShiftCounter_rst, '1', BITS - 2) when rising_edge(Clock);
ShiftCounter_eq   <= ShiftCounter_s(ShiftCounter_s'high);

-- generate DIGITS many systolic elements
genDigits : for i in 0 to DIGITS - 1 generate
Digit : entity PoC.arith_convert_bin2bcd_element
port map (
Clock       => Clock,
Reset       => Reset,

Shift_en    => Digit_Shift_en,
Shift_in    => Digit_Shift_in(i),
Shift_out   => Digit_Shift_in(i + 1),
BCD         => BCDDigits(i)
);
end generate;
end;


And here is a simulation (clickable): • Okay, I recently read up on your comment. I believe what you suggest, is what my countings variable takes care off. It stores the decimal value of my 4-bit binary input (INPUT). I need to store countings' ones in a variable called count_ones, and its tens in a variable called count_tens, same ultimately goes for hundreds and thousands as well (see my comment below). Jan 28, 2015 at 23:47