How to "slice" an std_logic_vector in VHDL? - syntax

I'm developing a little thing in VHDL and am quite new to it. I'm having trouble figuring out how to slice a bigger std_logic_vector into a smaller one.
For instance I have 3 signals:
signal allparts: std_logic_vector(15 downto 0);
signal firstpart: std_logic_vector(7 downto 0);
signal secondpart: std_logic_vector(7 downto 0);
Basically, what I want is to assign bits 15 through 8 to secondpart and bits 7 through 0 to firstpart. How exactly would I "slice" a vector like this without assigning individual bits

You can directly assign them:
firstpart <= allparts(15 downto 8);
secondpart <= allparts(7 downto 0);
...or if firstpart and secondpart are simply alternate ways to refer to part of the allparts signal, you may want to use an alias:
alias firstpart is allparts(15 downto 8);
alias secondpart is allparts(7 downto 0);

Related

Concatenation VHDL (2 8-bit vectors)

I was just wondering, how could I concatenate two 8 bit vectors together into a 16-bit vector with odata_H having the MSB and odata_L having the LSB? Any help would be appreciated. The vectors are data points given off from an ADT7420 temperature sensor.
signal BCD: std_logic_vector(11 downto 0);
signal Bin_Temp: std_logic_vector(7 downto 0);
signal Bin_Acc: std_logic_vector(7 downto 0);
signal Buff_Temp: std_logic_vector(7 downto 0);
signal Buff_Acc: std_logic_vector(7 downto 0);
signal odata_L: std_logic_vector(7 downto 0);
signal odata_H: std_logic_vector(7 downto 0);
signal notEN: std_logic;
signal odataT: std_logic_vector(15 downto 0);
begin
odataT <= odata_H & odata_L;
Bin_Temp <= odataT(8 downto 1);
notEN <= not(EN);
I don't know why in this case the concatenation apparently doesn't work. Nevertheless, another way of achieving it is by using the resize() function of the numeric_std library.
library ieee;
use ieee.numeric_std.all;
[...]
odataT <= std_logic_vector(resize(signed(odata_H), odata_L'length));
The concatenation (odata_H, odata_L) will be resized with a length of length (16 in this case).
Of course unsigned instead of signed is possible, if applicable.

Get position or range of alias

Suppose I have an alias for a a single bit or number of bits in a std_logic_vector declared such as this:
signal CR : std_logic_vector(7 downto 0);
alias CR_ARM : std_logic is CR(0);
alias CR_PS : std_logic_vector(3 downto 0) is CR(7 downto 4);
How can I access the range or position of the alias such as:
singal tmp : std_logic_vector(7 downto 0); -- output bus vector
tmp(CR_ARM'range) <= CR_ARM; -- does not compile
Range is only defined for array types. Even when VHDL-2017 will add ranges for scalar types, it won't solve your problem, because you want to know for which bit the alias was created.
Aliases are transparent in VHDL. There is no mechanism to reflect about aliases.
You could use this workaround, which doesn't look very nice:
signal CR : std_logic_vector(7 downto 0);
alias CR_ARM : std_logic_vector is CR(0 downto 0);
signal tmp : std_logic_vector(7 downto 0); -- output bus vector
-- now a slice name works
tmp(CR_ARM'range) <= CR_ARM;
Your second example won't work as expected. You should declare the alias with the same range constraints otherwise you will assign other bits when you use CR_PS'range.

VHDL multiple std_logic_vector to one large std_logic_vector

I have four std_logic_vectors (15 downto 0) and want to stack them into a std_logic_vector (63 downt 0) so fare I have found one way of doing it but is it the correct way or is there a more optimal and correct way to do it?
signal slv16_1,slv16_2,slv16_3,slv16_4 : std_logic_vector(15 downto 0);
signal slv64 : std_logic_vector(63 downto 0);
slv64(15 downto 0) <= slv16_1;
slv64(31 downto 16) <= slv16_2;
slv64(47 downto 32) <= slv16_3;
slv64(63 downto 48) <= slv16_4;
An easy way to accomplish this is to use the concatenation operator &. It achieves the same thing you did above, but with less code required.
slv64 <= slv16_4 & slv16_3 & slv16_2 & slv16_1;
Since the source vectors have unique names, I don't see a way to automate this. What you might be able to try is to never use the 16-bit vectors, and instead use slices of the larger 64 bit vector. So instead of an assignment like this:
slv16_1 <= "0101110000111010";
Use
slv64(15 downto 0) <= "0101110000111010";
Or instead of an entity instantiation where you connect slv16_2 like this:
output_port => slv16_2,
Use
output_port => slv64(31 downto 16),
I would really need to see more of your code to understand what might work best, but my basic answer is 'use the larger vector in the first place'.
If you can't do this for some reason, an alternative would be to declare your 16-bit vectors as an array of arrays:
type slv16_array_type is array (integer range <>) of std_logic_vector(15 downto 0);
signal slv16_array : slv16_array_type(3 downto 0);
You could then assign to the elements like this:
slv16_array(0) <= "0101";
You could combine the elements of this type with a generate loop:
slv16_combine : for i in 0 to 3 generate
slv64((16*(i+1))-1 downto 16*i) <= slv16_array(i);
end generate;
VHDL guide says that this one should work:
slv64 <= (slv16_4, slv16_3, slv16_2, slv16_1);

How do I split 16-bit data into 2 8-bit data in VHDL?

How do I split 16-bit data into 2 8-bit data?
signal part : std_logic_vector (16 downto 0);
signal part_1 : std_logic_vector (8 downto 0);
signal part_2 : std_logic_vector (8 downto 0);
The part is actually 17 bit, since 16 downto 0 is a 17 bit range, and the part_* are likewise 9 bit.
If the ranges are 15 downto 0 and 7 downto 0, then you can do the split with:
part_1 <= part( 7 downto 0);
part_2 <= part(15 downto 8);
Btw, quote by Martin Fowler / Phil Karlton:
There are two hard things in computer science:
cache invalidation, naming things, and off-by-one errors.
Why are your signals 17 bits and 9 bits long? I think they should be 16 and 8...
signal part : std_logic_vector (15 downto 0);
signal part_1 : std_logic_vector (7 downto 0);
signal part_2 : std_logic_vector (7 downto 0);
begin -- architecture begin
part_1 <= part(15 downto 8);
part_2 <= part(7 downto 0);
Pretty simple stuff... I'm surprised you didn't run across this in looking at a VHDL example.
There's also aggregate target assignment:
library ieee;
use ieee.std_logic_1164.all;
entity foo is
end entity;
architecture fum of foo is
type fie is array (natural range 0 to 1) of std_logic_vector (7 downto 0);
signal part: std_logic_vector (15 downto 0);
signal part_1: std_logic_vector (7 downto 0);
signal part_2: std_logic_vector (7 downto 0);
begin
(part_1, part_2) <= fie'(part(15 downto 8), part(7 downto 0));
end architecture;
Which is admittedly more useful for extracting elements of records in one fell swoop. What's slick here is that there's no place there's any named signal of type fie.
The reason for the aggregate on the right hand side is because the element size has to match on both sides of the assignment operator, both aggregates are treated as if they are type fie.
Doing this with records allows you to extract elements of varying sizes. Extracting fields from CPU machine instruction formats comes to mind. It allows you to use simple names without requiring aliases for element selected names. (There would be no named record).
When the element size is the same on both sides you can simply use a target aggregate:
library ieee;
use ieee.std_logic_1164.all;
entity fie is
end entity;
architecture fum of fie is
signal part: std_logic_vector (2 downto 0);
signal part_1: std_logic;
signal part_2: std_logic;
signal part_3: std_logic;
begin
(part_1, part_2, part_3) <= part;
end architecture;
These aggregates all use positional association. You can also use named association. Record aggregates require an others choice represent at least one element and all the elements have to have the same type (e.g. std_logic_vector).
Just for completeness: you can also use aliases which makes the signal assignment obsolete:
signal part : std_logic_vector (15 downto 0);
alias part_1 : std_logic_vector(7 downto 0) is part(15 downto 8);
alias part_2 : std_logic_vector(7 downto 0) is part(7 downto 0);

16 bit std_logic_vector to lower 8 bit std_logic-vector in vhdl

Am having an output of 16 bit std_logic_vector from one block.But in the later stage i have to use only lower 8 bit std_logic_vector.it creating synthesis problem...please tell me how to avoid this..
If you have a 16-bit std_logic_vector you can access the individual bytes like this:
signal largeVariable : std_logic_vector(15 downto 0);
signal lower8bitsVariable : std_logic_vector(7 downto 0);
signal upper8bitsVariable : std_logic_vector(7 downto 0);
(...)
lower8bitsVariable <= largeVariable(7 downto 0); --Store the lower 8 bits of largeVariable
upper8bitsVariable <= largeVariable(15 downto 8); --Store the upper 8 bits of largeVariable

Resources