VHDL adder, same word length? - vhdl

In VHDL i want to add a number of 5 bits and a number of 8 bits.(Unsigned) And how many bits does the output have?
I want my code to answer the questions i just asked. My code currently look like this...
My code is:
library ieee;
use ieee-std_logic_1164.all;
entity adder is
port( a : in unsigned (7 downto 0);
b : in unsigned (4 downto 0); - - Need to convert this to 8 bit right? But how?
z : out unsigned(7 downto 0)); - - This one must be 8 bits right? Cuz a & b & z must have the same WL. Or am i wrong?
end adder;
archictecture add of adder is
begin
z <= a + b;
end archictecture;

In package numeric_std for function "+" (L, R: UNSIGNED) return UNSIGNED the length of the longest argument defines the return value length:
function "+" (L, R: UNSIGNED) return UNSIGNED is
constant SIZE: NATURAL := MAX(L'LENGTH, R'LENGTH);
variable L01 : UNSIGNED(SIZE-1 downto 0);
variable R01 : UNSIGNED(SIZE-1 downto 0);
begin
if ((L'LENGTH < 1) or (R'LENGTH < 1)) then return NAU;
end if;
L01 := TO_01(RESIZE(L, SIZE), 'X');
if (L01(L01'LEFT)='X') then return L01;
end if;
R01 := TO_01(RESIZE(R, SIZE), 'X');
if (R01(R01'LEFT)='X') then return R01;
end if;
return ADD_UNSIGNED(L01, R01, '0');
end "+";
The maximum of the left and right arguments length is SIZE, the range of the two arguments is is resized to SIZE -1 downto 0 as arguments to ADD_UNSIGNED.
function ADD_UNSIGNED (L, R: UNSIGNED; C: STD_LOGIC) return UNSIGNED is
constant L_LEFT: INTEGER := L'LENGTH-1;
alias XL: UNSIGNED(L_LEFT downto 0) is L;
alias XR: UNSIGNED(L_LEFT downto 0) is R;
variable RESULT: UNSIGNED(L_LEFT downto 0);
variable CBIT: STD_LOGIC := C;
begin
for I in 0 to L_LEFT loop
RESULT(I) := CBIT xor XL(I) xor XR(I);
CBIT := (CBIT and XL(I)) or (CBIT and XR(I)) or (XL(I) and XR(I));
end loop;
return RESULT;
end ADD_UNSIGNED;
The RESULT's length is that of the L argument which is the same of both arguments to UNSIGNED_ADD. There is no carry out implied in the result.
As in your case the result, assigned to z can be 8 bits.
Fix the comment delimiters in the port declarations, add a use clause to access package numeric_std, fix a '-' that should be a '.', spelling of architecture and add a test bench adding values for a and b set to all '1's and you can analyze, elaborate and run your design without error, telling you there isn't an array length error executing.
To get that ninth 'bit' as an output of the adder you can RESIZE one of your arguments to + to 9 bits or concatenate one argument with leading zeros to make a 9 bit value:
z <= "0" & a + b;
It'll demonstrate that the 9th bit is needed for an accurate result:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity adder is
port(
a: in unsigned (7 downto 0);
b: in unsigned (4 downto 0);
z: out unsigned (8 downto 0)
);
end adder;
architecture add of adder is
begin
z <= "0" & a + b;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_adder is
end entity;
architecture foo of tb_adder is
signal a: unsigned (7 downto 0) := (others => '1');
signal b: unsigned (4 downto 0) := (others => '1');
signal z: unsigned (8 downto 0);
function unsigned_image(inp: unsigned) return string is
variable image_str: string (1 to inp'length);
alias input_str: unsigned (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end;
begin
DUT:
entity work.adder
port map (
a => a,
b => b,
z => z
);
MONITOR:
process
begin
wait for 1 ns;
report "z = " & unsigned_image(z);
wait;
end process;
end architecture;
david_koontz#Macbook: ghdl -a adder.vhdl
david_koontz#Macbook: ghdl -e tb_adder
david_koontz#Macbook: ghdl -r tb_adder
adder.vhdl:54:9:#1ns:(report note): z = 100011110

Other than this correction:
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Your code is fine.
Additionally, adding an 8 bit number and a 5 bit number produces a 9 bit number, because you can overflow. For example, "11111111" + "11111" overflows a 8 bit output, but doesn't overflow a 9 bit output.

Related

How can I calculate elements in one vector?

I'm new at VHDL code, and I'm trying to figure out, how is the easiest way to calculate elements in STD_LOGIC_VECTOR.
so how my ports look like:
Port ( D : in STD_LOGIC_VECTOR (width-1 downto 0); -- data input
parity : out STD_LOGIC -- parity bit
);
so I want to do something like this (code in c)
int helper = 0;
for (int i = 0; i < width; i++) {
if (D[i] == 1) {
helper++;
}
}
if (helper % 2 == 0) {
parity = 1;
}
if im not enought clear sorry for that, i can probably answer your question, if there will be.
Probably the best way to do this in VHDL is with xor_reduce from ieee.std_logic_misc. Addition modulo 2 is exactly the same as XOR, and xor_reduce XORs all of the inputs together, giving you the addition modulo 2 of your input bits. This would look like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.xor_reduce;
entity PARITY_GEN is
generic (width : integer := 8);
port( D: in std_logic_vector(width-1 downto 0);
parity: out std_logic
);
end PARITY_GEN;
architecture bhv of PARITY_GEN is
begin
process(D)
begin
parity <= xor_reduce(D);
end process;
end bhv;
If you don't want to include xor_reduce, you could do the same just using xor:
library ieee;
use ieee.std_logic_1164.all;
entity PARITY_GEN is
generic (width : integer := 8);
port( D: in std_logic_vector(width-1 downto 0);
parity: out std_logic
);
end PARITY_GEN;
architecture bhv of PARITY_GEN is
begin
process(D)
variable temp:std_logic_vector(width-1 downto 0);
begin
temp(0) := D(0);
loop:for i in 1 to width-1 generate
temp(i) := temp(i-1) xor D(i);
end generate;
parity <= temp(width-1);
end process;
end bhv;

VHDL n-bit barrel shifter

I have a 32 bit barrel shifter using behavior architecture. Now I need to convert it to an n-bit shifter. The problem that I'm facing is that there is some kind of restriction to the for loop that I have to put a constant as sentinel value.
Following is my Code
library IEEE;
use IEEE.std_logic_1164.all;
Entity bshift is -- barrel shifter
port (left : in std_logic; -- '1' for left, '0' for right
logical : in std_logic; -- '1' for logical, '0' for arithmetic
shift : in std_logic_vector(4 downto 0); -- shift count
input : in std_logic_vector (31 downto 0);
output : out std_logic_vector (31 downto 0) );
end entity bshift;
architecture behavior of bshift is
function to_integer(sig : std_logic_vector) return integer is
variable num : integer := 0; -- descending sig as integer
begin
for i in sig'range loop
if sig(i)='1' then
num := num*2+1;
else
num := num*2;
end if;
end loop; -- i
return num;
end function to_integer;
begin -- behavior
shft32: process(left, logical, input, shift)
variable shft : integer;
variable out_right_arithmetic : std_logic_vector(31 downto 0);
variable out_right_logical : std_logic_vector(31 downto 0);
variable out_left_logical : std_logic_vector(31 downto 0);
begin
shft := to_integer(shift);
if logical = '0' then
out_right_arithmetic := (31 downto 32-shft => input(31)) &
input(31 downto shft);
output <= out_right_arithmetic after 250 ps;
else
if left = '1' then
out_left_logical := input(31-shft downto 0) &
(shft-1 downto 0 => '0');
output <= out_left_logical after 250 ps;
else
out_right_logical := (31 downto 32-shft => '0') &
input(31 downto shft);
output <= out_right_logical after 250 ps;
end if;
end if;
end process shft32;
end architecture behavior; -- of bshift
any help will be appreciated
Your code is not a barrel shifter implementation, because a barrel shift is a mux-tree.
If you have a 32 bit BarrelShifter module, you will need a 5 bit Shift input, wherein every bit position i enables a 2^i shift operation.
So for example shift = 5d -> 00101b enables a mux in stage 1 to shift for 1 bit and a mux in stage 3 to shift 4 bits. All other mux stages are set to pass through (shift(i) = 0).
I also would not advice to mix up basic shifting with shift modes (arithmetic, logic, rotate) and directions (left, right).
arithmetic and logic is only different in the shift-in value
shift right can be done by a conversion => shiftright = reverse(shiftleft(reverse(input), n)
An open source implementation can be found here:
https://github.com/VLSI-EDA/PoC/blob/master/src/arith/arith_shifter_barrel.vhdl

VHDL: Is there a convenient way to assign ascii values to std_logic_vector?

In verilog, I can assign a string to a vector like:
wire [39:0] hello;
assign hello = "hello";
In VHDL, I'm having difficulty finding a method like this:
SIGNAL hello : OUT std_logic_vector (39 DOWNTO 0);
...
hello <= "hello";
I've been using:
hello <= X"65_68_6c_6c_6f";
which is unclear and time consuming for large strings.
I've looked at the textio package and thetxt_util package, but neither seem to be very clear on how to interpret a string and convert it to std_logic.
Is there a simple method of assigning ascii codes to std_logic in VHDL?
Here's a minimal example:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test IS
PORT(
ctrl : IN std_logic;
stdout : OUT std_logic_vector (39 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE rtl OF test IS
SIGNAL temp : std_logic_vector (39 DOWNTO 0);
BEGIN
stdout <= temp;
PROCESS(ctrl)
BEGIN
IF (ctrl = '0') THEN
temp <= "hello"; -- X"68_65_6C_6C_6F";
ELSE
temp <= "world";
END IF;
END PROCESS;
END rtl;
This one varies little for Morten's answer - it only uses one multiply, it copies the string instead of creating an alias, it uses an additional variable and it returns a standard logic vector with an ascending index range.
From a package called string_utils:
library ieee;
use ieee.numeric_std.all;
-- ...
function to_slv(s: string) return std_logic_vector is
constant ss: string(1 to s'length) := s;
variable answer: std_logic_vector(1 to 8 * s'length);
variable p: integer;
variable c: integer;
begin
for i in ss'range loop
p := 8 * i;
c := character'pos(ss(i));
answer(p - 7 to p) := std_logic_vector(to_unsigned(c,8));
end loop;
return answer;
end function;
You could add an argument with a default specifying ascending/descending index range for the return value. You'd only need to provided the argument for the non default.
A small general function is one way to do it, with a suggestion below:
library ieee;
use ieee.numeric_std.all;
...
-- String to std_logic_vector convert in 8-bit format using character'pos(c)
--
-- Argument(s):
-- - str: String to convert
--
-- Result: std_logic_vector(8 * str'length - 1 downto 0) with left-most
-- character at MSBs.
function to_slv(str : string) return std_logic_vector is
alias str_norm : string(str'length downto 1) is str;
variable res_v : std_logic_vector(8 * str'length - 1 downto 0);
begin
for idx in str_norm'range loop
res_v(8 * idx - 1 downto 8 * idx - 8) :=
std_logic_vector(to_unsigned(character'pos(str_norm(idx)), 8));
end loop;
return res_v;
end function;
To return an ascii value of a character, use this code:
some_variable <= character'pos('a'); --returns the 'a' ascii value
In your example you are trying to assign a string type to a std_logic_vector type.
That is simply not allowed. VHDL is strongly typed.
SIGNAL hello : OUT std_logic_vector (39 DOWNTO 0);
...
hello <= "hello";
If your goal is to convert from hexa to ascii for printing simulation result
you can simply do that:
character'val(to_integer(unsigned(my_std_logic_vector)))

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.

Multiplication of a scalar with a vector

I am writing code in VHDL in which a number is multiplied by a vector. But it gives an error.
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity multi is
port ( clk : in std_logic;
ipixel : in std_logic_vector(15 downto 0);
opixel : out std_logic_vector(15 downto 0)
);
end entity multi;
architecture rtl of multi is
begin
process (clk) begin
if rising_edge (clk) then
opixel (15 downto 11) <= std_logic_vector(unsigned(ipixel(15 downto 11))*3);
opixel (10 downto 5) <= std_logic_vector(unsigned(ipixel(10 downto 5))* 3);
opixel (4 downto 0) <= std_logic_vector(unsigned(ipixel(4 downto 0))* 3);
end if;
end process;
end architecture rtl;
The error is:
Target slice 5 elements; Value is 10 elements
When you multiply an unsigned value with a natural, this is defined in NUMERIC_STD as follows:
function "*" (L: UNSIGNED; R: NATURAL) return UNSIGNED is
begin
return L * TO_UNSIGNED(R, L'LENGTH);
end "*";
Return value will result in 2 * length of your unsigned factor!

Resources