VHDL- vector slicing - vhdl

I have input std_logic_vector of (0 to X).
Range of x is 0 to 1000 bytes and the code should support any value of X.
I would like to slice the input into 128 bit blocks, for further processing and operations.
a) how can it be done?
b) is there a way to make the following pseudo-code work? so i can adopt it for solving a)?
i need to use the loop index for naming the signals but i guess its not possible with VHDL (?)
for i in 0 to N loop
block_i <= input (X, X-127);
end loop;
Thanks in advance.

Something like this ?
library ieee;
use ieee.std_logic_1164.all;
entity slicer is
generic(X : natural:=1000);
port (input : in std_logic_vector(X*128-1 downto 0));
end entity;
architecture rtl of slicer is
type block_type is array(0 to X-1) of std_logic_vector(127 downto 0);
signal blocks : block_type;
begin
slicing:for i in 0 to X-1 generate
blocks(i) <= input(128*(i+1)-1 downto 128*i);
end generate;
end rtl;

You have a few options with how to accomplish this. One is to use the flattened 1-D array that is selectively sliced as demonstrated by #JCLL. Another option is to create a new type that is an array of an array.
subtype word is std_logic_vector(127 downto 0); -- Constrained subtype
type word_vec is array(natural range <>) of word; -- New unconstrained type
...
entity foo is
port (
X : in word_vec -- Get our constraint when instantiated
);
end entity;
...
for i in X'range loop
blocks(i) <= X(i);
end loop;
This solution skips the arithmetic needed for the 1-D slicing but is limited by the need for a constrained type for the elements of word_vec. This last limitation is lifted in VHDL-2008 where you can do the following:
-- Both unconstrained arrays
type word_vec is array(natural range <>) of std_logic_vector;
The best solution depends on what your task is and how much flexibility you need for size changes in the future.
A final less appealing option is to use a 2-D array but that gets ugly when you need more than bitwise access.

Yes, you can assign parts of a large logic vector to another smaller vector. I'm not sure about your specific implementation (you did not provide the signal types and sizes -- is the large vector 1000 bytes or 1000 bits?). However, If you know what X is at time of synthesis, use generics, like
entity foo is
generic(X : Natural);
port(input: in std_logic_vector(X-1 downto 0);
block_i: out std_logic_vector(127 downto 0));
end entity;
Otherwise you just need to pass in a size as well:
entity foo is
port(input: in std_logic_vector(X-1 downto 0);
block_i: out std_logic_vector(127 downto 0);
X : in Natural);
end entity;
And then use the size when you are assigning parts to block_i.
Note that you will need to either use the generic or a hard-coded constant (ie: 1000 for the worse case) for the loop. VHDL does not like variable loop ranges. You can work around this, but I usually don't need to (see: Using FOR loop in VHDL with a variable)

Related

Adding two vectors of 5 bit numbers in vhdl

I am new to vhdl, I am trying to add 2 vectors of 5 bit unsigned numbers.In the following code the signal firstsum gives proper output in waveform but the vector sum does not show any output, I am using quartus ii. What is the error in this code?
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
package UVEC is
subtype UINT5 is std_logic_vector (4 downto 0);
type UVEC5 is array (2 downto 0) of UINT5;
subtype UINT6 is std_logic_vector (5 downto 0);
type UVEC6 is array (2 downto 0) of UINT6;
end UVEC;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
use work.UVEC.all;
entity FP_Vecsum1 is
port(
a,b : in UVEC5;
sum : out UVEC6;
firstsum : out UINT6
);
end FP_Vecsum1;
architecture FP_Vecsum1_MX of FP_Vecsum1 is
begin
firstsum <= std_logic_vector(('0'&unsigned(a(0)))+('0'&unsigned(b(0))));
sum(0) <= std_logic_vector(('0'&unsigned(a(0)))+('0'&unsigned(b(0))));
sum(1) <= std_logic_vector(('0'&unsigned(a(1)))+('0'&unsigned(b(1))));
sum(2) <= std_logic_vector(('0'&unsigned(a(2)))+('0'&unsigned(b(2))));
end FP_Vecsum1_MX;
welcome to the VHDL world.
I also haven't found anything wrong with your code, but you can try the following, maybe this will help:
first, try to cast the signals to unsigned in the beginning of your architecture, before doing the math:
a_us(0) <= unsigned(a(0));
a_us(1) <= unsigned(a(1));
a_us(2) <= unsigned(a(2));
this is quite convenient: if your ports to the outside world are neutral vectors, the math inside your component is either signed or unsigned. do the conversion once, and you're free.
second, instead of manually doing the sign extension, now that you have determined your vectors as unsigned, you can use resize function to automatically set the summed vectors to the result length:
sum(0) <= std_logic_vector(resize(a_us(0),sum(0)'length) + resize(b_us(0),sum(0)'length));
you can also do a little trick by adding a zero with a relevant vector width:
sum(0) <= std_logic_vector( to_unsigned(0,sum(0)'length) + a_us(0) + b_us(0) );
it might look a little longer, but in my opinion it's a more robust code.
hope this helps,
ilan.

Calculate the module of a vector, in VHDL

How can I calculate the module of a vector?
As a vector is not a pre-defined type in VHDL it makes sense to me that there is no function implementing the modue of a vector. If there is such I have not found it.
This is basically a problem of obtaining the square root of a number, as the module can be defined as:
sqrt(a^2+b^2+...+n^2)
Implementing the sum of all the members of the vector squared is not a challenge so I think the most necessary part is having a function to calculate the square root of a number.
As far as I'm concerned there isn't any official package implementing this function. How to implement a function to calculate the module of a vector?
Or if you prefer it, how to implement a square root?
This is one possible solution. I will provide you 3 codes.
-The first one provides the type definition used for the vector. Its not important but it is needed to make it work.
-The second one is the package in which the function is defined. It is commented so that you can easily adapt it to any kind of vector. It can probably be upgraded to make it adapt by itself using some parameters by this works fine.
-The third one is a testbench to try it out.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package tipos is
constant bandas : positive := 4;
type vector32 is array (0 to bandas-1) of signed (31 downto 0);
end package tipos;
Be aware of calling properly the library with the vector definition. In my case it was compiled to work for the ModelSim simulation
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library work; use work.tipos.all;
package propios is
--function declaration.
function module (a : vector32; bands: natural) return unsigned;
end propios; --end of package.
package body propios is --start of package body
--definition of function
--based on: https://en.m.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
function module (a : vector32; bands: natural) return unsigned is --To adapt it to a diferent number of bits in the input vector:
--substitute the 71 for the needed number. Number of bits in each element of the vector *2 + power of two that can represent the maximum
--number of bands, or fields. In this case, 32bit numbers, maximum number of bands, 256, so 2^8. 32*2+8=72.
variable sum : unsigned(71 downto 0):= (others => '0');
variable b : unsigned(71 downto 0):=(0=>'0', 70 => '1', others => '0');
variable a_unsig: unsigned(31 downto 0):=(others =>'0');--for this vector use the same length as the input vector, 32bit in my case.
variable result: unsigned (71 downto 0):= (others => '0');
begin
for i in 0 to bands-1 loop--Sum of all the elements squared
a_unsig:=unsigned(a(i));
sum:=sum + (a_unsig * a_unsig);
end loop;
--Square root of sum
while b>sum loop--Do any needed changes here. You only have to change the 71's
b:='0'&'0'& b(71 downto 2);
end loop;
while (b/=0) loop
if (sum>=result+b) then
sum:=sum - (result + b);
result:=('0'& result(71 downto 1))+b;
else
result:='0'& result(71 downto 1);
end if;
b:='0' & '0' & b(71 downto 2);
end loop;
return result(35 downto 0);--sqrt(2^72)=2^36. Use half of the bits you put in place of 71
end module;
end propios; --end of the package body
And here is the testbench. Again take care of calling the packages properly
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.propios.all;
use work.tipos.all;
ENTITY test IS
END test;
Architecture simple of test is
signal a:vector32;
signal c: unsigned(35 downto 0);
signal b: natural:= 4;
begin
a(0)<="00000000110010011010011100000000";
a(1)<="00000000110010011010011100000000";
a(2)<="00000000110010011010011100000000";
a(3)<="00000000110010011010011100000000";
process
begin
wait for 200ps;
c<= module (a , b);
wait;
end process;
end simple;

Indexing of original vector in a function in VHDL

I want to write a function in VHDL which is given the top few bits of a std_logic_vector and does stuff to them but it seems to be that the indexing of my function still starts counting at the bottom of the whole vector.
I can get around this by first assigning my vector to a temporary signal and using that but I'm worried that I don't understand what's going on here.
Could someone explain why a and b don't get the same output in the below?
architecture rtl of inds is
function top_bit (c : std_logic_vector) return std_logic is
begin
return c(c'length-1);
end top_bit;
signal temp : std_logic_vector(2 downto 0);
begin
temp <= input(3 downto 1);
a <= top_bit(temp);
b <= top_bit(input(3 downto 1));
end rtl;
If you give them the input "0100", you get a='0', b='1'.
If you give them the input "1000", you get a='1', b='0'.
So a=temp(2)=input(3) and b=input(2) which is input("length of c" -1).
I don't think this makes sense, can someone justify it for me.
Edit: if you replace the declaration line with:
function top_bit (c : std_logic_vector(2 downto 0)) return std_logic is
then it works as I'd expect.
I suppose the vector c takes it's indexing from the vector it's given.
I'd like to see a function which takes an arbitrary slice of a vector and returns the top bit of that slice.
You are using the 'length attribute, where you could be using 'high. I think this would do what you're asking for.
I've got a print out on my wall of the table here http://www.csee.umbc.edu/portal/help/VHDL/attribute.html as a reference for what attributes are available.
The issue, is that c'length returns the length of the vector which is not necessarily a valid index. For example, say I declared the following signal:
signal temp : std_logic_vector(7 downto 4);
This would cause a range error calling top_bit. As you note in your comment on scary_jeff's answer, not all vectors are x downto 0. They could be x downto y. Or they could even by 0 to x or x to y. Assuming that c'length-1 is the top bit is only true if c is declared as std_logic_vector(N-1 downto 0) (which you discovered in your answer).
Just as a clarification. scary_jeff's answer is the correct way. However, you need to resolve what is meant by "top_bit". What if you are given a to vector, such as:
signal temp : std_logic_vector(4 to 7)
What is top bit? Bit 4 or bit 7? If you use 'high, you'll get bit 7. Is this the top bit? If you want bit 4 to be the top bit, you'll need to use 'low.

synthesis of dynamic mux on std_logic_vector bytes

I have a FIFO who's size is determined according to a parameter in the package:
signal fifo : std_logic_vector(FIFO_SIZE*8 -1 downto 0);
I also have a 4 bit vector (numOfBytes) saying how many bytes are in the FIFO at any given time (up to 8).
I want the data out (a single byte) from the FIFO to be determined according the numOfBytes signal:
Do <= fifo(to_integer(unsigned(numOfBytes)*8 -1 downto to_integer(unsigned(numOfBytes)*8 -8) when numOfBytes /= x"0" else (others => '0');
when simulating, this works well, however when I try to synthesis it (using Synopsys DC) I get an elaboration error upon linking the design saying "Constant value required (ELAB-922)".
The ELAB code means "This error message occurs because an expression in the indicated line of your RTL description does not evaluate to a constant value, as required by the language."
How else can I make the output mux so it will undergo synthesis?
if not for the parameter i'd change the Do line to a regular mux, but it can't work with the parameters. (I can't call fifo(63 downto 54) when fifo is 4 byte...)
p.s.
I tried working with conv_integer in the beginning, but changed to to_integer(unsigned())due to answers found on the web.
Signal indexes used to construct a range have to be compile-time constants for synthesis to accept them.
There are two ways to solve this problem:
1) Change your FIFO to use an array. This is the standard way of declaring any form of memory, such as a FIFO.
type fifo_type is array(0 to FIFO_SIZE-1) of std_logic_vector(8-1 downto 0);
signal fifo : fifo_type;
...
Do <= fifo(to_integer(unsigned(numOfBytes))-1) when(numOfBytes/=0) else (others=>'0');
2) Use a loop to convert the variable into a constant. This is a common way to code a generic mux.
Do <= (others=>'0');
for i in 0 to FIFO_SIZE-1 loop
if(numOfBytes=i+1) then
Do <= fifo((i+1)*8-1 downto i*8);
end if;
end loop;
I would recommend the first approach for larger, memory-based FIFOs, and the second for smaller, register-based ones.
If the FIFO created with a number of bytes, instead of combining it into the same std_logic_vector then Synopsys DC may be able to handle it. Code could look like:
library ieee;
use ieee.numeric_std.all;
architecture syn of mdl is
... Declaration of FIFO_SIZE natural constant
type fifo_t is array(natural range <>) of std_logic_vector(7 downto 0);
signal fifo : fifo_t(FIFO_SIZE - 1 downto 0);
begin
... Handling FIFO insert and remove
Do <= fifo(to_integer(unsigned(numOfBytes))) when numOfBytes /= x"0" else (others => '0');
end architecture;
If you don't need a runtime-dynamic size to the FIFO, use a generic on your entity.
If you truly need a dynamic sized FIFO, you'll have to use a loop in a process as someone else said. But be very careful how you use such a FIFO, as if you change the size of it while someone is reading or writing, bad things may happen!

vhdl ram module and use of registers

Ok another question in VHDL. Below is my code. Suppose that I want my input stored in ram. And lets say I want to add two of them. (do not give emphasis on it, later on it will be replaced). This is my code:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
USE ieee.numeric_std.ALL;
use work.my_package.all;
entity landmark_1 is
generic
(data_length :integer := 8;
address_length:integer:=3 );
port ( clk:in std_logic;
vin:in std_logic;
rst:in std_logic;
flag: in std_logic;
din: in signed(data_length -1 downto 0);
done: out std_logic
);
end landmark_1;
architecture TB_ARCHITECTURE of landmark_1 is
component ram IS
generic
(
ADDRESS_WIDTH : integer := 4;
DATA_WIDTH : integer := 8
);
port
(
clock : IN std_logic;
data : IN signed(DATA_WIDTH - 1 DOWNTO 0);
write_address : IN unsigned(ADDRESS_WIDTH - 1 DOWNTO 0);
read_address : IN unsigned(ADDRESS_WIDTH - 1 DOWNTO 0);
we : IN std_logic;
q : OUT signed(DATA_WIDTH - 1 DOWNTO 0)
);
end component;
signal inp1,inp2: matrix1_t(0 to address_length);
signal out_temp: signed(data_length-1 downto 0);
signal k:unsigned(address_length-1 downto 0);
signal i: integer range 0 to 100:=0;
begin
read1:ram generic map( ADDRESS_WIDTH=>address_length, DATA_WIDTH=>data_length) port map (clk,din,k,k,vin,out_temp);
inp1(i)<=out_temp;
process (clk)
begin
if (clk'event and clk='1') then
if (flag='1') then out_temp<=inp1(0)+inp1(1);
end if;
end if;
end process ;
end TB_ARCHITECTURE;
Below are my questions:
Why to use that ram and not just do inp(i)<=din; . I think that it will help synthesizer understand that this is a ram, but what else? Moreover, do I need inp1 registers. And if I a going to use them, again why use ram as an intermediate?
If inp1 is unnecessary, how I am going to fetch these two elements in my process? I mean I need something like ram(address1)+ram(address2), right?
Below is my ram_code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY ram IS
GENERIC
(
ADDRESS_WIDTH : integer := 4;
DATA_WIDTH : integer := 8
);
PORT
(
clock : IN std_logic;
data : IN signed(DATA_WIDTH - 1 DOWNTO 0);
write_address : IN unsigned(ADDRESS_WIDTH - 1 DOWNTO 0);
read_address : IN unsigned(ADDRESS_WIDTH - 1 DOWNTO 0);
we : IN std_logic;
q : OUT signed(DATA_WIDTH - 1 DOWNTO 0)
);
END ram;
ARCHITECTURE rtl OF ram IS
TYPE RAM IS ARRAY(0 TO 2 ** ADDRESS_WIDTH - 1) OF signed(DATA_WIDTH - 1 DOWNTO 0);
SIGNAL ram_block : RAM;
BEGIN
PROCESS (clock)
BEGIN
IF (clock'event AND clock = '1') THEN
IF (we = '1') THEN
ram_block(to_integer(unsigned(write_address))) <= data;
END IF;
q <= ram_block(to_integer(unsigned(read_address)));
END IF;
END PROCESS;
END rtl;
3.can anyone tell me why the q (output) is estimated one clock later?
EDIT: To sum up,I was told that I should use a ram and this is my implementation. The question is what I have gained by changing my inp1(i)<=din; when I inserted the ram model. And there fore how can I use it? (before using the ram I waws just wrote inp1(i)+inp2(i+1) for example).
EDIT2: PACKAGE FOR TYPES.
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
package my_package is
type matrix1_t is array(integer range<>) of signed(7 downto 0);
type big_matrix is array(integer range<>) of signed(23 downto 0);
type matrix2d is array (integer range<>) of big_matrix(0 to 3);
end my_package;
Why to use that ram and not just do inp(i)<=din;
In real world designs you use RAMs to store large amounts of data because they are smaller (physically, on the chip) that arrays of flip flops. During the synthesis process the RAM is replaced by one from your vendor's library. This RAM looks rather small, but I'm guessing you've been told to use one as an exercise.
Moreover, do I need inp1 registers. And if I a going to use them, again why use ram as an intermediate?
I'm not quite sure what imp1 is, as I don't know what a matrix_t is, but I'm guessing it's a register version of the RAM. In which case it's redundant.
If inp1 is unnecessary, how I am going to fetch these two elements in my process? I mean I need something like ram(address1)+ram(address2), right?
...and there's the real issue. You need to ask yourself 'If you can't read more that one thing in a cycle, how do you add two numbers?'
can anyone tell me why the q (output) is estimated one clock later?
Because that's how RAMs work. You apply an address in one cycle, and the data appears some cycles later (normally one, but not always)
These are real issues that you'll face in real designs. RAMs are necessary because of their smaller size. You need to know the issues that surround using them and how to work with them.
You aren't setting i to anything other than 0 so you will only ever assign to inp1(0).
Assuming the RAM is there to store many values, and you need to read two of them every clock cycle in order to do your adding, you need 2 RAM blocks (or a single dual-ported one) and then put the two addresses into those RAM blocks. The next cycle the two values you want will appear on the data outputs and you can sum them.
The clock-cycle delay you observe is in the nature of synchronous RAMs (which is what most FPGAs have for their "large storage") - some can create smaller asynchronous RAMs where the data appears a short delay after the read address changes, completely asynchronously to the clock.
I assume you're trying to represent a RAM with the signal inp1. However, the signal that represents the RAM is ram_block in your ram entity.
You are using the entity in a strange way because you connect the signal k as read and write address. There are two problems with that. Firstly, k doesn't seem to be driven anywhere in your design. Secondly, you probably don't want the two addresses to be the same.
I assume you want to write some values to the RAM and at the same time read two values and add them up. I suggest you use a process that sets a write address and a process that sets a read address. You also need at least one register with the width of the RAM output. The first value you read from the RAM is stored in that register. Then you add the value in that register and the second value read from the RAM and store the result in a different register.

Resources