16bit to bcd conversion - vhdl

I'm trying to make a 16bit to BCD conversion.
I have found this link for a 8 bit and I'm trying to convert it to 16 bits.
http://vhdlguru.blogspot.nl/2010/04/8-bit-binary-to-bcd-converter-double.html
I don't know what im doing wrong the rpm_1000 keeps changing and the rpm_100 stays at 4. Does anyone have a idea what i did wrong?
process (Hex_Display_Data)
variable i : integer:=0;
variable bcd : std_logic_vector(19 downto 0) := (others => '0');
variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
begin
for i in 0 to 15 loop -- repeating 16 times.
bcd(19 downto 1) := bcd(18 downto 0); --shifting the bits.
bcd(0) := bint(15); -- shift bit in
bint(15 downto 1) := bint(14 downto 0); --removing msb
bint(0) :='0'; -- adding a '0'
if(i < 15 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(3 downto 0) := bcd(3 downto 0) + "0011";
end if;
if(i < 15 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(7 downto 4) := bcd(7 downto 4) + "0011";
end if;
if(i < 15 and bcd(11 downto 8) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(11 downto 8) := bcd(11 downto 8) + "0011";
end if;
if(i < 15 and bcd(15 downto 12) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(15 downto 12) := bcd(15 downto 12) + "0011";
end if;
end loop;
rpm_1000 <= bcd(15 downto 12);
rpm_100 <= bcd(11 downto 8);
rpm_10 <= bcd(7 downto 4);
rpm_1 <= bcd(3 downto 0);
end process ;

Note four BCD digits can be wholly contained in 14 bits of input (your Hex_Display_Data) and unused bcd 'bits' (19 downto 16) will get eaten during synthesis along with all the add 3's that can't occur because their upper two bits are '0's (not > 4).
If you constrain your bcd value to 4 hex digits, and your loop iteration to 14 bits:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port (
input: in std_logic_vector (15 downto 0);
ones: out std_logic_vector (3 downto 0);
tens: out std_logic_vector (3 downto 0);
hundreds: out std_logic_vector (3 downto 0);
thousands: out std_logic_vector (3 downto 0)
);
end entity;
architecture fum of bin2bcd is
alias Hex_Display_Data: std_logic_vector (15 downto 0) is input;
alias rpm_1: std_logic_vector (3 downto 0) is ones;
alias rpm_10: std_logic_vector (3 downto 0) is tens;
alias rpm_100: std_logic_vector (3 downto 0) is hundreds;
alias rpm_1000: std_logic_vector (3 downto 0) is thousands;
begin
process (Hex_Display_Data)
type fourbits is array (3 downto 0) of std_logic_vector(3 downto 0);
-- variable i : integer := 0; -- NOT USED
-- variable bcd : std_logic_vector(15 downto 0) := (others => '0');
variable bcd: std_logic_vector (15 downto 0);
-- variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
variable bint: std_logic_vector (13 downto 0); -- SEE process body
begin
bcd := (others => '0'); -- ADDED for EVERY CONVERSION
bint := Hex_Display_Data (13 downto 0); -- ADDED for EVERY CONVERSION
for i in 0 to 13 loop
bcd(15 downto 1) := bcd(14 downto 0);
bcd(0) := bint(13);
bint(13 downto 1) := bint(12 downto 0);
bint(0) := '0';
if i < 13 and bcd(3 downto 0) > "0100" then
bcd(3 downto 0) :=
std_logic_vector (unsigned(bcd(3 downto 0)) + 3);
end if;
if i < 13 and bcd(7 downto 4) > "0100" then
bcd(7 downto 4) :=
std_logic_vector(unsigned(bcd(7 downto 4)) + 3);
end if;
if i < 13 and bcd(11 downto 8) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(11 downto 8)) + 3);
end if;
if i < 13 and bcd(15 downto 12) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(15 downto 12)) + 3);
end if;
end loop;
(rpm_1000, rpm_100, rpm_10, rpm_1) <=
fourbits'( bcd (15 downto 12), bcd (11 downto 8),
bcd ( 7 downto 4), bcd ( 3 downto 0) );
end process ;
end architecture;
Note the use of aliases to enable your names to be used in an existing otherwise compatible Minimal, Complete and Verifiable Example which your question did not provide.
Aggregate signal assignment is also taken from the original, your assignment to the individual digits should work just fine.
There are two changes besides limiting the conversion to 14 bits and the number of BCD digits to match the number of digits output.
The bcd and bint variables are now cleared every time the process is resumed (sensitive to updates to Hex_Display_Data). These were causing causing your otherwise unverifiable errors more than likely.
Extraneous parentheses have been removed.
You didn't supply context clauses. The code shown uses package numeric_std as opposed to the -2008 numeric_std_unsigned offering compatibility with earlier revisions of the standard while using IEEE authored packages.
You'll get something that works, provable with a testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd_tb is
end entity;
architecture foo of bin2bcd_tb is
signal input: std_logic_vector (15 downto 0) := (others => '0');
signal ones: std_logic_vector (3 downto 0);
signal tens: std_logic_vector (3 downto 0);
signal hundreds: std_logic_vector (3 downto 0);
signal thousands: std_logic_vector (3 downto 0);
begin
DUT:
entity work.bin2bcd
port map (
input => input,
ones => ones,
tens => tens,
hundreds => hundreds,
thousands => thousands
);
STIMULUS:
process
begin
for i in 0 to 1001 loop
wait for 20 ns;
input <= std_logic_vector(to_unsigned(9999 - i, 16));
end loop;
wait for 20 ns;
wait;
end process;
end architecture;
Some other stimulus scheme can be used to toggle BCD digit roll over of all four digits.
This testbench provides input values starting at 9999 and decrementing 1001 times to show all four digits transitioning:
I can easily be modified to prove every transition of every BCD digit.
In summary the errors you were encountering appear to have come from the difference in elaboration for variables in a subprogram, where bcd and bint would be dynamically elaborated and initialized every function call, and in the process where they would be only initialized once.
From examining Xilinx's User Guide 901 Vivado Design Suite User Guide, Synthesis (2015.3), Chapter 4: VHDL Support, Combinatorial Processes, case Statements, for-loop Statements, the for loop appears to be supported for synthesis and has been reported to be synthesis eligible in other double dabble questions on stackoverflow. The issue would be support for repetitive assignment to variables in repeated sequences of sequential statements, which should be supported. There are is at least one other double dabble question on stackoverflow where successful synthesis had been reported using such a for loop.
Note that constraining the input value you deal with to 14 bits doesn't detect the effects of larger binary numbers (> 9999) which your process does not otherwise do either providing only 4 BCD output digits. You could deal with that by checking if the input value is greater than 9999 (x"270F").
The + 3 represents 1 LUT depth in an FPGA (4 bit input, 4 bit output), there are some number of them layered in depth based on the size of the converted number (the range of i). Allowing time for conversion propagation through ADD3's is offset by the rate at which the display can be visually interpreted. If you updated Hex_Display_Data in the millisecond range you likely could not tell the difference visually.

Running the loop 16 times will cause the value in the BCD registers to be multiplied by 65536 (mod 100000) and added to the value in the binary registers. Say the value is 4000. Then 4000x65536 yields 44000. 44000x65536 yields 84000. 84000x65536 yields 24000. 24000x65536 yields 64000. And 64000x65536 yields 4000.
To make the algorithm work, you must start out by clearing the BCD registers. It also wouldn't hurt to fix the comment about how many times your loop runs.
Incidentally, a practical implementation of a binary to BCD converter should generally accept a clock input, and perform one step for each active clock edge. If your VHDL is running entirely in simulation the complexity of the resulting logic won't matter, but trying to perform everything at once in real hardware will be rather expensive. By contrast, the hardware to do a simple shift of the binary number and a multiply-by-two of the BCD number will be much simpler. Note that if you do things "all at once", the most significant bit of the output will depend upon the second-least-significant bit of the input, meaning the input signal will have to propagate through all the logic in one step. By contrast, if you shift by one bit per clock cycle, each bit of the output will depend only upon at most four bits of the input (since each digit will be in the range 0-9 before the adjustment phase, adding 3 will never cause a carry out).
Also, the "double dabble" algorithm requires that the adjustment be performed before the BCD shifts, but it looks as though the code is performing the adjustment after. Doing the adjustment after is fine if one looks at bit
ranges 16..13, 12..9, 8..5, and 4..1 rather than 15..12, etc. Alternatively, one could specify that the value of bits 19..17 should be the value of bits 18..16, the value of bits 16..13 should be either the value of bits 15..12 (if less than 5) or the value of bits 15..12, plus three (if greater), etc. Such a formulation would set the value of each bit in exactly one place, which would make it easier to see how it should be rendered into hardware.

Related

8 bit serial to parallel shifter in vhdl

I programmed an 8-bit shifter in vhdl:
entity 8b is
port(s, clk : in std_logic; p : out std_logic_vector (7 downto 0));
end entity;
architecture arch of 8b is
Signal iq : std_logic_vector (7 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
end if;
end process;
p <= iq;
end architecture;
The idea is that I'm taking input and giving it to my first D-FF.
Then over the next 7 cycles, the other Flip Flops get the other serial inputs which will be given to the parallel output p.
However, I'm not sure if this logic is flawed because this is the solution we got for this exercise:
architecture behavior of 8b is
signal p_intern : std_logic_vector(7 downto 0);
begin
P <= p_intern;
process(CLK)
begin
if rising_edge(CLK) then
p_intern <= p_intern(6 downto 0) & S;
end if;
end process;
end architecture;
But I don't get the p_intern <= p_inter(6 downto 0) & S; part.
Can someone please explain the logic behind this and if my version is also valid?
The only difference between the two implementations seem to be the lines
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
vs.
p_intern <= p_intern(6 downto 0) & S;
and that iq is named p_intern. Let's assume they are both named iq for the sake of comparison.
Let's see what they are doing:
The first implementation (yours) assigns to the positions of iq:
7 6 5 ... 1 0
s iq(7) iq(6) ... iq(2) iq(1)
The second implementation (the solution) assigns
7 6 5 ... 1 0
iq(6) iq(5) iq(4) ... iq(0) s
Where iq(6 downto 0) & s means "concatenate s to the right of iq(6 downto 0)".
So they are not equivalent. Your implementation shifts in the values from the left, and the solution shifts in the values from the right. Which one is correct depends on the specification (presumably the solution is correct).

How does a 32:8 mux work?

I'm programming a 32:8 mux in vhdl.
The task is based on a exam question that oviously can be interpreted several ways. The origianal task was to: Program a 32:8 mux, using "with select when", and "if then else". I did'nt get how the 32:8 mux would work, so I did'nt know where to start, but thanks to you guys I figured I would program it as a 4:1 mux passing 4 groups of 8 bits.
This is what I got:
library ieee;
use ieee.std_logic_1164.all;
entity mux_using_with is
port (
input :in std_logic_vector (31 downto 0);
sel :in std_logic_vector (1 downto 0);
mux_out :out std_logic_vector (7 downto 0));
end entity;
architecture behavior of mux_using_with is
begin
with (sel) select
mux_out <= input(7 downto 0) when '00',
input(15 downto 8) when '01',
input(23 downto 16) when '10',
input(31 downto 24) when others;
end architecture;
And for the if version:
library ieee;
use ieee.std_logic_1164.all;
entity mux_using_if is
port (
input :in std_logic_vector (31 downto 0);
sel :in std_logic_vector (1 downto 0);
mux_out :out std_logic_vector (7 downto 0));
end entity;
architecture behavior of mux_using_if is
begin
MUX:
process (sel, input) begin
if (sel = '00') then
mux_out <= input(7 downto 0);
elsif (sel = '00') then
mux_out <= input(15 downto 8);
elsif (sel = '00') then
mux_out <= input(23 downto 16);
else
mux_out <= input(31 downto 24);;
end if;
end process;
end architecture;
Have I made any obvious mistakes?
A 32:8 selects 8 bits from 32 bits. There are two obvious ways to do this (and other less obvious ones):
Select any contiguous group of 8 bits starting from any point in the 32-bit input, with possible wrap-around. This is actually a 'barrel shifter'. There are 32 'start' positions, so you need a 5-bit selector; or
Select one of the 4 groups [7:0], [15:8], [23:16], or [31:24]. In this case, you need a 2-bit selector to select one of these groups.
I'm going to assume you want (2), since you've got a 2-bit selector. So, each of your 8 output bits is actually a 4:1 mux. Bit 0 of the output selects from either bit 0, 8, 16, or 24 of the input, for example, depending on the state of your 2-bit selector.
There are 4 straightforward ways to do this in VHDL: a sequential case statement, a selected signal assignment, direct logic, or array element selection. There are examples of all 4 styles on the Maia site. These only have a 1-bit output, so your task is to turn it into an 8 bit output. Have a look and let us know if you have a problem.

Executing sequencial statments in VHDL for synthesis

So here's the problem. I've written code for a binary divider that should output 7-bit 7 segment display binary code to go into an 8 x 7segment display. (2 7segments for dividend,divisor,quotient,remainder each and in that order). This 8 x 7segment display on my dev-board has one 7-bit input(a to g) and a 3-bit select.
So the basic idea is I have to output the dividend,divisor,quotient and remainder sequentially, continuously and fast enough such that to the human eye the output looks constant despite the fact that the each of the eight 7 segments is being enabled one by one according to what my output is.
Originally, the divider gives all the outputs (dividend,divisor,quotient,remainder)in binary which are then converted by a function to 8-bit bcd and that bcd number is then broken down into two 4-bit bcd numbers by another function(Now I have 8 output variables: 2 representing dividend,2 representing divisor etc).These 4-bit numbers are converted by another function to 7 segment.
Here is the full code:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_ARITH.all;
entity division is
generic(SIZE: INTEGER := 8);
port(reset: in STD_LOGIC; --reset
en: in STD_LOGIC; --enable
clk: in STD_LOGIC; --clock
num: in STD_LOGIC_VECTOR((SIZE - 1) downto 0); --dividend
den: in STD_LOGIC_VECTOR((SIZE - 1) downto 0); --divisor
whatgoes:out STD_LOGIC_VECTOR(6 downto 0) --output
);
end division;
architecture behav of division is
signal bufreg: STD_LOGIC_VECTOR((2 * SIZE - 1) downto 0); --signal array to hold both accumulator and dividend registers as one i.e bufreg(18 bits)
signal dbuf: STD_LOGIC_VECTOR((SIZE - 1) downto 0); --signal array to hold the divisor
signal count: INTEGER range 0 to SIZE; --count to determine when to stop
signal MYcount: INTEGER range 0 to 100;
signal res: STD_LOGIC_VECTOR((SIZE - 1) downto 0); --result/quotient
signal rm : STD_LOGIC_VECTOR((SIZE - 1) downto 0); --remainder
alias ADreg is bufreg((2 * SIZE - 1) downto SIZE); --ADreg is is alias for top half of bufreg register(17th to 9th bit)
alias DVNDreg is bufreg((SIZE - 1) downto 0); --DVNDreg is is alias for bottom half of bufreg register(8th to 0th bit)
--Function definitions
function to_bcd ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector; --converts 8 bit binary to 8 bit BCD
function m7seg (bin : std_logic_vector(3 downto 0) ) return std_logic_vector; --converts 4 bit BCD to 7 bit 7segment
function breakdown1 ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector; --breaks an 8 bit BCD into a 4 bit BCD with lower bits
function breakdown2 ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector; ----breaks an 8 bit BCD into a 4 bit BCD with higher bits
--this function assigns the first 4 bits of an 8 bit BCD number to a 4-bit vector
function breakdown1 ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector is
variable bint : std_logic_vector(3 downto 0) :=bin(3 downto 0);
begin
return bint;
end breakdown1;
--this function assigns the last 4 bits of an 8 bit BCD number to a 4-bit vector
function breakdown2 ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector is
variable bint : std_logic_vector(3 downto 0) :=bin(7 downto 4);
begin
return bint;
end breakdown2;
--This function converts 8 bit binary to 8 bit BCD
function to_bcd ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector is
variable i : integer:=0;
variable bcd : std_logic_vector(7 downto 0) :=(others => '0');
variable bint : std_logic_vector(7 downto 0) :=bin;
variable bcd2 : std_logic_vector(7 downto 0) :=(others => '0');
begin
for i in 0 to 7 loop -- repeating 8 times.
bcd(7 downto 1) := bcd(6 downto 0); --shifting the bits.
bcd(0) := bint(7);
bint(7 downto 1) := bint(6 downto 0);
bint(0) :='0';
if(i < 7 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(3 downto 0) := bcd(3 downto 0) + "0011";
end if;
if(i < 7 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(7 downto 4) := bcd(7 downto 4) + "0011";
end if;
--if(i < 7 and bcd(11 downto 8) > "0100") then --add 3 if BCD digit is greater than 4.
--bcd(11 downto 8) := bcd(11 downto 8) + "0011";
--end if;
end loop;
bcd2(7 downto 0):=bcd(7 downto 0);
return bcd2;
end to_bcd;
--This function converts 4 bit bcd to 7 segment
function m7seg (bin : std_logic_vector(3 downto 0))return std_logic_vector is
variable bint : std_logic_vector(3 downto 0):=bin(3 downto 0);
variable out7 : std_logic_vector(6 downto 0);
begin
case bint is
when "0000"=> out7:="1111110";
when "0001"=> out7:="0110000";
when "0010"=> out7:="1101101";
when "0011"=> out7:="1111001";
when "0100"=> out7:="0110011";
when "0101"=> out7:="1011011";
when "0110"=> out7:="X011111";
when "0111"=> out7:="1110000";
when "1000"=> out7:="1111111";
when "1001"=> out7:="111X011";
when others=> out7:="0000000";
end case;
return out7;
end m7seg;
begin
--our process begins here (shift and subtract/ Non restoring division)
p_001: process(reset, en, clk, bufreg)
begin
if reset = '1' then
res <= (others => '0');
rm <= (others => '0');
dbuf <= (others => '0');
bufreg <= (others => '0');
count <= 0;
MYcount <= 1;
elsif rising_edge(clk) then
if en = '1' then
case count is
when 0 =>
ADreg <= (others => '0');
DVNDreg <= num;
dbuf <= den;
res <= DVNDreg;
rm <= ADreg;
count <= count + 1;
when others =>
if bufreg((2 * SIZE - 2) downto (SIZE - 1)) >= dbuf then
ADreg <= '0' & (bufreg((2 * SIZE - 3) downto (SIZE - 1)) - dbuf((SIZE - 2) downto 0));
DVNDreg <= DVNDreg ((SIZE - 2) downto 0) & '1';
else
bufreg <= bufreg((2 * SIZE - 2) downto 0) & '0';
end if;
if count /= SIZE then
count <= count + 1;
else
count <= 0;
end if;
end case;
end if;
res <= DVNDreg;
rm <= ADreg;
MYcount<=MYcount+1;
whatgoes<=(others => '0');
case MYcount is
when 2 =>
whatgoes<=m7seg(breakdown1(to_bcd(rm))); --first 7segment(lower bits of remainder)
when 3 =>
whatgoes<=m7seg(breakdown2(to_bcd(rm))); --second 7segment (higher bits of remainder)
when 4 =>
whatgoes<=m7seg(breakdown1(to_bcd(res))); --third 7segment (lower bits of result/quotient)
when 5 =>
whatgoes<=m7seg(breakdown2(to_bcd(res))); --fourth 7segment (higher bits of result/quotient)
when 6 =>
whatgoes<=m7seg(breakdown1(to_bcd(den))); --fifth 7segment (lower bits of divisor)
when 7 =>
whatgoes<=m7seg(breakdown2(to_bcd(den))); --sixth 7segment (higher bits of divisor)
when 8 =>
whatgoes<=m7seg(breakdown1(to_bcd(num))); --seventh 7segment (lower bits of number/dividend)
when 9 =>
whatgoes<=m7seg(breakdown2(to_bcd(num))); --eigth 7segment (higher bits of number/dividend)
when 10 =>
MYcount<=1;
when others =>
NULL;
end case;
end if;
end process;
end behav;
When I try to run a simulation, it gives me all kinds of funky stuff. I want the output (whatgoes(6 downto 0)) to change with the rising edge of the clock(clk). The problem is that since I'm a beginner at VHDL,Ive been having a lot of problems with synthesizing sequential statements.
Inside the process p_001 with enable, clock, and reset in the sensitivity list, i put this case statement. It executes on a positive edge condition.
Code extract:
case MYcount is
when 2 =>
whatgoes<=m7seg(breakdown1(to_bcd(rm))); --first 7segment(lower bits of remainder)
when 3 =>
whatgoes<=m7seg(breakdown2(to_bcd(rm))); --second 7segment (higher bits of remainder)
when 4 =>
whatgoes<=m7seg(breakdown1(to_bcd(res))); --third 7segment (lower bits of result/quotient)
when 5 =>
whatgoes<=m7seg(breakdown2(to_bcd(res))); --fourth 7segment (higher bits of result/quotient)
when 6 =>
whatgoes<=m7seg(breakdown1(to_bcd(den))); --fifth 7segment (lower bits of divisor)
when 7 =>
whatgoes<=m7seg(breakdown2(to_bcd(den))); --sixth 7segment (higher bits of divisor)
when 8 =>
whatgoes<=m7seg(breakdown1(to_bcd(num))); --seventh 7segment (lower bits of number/dividend)
when 9 =>
whatgoes<=m7seg(breakdown2(to_bcd(num))); --eigth 7segment (higher bits of number/dividend)
when 10 =>
MYcount<=1;
when others =>
NULL;
end case;
I'm pretty sure my problem lies here since the rest of my code works fine.
I apologize for uploading such a convoluted mess of code. I'm genuinely stuck and I've been at this for a good number of hours.
Any help would be greatly appreciated. I know it takes a special kind of devotion and patience to answer such a long,boring and nooby problem.
But to whoever can help or provide a link to something that has an answer to my kind of problem, you'd have done me a great service.
I'm using ISE 14.3and iSim.
So, thanks to rick, I solved this.
He helped me realize that I was forgetting to drive the 3-bit select output. As it turns out, driving it using a case statement and counting variable solved my problem of executing the code sequentially.
I know the code is not exactly written in an organized way but i hope with time i'll get better.
process (clk,tmp,rm,res,den,num)
variable CLR: boolean:=true;
begin
if (CLR=true) then
tmp <= "000";
CLR:=false;
elsif (clk'event and clk='1') then
tmp <= tmp + 1;
if tmp<=8 then
CLR:=true;
end if;
end if;
case tmp is
when "000" =>
whatgoes<=m7seg(breakdown1(to_bcd(rm))); --first 7segment(lower bits of remainder)
when "001" =>
whatgoes<=m7seg(breakdown2(to_bcd(rm))); --second 7segment (higher bits of remainder)
when "010" =>
whatgoes<=m7seg(breakdown1(to_bcd(res))); --third 7segment (lower bits of result/quotient)
when "011" =>
whatgoes<=m7seg(breakdown2(to_bcd(res))); --fourth 7segment (higher bits of result/quotient)
when "100" =>
whatgoes<=m7seg(breakdown1(to_bcd(den))); --fifth 7segment (lower bits of divisor)
when "101" =>
whatgoes<=m7seg(breakdown2(to_bcd(den))); --sixth 7segment (higher bits of divisor)
when "110" =>
whatgoes<=m7seg(breakdown1(to_bcd(num))); --seventh 7segment (lower bits of number/dividend)
when "111" =>
whatgoes<=m7seg(breakdown2(to_bcd(num))); --eigth 7segment (higher bits of number/dividend)
when others =>
NULL;
end case;
sel<=tmp;
end process;
I'm basically shooting in the dark here; maybe if you post a simulation picture it will help us understand your problem better. Anyway, since we're at it, why not talk about a few random issues:
The code would be easier to understand (and to work with) if you'd split it into a few blocks, each with a single purpose. You could have one block do the division, and output only the quotient and remainder. Another block could take in 8 BCD values, and multiplex them so that they appear correctly on your board's displays. If we can concentrate on one part of the problem at a time, it will be easier to spot anything wrong.
You mention a 3-bit select on the LCD, but I don't see in your code where you drive it. Maybe you should output something based on your signal MYcount?
To make sure your functions are working ok, you could put them in a package and create a self-cheking testbench. At least that's how I'd do it. This would take that variable out of the equation.
Please post some simulation results so that we can help you out.

VHDL How to convert 32 bit variable to 4 x 8bit std_logic_vector?

I have a question which is probably in 2 parts:
I am using a (nominally 32 bit) integer variable which I would like to write to an 8 bit UART as 4 bytes (i.e., as binary data)
i.e. variable Count : integer range 0 to 2147483647;
How should I chop the 32 bit integer variable into 4 separate 8 bit std_logic_vectors as expected by my UART code, and how should I pass these to the UART one byte at a time ?
I am aware std_logic_vector(to_unsigned(Count, 32)) will convert the integer variable into a 32 bit std_logic_vector, but then what ? Should I create a 32 bit std_logic_vector, assign the converted Count value to it, then subdivide it using something like the following code ? I realise the following assumes the count variable does not change during the 4 clock cycles, and assumes the UART can accept a new byte every clock cycle, and lacks any means of re-triggering the 4 byte transmit cycle, but am I on the right track here, or is there a better way ?
variable CountOut : std_logic_vector(31 downto 0);
process (clock)
variable Index : integer range 0 to 4 := 0;
begin
if rising_edge(clock) then
CountOut <= std_logic_vector(to_unsigned(Count, 32);
if (Index = 0) then
UartData(7 downto 0) <= CountOut(31 downto 24);
Index := 1;
elsif (Index = 1) then
UartData(7 downto 0) <= CountOut(23 downto 16);
Index := 2;
elsif (Index = 2) then
UartData(7 downto 0) <= CountOut(15 downto 8);
Index := 3;
elsif (Index =31) then
UartData(7 downto 0) <= CountOut(7 downto 0);
Index := 4;
else
Index := Index;
end if;
end if;
end process;
Any comments or recommendations would be appreciated.
Thanks,
MAI-AU.
You seem to be on the right track. I believe there are two basic solutions to this problem:
Register the output value as a 32-bit vector, and use different ranges for each output operation (as you did in your code example)
Register the output value as a 32-bit vector, and shift this value 8 bits at a time after each output operation. This way you can use the same range in all operations. The code below should give you an idea:
process (clock)
variable Index: integer range 0 to 4 := 0;
begin
if rising_edge(clock) then
if (Index = 0) then
CountOut <= std_logic_vector(to_unsigned(Count, 32));
Index := Index + 1;
elsif (Index < 4) then
UartData <= CountOut(31 downto 24);
CountOut <= CountOut sll 8;
Index := Index + 1;
end if;
end if;
end process;
Also, please check your assignments, in your example CountOut is declared as a variable but is assigned to as a signal.
There's nothing wrong with the code you've shown. You can do something to separate the the assignment to UartData using Index to allow a loop.
library ieee;
use ieee.std_logic_1164.all;
entity union is
end entity;
architecture foo of union is
type union32 is array (integer range 1 to 4) of std_logic_vector(7 downto 0);
signal UartData: std_logic_vector(7 downto 0);
begin
TEST:
process
variable quad: union32;
constant fourbytes: std_logic_vector(31 downto 0) := X"deadbeef";
begin
quad := union32'(fourbytes(31 downto 24), fourbytes(23 downto 16),
fourbytes(15 downto 8),fourbytes(7 downto 0));
for i in union32'RANGE loop
wait for 9.6 us;
UartData <= Quad(i);
end loop;
wait for 9.6 us; -- to display the last byte
wait; -- one ping only
end process;
end architecture;
Or use a type conversion function to hide complexity:
library ieee;
use ieee.std_logic_1164.all;
entity union is
type union32 is array (integer range 1 to 4) of std_logic_vector(7 downto 0);
end entity;
architecture fee of union is
signal UartData: std_logic_vector(7 downto 0);
function toquad (inp: std_logic_vector(31 downto 0)) return union32 is
begin
return union32'(inp(31 downto 24), inp(23 downto 16),
inp(15 downto 8), inp( 7 downto 0));
end function;
begin
TEST:
process
variable quad: union32;
constant fourbytes: std_logic_vector(31 downto 0) := X"deadbeef";
begin
quad := toquad (fourbytes);
for i in union32'RANGE loop
wait for 9.6 us;
UartData <= Quad(i);
end loop;
wait for 9.6 us; -- to display the last byte
wait; -- one ping only
end process;
end architecture;
And gives the same answer.

How to convert 8 bits to 16 bits in VHDL?

I have an input signal from ADC convertor that is 8 bits (std_logic_vector(7 downto 0)). I have to convert them to a 16 bits signal (std_logic_vector(15 downto 0)) for 16 bits signal processing to the 16 bits system.
If the 8 bit value is interpreted as signed (2's complement), then the general and standard VHDL conversion method is to use the IEEE numeric_std library:
library ieee;
use ieee.numeric_std.all;
architecture sim of tb is
signal slv_8 : std_logic_vector( 8 - 1 downto 0);
signal slv_16 : std_logic_vector(16 - 1 downto 0);
begin
slv_16 <= std_logic_vector(resize(signed(slv_8), slv_16'length));
end architecture;
So first the std_logic_vector is converted to a signed value, then the resize is applied, which will sign extend the signed value, and the result is finally converted back to std_logic_vector.
The conversion is rather lengthy, but has the advantage that it is general and works even if the target length is changed later on.
The attribute 'length simply returns the length of the slv_16 std_logic_vector, thus 16.
For unsigned representation instead of signed, it can be done using unsigned instead of signed, thus with this code:
slv_16 <= std_logic_vector(resize(unsigned(slv_8), slv_16'length));
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0);
begin
s16 <= X"00" & s8;
end;
This handles the conversion without having to edit the widths of the zeroes if either std_logic_vector changes:
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0) := (others => '0');
begin
s16(s8'range) <= s8;
end;
For completeness, yet another way which is occasionally useful:
-- Clear all the slv_16 bits first and then copy in the bits you need.
process (slv_8)
begin
slv_16 <= (others => '0');
slv_16(7 downto 0) <= slv_8;
end process;
I've not had to do this for vectors that I can recall, but I have had need of this under more complex circumstances: copying just a few relevant signals into a bigger, more complex, record was one time.
With the newly released VHDL-2019 standard you can do
larger_vec <= extend(shorter_vec);
where extend is a function defined as follows
function extend(vec : std_logic_vector) return target_vec of std_logic_vector is
variable result : std_logic_vector(target_vec'length - 1 downto 0) := (others => '0');
begin
assert vec'length <= target_vec'length report "Cannot extend to shorter vector";
result(vec'length - 1 downto 0) := vec;
return result;
end function;
Tool support is still a bit limited but at least one simulator supports this (Riviera-PRO).

Resources