Need to understand how to use Selected Signal Assignment and include a 4-bit internal signal, called WXYZ, by concatenating W with X with Y with Z for the following Boolean algebra expression F(W,X,Y,Z)=Y'Z'+W'X'+X'Y
ENTITY Part_2A IS
PORT(
W, X, Y, Z : IN STD_LOGIC;
G1 : OUT STD_LOGIC);
END Part_2A;
ARCHITECTURE sig OF Part_2A IS
SIGNAL inputs : STD_LOGIC_VECTOR(3 downto 0);
SIGNAL outputs: STD_LOGIC;
BEGIN
--Concatenate input ports into 4-bit signal
inputs <= W & X & Y & Z;
WITH inputs SELECT
outputs <= "1" when "0000",
"1" when "0001",
"1" when "0010",
"1" when "0011",
"1" when "0100",
"1" when "1000",
"1" when "1010",
"1" when "1011",
"1" when "1100",
"0" when others;
G1 <= outputs;
END sig;
You can't ask any better than
Need to understand how to use Selected Signal Assignment and include a 4-bit internal signal, called WXYZ, by concatenating W with X with Y with Z for the following Boolean algebra expression F(W,X,Y,Z)=Y'Z'+W'X'+X'Y
I don't even see a question mark there.
With the addition of a context clause referencing IEEE library std_logic_1164 and converting the string literals "1" and "0" to character literals '1' and '0' (character literals are acceptable enumeration literals, std_ulogic the base type of std_logic is an enumerated scalar type) and we have something like:
library ieee;
use ieee.std_logic_1164.all;
entity part_2a is
port (
w, x, y, z : in std_logic;
g1 : out std_logic
);
end entity part_2a;
architecture sig of part_2a is
signal inputs : std_logic_vector(3 downto 0);
signal outputs: std_logic;
begin
--concatenate input ports into 4-bit signal
inputs <= w & x & y & z;
with inputs select
outputs <= '1' when "0000",
'1' when "0001",
'1' when "0010",
'1' when "0011",
'1' when "0100",
'1' when "1000",
'1' when "1010",
'1' when "1011",
'1' when "1100",
'0' when others;
g1 <= outputs;
end architecture sig;
Which analyzes without error.
You may have been mislead by your VHDL tool. There are some VHDL implementations that specifically complain about the type mismatch. For instance ghdl:
ghdl -a part_2a.vhdl
part_2a.vhdl:21:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:22:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:23:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:24:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:25:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:26:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:27:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:28:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:29:21: can't match string literal "1" with type enumeration subtype "std_logic"
part_2a.vhdl:30:21: can't match string literal "0" with type enumeration subtype "std_logic"
ghdl: compilation error
While some quit at the first error:
nvc -a part_2a.vhdl
** Error: no one dimensional arrays of character type in context
File part_2a.vhdl, Line 21
outputs <= "1" when "0000",
^^^
If you have one that simply points at the beginning of the statement
WITH inputs SELECT
With no useful information you might think it's a concatenation problem (depending on what the actual error message said). Which explains why a Minimal, Complete, and Verifiable example can be valuable.
Error messages tend to be distinct to a particular vendor, and tell what you trying to do.
Related
update
#user1155120's comment below is correct:
This is telling you the error is somewhere in the realm of -- other assignments here
I had multiplication operations which I mistakenly believed functioned in the same manner as addition. My mistake.
I am working on a rudimentary ALU using VHDL.
Here is the code which is throwing an error:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_misc.all;
entity alu is
port (
A, B : in unsigned(31 downto 0);
sel : in unsigned(2 downto 0);
O : out unsigned(63 downto 0));
end entity alu;
architecture Behavioral of alu is
begin
O <= resize(A, 64) + resize(B, 64) when sel = "000"
-- other assignments here
end Behavioral;
My understanding of Unsigned addition in VHDL is that the length of the sum will be equal to the longest length of the operands. However, my code gives the following error:
ERROR: Array sizes do not match, left array has 64 elements, right array has 128 elements
Strange. However, if I change the resize values to be less than 64 bits, then the behavior follows my expectation (width=max width of operands). Like this:
O <= resize(A, 33) + resize(B, 33) when sel = "000"
I get the following error:
ERROR: Array sizes do not match, left array has 64 elements, right array has 33 elements
I end up being very confused. Why is the width of the output changing when I resize only to a certain value?
I am using the student license for Vivado 2020.
You probably have
O <= resize(A, 64) * resize(B, 64) when sel = whatever
Somewhere in your code on a lower line and you're messing up the line numbers when you read the error. The moment you change the addition to be wrong, that's the first line analysis fails on and you get the error you see now.
Consider the following VHDL code:
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1', others => '0');
Here, the indices 7 and 6 are important: they indicate which elements should be 1, and from that, the compiler can derive which ones should be 0.
Question 1
If I understand correctly, this can also be written as
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1') & (5 downto 0 => '0');
Now I am wondering how exactly this works, and whether the indices still matter or only the difference between them. The way I understand it, the expression (x downto y => z) creates an array with indices x downto y, whose elements are all equal to z (and have the same type). But do these indices matter when arrays are concatenated? I.e., could I also write any of the following:
constant c : std_logic_vector(7 downto 0) := (1 downto 0 => '1') & (5 downto 0 => '0');
constant c : std_logic_vector(7 downto 0) := (99 downto 98 => '1') & (4 downto -1 => '0');
Of course one could say that those statements, esp. the last one, aren't really clear, but my question is: Would they have the same result? Or would they cause some kind or error?
The reason I am wondering about this is that you could also write
constant c : std_logic_vector(7 downto 0) := "11" & "000000";
and the literal "11" doesn't have any range specified, so I'm not sure what exactly the type of this literal would be, but certainly not std_logic_vector(7 downto 6).
Question 2
Finally, I am wondering what is the difference between
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1') & (5 downto 0 => '0');
and
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1', 5 downto 0 => '0');
By this I mean: Is there any reason you would want/need to write the former (which seems more error-prone because it will give unexpected results if you e.g. swap the 2 aggregates) instead of the latter? Or is it just a matter of taste?
Lets start with literals. When you specify a literal, the default range is (type_index'low to type_index'low + len-1). The easiest way to see this is when specifying a constant, where the range is not required in the subtype:
constant SOME_CONSTANT : std_logic_vector := x"00";
Here, if you check the range of SOME_CONSTANT, you'll see its (0 to 7). This is because std_logic_vector is declared as:
type std_ulogic_vector is array(natural range <>) of std_logic;
The 'low value of natural is 0, which is the start point.
Lets say you went a bit crazy, and this:
type my_crazy_array_t is array(std_logic range <>) of integer;
and you declared a constant:
constant CRAZY : my_crazy_array_t := (0, 22);
The results are:
CRAZY('U') = 0
CRAZY('X') = 22
CRAZY'left = 'U'
CRAZY'right = 'X'
CRAZY'low = 'U'
CRAZY'high = 'X'
Because 'U' is the low value of std_logic, followed by 'X'.
On the other questions, it all works because VHDL is always context driven, and for arrays as long as the lengths match, the resulting arrays can always be mapped from 'left to 'right. In your examples the length is correct, and the subtype is know from the declaration, so mapping can occur as you specified.
NOTE: (4 downto -1 => '0'); is illegal, because -1 is not a valid index value for a std_logic_vector, so you would get an error (probably from the & function because it cannot work out what type you meant, because it cannot be std_logic_vector).
The difference is that the first one is a concatenation of a 2 bit and 6 bit bit string, and the 2nd is a complete 8 bit bit string. Which you use will probably be a matter of style. But usually, for this, I would use literals eg: constant c : std_logic_vector(7 downto 0) := x"C0"; what you use and when may depend on what is clearest to the user(s).
#include <stdio.h>
int main(void) {
char a[] = "125"; // (int)1, (int)2, (int)5. But array 'a' has a type char. So int is in char. ???
printf("%s", a);
}
In that code, each element of string literal has type int. But the array a has type char.
In C99 6.4.5 $2 fragment
The same considerations apply to each element of the sequence in a character string
literal or a wide string literal as if it were in an integer character constant or a wide
character constant
In C99 6.4.5 $5 fragment
For character string literals, the array elements have
type char, and are initialized with the individual bytes of the multibyte character
sequenceI think they are not compatible, it's a contradiction to me. What's wrong about my thought?
No, this is a string literal.
Quoting C11, chapter 6.4.5, String Literals:
A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz".[...]
To elaborate, the acceptable syntax for a string liteal is:
string-literal:
encoding-prefixopt " s-char-sequenceopt "
encoding-prefix:
u8
u
U
L
s-char-sequence:
s-char
s-char-sequence s-char
s-char:
any member of the source character set except
the double-quote ", backslash \, or new-line character
escape-sequence
and then, the "source character set", referring (Chapter 5.2.1/P3)
Both the basic source and basic execution character sets shall have the following members: the 26 uppercase letters of the Latin alphabet
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
the 26 lowercase letters of the Latin alphabet
a b c d e f g h i j k l m
n o p q r s t u v w x y z
the 10 decimal digits
0 1 2 3 4 5 6 7 8 9
the following 29 graphic characters
! " # % & ' ( ) * + , - . / :
; < = > ? [ \ ] ^ _ { | } ~
So, a construct like "123" is a string literal, not individual integers held by/in char.
char a[] = "125";
In that code, each element of string literal has type int. But the array a has type char.
No, the fact that it's a 5 does not mean it has to be an int. The type of which has to be determined by the context of where/how it is declared.
In your case that 5 is of type char because it is part of the string literal.
Also note that 5 can be one of any other types such as unsigned int, unsigned short, double, etc. So again you must look at how it's declared in the first place.
Consider a type
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
Why do I get a compiler error when I try to create a constant value of this type, for example. Note that I have only tried using Altera's Quartus II.
constant cFoo : foo := ( x"11" );
Error: VHDL Type mismatch error at [filename.vhd](line number): cFoo type does not match string literal.
However everything is ok if my type is
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
with an example assignment to a constant of:
constant cFoo : foo := ( x"00", x"11" );
Moreover consider that I try to assign index 0 with another constant. For example.
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
constant cBar : std_logic_vector(7 downto 0);
constant cFoo : foo := ( cBar );
To which the error the compiler spits out is now:
VHDL error at [filename.vhd](line number): type of identifier "cBar" does not agree with its usage as "foo" type.
So basically its telling me that the compiler does not realize that the assignment is to the index of 0 but instead an assignment to the the array type.
How can I let the compiler know that the assignment is to only index 0?
IEEE Std 1076 9.3.3 Aggregates, 9.3.3.1 para 4:
Both named and positional associations can be used in the same aggregate, with all positional associations appearing first (in textual order) and all named associations appearing next (in any order, except that it is an error if any associations follow an others association). Aggregates containing a single element association shall always be specified using named association in order to distinguish them from parenthesized expressions.
With an MCVE:
library ieee;
use ieee.std_logic_1164.all;
package ceefoo is
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
-- constant cFoo : foo := ( x"11" );
constant cfoo: foo := (0 => x"11");
-- or
constant cefoo: foo := (others => x"11");
end package;
You need to use named association with a single element. The first example specifies index 0, the second any elements.
Para 3 of the above quoted subsection:
Each element association associates an expression with elements (possibly none). An element association is said to be named if the elements are specified explicitly by choices; otherwise, it is said to be positional. For a positional association, each element is implicitly specified by position in the textual order of the elements in the corresponding type declaration.
It's helpful to see the BNF:
aggregate ::=
( element_association { , element_association } )
element_association ::=
[ choices => ] expression
choices ::= choice { | choice }
choice ::=
simple_expression
| discrete_range
| element_simple_name
| others
INTENTION:
I am reading data from RAM on ZedBoard, the RAM consists of 32 bits long words so I use the following buffer
type mem_word is array (0 to 127) of std_logic_vector(31 downto 0);
signal buffer_word : mem_word;
but then, I would like to address data in a linear fashion, in an intermediary linear buffer
signal buffer_linear : std_logic_vector(4095 downto 0);
buffer_linear <= buffer_word; -- !!! PROBLEM
so I can easily address any bit in the buffer without recalculating the position in specific word (of the buffer_word).
QUESTION:
How do I get from array of std_logic_vectors into 1 long std_logic_vector ? Is there a way to avoid concatenating 128 words in a loop ? (something like above buffer_linear <= buffer_word;)
You need a function to convert from vector-vector to a 1-dimensional vector.
My following example uses the type name T_SLVV_32 to denote that it is a vector of vectors, wherin the inner vector is 32 bit long. (See my linked source file, for a true 2-dimensional STD_LOGIC matrix type called T_SLM). So T_SLVV_32 is equivalen to your mem_word type.
subtype T_SLV_32 is STD_LOGIC_VECTOR(31 downto 0);
type T_SLVV_32 is array(NATURAL range <>) of T_SLV_32;
function to_slv(slvv : T_SLVV_32) return STD_LOGIC_VECTOR is
variable slv : STD_LOGIC_VECTOR((slvv'length * 32) - 1 downto 0);
begin
for i in slvv'range loop
slv((i * 32) + 31 downto (i * 32)) := slvv(i);
end loop;
return slv;
end function;
Usage:
buffer_linear <= to_slv(buffer_word);
This function creates no logic, just wiring.
Note: Accessing all bits of a memory at once, prevents synthesis tools of inferring RAM or ROM memory blocks!
Source: PoC.vectors
See my vector package at GitHub for more examples on transforming vectors and matrices forth and backwards.