Issues with indexing arrays in VHDL - vhdl

I have an assignment to create a simple microprocessor in VHDL. My code looks like this
architecture Behavioral of uc is
type instruction_t is array (255 downto 0) of std_logic_vector (15 downto 0);
constant LOAD : std_logic_vector(7 downto 0) :=x"01";
--some more instruction codes defined
signal PC : std_logic_vector (7 downto 0); -- program counter
signal cur_inst : std_logic_vector (15 downto 0);
constant ROM :
instruction_t :=
(
(LOAD & x"07"),
(ADD & x"05"),
-- some more code goes here
others => x"0000"
);
begin
process (CLK, RESET) is
begin
if RESET = '1' then
-- do stuff
elsif rising_edge(CLK) then
cur_inst <= ROM(conv_integer(PC));
PC <= PC + 1;
-- some other stuff
end if;
end process;
end Behavioral;
The problem I have is with this part:
cur_inst <= ROM(conv_integer(PC));
because simply nothing happens - cur_inst is always zero. I tried using
cur_inst <= ROM(to_integer(unsigned(PC));
but result is the same - I get nothing. PC is incremented properly, but I cannot read anything from ROM array. I also tried defining PC as unsigned or integer, but result is the same. What am I doing wrong?

Since you are defining instruction_t as an array(255 downto 0), initializing the array may be occuring in the opposite order that you intended.
(LOAD & x"07") will be assigned to ROM(255), (ADD & x"05") will be assigned to ROM(254), etc.
Define the type instruction_t as an array (0 to 255) to avoid this problem.

Another way of fixing the problem would have been to bind your instructions to the specific addresses you wanted, instead of just expecting it to happen : for that, use named association and write
constant ROM :
instruction_t :=
(
0 => (LOAD & x"07"),
1 => (ADD & x"05"),
-- some more code goes here
others => x"0000"
);

Related

Input data is not being loaded into registers - issues only in post-synthesis timing simulation [VHDL][Vivado] (SOLVED)

What this is
I'm trying to create a simple FIR filter. What I'm going to present you may not exactly be a FIR filter as I'm gradually increasing complexity of my project for educational purpouses till it reaches desired functionality.
What it should be doing
Basically what it should be doing so far:
load data to registers after applying load = 1,
unload processed data (which is product of multiplication of samples with corresponding coefficients) after applying start = 1.
Where it fails
However from what I've noticed it fails to load data into registers. Seems to be working like a latch, as after load drops to 0, the last vector value at input port is being latched in the registers. But I may be wrong, it just appears to be working like this in simulation.
Pre- and post-synthesis functional simulation is working! Only the post-synthesis timing is failing to work as desired!
What I've tried
Adding DONT_TOUCH parameter to entity declaration in its .vhd file,
Adding kind of buffer (unsigned variable) after data_in port from which the data is being transfered to registers - but it did not even appear in schematic after synthesis, maybe the DONT_TOUCH did not work?
Simulations pictures
Pre-synth functional - https://imgur.com/0TaNQyn
Post-synth timing - https://imgur.com/mEOv67t
Program
I'm using Vivado 2020.2 webpack
Testbench
Testbench code here: https://pastebin.pl/view/d2f9a4ad
Main code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity fir is
Port (
clk: in std_logic;
data_in: in unsigned(7 downto 0);
data_out: out unsigned(7 downto 0);
en: in std_logic;
load: in std_logic;
start: in std_logic;
reset: in std_logic
);
end fir;
architecture Behavioral of fir is
-- type coeff_array is array (0 to 7) of integer range 0 to 255;
constant reg_size: integer := 8;
constant filter_order: integer := 7;
type samples_reg is array (0 to reg_size-1) of unsigned(7 downto 0);
type coeffs_reg is array (0 to filter_order) of unsigned(7 downto 0);
begin
process(clk, reset)
-- variable coeffs: coeff_array := (0,0,0,0,0,0,0,0);
--variable b0: unsigned(7 downto 0) := 8D"0";
variable b0: unsigned(7 downto 0) := to_unsigned(1,8);
variable b1: unsigned(7 downto 0) := to_unsigned(2,8);
variable b2: unsigned(7 downto 0) := to_unsigned(3,8);
variable b3: unsigned(7 downto 0) := to_unsigned(4,8);
variable b4: unsigned(7 downto 0) := to_unsigned(5,8);
variable b5: unsigned(7 downto 0) := to_unsigned(6,8);
variable b6: unsigned(7 downto 0) := to_unsigned(7,8);
variable b7: unsigned(7 downto 0) := to_unsigned(8,8);
variable i: integer range 0 to reg_size := 0;
variable samples: samples_reg := (others => (others => '0'));
variable coeffs: coeffs_reg := (b0,b1,b2,b3,b4,b5,b6,b7);
variable data_processed: unsigned(15 downto 0) := (others => '0');
-- variable reg_element:
-- signal s1 : signed(47 downto 0) := 48D"46137344123";
begin
if reset = '1' then
-- data_out <= (others => '0');
samples := (others => (others => '0'));
data_processed := (others => '0');
i := 0;
-- synch part
elsif rising_edge(clk) and en = '1' then
samples := samples;
-- loading data
if load = '1' then
samples(i) := data_in;
i := i+1;
else null;
end if;
-- deloading data
if start = '1' then
data_processed := samples(i)*coeffs(i);
i := i+1;
else null;
end if;
-- reset counter after overflow
if(i = reg_size) then
i := 0;
else null;
end if;
-- reset counter if no data is being transferred
if load = '0' and start = '0' then
i := 0;
data_processed := (others => '0');
else null;
end if;
end if;
data_out <= data_processed(7 downto 0);
end process;
end Behavioral;
Other info
I just noticed that I'm holding load = 1 for one excessive cycle, which is why the highest number appears first.
The coefficients are: 1, 2, 3, 4, 5, 6, 7, 8.
In post-synth simulations after peeking into UUT, I've noticed that the samples registers are not loading the data (except for the last one, as I've mentioned earlier), the i is incrementing and the rest appears to be working properly.
I'll be happy to hear about some improvements for my code in addition to the problem solution!
Turns out in timing simulation I had to give the device at least 100 ns of warm-up time.
Seems like the timing simulations takes some factors related to device start-up into consideration -- anyway, I'm not sure about the explanation but I am sure of the above solution.
I have rephrased the title so others can find this post by searching for core problem in this case.
Good luck :)

How to attach a parity bit to a given 4 bit std_logic_vector?

Image of the DUT
I'm trying to write an internal nibble transmission guarded by a parity bit.
For this I want to write a transmitter/receiver logic which is shown in the image attached.
So I have a 4 bit input vector and generate a parity bit for it and here comes my problem.
I want to attach the parity bit to the input vector. But the input vector is only 4 bit. Is there a way to resize it by simply attaching the parity bit to the input vector or do i have to transmit the parity bit seperately?
And as a little side question in relation to the whole implementation:
Do I have to create seperated processes for the receiver and transmitter like I have in my code or do I simply have to write one process containing both?
My first idea was to simply use an internal vector with 5 bit to attach the parity bit but the problem is that I only want the given input as output in the end and there is the same problem. In the process of the parity checker I have to fill the output vector which is 4 bit with the intern 5 bit vector and have no idea if this simply works like I tried in my code.
I hope you can understand the problem.
Thanks.
architecture rtl of odd parity is
signal rxdat_s : out std_logic_vector(3 downto 0);
signal ok_s : out std_logic;
signal txdat_s : in std_logic_vector(3 downto 0);
signal secured_s : std_logic_vector (4 downto 0);
begin
odd_parity_gen: process ( txdat_s, clk ) is
variable txdat_v : std_logic_vector(3 downto 0);
variable secured_v : std_logic_vector(4 downto 0);
variable odd_parity_v : integer;
begin
txdat_v := txdat_s;
odd_parity_v := xnor txdat_v;
secured_v := txdat_v + odd_parity_v;
secured_s <= secured_v;
end process odd_parity_gen;
odd_parity_check: process () is
variable ok_v : integer;
variable rxdat_v : std_logic_vector(3 downto 0);
variable secured_v : std_logic_vector(4 downto 0);
begin
rxdat_v := rxdat_s;
secured_v := secured_s;
ok_v := ok_s;
ok_v := xnor secured_v;
rxdat_v := secured_v;
ok_s <= ok_v;
rxdat_s <= rxdat_v;
reg: process ( clk ) is
begin
if rising_edge (clk) then
if nres = '0' then
--reset all signals
else
--main logic
end if;
end if;
end process;
I assume this code has been cobbled together as example. You have input/output ports in an architecture and your ports are rather confusing: rxdat_s is an output and txdat_s is an input. Also you have no 5 bit output port which you need to send 4 bits plus parity.
Also this: secured_v := txdat_v + odd_parity_v; adds a an integer and a std_logic_vector which requires conversion or a library.
Assuming your parity generator is correct you can add a parity bit to the front using concatenation: the & operator.
secured_s <= odd_parity_v & rxdat_s;
Or at the back using:
secured_s <= rxdat_s & odd_parity_v;

Use of conv_integer in VHDL

I am in the process of trying to write some code that will simply just shift a 32 bit vector left or right, with a 5 bit input that will be used for the shift amount (shamt). The issue I am having is trying to convert an std_logic_vector to an integer. My code is this:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x : in std_logic_vector(31 downto 0);
shamt : in std_logic_vector( 4 downto 0);
y : out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
signal shift : integer;
signal temp : std_logic_vector(31 downto 0);
begin
shift <= conv_integer(unsigned(shamt));
temp <= x(shift downto 0);
y <= temp;
end beh;
The code is not complete I know, but to test some ideas I am trying to pass "00010" (2) into shamt, but shift comes out to be -2147483648. But I cannot figure out why it is doing this, nor can I find any resources online that shows anything different than what I am doing. I greatly appreciate any help.
-2147483648 (-2**31) is the default initial value for integers, being the leftmost, most negative value in its range. It suggests that the signal assignment to shift has not executed. Most likely because it is a continuous assignment and there hasn't been an event on shamt to cause it to update.
std_logic_arith is not an IEEE standard library. You should use to_integer() from ieee.numeric_std instead. It is also beneficial to keep numeric ports as unsigned or signed so that your intent is clear and to minimize type conversions. Also, you cannot directly assign the variable length slice of x to temp since their lengths do not match. You should use resize() (from numeric_std) to extend the length back to 32-bits or rethink your approach.
I fixed the obvious typo in the entity name, started the simulation (ModelSim) and forced the signal shamt to "00010". Then just after trying to run for 1 ps, ModelSim complains about:
Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 0 (-2147483648 downto 0 (null array)).
Time: 0 ps Iteration: 0 Process: /shiftlogical/line__16 File: shiftlogical.vhdl
Fatal error in Architecture beh at shiftlogical.vhdl line 16
That is because all your concurrent statements are executed in parallel. The new signal values are scheduled for the next delta cycle within the simulation. Thus, the line
temp <= x(shift downto 0);
is executed with the old value of shift which is the initial value of this signal. The initial value of an integer is -2**31 as also Kevin pointed out.
Of course you can initialize the signal shift, but the only value which will not result in an error will be 31 because in this asignment the signal on the left and the expression on the right must match in array (std_logic_vector) size. The signal shamt must be forced to "11111" as well, so that shift keeps 31.
You cannot easily fix this, because for a left shift you must add zeros at the right (LSB) and for a right shift zeros or the sign at the left (MSB).
#Martin Zabel what I had really tested there was to see if shift would hold an integer value which it did until I tried to pass it in for temp <= x(shift downto 0); What I realized was that the signal needed to really be a variable to work as intended and as follows my code consists of:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x: in std_logic_vector(31 downto 0);
shamt: in std_logic_vector(4 downto 0);
dir: in std_logic;
y: out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
begin
process(dir)
variable shift : integer;
begin
shift := conv_integer(unsigned(shamt));
if(dir = '0') then --Left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
elsif(dir = '1') then --Right shift
y(31-shift downto 0) <= x(31 downto shift);
y(31 downto 31-shift) <= (others => '0');
else --Always left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
end if;
end process;
end beh;

Dynamic Arrray Size in VHDL

I want to use dynamic range of array , so using "N" for converting an incoming vector signal to integer. Using the specifc incoming port "Size" gives me an error, while fixed vector produces perfect output.
architecture EXAMPLE of Computation is
signal size :std_logic_vector (7 downto 0);
process (ACLK, SLAVE_ARESETN) is
variable N: integer:=conv_integer ("00000111") ; ---WORKING
--variable N: integer:=conv_integer (size) ; -- Not working
type memory is array (N downto 0 ) of std_logic_vector (31 downto 0 );
variable RAM :memory;
Only reason to do this type of coding is send as much data as possible to FPGA .As I need to send Data from DDR to Custom IP via DMA in vivado may be more than 100 MB. so kindly guide me if I am trying to implement in wrong way as stated above.
You can't do that in VHDL. What kind of hardware would be generated by your code? If you don't know, the synthesizer won't either.
The way to do this kind of thing is to set N to the largest value you want to support, and use size in your logic to control your logic appropriately. It's difficult to give more pointers without more information, but as an example, you could use a counter to address your ram, and have it reset when it's greater than size.
Update
Here's a counter example. You have to make sure that size doesn't change while operating or it will fall into an unknown state. A real design should have reset states to ensure correct behaviour.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity example is
port (
clk : std_logic;
rst : in std_logic;
size : in unsigned(7 downto 0);
wr : in std_logic;
din : in std_logic_vector(31 downto 0)
);
end entity;
architecture rtl of example is
signal counter : unsigned(7 downto 0);
type ram_t is array(0 to 255) of std_logic_vector(31 downto 0);
signal ram : ram_t;
begin
RAM_WR: process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
counter <= (others => '0');
else
if wr = '1' then
ram(to_integer(counter)) <= din;
if counter = size then
counter <= (others => '0');
else
counter <= counter + 1;
end if;
end if;
end if;
end if;
end process RAM_WR;
end architecture rtl;
I believe you can only have a generic an array constraint in a process. Otherwise, the compiler cannot elaborate.
In a function or procedure, you can have truly variable array bounds.

How to declare an output with multiple zeros in VHDL

Hello i am trying to find a way to replace this command: Bus_S <= "0000000000000000000000000000000" & Ne; with something more convenient. Counting zeros one by one is not very sophisticated. The program is about an SLT unit for an ALU in mips. The SLT gets only 1 bit(MSB of an ADDSU32) and has an output of 32 bits all zeros but the first bit that depends on the Ne=MSB of ADDSU32. (plz ignore ALUop for the time being)
entity SLT_32x is
Port ( Ne : in STD_LOGIC;
ALUop : in STD_LOGIC_VECTOR (1 downto 0);
Bus_S : out STD_LOGIC_VECTOR (31 downto 0));
end SLT_32x;
architecture Behavioral of SLT_32x is
begin
Bus_S <= "0000000000000000000000000000000" & Ne;
end Behavioral;
Is there a way to use (30 downto 0)='0' or something like that? Thanks.
Try this: bus_S <= (0 => Ne, others => '0')
It means: set bit 0 to Ne, and set the other bits to '0'.
alternative to the given answers:
architecture Behavioral of SLT_32x is
begin
Bus_S <= (others => '0');
Bus_S(0) <= ne;
end Behavioral;
Always the last assignment in a combinatoric process is taken into account. This makes very readable code when having a default assignment for most of the cases and afterwards adding the special cases, i.e. feeding a wide bus (defined as record) through a hierarchical block and just modifying some of the signals.

Resources