Dynamic Arrray Size in VHDL - 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.

Related

VHDL: big slv array slicing indexed by integer (big mux)

I want to slice a std_logic_vector in VHDL obtaining parts of it of fixed dimensions.
The general problem is:
din N*M bits
dout M bits
sel clog2(N) bits
Expected behaviour in an example (pseudocode): input 16 bit, want to slice it in 4 subvectors of 4bit each.
signal in: std_logic_vector(N*M-1 downto 0);
signal sel: integer;
-- with sel = 0
output <= in(N-1:0);
--with sel = 1 output <= in(2N-1:N)
-- with sel = 2
output <= in(3N-1:2N)
.....
--with sel = M-1
output <= in(M*N-1:(M-1)N)
I know a couples of way to do this, but I don't know which one is the best practice and give the best results in synthesis.
the entity
din: in std_logic_vector(15 downto 0);
dout: out std_logic_vector(3 downto 0);
sel: in std_logic_vecotor(1 downto 0)
CASE STATEMENT
case sel is
when "00" => dout <= din(3:0);
when "01" => dout <= din(7:4);
when "10" => dout <= din(11:8);
when "11" => dout <= din(15:12);
when others => ....`
It clearly implement a mux, but it's not generic at all and If the input gets big it's really hard to write and to codecover.
INTEGER INDEXING
sel_int <= to_integer(unsigned(sel));
dout <= din(4*(sel_int+1) - 1 downto 4*sel_int);
Extremely easy to write and to mantain, BUT it can have problems when the input is not a power of 2. For example, if I want to slice a 24bit vector in chunks of 4, what happen when the integer conversion of sel brings to the index 7?
A STRANGE TRADEOFF
sel_int <= to_integer(unsigned(sel));
for i in 0 to 4 generate
din_slice(i) <= din(4*(i+1)-1 downto 4*i);
end generate dout <= din_slice(sel_int);
I'm searching a solution that is general enough to be used with various input/output relationships and safe enough to be synthesized consistently everytime.
The Case statement is the only one with the Others case (that feels really safe), the other solutions rely on the slv to integer conversion and indexing that feels really comfortable but not so reliable.
Which solution would you use?
practical usecase
I have a 250bit std_logic_vector and I need to select 10 contigous bits inside of it starting from a certain point from 0 to 239. How can I do that in a way that is good for synthesis?
There is another option that is accepted by tools that allow VHDL 2008 (which includes Vivado and Prime Pro). You can use an unconstrained 2d type from a package:
type slv_array_t is array(natural range <>) of std_logic_vector; --vhdl 2008 unconstrained array type
then you can simply select which port you want. And it is as generic as you like.
library ieee;
use ieee.std_logic_1164.all;
use work.my_pkg.all;
entity mux is
generic (
N : natural;
M : natural
);
port (
sel : in natural;
ip : in slv_array_t (N-1 downto 0)(M-1 downto 0);
op : out std_logic_vector (M-1 downto 0);
);
end entity;
architecture rtl of mux is
begin
op <= ip(sel);
end architecture;
First you must extend the incoming data to be sure to have always as much bits as you need for connecting all multiplexer inputs (see the code below, process p_extend).
This will not create any logic at synthesis.
Second you must convert the resulting vector into an array, which you can access later by an index (see the code below, process p_create_array).
Again this will not create any logic at synthesis.
At last you must access this array by the select input signal (see the code below, process p_mux).
library ieee;
use ieee.std_logic_1164.all;
entity mux is
generic (
g_data_width : natural := 250;
g_slice_width : natural := 10;
g_sel_width : natural := 5;
g_start_point : natural := 27
);
port (
d_i : in std_logic_vector(g_data_width-1 downto 0);
sel_i : in std_logic_vector(g_sel_width-1 downto 0);
d_o : out std_logic_vector(g_slice_width-1 downto 0)
);
end entity mux;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture struct of mux is
signal data : std_logic_vector(g_slice_width * 2**g_sel_width-1 downto 0);
type t_std_logic_slice_array is array (natural range <>) of std_logic_vector(g_slice_width-1 downto 0);
signal mux_in : t_std_logic_slice_array (2**g_sel_width-1 downto 0);
begin
p_extend: process(d_i)
begin
for i in 0 to g_slice_width * 2**g_sel_width-1 loop
if i+g_start_point<g_data_width then
data(i) <= d_i(i+g_start_point);
else
data(i) <= '0';
end if;
end loop;
end process;
p_create_array: process (data)
begin
for i in 0 to 2**g_sel_width-1 loop
mux_in(i) <= data((i+1)*g_slice_width-1 downto i*g_slice_width);
end loop;
end process;
p_mux: d_o <= mux_in(to_integer(unsigned(sel_i)));
end architecture;

Weird behaviour in vhdl average using Microsemi FPGA

Good Afternoon, I am working on some code of averaging with a sliding window using VHDL language.
The problem is that the accumulator takes sometimes wrong values. (generally after restart)
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.std_logic_unsigned.all;
entity cc_rssi_avr is
port (
nrst : in std_logic;
clk : in std_logic; --
ena : in std_logic;
data_in : in std_logic_vector(9 downto 0);
data_out : out std_logic_vector(9 downto 0)
);
end cc_rssi_avr;
architecture rtl of cc_rssi_avr is
constant buffer_size : natural :=8;
type MEM is array(0 to buffer_size-1) of std_logic_vector(9 downto 0);
signal shift_LT : MEM:=(others =>(others=>'0'));
signal sum_val:std_logic_vector(12 downto 0);
begin
--shift input data at every clock edge
process(clk,nrst)
begin
if nrst='0' then
shift_LT <= (others => (others => '0'));
sum_val <= (others=>'0');
elsif clk'event and clk='1' then
if ena = '0' then
shift_LT<=(others=>(others=>'0'));
sum_val<=(others=>'0');
else
shift_LT(0) <= data_in;
shift_LT(1 to buffer_size-1) <= shift_LT(0 to buffer_size-2);
sum_val <= sum_val + ("000"&data_in) - ("000"&shift_LT(buffer_size-1));
end if;
end if;
end process;
data_out<=sum_val(sum_val'high downto 3);
end rtl;
The problem is somehow, sum_val adds a value without subtraction or subtracts without addition, in a way that if the input returns to 0, the output returns to 7850 or a random value but not zero.
The design is running # 20 MHz (FPGA : Microsemi Smartfusion M2S050), and consists on an ADC driven by FPGA clock, and its output is routed to the FPGA pins so the samples are processed with this module in order to compute the average on 8 samples.
One last information that might be useful : FPGA is 92.6% Occupied (4LUT).
Can anyone provide some help.
Thanks

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;

VHDL Code: Illegal type conversion converting std_logic_vector

I am trying to be multiply the values in the line:
Q<= unsigned(reg_output) or (unsigned(multiplicand) and unsigned(shifted_lsb)*"0010");
note: I know multiplicand is a std_logic_vector, I did this for comparison via the if's.
Everytime I compile I get the error:
Illegal type conversion from ieee.std_logic_1164.STD_LOGIC to ieee.NUMERIC_STD.UNSIGNED (non-numeric to array).
here is my code below:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity shiftaddr is
port(
clk, clear : in std_logic;
multiplicand: in std_logic_vector(3 downto 0);
reg_output: in unsigned(7 downto 0);
shifted_lsb: in std_logic;
Q: out unsigned(7 downto 0) );
end shiftaddr;
architecture arch of shiftaddr is
signal temp: std_logic_vector(3 downto 0);
begin
shift: process(clk,clear,multiplicand, shifted_lsb,reg_output) --Define a process and state the inputs
begin
if (clk = '0') then
Q <= reg_output;
end if;
if (clk = '1') then
if (multiplicand(0) = '1') then Q <= (reg_output);
end if;
if (multiplicand(1) = '1') then
Q<= unsigned(reg_output) or (unsigned(multiplicand) and unsigned(shifted_lsb)*"0010");
end if;
end if;
end process;
end arch;
How do I go about fixing this? Thanks
The problem comes from:
unsigned(shifted_lsb)*"0010"
shifted_lsb is not a vector, you cannot convert it to unsigned which is a vector type. As suggested by Khanh N. Dang you could just test its value instead.
But your code is probably bogus: your sensitivity list is not that of a synchronous process while one of your signals is named clk. Moreover, if you want your process to be a synchronous one you will have a problem because you are using both states of the clock. You should probably:
indent your code so that we can read it without too much effort,
think hardware first: if you have a clear idea of the hardware you want (registers, adders, multiplexers...), coding usually becomes very easy,
read again the part of your text book about synchronous processes.

Accessing 2 elements of the same array in VHDL

I am trying to assign 2 values from 2 different addresses in my array in VHDL, but somehow they always return to me a wrong value (most of the time, zero). I tested it with only 1 address and 1 data output it returned the correct value.
architecture Behavioral of registerFile is
type reg_type is array (31 downto 0) of std_logic_vector (31 downto 0);
signal REG : reg_type := (x"00000031", x"00000030", x"00000029", x"00000028", x"00000027", x"00000026", x"00000025", x"00000024", x"00000023", x"00000022", x"00000021", x"00000020",x"00000019",x"00000018", x"00000017", x"00000016", x"00000015", x"00000014", x"00000013", x"00000012", x"00000011", x"00000010", x"00000009", x"00000008", x"00000007",x"00000006", x"00000005", x"00000004", x"00000003", x"00000004", x"00000001", x"00000000");
begin
process(clk)
begin
if clk'event and clk='1' then
if ENABLE = '1' then
if readReg = '1' then -- read from register
DATAone <= REG(conv_integer(ADDRone));
DATAtwo <= REG(conv_integer(ADDRtwo));
else
REG(conv_integer(ADDRone)) <= DATAone;
REG(conv_integer(ADDRtwo)) <= DATAtwo;
end if;
end if;
end if;
end process;
end Behavioral;
Would appreciate some help, I tried googling but it's all either multidimensional arrays or only accessing 1 element at a time.
Thanks.
I'm not sure that this is synthesizable in most fabric. You could create two copies of the reg array and index into each of them.
It seems like you are trying to implement a quad-port memory. Anyway, even if your register file is not exactly a 4-port memory, it probably can be implemented around one.
Altera has an example of such a memory in their Advanced Synthesis Cookbook. The picture below shows the relevant part:
If use the Altera example files, it will instantiate Altera primitives, and use FPGA block RAM for storage. If you are concerned about portability, or you just want to look at some VHDL code that does what you want, check the example below. It implements roughly the same circuit shown in the figure, and it will most likely be synthesized as distributed memory in the FPGA.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Quad-port RAM with 2 read ports 2 write ports. The design uses 2 memory blocks
-- (MAIN_MEMORY and SHADOW_MEMORY) to allow for simultaneous writes. Port A writes to
-- main memory, Port B writes to shadow memory. On a read from either port, data is
-- read from the memory block that was most recently written at the given position.
entity quad_port_ram is
generic (
ADDRESS_WIDTH: natural := 5;
DATA_WIDTH: natural := 32
);
port (
clock: in std_logic;
read_addr_a: in natural range 0 to 2**ADDRESS_WIDTH-1;
read_data_a: out std_logic_vector(DATA_WIDTH-1 downto 0);
write_addr_a: in natural range 0 to 2**ADDRESS_WIDTH-1;
write_data_a: in std_logic_vector(DATA_WIDTH-1 downto 0);
write_enable_a: in std_logic;
read_addr_b: in natural range 0 to 2**ADDRESS_WIDTH-1;
read_data_b: out std_logic_vector(DATA_WIDTH-1 downto 0);
write_addr_b: in natural range 0 to 2**ADDRESS_WIDTH-1;
write_data_b: in std_logic_vector(DATA_WIDTH-1 downto 0);
write_enable_b: in std_logic
);
end;
architecture rtl of quad_port_ram is
type memory_type is (MAIN_MEMORY, SHADOW_MEMORY);
type memory_type_array is array (natural range <>) of memory_type;
-- Keep track of which memory has the most recently written data for each address
signal most_recent_port_for_address: memory_type_array(0 to 2**ADDRESS_WIDTH-1);
type memory_array is array (0 to 2**ADDRESS_WIDTH-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
type dual_memory_array is array (memory_type) of memory_array;
-- Store the actual memory bits. Access like this:
-- memory_data(memory_type)(address)(bit_position)
signal memory_data: dual_memory_array;
-- Auxiliary signals to decide where to read the data from (main or shadow)
signal most_recent_port_for_addr_a, most_recent_port_for_addr_b: memory_type;
begin
process (clock) begin
if rising_edge(clock) then
if write_enable_a then
memory_data(MAIN_MEMORY)(write_addr_a) <= write_data_a;
most_recent_port_for_address(write_addr_a) <= MAIN_MEMORY;
end if;
if write_enable_b then
if (write_enable_a = '0') or (write_addr_a /= write_addr_b) then
memory_data(SHADOW_MEMORY)(write_addr_b) <= write_data_b;
most_recent_port_for_address(write_addr_b) <= SHADOW_MEMORY;
end if;
end if;
end if;
end process;
most_recent_port_for_addr_a <= most_recent_port_for_address(read_addr_a);
most_recent_port_for_addr_b <= most_recent_port_for_address(read_addr_b);
read_data_a <= memory_data(most_recent_port_for_addr_a)(read_addr_a);
read_data_b <= memory_data(most_recent_port_for_addr_b)(read_addr_b);
end;

Resources