How does the shift register work in binary to bcd conversion - binary

I found this code for a 12 bit binary to bcd conversion but I can't seem to understand the shift register part (just showing the state machine part). I need help in understanding how exactly the '&' works in a shift register and if someone can also produce a different way for the shift register part to look something like the code below as it is easier to understand the flow of data:
ishiftRegister(7) <= Rxd;
ishiftRegister(6 downto 0) <= iShiftRegister(7 downto 1);
-- State Machine
process(present_state, binary, binary_in, bcd_temp, bcds_reg, shift_counter)
begin
next_state <= present_state;
bcds_next <= bcd_temp;
binary_next <= binary;
shift_counter_next <= shift_counter;
case present_state is
when st_start =>
next_state <= st_shift;
binary_next <= binary_in;
bcds_next <= (others => '0');
shift_counter_next <= 0;
when st_shift =>
if shift_counter = 12 then
next_state <= st_stop;
else
binary_next <= binary(10 downto 0) & 'L';
bcds_next <= bcds_reg(18 downto 0) & binary(11);
shift_counter_next <= shift_counter + 1;
end if;
when st_stop=>
next_state <= st_start;
end case;
end process;

The & is a concatenation operator. Check for example this question for more discussion: Concatenating bits in VHDL
bcds_next <= bcds_reg(18 downto 0) & binary(11);
With bcds_reg(18 downto 0) you take the 19 least significant bits of bcds_reg vector (and drop the most significant bit out). I.e. the register is shifted to the left. The binary(11) is the most significant bit of a 12-bit vector binary. Concatenating a 19-bit vector and a single bit with & creates you a 20-bit vector which you can then assing to the 20-bit vector bcds_next.
For your other question, I think the following would also be possible and an equal operation without the & operator.
bcds_next(19 downto 1) <= bcds_reg(18 downto 0);
bcds_next(0) <= binary(11);

Related

VHDL - BCD to Binary input buffer - issues displaying the result

I am using Vivado 2014.2 to write VHDL code for a BCD to Binary input buffer that could be used for a calculator or a combo lock.
My method is simple. to do x*10 it is the same as x(2 + 8) = x*2 + x*8.
x*2 = 1 left shift (2^1 = 2)
x*8 = 3 left shifts (2^3 = 8)
The output buffer(tempC) is shifted and added before the input is added. This is done so that when starting from null so that the first digit entered doesn't come out multiplied by 10.
My code compiles and runs on an artix 7 fpga, but I am having issues making sure that the output buffer(tempC) is working correctly. It refuses to output any data, but I am not sure why.
I could be adding the values together wrong but I dont think its that. Maybe i'm casting to a wrong data type?
Any help is greatly appreciated.
-- Engineer: greatgamer34
--
-- Create Date: 01/25/2017 04:57:02 PM
-- Design Name:
-- Module Name: buff - Behavioral
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity buff is
Port ( Data : in STD_LOGIC_VECTOR (3 downto 0); ----4bit BCD value input
Clock : in STD_LOGIC;
Reset : in STD_LOGIC;
Output : out STD_LOGIC_VECTOR (15 downto 0);
aout : out STD_LOGIC_VECTOR (6 downto 0));-- 7 segment display output for current state.
end buff;
architecture Behavioral of buff is
type states is (state0, state1, state2, state3);
signal currentstate, nextstate: states;
signal tempA: STD_LOGIC_VECTOR (15 downto 0);---used to store 'Data' for addition.
signal tempB: STD_LOGIC_VECTOR (15 downto 0);---used for x2('Data').
signal tempC: STD_LOGIC_VECTOR (15 downto 0);---used as output register.
signal tempD: STD_LOGIC_VECTOR (15 downto 0);---used for sending data to LED's.
signal tempE: STD_LOGIC_VECTOR (15 downto 0);---used for x8('Data')
begin
Process(Reset,clock)
Begin
if(Reset = '1') then
tempC <= "0000000000000000"; --clear tempC
tempA <= "0000000000000000"; --clear tempA
currentstate <= state0; -------reset state to 0
elsif(clock'event and clock = '1') then
output <= (tempD);--dispaly the output of the buffer
currentstate<=nextstate; -- advance states
end if;
end process;
process(currentstate)
begin
case currentstate is
when state0 =>
tempA(3 downto 0) <= Data; -- load in 4 bit data intoi 16 bit register
tempD <= (tempA); --output the input data(used for debugging)
nextstate <= state1;
aout <= not "1111110"; -- output on the 7 seg the number 0
when state1 =>
tempB <= tempC(14 downto 0) & '0'; --left shift tempC(the output register) save to tempB; this is the x2 multiplication
tempD <= (tempA); -- output the input data(used for debugging)
nextstate <= state2;
aout <= not "0110000"; -- output on the 7 seg the number 1
when state2 =>
tempE <= tempC(12 downto 0) & "000"; --left shift tempC(the output register) three times save to tempE; this is the x8 multiplication
--tempC <=std_logic_vector( unsigned(tempE) + unsigned(tempD)); (TESTING)
tempC <=std_logic_vector( ('0' & unsigned(tempE(14 downto 0))) + ('0' & unsigned(tempD(14 downto 0)))); --add the first 15 bits of tempD and tempE(this is how we multiply by 10)
tempD <= (tempC); -- output the x10 output register
nextstate <= state3;
aout <= not "1101101" ; -- output on the 7 seg the number2
when state3 =>
-- tempC <= ('0' & tempC(14 downto 0)) + ('0' & tempA(14 downto 0)); (TESTING)
tempC <= std_logic_vector( ('0' & unsigned(tempC(14 downto 0))) + ('0' & unsigned(tempA(14 downto 0)))); --add the 'Data' to the x10 shifted number.
tempD <= (tempC);
nextstate <= state0;
aout <= not "1111001"; -- output on the 7 seg the number3
end case;
end process;
end behavioral;
Answer:
tempC is reset in the clocked process and then gets new values assigned in the combinatorial process.
It is not allowed to assign a signals a value in two different processes. Also the sensitivity list of the combinatorial process is missing signals.
Observations:
Use logical names for your signals tempX is very confusing. Also I cant imagine that your BCD circuit will be called BUFF ;)
Check the sensitivity list of your combinatoric process.
Google on how a state machine needs to be constructed
Simulation of your design in very important (especially for larger designs)
have a look at the different tutorials online eg Xilinx Vivado
2015.2 Simulation Tutorial
Happy debugging
Okay with help from some of the comments and answers I was able to get it to work. The following is the code used.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity buff is
Port ( Data : in STD_LOGIC_VECTOR (3 downto 0); ----4bit BCD value input
Clock : in STD_LOGIC;
Reset : in STD_LOGIC;
Output : out STD_LOGIC_VECTOR (15 downto 0);
aout : out STD_LOGIC_VECTOR (6 downto 0));-- 7 segment display output for current state.
end buff;
architecture Behavioral of buff is
type states is (state0, state1, state2, state3, state4);
signal currentstate, nextstate: states;
signal tempA: STD_LOGIC_VECTOR (3 downto 0);---used to store 'Data' for addition.
signal tempB: STD_LOGIC_VECTOR (15 downto 0);---used for x2('Data').
signal tempC: STD_LOGIC_VECTOR (15 downto 0);---used as output register.
signal tempD: STD_LOGIC_VECTOR (15 downto 0);---used for sending data to LED's.
signal tempE: STD_LOGIC_VECTOR (15 downto 0);---used for x8('Data')
signal tempF: STD_LOGIC_VECTOR (15 downto 0);
begin
Process(Reset,clock)
Begin
if(Reset = '1') then
currentstate <= state4;
Output <= "0000000000000000"; -------reset state
elsif(clock'event and clock = '1') then
Output <= tempD ;--display the output of the buffer
currentstate <= nextstate; -- advance states
end if;
end process;
process(currentstate)
begin
case currentstate is
when state0 =>
tempA <= Data; -- load in 4 bit data intoi 16 bit register
tempD(3 downto 0) <= tempA; --output the input data(used for debugging)
nextstate <= state1;
aout <= not "1111110"; -- output on the 7 seg the number 0
when state1 =>
tempB <= (tempC(14 downto 0) & "0"); --left shift tempC(the output register) save to tempB; this is the x2 multiplication
tempD <= (tempB); -- output the input data(used for debugging)
nextstate <= state2;
aout <= not "0110000"; -- output on the 7 seg the number 1
when state2 =>
tempE <= tempC(12 downto 0) & "000"; --left shift tempC(the output register) three times save to tempE; this is the x8 multiplication
--tempF <=std_logic_vector( unsigned(tempE) + unsigned(tempB)); --(TESTING)
tempF <=std_logic_vector( ('0' & unsigned(tempE(14 downto 0))) + ('0' & unsigned(tempB(14 downto 0)))); --add the first 15 bits of tempD and tempE(this is how we multiply by 10)
tempD <= tempE; -- output the x10 output register
nextstate <= state3;
aout <= not "1101101" ; -- output on the 7 seg the number2
when state3 =>
--tempC <=std_logic_vector( unsigned(tempC) + unsigned(tempA));
tempC <= std_logic_vector( ('0' & unsigned(tempF(14 downto 0))) + ("000000000000" & unsigned(tempA))); --add the 'Data' to the x10 shifted number.
tempD <= tempC;
nextstate <= state0;
aout <= not "1111001"; -- output on the 7 seg the number3
when state4 =>
tempC <= "0000000000000000";
tempA <= "0000";
tempB <= "0000000000000000";
tempD <= "0000000000000000";
tempE <= "0000000000000000";
tempF <= "0000000000000000";
nextstate <= state0;
aout <= not "0110011";
end case;
end process;
end behavioral;

VHDL. There are 2 loadless signals in this design

I just started VHDL coding and i uses XILINX Artix-7/NEXYS 4 to practice.
I only want to design the seven segment display and let it dsiplay the numbers from 0 to 9.
My English is not very good, please forgive me, I tried to express my question.
In my code,i split the architecture into four steps.
First,i down the clk(100MHZ) to 1hz. Second,i use counter to count the number from 0 to 9 then use the double dabble algorithm separate the number.Last,i wrote a BCD to 7 segment decoder and choose the first anode.
The problem is that warning appears when i was implement circuits,even though the synthesize is fine(but the RTL show that signal has not connect obviously).
The problem seems to between the double dabble algorithm and counter?
(since it has wrong after add this code)
I really want to know how could i solve this problem?And when will this warning appear?Maybe my code have big wrong?
WARNING:Par:288 - The signal clk_IBUF has no load. PAR will not attempt to route this signal.
Finished initial Timing Analysis. WARNING:Par:288 - The signal btnD_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:283 - There are 2 loadless signals in this design. This design will cause Bitgen to issue DRC warnings.
By the way,I know there has many ways to achieve my goal,but i really want to know what a wrong with this.
If any one can help me,THANKS A LOT.
Here is my code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.std_logic_unsigned.all;
use IEEE.numeric_std.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity top is
Port ( clk : in STD_LOGIC;
btnD : in STD_LOGIC;
an : out STD_LOGIC_VECTOR (7 downto 0);
seg : out STD_LOGIC_VECTOR (6 downto 0));
end top;
architecture Behavioral of top is
signal clk_1hz_s : STD_LOGIC := '1';
signal clk_1hz : STD_LOGIC;
signal counter_clock : integer range 0 to 5000000 := 0;
signal sec_turth : STD_LOGIC_VECTOR (7 downto 0);
signal sec_1 : STD_LOGIC_VECTOR (3 downto 0);
begin
--new clk--
process(clk,btnD)
begin
if (clk' event and clk='1') then
if (btnD = '1') then
counter_clock <= 0;
clk_1hz_s <= '1';
elsif (counter_clock = 5000000 - 1 ) then
counter_clock <= 0;
clk_1hz_s <= NOT(clk_1hz_s);
else
counter_clock <= counter_clock + 1;
end if;
end if;
end process;
clk_1hz <= clk_1hz_s;
--counter--
process(clk_1hz)
variable sec :integer range 0 to 9 :=0;
begin
if (clk_1hz' event and clk_1hz='1') then
if sec > 8 then
sec := 0;
else
sec := sec + 1;
end if;
end if;
sec_turth <= STD_LOGIC_VECTOR(to_unsigned(sec,8)(7 downto 0));
end process;
--double dabble algorithm--
process(sec_turth)
variable temp_sec : STD_LOGIC_VECTOR (7 downto 0);
variable bcd_sec : unsigned (7 downto 0):= (others => '0');
begin
temp_sec := sec_turth;
bcd_sec := (others => '0');
for i in 0 to 7 loop
if bcd_sec(3 downto 0) > 4 then
bcd_sec(3 downto 0) := bcd_sec(3 downto 0) + 3;
end if;
-- if bcd_sec(7 downto 4) > 4 then
-- bcd_sec(7 downto 4) := bcd_sec(7 downto 4) + 3;
-- end if;
bcd_sec := bcd_sec(7 downto 1) & temp_sec(7);
temp_sec := temp_sec(7 downto 1) & '0';
end loop;
sec_1 <= STD_LOGIC_VECTOR(bcd_sec(3 downto 0));
--sec_2 <= STD_LOGIC_VECTOR(bcd_sec(7 downto 4));
end process;
--decoder--
with sec_1 select
seg <= "1000000" when "0000",--0
"1111001" when "0001",--1
"0100100" when "0010",--2
"0110000" when "0011",--3
"0011001" when "0100",--4
"0010010" when "0101",--5
"0000010" when "0110",--6
"1011000" when "0111",--7
"0000000" when "1000",--8
"0011000" when "1001",--9
"0001110" when "1111",--F
"1111111" when others;--close all
an <= "11111110";--choose the first anode
end Behavioral;
The warnings mean that in your code both inputs don't influence any output and thus are not worth being connected to any internal component.
Please get more familiar with the concept of variables. Especially with the sec-counter process, you should know that you can't assume that the variable keeps its value saved between two process runs, i.e. each rising edge on clk_1hz resets the variable sec. Better declare it as a signal as you do with counter_clock. Then you would of course also need a reset routine inside the counter process:
-- In the architecture header:
signal current_value: integer range 0 to 9;
-- one-digit counter --
process(clk_1hz)
begin
if (clk_1hz'event and clk_1hz='1') then
if (btnD = '1') then
current_value <= 0;
elsif current_value > 8 then
current_value <= 0;
else
current_value <= current_value + 1;
end if;
end if;
end process;
-- I assume, you really need 8 bits here:
sec_turth <= STD_LOGIC_VECTOR(to_unsigned(current_value,8));
For a single-digit number between 0 and 9, your double dabble algorithm with all its variables is unnecessary since the values are already present in BCD. If I remove that process and simply connect lower 4 bits of sec_turth to sec_1 then the warnings disappear and I can view the schematic:
sec_1 <= sec_turth(3 downto 0);
Some other issues:
Your clock divider process is defined to be sensitive to clk and btnD inputs. This is usually the case for asynchronous reset behavior which is not implemented inside the process. If you want an asynchronous reset, do something like this:
clk_div: process(clk,btnD)
begin
if btnD = '1' then
-- do the reset
counter_clock <= 0;
clk_1hz_s <= '1';
elsif clk'event and clk = '1' then
-- do the synchronous operations
if (counter_clock = 5000000 - 1 ) then
counter_clock <= 0;
clk_1hz_s <= NOT(clk_1hz_s);
else
counter_clock <= counter_clock + 1;
end if;
end if;
end process clk_div;
If that should be a clock synchronous reset, please remove btnD from the sensitivity list as I did in the first code listing.
Also, I've seen that you have a space after the tick ' in the clk'event attribute that at least makes the code highlighted differently than without the space. Correct that and you might get rid of the clk-related warning.
Edit: No, if the variables are removed then the space does not matter.
Hope I could help, please let me know if I can improve the answer!

TTL finder / output in a input

I want to create a circuit which has two inputs a clock and an enable
and three outputs. What I want this circuit to do is that it has a
variable (cont) that goes from "00" to "11" and two of the outputs
(sal_1 and sal_2) take the values of cont(0) and cont(1) and go to the
inputs of a ttl ic (AND , OR, XOR) and then the output of the ttl ic
goes back to the circuit and is saved (results) after that, the vector
that is created from the differents results of the ttl ic ouputs is
compared with vectors already predefined and find the one that matches
it and returns the value.
I have a hard time with the output and then input times, it seems that
there is a special way to do this.
Here is my code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity ttl_finder is
port( clk, ena, sal_ttl : in std_logic;
sal_1, sal_2 : out std_logic;
sal_f : out std_logic_vector(3 downto 0));
end entity;
architecture ttl_tester of ttl_finder is
signal cont : std_logic_vector(1 downto 0) := "00";
signal results : std_logic_vector(3 downto 0) := "0000";
begin
process(clk, ena)
variable c : std_logic;
variable d : std_logic;
variable e : std_logic;
begin
if ena = '1' then
if cont < "11" then
sal_1 <= cont(0);
sal_2 <= cont(1);
if rising_edge(clk) then
results(conv_integer(cont)) <= sal_ttl;
end if;
cont <= cont + 1;
else
sal_1 <= cont(0);
sal_2 <= cont(1);
if rising_edge(clk) then
results(conv_integer(cont)) <= sal_ttl;
end if;
cont <= "00";
end if;
end if;
end process;
sal_f <= results;
end ttl_tester;

Convert 8bit binary number to BCD in VHDL

The algorithm is well known, you do 8 left shifts and check the units, tens or hundreds bits (4 each) after each shift. If they are above 4 you add 3 to the group and so on...
Here is a process based solution that does not work. It will compile but the output is not what I wanted. Any thoughts what could be the problem?
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
entity hex2bcd is
port ( hex_in : in std_logic_vector (7 downto 0) ;
bcd_hun : out std_logic_vector (3 downto 0) ;
bcd_ten : out std_logic_vector (3 downto 0) ;
bcd_uni : out std_logic_vector (3 downto 0) ) ;
end hex2bcd ;
architecture arc_hex2bcd of hex2bcd is
begin
process ( hex_in )
variable hex_src : std_logic_vector (7 downto 0) ;
variable bcd : std_logic_vector (11 downto 0) ;
begin
hex_src := hex_in ;
bcd := (others => '0') ;
for i in 0 to 7 loop
bcd := bcd(11 downto 1) & hex_src(7) ; -- shift bcd + 1 new entry
hex_src := hex_src(7 downto 1) & '0' ; -- shift src + pad with 0
if bcd(3 downto 0) > "0100" then
bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
end if ;
if bcd(7 downto 4) > "0100" then
bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
end if ;
if bcd(11 downto 8) > "0100" then
bcd(11 downto 8) := bcd(11 downto 8) + "0011" ;
end if ;
end loop ;
bcd_hun <= bcd(11 downto 8) ;
bcd_ten <= bcd(7 downto 4) ;
bcd_uni <= bcd(3 downto 0) ;
end process ;
end arc_hex2bcd ;
The comments were getting too long.
Consider the following block diagram:
This represents an unrolled loop (for i in 0 to 7 loop) and shows that no add +3 occurs before i = 2 for the LS BCD digit and no add +3 occurs before i = 5 for the middle BCD digit, and no adjustment occurs on the MS BCD digit, which is comprise in part of static '0' values.
This gives us a total of 7 add3 modules (represented by the enclosing if statement, and conditional add +3).
This is demonstrated in VHDL:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin8bcd is
port (
bin: in std_logic_vector (7 downto 0);
bcd: out std_logic_vector (11 downto 0)
);
end entity;
architecture struct of bin8bcd is
procedure add3 (signal bin: in std_logic_vector (3 downto 0);
signal bcd: out std_logic_vector (3 downto 0)) is
variable is_gt_4: std_logic;
begin
is_gt_4 := bin(3) or (bin(2) and (bin(1) or bin(0)));
if is_gt_4 = '1' then
-- if to_integer(unsigned (bin)) > 4 then
bcd <= std_logic_vector(unsigned(bin) + "0011");
else
bcd <= bin;
end if;
end procedure;
signal U0bin,U1bin,U2bin,U3bin,U4bin,U5bin,U6bin:
std_logic_vector (3 downto 0);
signal U0bcd,U1bcd,U2bcd,U3bcd,U4bcd,U5bcd,U6bcd:
std_logic_vector (3 downto 0);
begin
U0bin <= '0' & bin (7 downto 5);
U1bin <= U0bcd(2 downto 0) & bin(4);
U2bin <= U1bcd(2 downto 0) & bin(3);
U3bin <= U2bcd(2 downto 0) & bin(2);
U4bin <= U3bcd(2 downto 0) & bin(1);
U5bin <= '0' & U0bcd(3) & U1bcd(3) & U2bcd(3);
U6bin <= U5bcd(2 downto 0) & U3bcd(3);
U0: add3(U0bin,U0bcd);
U1: add3(U1bin,U1bcd);
U2: add3(U2bin,U2bcd);
U3: add3(U3bin,U3bcd);
U4: add3(U4bin,U4bcd);
U5: add3(U5bin,U5bcd);
U6: add3(U6bin,U6bcd);
OUTP:
bcd <= '0' & '0' & U5bcd(3) & U6bcd & U4bcd & bin(0);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin8bcd_tb is
end entity;
architecture foo of bin8bcd_tb is
signal bin: std_logic_vector (7 downto 0) := (others => '0');
-- (initialized to prevent those annoying metavalue reports)
signal bcd: std_logic_vector (11 downto 0);
begin
DUT:
entity work.bin8bcd
port map (
bin => bin,
bcd => bcd
);
STIMULUS:
process
begin
for i in 0 to 255 loop
bin <= std_logic_vector(to_unsigned(i,8));
wait for 1 ns;
end loop;
wait for 1 ns;
wait;
end process;
end architecture;
That when the accompanying test bench is run yields:
And if you were to scroll through the entire waveform you'd find that all bcd outputs from 001 to 255 are present and accounted for (no holes), no 'X's or 'U's anywhere.
From the representation in the block diagram showing i = 7 we see that no add +3 occurs after the final shift.
Also note that the LSB of bcd is always the LSB of bin, and that bcd(11) and bcd(10) are always '0'.
The add3 can be hand optimized to create an increment by 3 using logic operators to get rid of any possibility of reporting meta values derived from bin (and there'd be a lot of them).
As far as I can tell this represents the most optimized representation of 8 bit binary to 12 bit BCD conversion.
Sometime previously I wrote a C program to provide input to espresso (a term minimizer):
/*
* binbcd.c - generates input to espresso for 8 bit binary
* to 12 bit bcd.
*
*/
#include <stdlib.h>
#include <stdio.h>
int main (argc, argv)
int argc;
char **argv;
{
int binary;
int bit;
char bcd_buff[4];
int digit;
int bcd;
printf(".i 8\n");
printf(".o 12\n");
for (binary = 0; binary < 256; binary++) {
for ( bit = 7; bit >= 0; bit--) {
if ((1 << bit) & binary)
printf("1");
else
printf("0");
}
digit = snprintf(bcd_buff,4,"%03d",binary); /* leading zeros */
if (digit != 3) {
fprintf(stderr,"%s: binary to string conversion failure, digit = %d\n",
argv[0],digit);
exit (-1);
}
printf (" "); /* input to output space */
for ( digit = 0; digit <= 2; digit++) {
bcd = bcd_buff[digit] - 0x30;
for (bit = 3; bit >= 0; bit--) {
if ((1 << bit) & bcd)
printf("1");
else
printf("0");
}
}
/* printf(" %03d",binary); */
printf("\n");
}
printf (".e\n");
exit (0);
Then started poking around with intermediary terms, which leads you directly to what is represented in the block diagram above.
And of course you could use an actual component add3 as well as use nested generate statements to hook everything up.
You won't get the same minimized hardware from a loop statement representation without constraining the if statements (2 < i < 7 for the LS BCD digit, 5 < i < 7 for the middle BCD digit).
You'd want the subsidiary nested generate statement to provide the same constraints for a shortened structural representation.
A logic operator version of add3 is shown on PDF page 5 on the university lecture slides for Binary to BCD Conversion using double dabble, where the forward tick is used for negation notation, "+" signifies OR, and Adjacency signifies AND.
The add3 then looks like:
procedure add3 (signal bin: in std_logic_vector (3 downto 0);
signal bcd: out std_logic_vector (3 downto 0)) is
begin
bcd(3) <= bin(3) or
(bin(2) and bin(0)) or
(bin(2) and bin(1));
bcd(2) <= (bin(3) and bin(0)) or
(bin(2) and not bin(1) and not bin(0));
bcd(1) <= (bin(3) and not bin(0)) or
(not bin(2) and bin(1)) or
(bin(1) and bin(0));
bcd(0) <= (bin(3) and not bin(0)) or
(not bin(3) and not bin(2) and bin(0)) or
(bin(2) and bin(1) and not bin(0));
end procedure;
Note this would allow package numeric_std (or equivalent) to be dropped from the context clause.
If you write signals in AND terms in the same order (in this case left to right) the duplicated AND terms show up well, as the also do using espresso. There is no value in using intermediary AND terms in an FPGA implementation, these all fit it LUTs just the way they are.
espresso input for add3:
.i 4
.o 4
0000 0000
0001 0001
0010 0010
0011 0011
0100 0100
0101 1000
0110 1001
0111 1010
1000 1011
1001 1100
1010 ----
1011 ----
1100 ----
1101 ----
1110 ----
1111 ----
.e
And espresso's output (espresso -eonset):
.i 4
.o 4
.p 8
-100 0100
00-1 0001
--11 0010
-01- 0010
-110 1001
-1-1 1000
1--1 1100
1--0 1011
.e
When you consider the combinatorial 'depth' of the binary to BCD conversion, for an FPGA it's 6 LUTs (the 6th an input to something following). That likely limits the clock speed to something shy of 100 MHz if the conversion occurs in one clock.
By pipelining or using sequential logic (clocked loop) you'd be able to run an FPGA at it's fastest speed while executing in 6 clocks.
At least two issues appear:
Adding is done after shift, and not before as described in the Double dabble algorithm
The bcd shift goes bcd(11 downto 1), but should be bcd(10 downto 0)
So try with the code:
process ( hex_in )
variable hex_src : std_logic_vector (7 downto 0) ;
variable bcd : std_logic_vector (11 downto 0) ;
begin
hex_src := hex_in ;
bcd := (others => '0') ;
for i in 0 to 7 loop
if bcd(3 downto 0) > "0100" then
bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
end if ;
if bcd(7 downto 4) > "0100" then
bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
end if ;
if bcd(11 downto 8) > "0100" then
bcd(11 downto 8) := bcd(11 downto 8) + "0011" ;
end if ;
bcd := bcd(10 downto 0) & hex_src(7) ; -- shift bcd + 1 new entry
hex_src := hex_src(6 downto 0) & '0' ; -- shift src + pad with 0
end loop ;
bcd_hun <= bcd(11 downto 8) ;
bcd_ten <= bcd(7 downto 4) ;
bcd_uni <= bcd(3 downto 0) ;
end process ;
However, the implementation may require a slow clock...
Based on Davids observations in the comments, the code be optimized to:
process ( hex_in )
variable hex_src : std_logic_vector (4 downto 0) ;
variable bcd : std_logic_vector (11 downto 0) ;
begin
bcd := (others => '0') ;
bcd(2 downto 0) := hex_in(7 downto 5) ;
hex_src := hex_in(4 downto 0) ;
for i in hex_src'range loop
if bcd(3 downto 0) > "0100" then
bcd(3 downto 0) := bcd(3 downto 0) + "0011" ;
end if ;
if bcd(7 downto 4) > "0100" then
bcd(7 downto 4) := bcd(7 downto 4) + "0011" ;
end if ;
-- No roll over for hundred digit, since in 0 .. 2
bcd := bcd(10 downto 0) & hex_src(hex_src'left) ; -- shift bcd + 1 new entry
hex_src := hex_src(hex_src'left - 1 downto hex_src'right) & '0' ; -- shift src + pad with 0
end loop ;
bcd_hun <= bcd(11 downto 8) ;
bcd_ten <= bcd(7 downto 4) ;
bcd_uni <= bcd(3 downto 0) ;
end process ;
1.you need take bit 10 to 0 of BCD and from 6 to 0 of hex_src to shift properly.
2.after the 8th shift, the hex_src value you should not add further, try restricting adding
on 7th shifting, you can use if statement to avoid.
after each conversion reset BCD value to zero.
after above correction code should work
This works in quartus 18.1 lite
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
--converting a 8bit binary number to a 12bit bcd
entity bin2bcd is
port (bin :in std_logic_vector (7 downto 0);
bcd1 : out std_logic_vector (3 downto 0);
bcd2 : out std_logic_vector (3 downto 0);
bcd3 : out std_logic_vector (3 downto 0));
end entity;
architecture rtl of bin2bcd is
begin
process ( bin )
variable binx : std_logic_vector (7 downto 0) ;
variable bcd : std_logic_vector (11 downto 0) ;
begin
bcd := (others => '0') ;
binx := bin(7 downto 0) ;
for i in binx'range loop
if bcd(3 downto 0) > "0100" then
bcd(3 downto 0) := std_logic_vector(unsigned( bcd(3 downto 0)) + "0011");
end if ;
if bcd(7 downto 4) > "0100" then
bcd(7 downto 4) := std_logic_vector(unsigned( bcd(7 downto 4)) + "0011");
end if ;
bcd := bcd(10 downto 0) & binx(7) ;
binx := binx(6 downto 0) & '0' ;
end loop ;
bcd3 <= bcd(11 downto 8) ;
bcd2 <= bcd(7 downto 4) ;
bcd1 <= bcd(3 downto 0) ;
end process ;
end architecture;

VHDL ALU undefined value

I'm learning VHDL for programming a FPGA, basic (but hard-for-me) projects. I have this ALU. It is supossed to be a 4-bit ALU. But when I want to make the Add operation the value of result is UUUU. For all other operations is working fine.
Any advise?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU is
Port (
clk: in std_logic;
reset: in std_logic;
operation: in std_logic_vector (2 downto 0)
);
end ALU;
architecture Behavioral of ALU is
signal A : std_logic_vector (3 downto 0) := "0001";
signal B : std_logic_vector (3 downto 0) := "1111";
signal result : std_logic_vector (7 downto 0);
signal flags : std_logic_vector (2 downto 0); -- [S,OF,Z]
begin
process (operation) begin
flags <= (others => '0');
result <= (others => '0');
case operation is
when "000" =>
result <= std_logic_vector((unsigned("0000"&A) + unsigned(B)));
flags(1) <= result(4);
when "001" =>
if (A >= B) then
result <= std_logic_vector(unsigned("0000"&A) - unsigned(B));
flags(2) <= '0';
else
result <= std_logic_vector(unsigned("0000"&B) - unsigned(A));
flags(2) <= '1';
end if;
when "010" =>
result <= "0000"&A and "0000"&B;
when "011" =>
result <= "0000"&A or "0000"&B;
when "100" =>
result <= "0000"&A xor "0000"&B;
when "101" =>
result <= not ("1111"&A);
when "110" =>
result <= not ("1111"&B);
when "111" =>
result <= std_logic_vector(unsigned(A) * unsigned(B));
when others =>
result <= (others => 'Z');
end case;
end process;
end Behavioral;
The only way I can see all Us happening (with the code as is) is if the process never executes. Which means you must have no transactions on the operation signal for the add operation.
Which only raises more questions:
Are you definitely getting Us (not Xs maybe?): is something else driving the signal as well?
Can you post your testbench code?
The first two things that come to mind looking at your code are:
You should include A and B in the process sensitivity list (now it only contains operation).
You can't use result(4) to set flags(1), as result(4) will only be updated after the process, and result itself isn't on the sensitivity list again so the process won't be triggered again to reflect the changed value. The best option is probably to store the sum in a variable, then assign that to result and the overflow bit.