VHDL coding tips and tricks: BCD converter
Showing posts with label BCD converter. Show all posts
Showing posts with label BCD converter. Show all posts

Monday, April 19, 2010

VHDL: 8 bit Binary to BCD converter with Testbench

    All numerical values are fundamentally handled as binary numbers inside the FPGA. But that is not so human readable, isnt it? Even when we write a VHDL program, most of us would prefer to write, 
a <= 10; instead of a <= "1010";.

    When viewing signals in a simulation waveform, we can easily change the radix of the signal as per our convenience. But when we test the design on a real FPGA board, we would need to use dedicated display panels such as 7 segment decoders to see the binary numbers in decimal format. This is where BCD format comes in. 

    The decimal number 10, when converter to BCD format would be "10". Looks the same, except that, here each digit is given 4 bits for their storage. Though 4 bits can store from 0 to 15, we limit the range from 0 to 9, just like that of a regular decimal number.

    In this blog post, I want to share a VHDL function for converting an 8 bit binary number into a 3 digit (or 12 bit binary) BCD number. BCD stands for Binary Coded Decimal. The algorithm used is known as double dabble. You can read more on it here at, Double Dabble(wiki).

    A self checking testbench has been written as well, to verify the function. 

BCD Converter + Testbench:


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

--empty entity for testbenches.
entity tb_bcd_conversion is
end tb_bcd_conversion;

architecture Behavioral of tb_bcd_conversion is

--Function definition
function to_bcd ( bin : unsigned(7 downto 0) ) return unsigned is
    variable i : integer:=0;
    variable bcd : unsigned(11 downto 0) := (others => '0');
begin
    for i in 7 downto 1 loop  --iterating 7 times.
        --left shifting the bits and padding to the lsb
        bcd := bcd(10 downto 0) & bin(i);  
        --increment 3 if BCD digit at 1's is greater than 4.
        if(bcd(3 downto 0) > 4) then 
            bcd(3 downto 0) := bcd(3 downto 0) + 3;
        end if;
        --increment 3 if BCD digit at 10's is greater than 4.
        if(bcd(7 downto 4) > 4) then 
            bcd(7 downto 4) := bcd(7 downto 4) + 3;
        end if;
        --we dont need to repeat the above if statement for 100's position. Why?
        --Because input is 8 bit, which means maximum value at 100's position is 2.
    end loop;
    bcd := bcd(10 downto 0) & bin(0);  --final left shifting
    return bcd;  --return the result
end function to_bcd;
--End of function definition

--signals used to test the function.
--They help us to view the results in simulation waveform
signal bcd_out : unsigned(11 downto 0);
signal bcd_out_int: integer;

begin

--process where we test the binary to bcd function
stimulus_process: process
--variables used for testing. 
--Varibales are useful because they get updated rightaway.
--But they cant be seen in simulation waveform, thats why we assign
--them to signals before exiting the process.
variable bcd_out_int_var : integer;
variable bcd_out_var : unsigned(11 downto 0);
begin
    --test for all the 256 values the 8 bit input can take.
    for i in 0 to 255 loop
        bcd_out_var := to_bcd(to_unsigned(i,8));
        --convert bcd to decimal value by multiplying respective digits with 1,10 and 100.
        bcd_out_int_var := to_integer(bcd_out_var(3 downto 0)) + 
            to_integer(bcd_out_var(7 downto 4))*10 +  
            to_integer(bcd_out_var(11 downto 8))*100;
        --the assert statement is used to implement a self checking testbench.
        --we dont need to manually verify if each input is correctly converted,
        --but the testbench does it for us. If the statement in the 'assert' is
        --incorrect a 'warning' message will be reported in modelsim
        assert bcd_out_int_var = i;
        --assign to signals to see the results in simulation waveform
        bcd_out_int <= bcd_out_int_var;
        bcd_out <= bcd_out_var;
        --let the results stay the same for some time, so that human eyes could catch it.
        wait for 10 ns;
    end loop; 
    wait;  --testing done. wait Endlessly.
end process;

end Behavioral;


Simulation Waveform:


Some sample inputs and the corresponding outputs are shown below:
binary = "01100011",      output = "0000 1001 1001"  (99).
binary = "11111110",      output = "0010 0101 0100"  (254).
binary = "10111011",      output = "0001 1000 0111"  (187).

A part of the simulation waveform from Modelsim is shared below:


simulation waveform of binary to bcd converter in vhdl modelsim


Schematic after synthesis:


The code was synthesised using Xilinx Vivado 2023.2. The schematic generated after synthesis is shared below:

schematic from xillinx vivado for bcd converter



Note :- The code can be modified to convert any length binary number to corresponding BCD digits. This require very little change in the code. May be you could try that as a homework.