I want to apologize for this + - popular question, but nowhere did I find a specific implementation on vhdl. I write the algorithm from scratch and I have a problem with math implementation. The output is invalid. nothing counts, but just shows 1 value. If someone knows what i need to do, how to fix it, would be very grateful for any help.
Math part
library IEEE;
use IEEE.STD_LOGIC_1164.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 massive is
port (
clk : in std_logic;
reset : in std_logic;
sinus : out std_logic_vector (15 downto 0));
end massive;
architecture Behavioral of massive is
type my_type is array (0 to 16) of signed (15 downto 0);
signal x : my_type;
signal y : my_type;
signal z : my_type;
signal j : my_type := ("1010111111001000", "0110011111000101", "0011011011010100", "0001101111010101", "0000110111111000",
"0000011011111110", "0000001101111111", "0000000111000000", "0000000011100000", "0000000001110000",
"0000000000111000", "0000000000011100", "0000000000001110", "0000000000000111", "0000000000000100",
"0000000000000010", "0000000000000001");
begin
process(clk)
begin
x(0) <= "0000010100000110";
y(0) <= "0000000000000000";
z(0) <= "0000000000000000";
if rising_edge(clk) then
if reset <= '1' then
For n in 0 to 15 loop
if (z(n) >= 0) then
x(n+1) <= x(n) - (y(n)/2**n);
y(n+1) <= y(n) + (x(n)/2**n);
z(n+1) <= z(n) + j(n);
else
x(n+1) <= x(n) +(y(n)/2**n);
y(n+1) <= y(n) -(x(n)/2**n);
z(n+1) <= z(n) - j(n);
end if;
end loop;
sinus <= std_logic_vector(y(16));
end if;
end if;
end process;
end Behavioral;
Rotation part
entity step_control is
generic (
first : integer := 0;
second : integer := 1;
third : integer := 2;
fourth : integer := 3;
);
Port ( clk : in STD_LOGIC;
Angle : out STD_LOGIC_VECTOR (12 downto 0);
quarter_in : out STD_LOGIC_VECTOR (1 downto 0));
end step_control;
architecture Behavioral of step_control is
signal Ang : std_logic_vector (12 downto 0) := (others => '0');
signal state : unsigned (1 downto 0) := to_unsigned(first,2);
signal count_ang : std_logic_vector (11 downto 0) := (others => '0');
begin
process (clk)
begin
if (rising_edge(clk)) then
case(state) is
when to_unsigned(first,2) => if (count_ang >= 3999) then --00
state <= to_unsigned(second,2);
count_ang <= "000000010000";
quarter_in <= "01";
Ang <= Ang - 16;
else
state <= to_unsigned(first,2);
quarter_in <= "00";
Ang <= Ang + 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(second,2) => if (count_ang >= 3999) then --01
state <= to_unsigned(third,2);
count_ang <= "000000010000";
quarter_in <= "10";
Ang <= Ang + 16;
else
state <= to_unsigned(second,2);
quarter_in <= "01";
Ang <= Ang - 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(third,2) => if (count_ang >= 3999) then
state <= to_unsigned(fourth,2);
count_ang <= "000000010000";
quarter_in <= "11";
Ang <= Ang - 16;
else
state <= to_unsigned(third,2);
quarter_in <= "10";
Ang <= Ang + 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(fourth,2) => if (count_ang >= 3999) then
state <= to_unsigned(first,2);
count_ang <= "000000010000";
quarter_in <= "00";
Ang <= Ang + 16;
else
state <= to_unsigned(fourth,2);
quarter_in <= "11";
Ang <= Ang - 16;
count_ang <= count_ang + 16;
end if;
when others => count_ang <= (others => '0');
end case;
end if;
end process;
Angle <= Ang;
end Behavioral;
And testbench (but I do not know, I'm kind of all asking in the module. and my "empty" tesbench is obtained)
ENTITY testmass IS
END testmass;
ARCHITECTURE behavior OF testmass IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT massive
PORT(
clk : IN std_logic;
reset : IN std_logic;
sinus : OUT std_logic_vector(15 downto 0)
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal reset : std_logic := '0';
--Outputs
signal sinus : std_logic_vector(15 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: massive PORT MAP (
clk => clk,
reset => reset,
sinus => sinus
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
Your question isn't a Minimal, Complete and Verifiable example, it's not verifiable:
Describe the problem. "It doesn't work" is not a problem statement. Tell us what the expected behavior should be. Tell us what the exact wording of the error message is, and which line of code is producing it. Put a brief summary of the problem in the title of your question.
The output is invalid. nothing counts, but just shows 1 value.
What's the one value? When someone attempts to duplicate your problem one thing we see is assertion warnings for each evaluation of z(n) in the process in entity massive:
if (z(n) >= 0) then
The issue is subtle as basic to VHDL signals.
You assign values to signals in the process and expect them to be immediately available. That does not occur. No signal is updated while any process has yet to have been resumed and subsequently suspended in the current simulation cycle.
For each simulation time in the projected output waveform (a queue) there is only one entry. Subsequent assignments (which don't occur here) would result in only the last value being queued.
More important is that the future value isn't available in the current simulation cycle.
x, y and z can be variables declared in the process instead:
architecture foo of massive is
-- not predefined before -2008:
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (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 function;
begin
process (clk)
type my_type is array (0 to 16) of signed (15 downto 0);
variable x: my_type;
variable y: my_type;
variable z: my_type;
constant j: my_type := ("1010111111001000", "0110011111000101",
"0011011011010100", "0001101111010101",
"0000110111111000", "0000011011111110",
"0000001101111111", "0000000111000000",
"0000000011100000", "0000000001110000",
"0000000000111000", "0000000000011100",
"0000000000001110", "0000000000000111",
"0000000000000100", "0000000000000010",
"0000000000000001");
begin
x(0) := "0000010100000110";
y(0) := "0000000000000000";
z(0) := "0000000000000000";
if rising_edge(clk) then
if reset = '0' then -- reset not driven condition was <=
report "init values:" & LF & HT &
"x(0) = " & to_string(x(0)) & LF & HT &
"y(0) = " & to_string(y(0)) & LF & HT &
"z(0) = " & to_string(z(0));
for n in 0 to 15 loop
if z(n) >= 0 then
x(n + 1) := x(n) - y(n) / 2 ** n;
y(n + 1) := y(n) + x(n) / 2 ** n;
z(n + 1) := z(n) + j(n);
else
x(n + 1) := x(n) + y(n) / 2 ** n;
y(n + 1) := y(n) - x(n) / 2 ** n;
z(n + 1) := z(n) - j(n);
end if;
report "n = " & integer'image(n) & LF & HT &
"x(" & integer'image(n + 1) & ") = " &
to_string(x(n + 1)) & LF & HT &
"y(" & integer'image(n + 1) & ") = " &
to_string(y(n + 1)) & LF & HT &
"z(" & integer'image(n + 1) & ") = " &
to_string(z(n + 1));
end loop;
sinus <= std_logic_vector(y(16));
report "sinus = " & to_string(y(16));
end if;
end if;
end process;
end architecture foo;
The report statements are added to allow the values to be output to the simulation console. Without the passage of time between successive assignments to variables values of variables in waveform have no useful meaning. There are simulators that won't report variables in waveform dumps.
And the above architecture produces:
ghdl -a testmass.vhdl
ghdl -e testmass
ghdl -r testmass
testmass.vhdl:86:17:#5ns:(report note): init values:
x(0) = 0000010100000110
y(0) = 0000000000000000
z(0) = 0000000000000000
testmass.vhdl:100:21:#5ns:(report note): n = 0
x(1) = 0000010100000110
y(1) = 0000010100000110
z(1) = 1010111111001000
testmass.vhdl:100:21:#5ns:(report note): n = 1
x(2) = 0000011110001001
y(2) = 0000001010000011
z(2) = 0100100000000011
testmass.vhdl:100:21:#5ns:(report note): n = 2
x(3) = 0000011011101001
y(3) = 0000010001100101
z(3) = 0111111011010111
testmass.vhdl:100:21:#5ns:(report note): n = 3
x(4) = 0000011001011101
y(4) = 0000010101000010
z(4) = 1001101010101100
testmass.vhdl:100:21:#5ns:(report note): n = 4
x(5) = 0000011010110001
y(5) = 0000010011011101
z(5) = 1000110010110100
testmass.vhdl:100:21:#5ns:(report note): n = 5
x(6) = 0000011011010111
y(6) = 0000010010101000
z(6) = 1000010110110110
testmass.vhdl:100:21:#5ns:(report note): n = 6
x(7) = 0000011011101001
y(7) = 0000010010001101
z(7) = 1000001000110111
testmass.vhdl:100:21:#5ns:(report note): n = 7
x(8) = 0000011011110010
y(8) = 0000010010000000
z(8) = 1000000001110111
testmass.vhdl:100:21:#5ns:(report note): n = 8
x(9) = 0000011011110110
y(9) = 0000010001111010
z(9) = 0111111110010111
testmass.vhdl:100:21:#5ns:(report note): n = 9
x(10) = 0000011011110100
y(10) = 0000010001111101
z(10) = 1000000000000111
testmass.vhdl:100:21:#5ns:(report note): n = 10
x(11) = 0000011011110101
y(11) = 0000010001111100
z(11) = 0111111111001111
testmass.vhdl:100:21:#5ns:(report note): n = 11
x(12) = 0000011011110101
y(12) = 0000010001111100
z(12) = 0111111111101011
testmass.vhdl:100:21:#5ns:(report note): n = 12
x(13) = 0000011011110101
y(13) = 0000010001111100
z(13) = 0111111111111001
testmass.vhdl:100:21:#5ns:(report note): n = 13
x(14) = 0000011011110101
y(14) = 0000010001111100
z(14) = 1000000000000000
testmass.vhdl:100:21:#5ns:(report note): n = 14
x(15) = 0000011011110101
y(15) = 0000010001111100
z(15) = 0111111111111100
testmass.vhdl:100:21:#5ns:(report note): n = 15
x(16) = 0000011011110101
y(16) = 0000010001111100
z(16) = 0111111111111110
testmass.vhdl:109:17:#5ns:(report note): sinus = 0000010001111100
Where we see the values of your array elements are changing instead of propagating 'X's through addition (or subtraction when z(n) < 0), assigned in the previous loop iteration.
Also note the reset doesn't change value in the testbench and there is an erroneous evaluation for it's value using the relational operator "<=" in the original massive process.
j is not assigned other than an initial value and is shown as a constant in the above architecture.
I'm personally somewhat skeptical you can perform these 16 chained additions or subtractions along with selecting which operation in one 10 ns clock.
Related
I'm new to VHDL and I'm writing a test bench for an XNOR gate. The simple solution was to manually go through each combination of the two inputs but with more inputs this will take too long. How can I write this as a for loop in VHDL?
process
begin
p0 <= '1';
p1 <= '0';
wait for 1 ns;
if (pout = '1') then
error <= '1';
end if;
wait for 200 ns;
p0 <= '1';
p1 <= '1';
wait for 1 ns;
if (pout = '0') then
error <= '1';
end if;
wait for 200 ns;
p0 <= '0';
p1 <= '1';
wait for 1 ns;
if (pout = '1') then
error <= '1';
end if;
wait for 200 ns;
p0 <= '0';
p1 <= '0';
wait for 1 ns;
if (pout = '0') then
error <= '1';
end if;
wait for 200 ns;
end process;
If p0 and p1 are inputs to the device under test and their base type is compatible with the element type of type unsigned:
library ieee;
use ieee.std_logic_1164.all;
entity xnor2 is
port (
p0: in std_logic;
p1: in std_logic;
pout: out std_logic
);
end entity;
architecture foo of xnor2 is
begin
pout <= not (p0 xor p1);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity inputs is
end entity;
architecture foo of inputs is
signal p0, p1, pout: std_logic;
signal error: std_logic := '0';
begin
DUT:
entity work.xnor2
port map (
p0 => p0,
p1 => p1,
pout => pout
);
process
use ieee.numeric_std.all; -- for example, if not already visible
variable elements: unsigned (1 downto 0);
begin
elements := (others => '0');
for i in 0 to 2 ** elements'length - 1 loop
p0 <= elements(0);
p1 <= elements(1);
wait for 1 ns;
report LF & "i = " & integer'image(i) &
LF & HT & "p0 = " & std_ulogic'image(p0) &
" p1 = " & std_ulogic'image(p1) &
" error = " & std_ulogic'image(error);
if pout = '0' then
error <= '1';
end if;
wait for 200 ns;
elements := elements + 1;
end loop;
wait;
end process;
end architecture;
Which reports:
ghdl -r inputs
inputs.vhdl:45:13:#1ns:(report note):
i = 0
p0 = '0' p1 = '0' error = '0'
inputs.vhdl:45:13:#202ns:(report note):
i = 1
p0 = '1' p1 = '0' error = '0'
inputs.vhdl:45:13:#403ns:(report note):
i = 2
p0 = '0' p1 = '1' error = '1'
inputs.vhdl:45:13:#604ns:(report note):
i = 3
p0 = '1' p1 = '1' error = '1'
Where we also see error has no obvious meaning.
Without providing a minimal, complete, and verifiable example in the question there's some risk an answer may have one or more errors and future readers can't as easily verify the solution.
The idea here is to use a binary representing counter with as many bits (elements) as inputs and assign the value of bits (elements) to respective inputs in each loop iteration.
That binary value can also be provided directly from the integer value of the loop parameter. See How to easily group and drive signals in VHDL testbench which also uses aggregate assignment:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity agg_assign is
end entity;
architecture foo of agg_assign is
signal A, B, C: std_logic;
begin
process
begin
wait for 10 ns;
for i in 0 to 7 loop
(A, B, C) <= std_logic_vector(to_unsigned(i, 3));
wait for 10 ns;
end loop;
wait;
end process;
end architecture;
You can also create a record subtype to mix element and array assignments:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity aggr_rec_assign is
end entity;
architecture foo of aggr_rec_assign is
signal A, B, C: std_logic;
signal D: std_logic_vector (2 downto 0);
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (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 function;
begin
process
type inputs_rec is
record
A: std_logic;
B: std_logic;
C: std_logic;
D: std_logic_vector (2 downto 0);
end record;
variable elements: unsigned (5 downto 0);
begin
wait for 10 ns;
for i in 0 to 2 ** elements'length - 1 loop
elements := to_unsigned(i, elements'length);
(A, B, C, D) <=
inputs_rec'(
elements(5),
elements(4),
elements(3),
std_logic_vector(elements(2 downto 0))
);
wait for 10 ns;
report LF & HT & "i = "& integer'image(i) & " (A, B, C, D) = " &
std_ulogic'image(A) & " " &
std_ulogic'image(B) & " " &
std_ulogic'image(C) & " " &
to_string(D);
end loop;
wait;
end process;
end architecture;
where in both cases the aggregate assignment would be the place to select the order inputs are extracted from the binary value.
I have problem with assignment and cant solve it. In this part of code:
KS1 <= regA when Y(5)='0' else
not regA(0) & not regA(0) & regA(1 to 3) & "000" when (Y(5)='1' and regA(0)='1') else
(not(regA(0) & regA) +'1') & "000";
ERROR
ERRROR: In process OperationUnit.vhd:94
Target Size 8 and source size 12 for array dimension 0 does not match.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
entity OperationUnit is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
A : in STD_LOGIC_VECTOR (0 to 7);
B : in STD_LOGIC_VECTOR (0 to 3);
Y : in STD_LOGIC_VECTOR (1 to 11);
R : out STD_LOGIC_VECTOR (0 to 7);
P : out STD_LOGIC_VECTOR (0 to 1);
F : out STD_LOGIC_VECTOR (0 to 2));
end OperationUnit;
architecture OperationUnit_arch of OperationUnit is
signal regA : std_logic_vector(0 to 7); -- Register А
signal regB : std_logic_vector(0 to 3); -- Register В
signal regR : std_logic_vector(0 to 7) := (others => '0'); -- Register Result, fill zeros.
signal regP : std_logic_vector(0 to 1); -- Register of type of result
signal KS1 : std_logic_vector(0 to 7);
signal KS2 : std_logic_vector(0 to 7);
signal KS3 : std_logic_vector(0 to 7);
signal SM : std_logic_vector(0 to 8) := (others => '0'); -- sum
signal KS4 : std_logic_vector(0 to 7);
begin
regA_p : process(clk) -- process register A starting with change clock.
begin
if clk' event and clk = '1' then
if reset = '1' then -- reset synchronous
regA <= "00000000";
else
if Y(1) = '1' then
regA <= A & "0000";
elsif Y(2) = '1' then
regA<= regA(0) & '0' & regA(1 to 6);
end if;
end if;
end if;
end process regA_p;
regB_p : process(clk) -- process register B starting with change clock.
begin
if clk' event and clk = '1' then
if reset = '1' then -- reset synchronous
regB <= "0000";
else
if Y(3) = '1' then
regB <= B;
elsif Y(4) = '1' then
regB <= regB(0) & regB(2 to 3) & regB(0);
end if;
end if;
end if;
end process regB_p;
KS1 <= regA when Y(5)='0' else
not regA(0) & not regA(0) & regA(1 to 3) & "000" when (Y(5)='1' and regA(0)='1') else
(not(regA(0) & regA) +'1') & "000";
KS2 <= regA when Y(6)='0' else "00000000";
KS3 <= regR when Y(7)='0' else
regB(0) & regB(0) & regB(1 to 3) & "000" when (Y(7)='1' and regB(0)='0') else
regB(0) & regB(0) & (not(regB(1 to 3)) + '1');
SM <= (('0' & KS1) + ('0' & KS2) + SM(0)) after 1 ns;
KS4 <= (regA(0) xor regB(0)) & SM(2 to 8) when Y(8)='0' else
SM(1) &
((SM(5) and (not SM(3))) or
(SM(4) and (not SM(3)))or
(SM(3) and (not SM(4)) and (not SM(5)))) &
((SM(4) and (not SM(5))) or (SM(5) and (not SM(4)))) & SM(5) & "0000" when (Y(8)='1' and SM(1)='1') else
SM(1) & SM(3 to 5) & "0000";
regR_p : process(clk) -- process register R starting with change clock.
begin
if clk' event and clk = '1' then
if reset = '1' then -- reset synchronous
regR <= x"00";
else
case Y(9 to 10) is
when "01" => -- load
regR <= KS4(0 to 7);
when "10" => -- reset
regR <= x"00";
when others => null;
end case;
end if;
end if;
end process regR_p;
regP_p : process(clk) -- process register P starting with change clock.
begin
if clk' event and clk = '1' then
if reset = '1' then -- reset synchronous
regP <= "00";
else
if Y(11) = '1' then
if SM(3 to 7) = "00000" then
regP <= "00";
elsif (SM(1 to 2) = "00")and (SM(3 to 5) /= "000") then
regP <= "01";
elsif (SM(1 to 2) = "11")and (SM(3 to 5) /= "111") then
regP <= "10";
elsif (SM(1) /= SM(2)) then
regP <= "11";
end if;
end if;
end if;
end if;
end process regP_p;
R <= regR;
P <= regP;
F(0) <= regA(0);
F(1) <= regB(0);
F(2) <= regB(1);
end OperationUnit_arch;
You need to go through the size of target and source in assigns, since there is size mismatch several places, for example assign to regA in line 42:
A : in STD_LOGIC_VECTOR (0 to 7);
...
signal regA : std_logic_vector(0 to 7); -- Register А
...
regA <= A & "0000";
The target size is 8 bit (signal regA : in std_logic_vector(0 to 7)) and source size is 8 bit (A : in STD_LOGIC_VECTOR (0 to 7);) + 4 bit ("0000") = 12 bit.
There may be some warnings in the compile from ISim about all the places with size mismatch.
I have a problem with for loops in below code - in the simulation it shows like the only last increment of the loop is done, for example:
On the inputs I give (obviously in 8-bit SIGNED for the w0, w1, w2):
x1 = 1; x2 = 1; w0 = -32; w1 = 63; w2 = 63
and on the output I recieve u = 31 instead of u = 94.
So it seems the equation is:
u = (x2 * w2) - w0
Instead of:
u = (x1 * w1) + (x2 * w2) - w0
I know that the loops in VHDL works differently than in C, but the usage of variables should do the trick. Unfortunately, I'm missing something. What it might be?
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY NeuronBehavioral IS
GENERIC ( n: INTEGER := 1;
m: INTEGER := 2;
b: INTEGER := 8);
PORT ( x1 : in STD_LOGIC;
x2 : in STD_LOGIC;
w0 : in SIGNED (b-1 downto 0); --11100000 (-32)
w1 : in SIGNED (b-1 downto 0); --00111111 (63)
w2 : in SIGNED (b-1 downto 0); --00111111 (63)
u : out STD_LOGIC_VECTOR (b-1 downto 0));
END NeuronBehavioral;
ARCHITECTURE Behavioral OF NeuronBehavioral IS
TYPE weights IS ARRAY (1 TO n*m) OF SIGNED(b-1 DOWNTO 0);
TYPE inputs IS ARRAY (1 TO m) OF SIGNED(b-1 DOWNTO 0);
TYPE outputs IS ARRAY (1 TO n) OF SIGNED(b-1 DOWNTO 0);
BEGIN
PROCESS (w0, w1, w2, x1, x2)
VARIABLE weight: weights;
VARIABLE input: inputs;
VARIABLE output: outputs;
VARIABLE prod, acc: SIGNED(b-1 DOWNTO 0);
BEGIN
input(1) := "0000000" & x1;
input(2) := "0000000" & x2;
weight(1) := w1;
weight(2) := w2;
L1: FOR i IN 1 TO n LOOP
acc := (OTHERS => '0');
L2: FOR j IN 1 TO m LOOP
prod := input(j)*weight(m*(i-1)+j);
acc := acc + prod;
END LOOP L2;
output(i) := acc + w0;
END LOOP L1;
u <= STD_LOGIC_VECTOR(output(1));
END PROCESS;
END Behavioral;
Testbench:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY NeuronTB IS
END NeuronTB;
ARCHITECTURE behavior OF NeuronTB IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT NeuronBehavioral
PORT(
x1 : IN std_logic;
x2 : IN std_logic;
w0 : IN SIGNED(7 downto 0);
w1 : IN SIGNED(7 downto 0);
w2 : IN SIGNED(7 downto 0);
u : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal x1 : std_logic := '0';
signal x2 : std_logic := '0';
signal w0 : SIGNED(7 downto 0) := (others => '0');
signal w1 : SIGNED(7 downto 0) := (others => '0');
signal w2 : SIGNED(7 downto 0) := (others => '0');
--Outputs
signal u : std_logic_vector(7 downto 0);
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: NeuronBehavioral PORT MAP (
x1 => x1,
x2 => x2,
w0 => w0,
w1 => w1,
w2 => w2,
u => u
);
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
x1 <= '1';
x2 <= '1';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '1';
x2 <= '0';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '0';
x2 <= '1';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '0';
x2 <= '0';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait;
end process;
END;
The question did not originally provide a Minimal, Complete and Verifiable example, lacking the means to replicate the error much less the expected result. That's not the total barrier to the actual problems.
There's an out of bounds error for
prod := input(j) * weight( m * (i - 1) + j);
The right hand expression of type signed will have a length of the sum of the lengths of multiplicand (input(j)) and multiplier (weight( m * (i - 1) + j)).
Detecting the eventual effective value produced by evaluating the projected output waveform from the right hand expression in an assignment statement has a matching element for each element of the target is required by the standard (see IEEE Std 1076-2008 14.7.3.4 Signal update, -1993 thru -2002 12.6.2 Propagation of signal values).
(When tools allow suspension of performing this check by command line flag or configuration it's with the expectation that it would have been done at some point and that there's a performance increase in eliminating it.)
With regards to no needing an MCVe some simulators allow running a model with top level ports. This problem can identified by providing default values for all inputs. Depending on VHDL revision a report statement with to_string(output(1) can show the original cited answer.
port (
x1: in std_logic := '1'; -- default added
x2: in std_logic := '1'; -- default added
w0: in signed (b-1 downto 0) := to_signed(-32,b); --11100000 (-32) -- default added
w1: in signed (b-1 downto 0) := to_signed(63, b); --00111111 (63)
w2: in signed (b-1 downto 0) := to_signed(63, b); --00111111 (63)
u: out std_logic_vector (b-1 downto 0)
);
When run with ghdl the design specification produced a bounds failure in loop L2.
In the unlabeled process changing the declaration of prod:
variable prod: signed(b * 2 - 1 downto 0);
And the assignment to acc:
acc := acc + prod (b - 1 downto 0);
Allowed the calculation to complete, producing
neuronbehavioral.vhdl:58:9:#0ms:(report note): u = 01011110
With an added last statement to the process:
report "u = " & to_string (output(1));
For non VHDL-2008 compliant simulators a to_string function can be added to the declarative region of the process statement:
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (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 function;
Note the report value is the 8 bit signed value for 94.
Also the declarations for prod, acc and u should be examined to insure the design is capable of producing a result within the bounds of input values for w0, w1 and w2.
Not only is VHDL strongly typed, it's particular about mathematical meaning. It's an error if a result is incorrect, hence the product of the "*" operator has a length sufficient to produce a valid mathematical result. This can be seen in the numeric_std package body.
With the above patches to the design specification the testbench produces:
ghdl -r neurontb
neuronbehavioral.vhdl:58:9:#0ms:(report note): u = 00000000
neuronbehavioral.vhdl:58:9:#100ns:(report note): u = 01011110
neuronbehavioral.vhdl:58:9:#200ns:(report note): u = 00011111
neuronbehavioral.vhdl:58:9:#300ns:(report note): u = 00011111
neuronbehavioral.vhdl:58:9:#400ns:(report note): u = 11100000
Because input(j) can only be "00000000" or "000000001" based on the inputs x1 and x2) there's an alternative to the above changes:
prod := resize(input(j) * weight( m * (i - 1) + j), b);
The multiplier result can be resized (taking the least significant b length bits). the left most multiply is either by 0 or by 1.
Because the value of input(j) is either zero or one (as an 8 bit signed value) the first multiply can eliminated:
architecture foo of neuronbehavioral is
type weights is array (1 to n*m) of signed(b-1 downto 0);
-- type inputs is array (1 to m) of signed(b-1 downto 0); -- CHANGED
type inputs is array (1 to m) of std_logic;
type outputs is array (1 to n) of signed(b-1 downto 0);
begin
process (w0, w1, w2, x1, x2)
variable weight: weights;
variable input: inputs;
variable output: outputs;
-- variable prod: signed(b * 2 - 1 downto 0); -- RESTORED:
variable prod: signed(b - 1 downto 0);
variable acc: signed(b - 1 downto 0);
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (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 function;
begin
-- input(1) := "0000000" & x1; -- CHANGED
-- input(2) := "0000000" & x2; -- CHANGED
input := x1 & x2; -- ADDED
weight(1) := w1;
weight(2) := w2;
l1:
for i in 1 to n loop
acc := (others => '0');
l2:
for j in 1 to m loop
if input(j) = '1' then -- ADDED
-- prod := input(j) * weight( m * (i - 1) + j); -- CHANGED
prod := weight(m * (i - 1) + j); -- ADDED
else -- ADDED
prod := (others => '0'); -- ADDED
end if; -- ADDED
-- acc := acc + prod (b - 1 downto 0); -- RESTORED:
acc := acc + prod;
end loop l2;
output(i) := acc + w0;
end loop l1;
u <= std_logic_vector(output(1));
report "u = " & to_string (output(1));
end process;
end architecture foo;
For the second multiplier calculating the index for weight observe that all the variables are either generic constants or declared implicitly in loop statements. While the latter are dynamically elaborated at execution time in VHDL their value is considered static during traversal of the sequential statements in the each loop statement.
The sequence of statements in a loop statement are unrolled in synthesis. The equivalent in concurrent statements would be through the use of for generate statement replicating the various statements as concurrent statements. Note this would require signals (shared variables are not portable nor guaranteed to be supported for disparate vendor tool chains).
A concurrent statement version would look something like:
architecture foo of neuronbehavioral is
type weights is array (1 to n*m) of signed(b - 1 downto 0);
type inputs is array (1 to m) of std_logic;
type outputs is array (1 to n) of signed(b - 1 downto 0);
signal weight: weights;
signal input: inputs;
signal output: outputs;
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (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 function;
begin
weight <= w1 & w2;
input <= x1 & x2;
l1:
for i in 1 to n generate
type accums is array (1 to m) of signed (b - 1 downto 0);
signal accum: accums;
function acc (inp: accums) return signed is
variable retval: signed (b - 1 downto 0) := (others => '0');
begin
for i in accums'range loop
retval := retval + inp(i);
end loop;
return retval;
end function;
begin
l2:
for j in 1 to m generate
accum(j) <= weight(m * (i - 1) + j) when input(j) = '1' else
(others => '0');
end generate;
output(i) <= acc(accum) + w0;
end generate;
u <= std_logic_vector(output(1));
MONITOR:
process
begin
wait on x1, x2, w0, w1, w2;
wait for 0 ns;
wait for 0 ns;
wait for 0 ns;
wait for 0 ns;
report "u = " & to_string (output(1));
end process;
end architecture foo;
Where no multiply is used and all the statically indexed elements are accumulated in two places. The wait for 0 ns; statements in the MONITOR process are to overcome delta delays in 0 delay assignment through successive signals. (Somewhere there's something doing discrete events, for x1 and x2 if for no other purpose.)
This gives the same answer as above:
ghdl -r neurontb
neuronbehavioral.vhdl:169:9:#100ns:(report note): u = 01011110
neuronbehavioral.vhdl:169:9:#200ns:(report note): u = 00011111
neuronbehavioral.vhdl:169:9:#300ns:(report note): u = 00011111
neuronbehavioral.vhdl:169:9:#400ns:(report note): u = 11100000
and represents the same hardware.
I am new to VHDL, and I trying to verify UART receiver how is it works.
I synthesized the code below (quoted form the book) and its fine but if needs more let me know :).
The frequency for my board is 100 Mhz and the data I want receive is 8 bits, baud rate is 115200, how the clock and tick should be in the testbench or what is the right testbench here?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity uart_rx is
generic(
data_bits: integer := 8; -- # d a t a b i t s
stop_bit_ticks: integer := 16 -- # t i c k s f o r s t o p b i t s
);
Port ( rx : in STD_LOGIC;
clk : in STD_LOGIC;
reset: in STD_LOGIC;
tick : in STD_LOGIC;
rx_done : out STD_LOGIC;
data_out : out STD_LOGIC_VECTOR (7 downto 0));
end uart_rx;
architecture arch of uart_rx is
type state_type is (idle, start, data, stop);
SIGNAL state_reg, state_next: state_type;
SIGNAL s_reg, s_next: UNSIGNED(3 downto 0);
SIGNAL n_reg, n_next: UNSIGNED(2 downto 0);
SIGNAL b_reg, b_next: STD_LOGIC_VECTOR(7 downto 0);
begin
-- FSMD s t a t e & d a t a r e g i s t e r s
process(clk, reset) -- FSMD state and data regs.
begin
if (reset = '1') then
state_reg <= idle;
s_reg <= (others => '0');
n_reg <= (others => '0');
b_reg <= (others => '0');
--rx_done <= '0';
-- rx <= '1';
elsif (clk'event and clk='1') then
state_reg <= state_next;
s_reg <= s_next;
n_reg <= n_next;
b_reg <= b_next;
end if;
end process;
-- n e x t - s t a t e l o g i c & d a t a p a t h f u n c t i o n a l u n i t s / r o u t i n g
process (state_reg, s_reg, n_reg, b_reg, tick, rx)
begin
state_next <= state_reg;
s_next <= s_reg;
n_next <= n_reg;
b_next <= b_reg;
rx_done <= '0';
case state_reg is
when idle =>
if (rx = '0') then
state_next <= start;
s_next <= (others => '0');
end if;
when start =>
if (tick = '1') then
if (s_reg = 7) then
state_next <= data;
s_next <= (others => '0');
n_next <= (others => '0');
else
s_next <= s_reg + 1;
end if;
end if;
when data =>
if (tick = '1') then
if (s_reg = 15) then
s_next <= (others => '0');
b_next <= rx & b_reg(7 downto 1);
if (n_reg = (data_bits - 1)) then
state_next <= stop;
else
n_next <= n_reg + 1;
end if;
else
s_next <= s_reg + 1;
end if;
end if;
when stop =>
if (tick = '1') then
if (s_reg = (stop_bit_ticks - 1)) then
state_next <= idle;
rx_done <= '1';
else
s_next <= s_reg + 1;
end if;
end if;
end case;
end process;
data_out <= b_reg;
end arch;
Typically, UART receivers run at 8 times the bit rate. If your bit rate is 115200, this means a sample rate of 921600. If you are running at 100Mzh, you will need to create a clock divider to get you from 100 MHz to the desired sample rate. To go from 921600 to 100 MHz the following will work:
100 MHz = 100,000,000 Hz
921600 samples/sec = 921,600 Hz
divider = 100,000,000/921,600 = 108.51.
Thus, you will need a counter that will count up to 109 (we round up as we have to sample at an integer of the clock rate) on rising_edge(clock), then raise an enable signal that tells your component its time to sample the line and reset the counter. The example above assumed 8 samples/bit which is typical to my knowledge. Thus, if you set the period of your main clock in the simulation to be 1ns and set up the counter circuit I described above, you should get the test bench you are looking for.
EDIT: warning about uneven clock division
Almost forgot to mention this. Since your clock rate does not divide evenly into the bit rate for the UART, some extra care must be taken when coding up this circuit. Your sample rate will move later and later in the transmission with the scheme I have proposed. You will probably have to add a simple offset to change your counter to 108 on the even bits to keep you more aligned with the incoming data bits.
See here for some more info: https://electronics.stackexchange.com/questions/42236/uart-receiver-clock-speed
I am trying to implement a few "ball" bouncing around on a 800x600 screen. I dont completely understand how to make the 2nd ball move on the screen. Right now, it just stays on the screen statically at a certain position.
Here is a shot at what I've done so far.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pong is
Port ( myclk : in STD_LOGIC;
rgb : out STD_LOGIC_VECTOR (2 downto 0);
hs : out STD_LOGIC;
vs : out STD_LOGIC);
end pong;
architecture Behavioral of pong is
signal clk: STD_LOGIC;
signal horz_scan: STD_LOGIC_VECTOR (9 downto 0);
signal vert_scan: STD_LOGIC_VECTOR (9 downto 0);
signal vinc_flag: STD_LOGIC;
signal dx: STD_LOGIC;
signal dy: STD_LOGIC;
signal refresh_counter: STD_LOGIC;
signal posx: integer := 300;
signal posy: integer := 300;
signal color: STD_LOGIC_VECTOR (2 downto 0) := "111";
signal vinc_flag2: STD_LOGIC;
signal dx2: STD_LOGIC;
signal dy2: STD_LOGIC;
signal posx2: integer := 300;
signal posy2: integer := 300;
signal color2: STD_LOGIC_VECTOR (2 downto 0) := "001";
signal refresh_counter2: STD_LOGIC;
signal horz_scan2: STD_LOGIC_VECTOR (9 downto 0);
signal vert_scan2: STD_LOGIC_VECTOR (9 downto 0);
signal clk2: STD_LOGIC;
begin
-- Clock divide by 1/2
process(myclk)
begin
if myclk = '1' and myclk'Event then
clk <= not clk;
end if;
end process;
-- horizonal clock
process(clk)
begin
if clk = '1' and clk'Event then
if horz_scan = "1100100000" then
horz_scan <= "0000000000";
else
horz_scan <= horz_scan + 1;
end if;
end if;
end process;
-- vertial clock (increments when the horizontal clock is on the front porch
process(vinc_flag)
begin
if vinc_flag = '1' and vinc_flag'Event then
if vert_scan = "1000001001" then
vert_scan <= "0000000000";
refresh_counter <= refresh_counter xor '1';
else
vert_scan <= vert_scan + 1;
end if;
end if;
end process;
process(vinc_flag2)
begin
if vinc_flag2 = '1' and vinc_flag2'Event then
if vert_scan2 = "1000001001" then
vert_scan2 <= "0000000000";
refresh_counter2 <= refresh_counter2 xor '1';
else
vert_scan2 <= vert_scan2 + 1;
end if;
end if;
end process;
process(refresh_counter)
begin
if refresh_counter = '1' and refresh_counter'Event then
if dx = '0' then
posx <= posx + 1;
else
posx <= posx -1;
end if;
if dy = '0' then
posy <= posy + 1;
else
posy <= posy -1;
end if;
color <= "100";
end if;
end process;
process(refresh_counter2)
begin
if refresh_counter2 = '1' and refresh_counter2'Event then
if dx2 = '0' then
posx2 <= posx2 + 1;
else
posx2 <= posx2 -1;
end if;
if dy2 = '0' then
posy2 <= posy2 + 1;
else
posy2 <= posy2 -1;
end if;
color2 <= "001";
end if;
end process;
process(posx)
begin
if posx = 144 then
dx <= '0';
elsif posx = 734 then
dx <= '1';
end if;
end process;
process(posy)
begin
if posy = 35 then
dy <= '0';
elsif posy = 465 then
dy <= '1';
end if;
end process;
process(posx2)
begin
if posx = 144 then
dx <= '0';
elsif posx = 734 then
dx <= '1';
end if;
end process;
process(posy2)
begin
if posy = 35 then
dy <= '0';
elsif posy = 465 then
dy <= '1';
end if;
end process;
-- horizontal sync for 96 horizontal clocks (96 pixels)
hs <= '1' when horz_scan < 96 else '0';
-- vertial sync for 2 scan lines
vs <= '1' when vert_scan(9 downto 1) = "000000000" else '0';
rgb <= color when (vert_scan >= posy and vert_scan < (posy+50) and horz_scan >= posx and horz_scan < posx+50) or (vert_scan >= posy2 and vert_scan < (posy2+50) and horz_scan >= posx2 and horz_scan < (posx2+50)) else "000";
vinc_flag <= '1' when horz_scan = "1100011000" else '0';
end Behavioral;
There seems to be a copy and paste error in your code. The last two processes are sensitive to posx2 and posy2 respectively, but you seem to be changing the state of the first ball (dx and dy). Shouldn't you be changing dx2 and dy2 instead?
Also, here are two suggestions to make your code more readable:
Instead of declaring your counters as std_logic_vectors and comparing them against bit-string literals (e.g., if vert_scan2 = "1000001001" then ...), why not declare the counters as integers? That would contribute to making you code more readable.
Don't use "magic numbers" or hardcoded literals spread throughout your code (e.g., in the expression if posx = 144 then ..., 144 is a magic number). Instead, create a constant with a meaningful name (constant BALL_X_POS_MIN: integer := 144;) and use it in your expressions (if posx = BALL_X_POS_MIN then ...).