VHDL weird bit errors seemingly makes no sense - arrays

I have a Micro-Nova FPGA dev board with a Xilinx Spartan-3A. I am trying to make it communicate bits over GPIO on a raspberry pi using 3 pins: REQ, ACK, DATA. The code works fine if I uncomment the bit_data assignments and comment out "bit_data := data_out(data_ofs);" and on the Pi i get a continous 10101010... etc. But if I leave the code as pasted below I get the wrong bits at random times eg. 1010110100... etc.
Any idea what could be the problem?:
VHDL on FPGA:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity xclock is
Port(CLK : in STD_LOGIC;
REQ : in STD_LOGIC;
ACK : out STD_LOGIC;
DATA : out STD_LOGIC);
end xclock;
architecture Behavioral of xclock is
begin
process(CLK)
variable data_ofs : integer range 0 to 2 := 0;
variable data_out : std_logic_vector(1 downto 0) := "01";
variable bit_data : std_logic := '0';
variable ack_data : std_logic := '0';
variable LASTREQ : std_logic := '0';
variable seconds : integer range 0 to 50000000 := 0;
variable tick : integer range 0 to 50000000 := 0;
begin
if CLK'event and CLK = '1' then
tick := tick + 1;
if tick = 49999999 then
tick := 0;
seconds := seconds + 1;
if seconds = 49999999 then
seconds := 0;
end if;
end if;
if seconds > 1 then
if REQ /= LASTREQ and REQ /= ack_data then
LASTREQ := REQ;
if REQ = '1' then
--bit_data := '1';
ack_data := '1';
else
--bit_data := '0';
ack_data := '0';
end if;
bit_data := data_out(data_ofs);
data_ofs := data_ofs + 1;
if data_ofs = 2 then
data_ofs := 0;
end if;
end if;
end if;
DATA <= bit_data;
ACK <= ack_data;
end if;
end process;
end Behavioral;
Bash script on Pi:
REQ=27
ACK=17
DATA=22
gpio -g mode $REQ out
gpio -g mode $ACK in
gpio -g mode $DATA in
gpio -g write $REQ 1
e=1
while [ 1 ]; do
while [ 1 ]; do
if [ `gpio -g read $ACK` -eq 1 ]; then
while [ 1 ]; do
d=`gpio -g read $DATA`
echo $d
if [ $d -ne $e ]; then
echo error DATA should be $e
sleep 1
else
if [ $e -eq 0 ]; then
e=1
else
e=0
fi
break
fi
done
gpio -g write $REQ 0
break;
fi
done
while [ 1 ]; do
if [ `gpio -g read $REQ` -eq 0 ]; then
while [ 1 ]; do
d=`gpio -g read $DATA`
echo $d
if [ $d -ne $e ]; then
echo error DATA should be $e
sleep 1
else
if [ $e -eq 0 ]; then
e=1
else
e=0
fi
break
fi
done
gpio -g write $REQ 1
break;
fi
sleep 1
done
done
Any help will be greatly appreciated. Pulling my hair out on this one!

I spent some time trying to figure out how your code is supposed to work (what the protocol is), but I gave up. Building off what other have suggested, you might try to make the following modifications and see if it makes any difference.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity xclock is
port(CLK : in STD_LOGIC;
REQ : in STD_LOGIC;
ACK : out STD_LOGIC;
DATA : out STD_LOGIC);
end xclock;
architecture Behavioral of xclock is
signal req_reg1, req_reg2, req_int, last_req : std_logic := '0';
signal bit_data_reg, ack_reg : std_logic;
begin
process(CLK)
variable data_ofs : integer range 0 to 2 := 0;
variable data_out : std_logic_vector(1 downto 0) := "01";
variable bit_data : std_logic := '0';
variable ack_data : std_logic := '0';
variable seconds : integer range 0 to 50000000 := 0;
variable tick : integer range 0 to 50000000 := 0;
begin
if CLK'event and CLK = '1' then
-- Input registers help prevent metastability on REQ line
-- Note that if there is significant bounce or glitching, then
-- you will also need a deglitcher.
req_reg1 <= REQ;
req_reg2 <= req_reg1;
req_int <= req_reg2;
tick := tick + 1;
if tick = 49999999 then
tick := 0;
seconds := seconds + 1;
if seconds = 49999999 then
seconds := 0;
end if;
end if;
if seconds > 1 then
-- Using the registered inputs instead of the direct REQ input.
if req_int /= last_req and req_int /= ack_data then
last_req <= req_int;
if req_int = '1' then
ack_data := '1';
else
ack_data := '0';
end if;
bit_data := data_out(data_ofs);
data_ofs := data_ofs + 1;
if data_ofs = 2 then
data_ofs := 0;
end if;
end if;
end if;
-- Register outputs to ensure consistent OREG packing, if enabled
bit_data_reg <= bit_data;
ack_reg <= ack_data;
DATA <= bit_data_reg;
ACK <= ack_reg;
end if;
end process;
end Behavioral;
The modifications to the code do two things:
Register the input REQ a couple times to reduce the probability of metastability, and then only use the registered values instead of the pin itself. (Read more)
Register the outputs (twice) to ensure that the output register can be placed in an OREG (in IOB), which ensures consistent clock-to-out timing at the output pad. At the boundaries of your device, when possible, it is nice to place a plain FF register stage which guarantees that packing into OREG is possible. Otherwise there may be a feedback path from last register stage back into your design which prevents packing.

Related

Assigning to record type arrays in generate statements

How do you use record arrays in generate statements in VHDL? Below is what I have done, which passes synthesis and implementation in Vivado (2021.1). However, when I simulate it, it shows none of the record signals getting assigned and are always "U". I can also not find any examples of record fields used in port maps in generate statements.
type record_a_t is record
a : std_logic;
b : std_logic_vector(7 downto 0);
c : std_logic_vector(3 downto 0);
d : std_logic;
e : std_logic;
end record record_a_t;
type record_a_array_t is array (0 to 3) of record_a_t;
signal record_a_array : record_a_array_t;
Then, I generate the modules with signal mapping like:
GEN_MODULES : for i in 0 to 3 generate
modules : entity work.module
port map(
clk => clk,
rst_n => rst_n,
a => record_a_array(i).a,
b => record_a_array(i).b,
c => record_a_array(i).c,
d => record_a_array(i).d,
e => record_a_array(i).e
);
end generate GEN_MODULES;
Again, the above seems to pass all the tools syntax checking and builds in Vivado, but simulation (RivPro 2018) and implementation show signals not getting assigned or changing. They are always "U", even if driven from the module. For example, if port a is an output that is initialized in the module, record_a_array(i).c is always "U". Even the module output port is "U", as if the internal initialization is ignored, which makes no sense to me.
Below is an example.
Test Module:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity module is
port(
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : out std_logic_vector(7 downto 0);
c : out std_logic_vector(3 downto 0);
d : out std_logic;
e : out std_logic
);
end module;
architecture rtl of module is
begin
process(clk, rst_n)
begin
if(rst_n = '0') then
b <= (others=> '0');
c <= (others=> '0');
d <= '0';
e <= '0';
elsif(rising_edge(clk)) then
if(a = '1') then
b <= b + '1';
c <= c + '1';
d <= not d;
e <= not e;
end if;
end if;
end process;
end rtl;
Test Bench:
library ieee;
use ieee.std_logic_1164.all;
entity testbench is
end entity testbench;
---------------------------------------------------
architecture arch of testbench is
---------------------------------------------------
type record_a_t is record
a : std_logic;
b : std_logic_vector(7 downto 0);
c : std_logic_vector(3 downto 0);
d : std_logic;
e : std_logic;
end record record_a_t;
type record_a_array_t is array (0 to 3) of record_a_t;
signal record_a_array : record_a_array_t;
signal clk : std_logic := '1';
signal rst_n : std_logic := '0';
---------------------------------------------------
begin
clk <= not clk after 5 ns;
rst_n <= '1' after 20 ns;
GEN_MODULES : for i in 0 to 3 generate
modules : entity work.module
port map(
clk => clk,
rst_n => rst_n,
a => record_a_array(i).a,
b => record_a_array(i).b,
c => record_a_array(i).c,
d => record_a_array(i).d,
e => record_a_array(i).e
);
end generate GEN_MODULES;
process(clk, rst_n)
begin
if(rst_n = '0') then
for i in 0 to 3 loop
record_a_array(i).a <= '0';
end loop;
elsif(rising_edge(clk)) then
for i in 0 to 3 loop
record_a_array(i).a <= not record_a_array(i).a;
end loop;
end if;
end process;
end arch;
Simulation:
Simulation of module example
Notice how the record signals wired to the module outputs in at the TestBench level are never defined and how the outputs of the generated module instances themselves are not driven, even though they all get asserted in the reset condition. The only signal that gets driven is the 'a' signal from the test bench level.
Since the record is not crossing into the RTL space, unwanted drivers can be turned off using std_logic using 'Z':
constant REC_INIT : record_a_t := (
a => 'Z',
b => "ZZZZZZZZ",
c => "ZZZZ",
d => 'Z',
e => 'Z'
) ;
. . .
signal record_a_array : record_a_array_t := (0 to 3 => REC_INIT) ;
As you start to look at the issue in the LRM, you might also note you can find the issues the IEEE VHDL working group has recorded at: : https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues. There is a remotely related issue in https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues/275 that may be able to address both its issue and this one - though time will tell on that.
For verification, I use Open Source VHDL Verification Methodology (OSVVM). We use records on ports and as a result, use special resolution functions with them so they do not require initialization.

Modelsim. Length of arrays do not match

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).

VHDL: Multiple for loop serial execution

I might be new to synthesizing loops. I am trying to create a counting sort in VHDL which takes arbitary length(say N) of integer array as input for sorting.
The code for design heavily relies on for loop. The looping logic seems to be parallel within a process or may be across processes. So I put all of the for loop in one process. But with that, the loops seem to execute in parallel independently. Which defeats the purpose as one loop should follow the other.
I have used counting sort algorithm from https://www.geeksforgeeks.org/counting-sort/
I am unable to get the logic working as mentioned in the algorithm.
Q1: How does the for loop execute within a process. Does all the for loop execute in parallel.
Q2:Is there an alternate way of implementing this for loop logic in VHDL, so that it executes serially?
Q3:Are there limitations for synthesizing for loops?
Design code:
library ieee;
use ieee.std_logic_1164.all;
package sorting_pkg is
type intarray is array(natural range <>) of std_logic_vector(7 downto 0);
end package;
library ieee;
use ieee.std_logic_1164.all;
use work.sorting_pkg.all;
use IEEE.NUMERIC_STD.all;
use ieee.std_logic_unsigned.all;
entity Sorting is
generic (
N : integer );
port(
--clk : in STD_LOGIC;
rst : in STD_LOGIC;
inStream : in intarray(0 to N-1);
outStream : out intarray(0 to N-1);
BoutArray: out intarray(0 to 16);
CoutArray: out intarray(0 to 16)
);
end entity;
architecture behavior of Sorting is
signal BArray: intarray(0 to 16) := (others => "00000000");
signal CArray: intarray(0 to 16) := (others => "00000000");
signal DArray: intarray(0 to 16) := (others => "00000000");
--signal Aindex1,Aindex2,Cindex,k: std_logic_vector(7 downto 0);
--signal Aindex1,Aindex2,Cindex,k : natural range 0 to 16;
begin
process
begin
if(rst = '1') then
outStream <=(others => "00000000");
else
Bloop: for i in 0 to N-1 loop
BArray(to_integer(unsigned(inStream(i)))) <=BArray(to_integer(unsigned(inStream(i)))) + 1;
end loop;
CArray(0) <= BArray(0);
Cloop: for j in 1 to 16 loop
CArray(j) <= BArray(j) + CArray(j - 1);
end loop;
Coutloop:for l in 0 to N-1 loop
DArray(to_integer(unsigned(inStream(l)))) <= CArray(to_integer(unsigned(inStream(l)))) - 1;
end loop;
outloop:for m in 0 to N-1 loop
outStream(to_integer(unsigned(DArray(to_integer(unsigned(inStream(m))))))) <= inStream(m);
end loop;
BoutArray <= BArray;
CoutArray <= DArray;
end if;
wait;
end process;--end proc
end architecture;
Testbench code:
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.sorting_pkg.all;
use IEEE.NUMERIC_STD.all;
use ieee.std_logic_unsigned.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 leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity tb_camera is
-- Port ( );
end tb_camera;
architecture Behavioral of tb_camera is
component Sorting
generic (
N : integer := 10);
PORT
(--clk: in std_logic;
rst : in std_logic;
inStream : in intarray(0 to 9);
outStream : out intarray(0 to 9);
BoutArray: out intarray(0 to 16);
CoutArray: out intarray(0 to 16)
);
end component;
signal A : intarray(0 to 9);
signal D : intarray(0 to 9);
signal rst_tb : std_logic;
-- signal clk_tb : std_logic;
signal BoutArray : intarray(0 to 16);
signal CoutArray : intarray(0 to 16);
--constant clk_period : time :=500ns;
begin
uut:Sorting port map (inStream => A, outStream => D, rst => rst_tb,
BoutArray => BoutArray, CoutArray=> CoutArray );
sim_tb:process
begin
wait for 100ns;
rst_tb<='1';
wait for 100ns;
rst_tb<='0';
--wait for 50ns;
A(0 to 9) <= (0 => x"07",
1 => x"09",
2 => x"06",
3 => x"02",
4 => x"05",
5 => x"00",
6 => x"08",
7 => x"01",
8 => x"03",
9 => x"04");
wait;
end process;
end Behavioral;

Swap elements in an array - VHDL

I have a piece of code in VHDL:
I want to swap the signalIn(0) and signalIn(1) values.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity SwapFP is
port(clockIn:in std_logic);
end SwapFP;
architecture Behavioral of SwapFP is
signal tempOne,tempTwo,a1,a2 : STD_LOGIC_VECTOR(31 DOWNTO 0);
signal state : integer range 0 to 7 := 0;
begin
process(clockIn) is
type floatingPointArray is array(1 downto 0) of std_logic_vector(31 downto 0);
variable signalIn : floatingPointArray;
begin
signalIn(0) := X"3D52CEF8";
signalIn(1) := X"3FBC9F1A";
if rising_edge(clockIn) then
case state is
when 0 =>
tempOne <= signalIn(0);
tempTwo <= signalIn(1);
state <= 1;
when 1 =>
signalIn(1) := tempOne;
signalIn(0) := tempTwo;
state <= 2;
when 2 =>
a1 <= signalIn(0);
a2 <= signalIn(1);
state <= 3;
when others =>
end case;
end if;
end process;
end Behavioral;
In a1 and a2 signals, I am getting the original values X"3D52CEF8" and X"3FBC9F1A" respectively. Means that swapping is not happening. Why is it so?
Your variable assignments to signalIn at the top of the process happen every time the process runs. When state is 2, the values you assigned to signalIn when state equaled 1 are overwritten by this initial assignment.
You can much more easily swap two items like this:
process (clk)
begin
if (rising_edge(clk)) then
signalIn(0) <= signalIn(1);
signalIn(1) <= signalIn(0);
end if;
end process;
This works because the signal assignments using <= do not take place immediately, rather they are scheduled to take place after the process has run.

Sum of Array elements VHDL

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;

Resources