I'm new to VHDL and I have a problem I don't know how to resolve.
The problem appears when I'm doing the simulation, but the code compiles correctly.
Here is the problem :
entity fir is
port ( clock : in STD_LOGIC;
reset : in STD_LOGIC;
X : in STD_LOGIC_VECTOR (7 downto 0); -- X = X(n)
Y : out STD_LOGIC_VECTOR (16 downto 0)); -- Y = Y(n)
end fir;
architecture Behavioral of fir is
signal X_s, XZ1, XZ2, XZ3, XZ4, XZ5, XZ6, XZ7 : signed (7 downto 0); -- XZi = X(n-i)
signal Y_s : signed (16 downto 0);
constant A : signed(7 downto 0) := "00001011"; -- A=11
(constant B,C,D,E,F,G,H similary to A)
begin
process (clock, reset)
begin
X_s <= signed(X);
if (rising_edge(clock)) then
if (reset = '1') then
X_s <= (others => '0');
Y_s <= (others => '0');
XZ1, XZ2,XZ3...XZ7 <= (others => '0'); <= (others => '0');
else
XZ1 <= X_s;
XZ2 <= XZ1;
XZ3 <= XZ2;
XZ4 <= XZ3;
XZ5 <= XZ4;
XZ6 <= XZ5;
XZ7 <= XZ6;
end if;
end if;
end process;
Y_s <= (X_s*A) + (XZ1*B) + (XZ2*C) + (XZ3*D) + (XZ4*E) + (XZ5*F) + (XZ6*G) + (XZ7*H);
Y <= std_logic_vector(Y_s);
end Behavioral;
This line :
Y_s <= (X_s*A) + (XZ1*B) + (XZ2*C) + (XZ3*D) + (XZ4*E) + (XZ5*F) + (XZ6*G) + (XZ7*H);
returns this error : "array shape mismatch - no matching element"
I firstly think it was because of its size, but the problem is still there even if I replace this line :
Y_s <= (X_s*A) + (XZ1*B) + (XZ2*C) + (XZ3*D) + (XZ4*E) + (XZ5*F) + (XZ6*G) + (XZ7*H);
by this one :
Y_s <= (X_s*A);
However, it works with this line : (just to see if the rest of the code is correct) :
Y_s <= (others => '0');
What could I do ?
Thanks a lot.
Your simple case:
Y_s <= (X_s*A);
Y_s - 17 wires (16 downto 0). X_s - 8 wires (7 downto 0). A - 8 wires (7 downto 0). 8 + 8 != 17.
Complex sum:
Y_s <= (X_s*A) + (XZ1*B) + (XZ2*C) + (XZ3*D) + (XZ4*E) + (XZ5*F) + (XZ6*G) + (XZ7*H);
Result sizes for addition and multiplication:
| Operation | Size of result |
+------------+------------------------------+
| Y <= A + B | Maximum (A'Length, B'Length) |
| V <= A * B | A'Length + B'Length |
Therefore your whole sum has size 16: Maximum(8+8,8+8,8+8,8+8,8+8,8+8,8+8,8+8).
Section "“Signed”/“Unsigned” Addition without Overflow" on this page explains how to solve this.
Properly sizing Y_s should solve your problem.
You also should move the assignment X_s <= signed(x) outside the process statement and remove X_s<= (others => '0') assignment inside the reset condition.
Related
I have written a program in modelsim that add to numbers and put the result in Ra/Sum. I have used a tristate buffer, but I get this: Fatal: (vsim-3420) Array lengths do not match. Left is 16 (15 downto 0). Right is 8 (7 downto 0). I understand that this is because they have different lengths. But they cant have the same length either, because then I get an error when adding add1 and add2 and putting them in Sum. So what can I do to make this work?
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;
entity MAC is
generic (width: integer := 8);
port(
clk, reset : in STD_LOGIC;
MLS_select : in STD_LOGIC;
Rn, Rm, Ra : in STD_LOGIC_VECTOR(width-1 downto 0);
Rd : out STD_LOGIC_VECTOR(width-1 downto 0)
);
end;
architecture behavioral of MAC is
signal mul1, mul2, add1 : UNSIGNED(width-1 downto 0);
signal add2, sum : UNSIGNED(width*2-1 downto 0);
begin
process(clk, reset)
begin
if reset = '1' then Rd <= (others => '0');
elsif rising_edge(clk) then
Rd <= STD_LOGIC_VECTOR(sum(width-1 downto 0));
end if;
end process;
mul1 <= UNSIGNED(Rn);
mul2 <= UNSIGNED(Rm);
add1 <= UNSIGNED(Ra);
add2 <= mul1*mul2;
sum <= add2 when clk = '1' else add2;
sum <= add1+add2;
end architecture;
At first, ... when clk = '1' else ... will create a latch, but no flip-flop.
You need to use ... when rising_edge(clk);.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MAC is
generic (width: integer := 8);
port(
clk, reset : in STD_LOGIC;
MLS_select : in std_logic;
Rn, Rm, Ra : in std_logic_vector(width - 1 downto 0);
Rd : out std_logic_vector(width - 1 downto 0) := (others => '0')
);
end entity;
architecture rtl of MAC is
signal mul1, mul2, add1 : unsigned(width - 1 downto 0);
signal add2, sum : unsigned(width * 2 - 1 downto 0);
begin
process(clk, reset)
begin
if (reset = '1') then
Rd <= (others => '0');
elsif rising_edge(clk) then
Rd <= std_logic_vector(sum(Rd'range));
end if;
end process;
mul1 <= unsigned(Rn);
mul2 <= unsigned(Rm);
add1 <= unsigned(Ra);
add2 <= (mul1 * mul2) when rising_edge(clk);
sum <= resize(add1, add'length) + add2;
end architecture;
Signal MLS_select is unused. There is no need to calculate the sum with so many bits. I suggest to truncate add2 before the addition, to reduce the number of unused bits (and warnings generated by them).
I have an array / vector and I want to generate a new array by processing the first. A simple example of what I need is that every i-th element from the new array is the sum of the i-1, i, and i+1 elements from the first one.
I know this can be done very easily in a sequential manner by iterating through the array. I was wandering if there any kind of assigning expression that would generalize this and make this a parallel operation.(like in math: new[i] := old[i - 1] + old[i] + old[i + 1], where i ∈ (1, n) ).
As your question is about parallelism, I assume that you are interested in the hardware that will be synthesized from your VHDL description, not by the simulation.
Parallelism is a matter of when all these additions take place? If your design is synchronous - let's say of the rising edge of a clock named clk - then:
subtype word: unsigned(7 downto 0);
type word_array is array(natural range <>) of word;
signal a: word_array(0 to 15);
signal b: word_array(1 to 14);
...
process(clk)
begin
if rising_edge(clk) then
for i in 1 to 14 loop
b(i) <= a(i - 1) + a(i) + a(i + 1);
end loop;
end if;
end process;
will compute in parallel the 14 values in array b at each rising edge of the clock. And it will instantiate as many 8-bits adders as needed to do this. The question is not whether you are using a for loop or something else, it is really when do these operations take place? The answer is in the description: during the very same clock period.
You could overload the "+" operator to work on vectors:
function "+"(a, b: word_array) return word_array is
constant n: positive := a'length;
variable va: word_array(0 to n - 1) := a;
variable vb: word_array(0 to n - 1) := b;
variable sum: word_array(0 to n - 1);
begin
if n = 1 then
sum(0) := va(0) + vb(0);
else
sum := (va(0 to n / 2 - 1) + vb(0 to n / 2 - 1)) &
(va(n / 2 to n - 1) + vb(n / 2 to n - 1));
end if;
return sum;
end function "+";
and use it to apparently write a more parallel description:
process(clk)
begin
if rising_edge(clk) then
b <= a(0 to 13) + a(1 to 14) + a(2 to 15);
end if;
end process;
but it would make no difference and the resulting hardware would be the same.
You could also use a generate statement to do the same:
g: for i in 1 to 14 generate
process(clk)
begin
if rising_edge(clk) then
b(i) <= a(i - 1) + a(i) + a(i + 1);
end if;
end process;
end generate g;
but, again, it would make no difference for the synthesizer.
I want do drive a 4x16 LCD display using VHDL. The first line should say "FREQ: 000 RPM" where the zeroes represent incoming 8-bit frequency data. Same for the next lines with different data, also 8-bit. My VHDL code is as follows:
-- 16 Characters
subtype string16_type is string(1 to 16);
-- 4 string of 16 characters
type message4x16_type is array(1 to 4) of string16_type;
-- Define messages displayed
constant message_home: message4x16_type := ( --1234567890123456
1 => "FREE MODE ",
2 => "PARCOURS ",
3 => "- - - - - - - - ",
4 => " - - - - - - - -");
constant message_info: message4x16_type := ( --1234567890123456
1 => "FREQ: 000 RPM ",
2 => "SPEED: 000 KM/H ",
3 => "DIST: 000 KM ",
4 => "MORE INFO ");
-- Character amount in line
signal character_counter: integer range 1 to 16;
-- Line amount on LCD
signal line_counter : integer range 1 to 4;
Then follows a state machine, with state write_char looking partly like this:
if msg_select = '0' then
aline := message_home(line_counter);
elsif msg_select = '1' then
aline := message_info(line_counter);
end if;
data <= std_logic_vector(to_unsigned(character'pos(aline(character_counter)),8));
Everything works smoothily this way but I can't think of a way to implement the frequency data into the message, like using %i in C. I am aware of the 'record' statement but not sure how to use it in this situation. Any other ways to implement the data are very welcome.
Thanks on forehand.
Declaring types, constants and signals as before:
-- 16 characters
type lcd_line_type is array(0 to 15) of character;
-- 4 lines of 16 characters
type message4x16_type is array(0 to 3) of lcd_line_type;
-- Define messages displayed
constant message_home : message4x16_type := (
--1234567890123456
"FREE MODE ",
"PARCOURS ",
"- - - - - - - - ",
" - - - - - - - -"
);
constant message_info : message4x16_type := (
--1234567890123456
"FREQ: 000 RPM ",
"SPEED: 000 KM/H ",
"DIST: 000 KM ",
"MORE INFO "
);
-- Character amount in line
signal character_counter : integer range 0 to 15;
-- Line amount on LCD
signal line_counter : integer range 0 to 3;
subtype rawchar is std_logic_vector(7 downto 0);
type rawstring is array(natural range <>) of rawchar;
signal rpm : rawstring(2 downto 0);
signal kmh : rawstring(2 downto 0);
function to_rawchar(char : character) return rawchar is
begin
return std_logic_vector(to_unsigned(character'pos(char), 8));
end function;
Usage example:
if msg_select = '0' then
data <= to_rawchar(message_home(line_counter)(character_counter));
elsif msg_select = '1' then
case line_counter is
when 0 =>
-- replace 000 by rpm(2:0)
case character_counter is
when 6 => data <= rpm(2);
when 7 => data <= rpm(1);
when 8 => data <= rpm(0);
when others => data <= to_rawchar(message_info(0)(character_counter));
end case;
when 1 =>
-- replace 000 by kmh(2:0)
case character_counter is
when 7 => data <= kmh(2);
when 8 => data <= kmh(1);
when 9 => data <= kmh(0);
when others => data <= to_rawchar(message_info(1)(character_counter));
end case;
-- ...
end case;
end if;
The first case tests for the requested line. The second case overrides the constant values at particular positions.
I additionally extracted the char to slv conversion into a function.
I am writing VHDL code in which I have used tempx and tempz as variables and tried to concatenate them, but I am having some errors on the line annotated below. Suggestions on what to do please?
The errors are:
Error (10500): VHDL syntax error at ArrayDivider.vhd(53) near text ":="; expecting "(", or "'", or ".",
Error (10500): VHDL syntax error at ArrayDivider.vhd(53) near text "&"; expecting "(", or "'", or "."
Code:
------- Array Divider --------
library ieee;
use ieee.std_logic_1164.all;
----- Entity -----
entity ArrayDivider is
generic
(
---- For x/y
Nx : integer := 8; --- Number of bits in x
Ny : integer := 4 --- Number of bits in y
);
port
(
ipx : in std_logic_vector(Nx-1 downto 0); -- Input x --- (Nx-1 downto 0)
ipy : in std_logic_vector(Ny-1 downto 0); -- Input y --- (Ny-1 downto 0)
opd : out std_logic_vector(Nx-Ny downto 0); -- Quotient --- (Nx-Ny downto 0)
opr : out std_logic_vector(Ny-1 downto 0) -- Remainder --- (Ny-1 downto 0)
);
end ArrayDivider;
----- Architecture -----
Architecture Div of ArrayDivider is
--- This component will compare ipy with parts of ipx of given bits and ---
--- generate bits of divident as well as partial subtraction results ---
--- x = parts of ipx (tempx), y = ipy, op = opd(x) and final z = opr ---
component Cmp is
generic
(
N : integer := 4
);
port
(
x : in std_logic_vector(N-1 downto 0); --- N-1 downto 0
y : in std_logic_vector(N-1 downto 0); --- N-1 downto 0
z : out std_logic_vector(N-1 downto 0); --- N-1 downto 0
op : out std_logic
);
end Component;
variable tempx : std_logic_vector(Ny-1 downto 0) := ipx(Nx-1 downto Nx-Ny); --- (Ny-1 downto 0) (Nx-1 downto Nx-Ny)
variable tempz : std_logic_vector(Ny-1 downto 0); --- (Ny-1 downto 0)
begin
lup:
for a in Nx-Ny downto 0 generate --- Nx-Ny downto 0
begin
Cmpa: Cmp generic map(Ny) port map(tempx, ipy, tempz, opd(a)); --- (Ny)
grea:
if(a > 0) generate
tempx := tempz(Ny-2 downto 0) & ipx(a-1); --- (Ny-2 downto 0)
end generate grea;
zero:
if(a = 0) generate
opr <= tempz;
end generate zero;
end generate lup;
end Div;
as you are not using a process, you should use signals instead of variables for tempx and tempz. your line 53 must then look as follows:
tempx <= tempz(Ny-2 downto 0) & ipx(a-1);
however, probably the use of a process makes more sense. then you have to implement your cmp component as a procedure (not done in example below). the process could look as follows:
...
end Component;
begin
div_proc: process(ipy, ipx)
variable tempx : std_logic_vector(Ny-1 downto 0) ;
variable tempz : std_logic_vector(Ny-1 downto 0);
begin
lup:
for a in 1 downto 0 loop
-- Cmpa: Cmp generic map(Ny) port map(tempx, ipy, tempz, opd(a));
grea:
if(a > 0) then
tempx := tempz(Ny-2 downto 0) & ipx(a-1);
end if;
zero:
if(a = 0) then
opr <= tempz;
end if;
end loop;
end process div_proc;
...
I am new to VHDL and I searched all of the internet and i didnt find anything that would help me !
I am trying to add the elements of an array (32 Elements !), so i cant just write
for example s <= s(0) + s(1) + s(3) ... s(5) + ....s(32)
how can i generalise such a calculation ??
or what am i doing wrong ?
My Code (that didnt work in the simulation) is ..
(just for 5 elemets ....)
library IEEE;
library work;
library std;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use ieee.std_logic_arith.all;
entity main is Port (
EIN : in std_logic;
AUS_1 : out std_logic_vector(3 downto 0));
end main;
architecture Behaviour of main is
type Cosinus is array (0 to 4) of std_logic_vector(3 downto 0);
type Sinus is array (0 to 4) of std_logic_vector(3 downto 0);
Signal SumSin :std_logic_vector(3 downto 0);
begin
main : process(Ein)
variable Cos : Cosinus;
variable Sin : Sinus;
begin
if( Ein='1' ) then
sin(0) := "0011";
sin(1) := "0001";
sin(2) := "1010";
sin(3) := "1111";
sin(4) := "1110";
for n in 0 to 4 loop
SumSin <= SumSin + Sin(n);
end loop;
else
sin(0) := "1011";
sin(1) := "0101";
sin(2) := "1000";
sin(3) := "1001";
sin(4) := "1100";
for n in 0 to 4 loop
SumSin <= SumSin + Sin(n);
end loop;
end if;
end process;
Aus_1 <= SumSin;
end Behaviour;
I would be thanksfull
First... Don't use std_logic_arith.
Then, Use a variable for the running sum and assign is to a signal afterwards:
...
main : process(Ein)
variable Cos : Cosinus;
variable Sin : Sinus;
variable SumSin : signed(3 downto 0);
begin
sumsin := (others => '0');
....
for n in Sin'range loop
SumSin := SumSin + Sin(n);
end loop;
end if;
Aus_1 <= SumSin;
end process;