In VHDL what is means of "if (('0' & next_a)=15) then" - vhdl

In VHDL what is means of "if (('0' & next_a)=15) then"
next_a is vecotr length 4 (next_a : std_logic_vector(3 downto 0))
Thanks you!

It means the author didn't understand what he was doing.
The author apparently realises (or found out in a debugging session) that 15 cannot be represented as a signed 4-bit value, though he is perhaps unaware that it can be represented as an unsigned 4-bit value.
And he is probably using one of those non-standard Synopsys libraries that defaults to a signed interpretation on non-numeric data like std_logic_vector.
So instead of making it clear to the compiler that he wants an unsigned comparison, he sign-extends next_a by prepending '0'to generate a 5-bit signed representation.
If he had taken a clearer view of the design in the first place, he would have used the numeric_std libraries and declared next_a as unsigned(3 downto 0) or even natural range 0 to 15. And written
if next_a = 15 then
If he was forced to use std_logic_vector for some reason, then
if unsigned(next_a) = 15 then
would make the operation equally clear.
If you read this in a book, burn the book (responsibly : avoid forest fires!). And banish constructs like this, and where you reasonably can, those non-standard libraries, from your own code.

Related

Partially constrained vector and arrays in VHDL

Is there some way to define an alias, function or subtype in a package to define syntactic sugar around constrained vector declaration?
I often declare port and signals in VHDL as std_logic_vector(N - 1 downto 0). I would like some syntactic sugar around this. something similar to this:
context work.common;
entity X is
generic(
byteSize : integer := 8
);
port(
DataIn : in logic_bus(byteSize);
DataOut : out logic_bus(byteSize)
);
end entity;
architecture X_arch of X is
signal DataSignal : logic_bus(byteSize);
begin
DataOut <= DataSignal;
DataSignal <= DataIn;
end architecture;
I would like to have this syntactic sugar defined all over my project, i.e., avoid defining a subtype in the architecture if possible. I'm very confused with the usage of open, natural range <>, the difference between type and subtype, and what kind of things functions can return.
regarding constraints inference
I would like to stress that I'm looking for a way to abstract away the definition of similar vector constraints.
The proposal to leave my vector completely unconstrained, while a clever workaround, has strings attached to it that I would like to avoid :
It is not compatible with type casting see here.
It doesn't communicate the relationship between ports (for instance it doesn't communicate that DataIn and DataOut are supposed to be the same size)
It risks to allow badly sized bus designs to pass synthesis by mistake (accidental meaning)
For this reasons, my workplace coding style has banned unconstrained types in ports in favor of generics. Thank you for your understanding.
I assume that you want logic_bus(x) to be some kind function/alias/subtype to abstract away std_logic_vector(N-1 downto 0), working around constrained vector declaration.
VHDL have a quite small user base in terms of numbers. So much of what of the language you can use is highly tool dependent. Make sure you have read up on the supported features of vhdl-2008 for your development environment. As a main user of Xilinx UG901 is my go to for Vivado. Even though a feature is supported you might sometime be required to add an keep attribute to make it not be optimized away in synthesis.
Since a few years back Vivado have a quite full support for vhdl-2008
Unbounded arrays have been supported for even longer.
Generic package have just seen the light of day and seems to be a bit different in Mentor and Xilinx interpretation, but you can make it implement.
Generic types is a part of the language, but I have never got it to work the way I needed it to. (I always try to keep to sl and slv in entity)
As I'm not sure about your environment I can only answer for mine.
Full VHDL-2008 support is assumed
Unconstrained slv
Working around constrained vector definition by avoiding it.
entity X is
port(
DataIn : in std_logic_vector;
DataOut : out std_logic_vector
);
end entity;
architecture X_arch of X is
-- guiding DataSignal with to have a relationship with some signal is usally needed
signal DataSignal : std_logic_vector(DataIn'range);
begin
assert DataIn'length = DataOut'length
report "length missmatch of input and output data"
severity ERROR;
DataOut <= DataSignal;
DataSignal <= DataIn;
end architecture;
Asserts will need to be enabled for synthesis, ether for the run or appended to the synthesis strategy. (see ug901, for Xilinx or check vendor docs)
Unconstrained vectors need to be constrained at the top level. Some times a bit flakey in multi layered component designs. Signals are usually a bit iffy about how they get inferred.
Higher dimensional data can also be unconstrained
type slv_2d is array(natural range <>) of std_logic_vector;
-- Constrain multiple dimensions at once
-- (this might still be broken in GHDL, open issue last time i checked)
-- synthesis/implementation in Vivado works
-- simulates in Modelsim/Questa works
signal test_signal : slv_2d(0 to 5)(7 downto 0);
-- constants can de inferred from assignment
constant test_signal : slv_2d := ("001", "010", "011", "100" );
subtype I usually think about as limiting a type further.
-- integer may be any value within -2147483648 to +2147483647.
-- I might have an issue or a design restriction to highlight
-- I usually don't use subtypes
subtype my_range is integer range 0 to 255;
-- Will throw error if outside of range 0 to 255.
variable cnt : my_range := 0;
I really recommend reading ug901 "Supported VHDL-2008 Features" section of the latest release, even if you don't work with Xilinx. Dolus have a few really good writeups on vhdl-2008 that might strike your fancy and will talk about related features to what you are looking for.

Compare std_logic_vector to a constant using std_logic_vector package ONLY

I use the following package only in my VHDL file:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
In the code, I compare a std_logic_vector signal : A with a constant value, e.g
...if A<="00001011" then
yet the code was checked correctly by Xilinx ISE. My understanding is that STD_LOGIC_1164 package does not include an implementation of inequalities having as an operand std_logic_vector so why the above code statement was accepted and will the above comparison treat A as signed or unsigned number?
-- Copying my comp.lang.vhdl reply to this post. Sorry some duplicates, but some does not.
All enumerated types and arrays of enumerated types implicitly define the regular ordering relational operators (>, >=, <, <=). Unfortunately it is not numerically ordered, so the results may not be as expected. Instead it is dictionary ordered.
First you have to look at the element type, which is std_logic whose base type is std_ulogic. For an enumerated type, such as std_ulogic, left values are less than right values, hence, for std_ulogic (and std_logic):
'U' < 'X' < '0' < '1' < 'Z' < 'W' < 'L' < 'H' < '-'
For equal length arrays whose element base type is std_ulogic (such as std_logic_vector or std_ulogic_vector) whose values are only 0 or 1, things work out fine:
"1010" > "0101"
Note that dictionary comparisons always compare the left element first. Hence, for string, something that starts with 'S' is always less than something that starts with 'T' independent of length. This is great for sorting strings into a dictionary and is the only practical default - if we are going to provide such as thing.
OTOH, this is not so great if you are thinking things are numeric. For example, if the arrays are not equal length, then the following is true because the leading '1'on the left parameter is > the leading '0' of the right parameter.
"100" > "0111"
Hence, with only "use ieee.std_logic_1164.all", you have potential exposure to bad coding practices that mistakenly think of std_logic_vector as numeric (such as unsigned).
Many will argue, never use std_logic_vector for math and ">" is math. I generally agree.
So what do I do? How do I protect my design and design team from this. First you have to decide a policy and how to implement it.
1) Forbid use of regular ordering relational operators (>, >=, <, <=) with std_logic_vector and enforce it with a lint tool. However this means you have to buy and require the use of a lint tool.
2) Forbid use of regular ordering relational operators (>, >=, <, <=) with std_logic_vector and enforce it by using the both of the following package references. Note that this generates errors by referencing two definitions for each of the operators, and hence, when used the expression becomes ambiguous. Note this may be problematic since numeric_std_unsigned was introduced in 1076-2008 and it may not yet be supported by your synthesis tools.
library ieee ;
use ieee.numeric_std_unsigned.all ;
use ieee.std_logic_unsigned.all ;
3) Relax the rules some. Our biggest concern is design correctness. Allow std_logic_vector to be interpreted as an unsigned value and either reference numeric_std_unsigned (preferred, but it is VHDL-2008 and may not be implemented by your synthesis tool yet - but if it is not be sure to submit a bug report) or std_logic_unsigned (not preferred - this is an old shareware package that is not an IEEE standard and perhaps does not belong in the IEEE library - OTOH, it is well supported and it plays nice with other packages - such as numeric_std).
The nice result of this is that it also allows comparisons that include integers:
if A <= 11 then
Note, some suggest that the overloading of ">" and friends in numeric_std_unsigned/std_logic_unsigned is illegal. This was a very conservative interpretation of 1076 prior to VHDL-2008. It was fixed for all revisions of VHDL with an ISAC resolution prior to VHDL-2008 that determined that explicitly defined operators always overload implicitly defined operators without creating any ambiguity. I note that even the VHDL FAQ is out of date on this issue.
4) Be formal, but practical. Never use std_logic_vector. Only use numeric types, such as unsigned and signed from package ieee.numeric_std. Types signed and unsigned also support comparisons with integers.
There are probably a few strategies I left out.
Note that VHDL-2008 introduces matching operators which also address this issue by not defining them for types that do not have a numeric interpretation. These operators are: ?=, ?/=, ?>, ?>=, ?<, ?<=
"<=" is called a relational operator in VHDL.
It's predefined. See IEEE Std 1076-2008, 9.2.3 Relational operators the table. It's a predefined operator for any scalar or single dimensional discrete array type.
std_logic_vector qualifies as a single dimensional discrete array type, it's element types discrete, in this case being enumerated types (std_logic/std_ulogic). See 5.2 Scalar types, 5.2.1 General, wherein the first paragraph demonstrates an enumerated type is discrete.
And for a simpler answer it's part of the language.
Short answer: you need to use an extra package: ieee.numeric_std
I must assume that you have defined A as a std_logic_vector(7 downto 0).
This data type represents an array of bits. There is no numeric value associated with it. Hence, the comparison between A and your bit string literal does not make sense.
If you want to compare the numeric values represented by A, you need to use unsigned(7 downto 0) or signed(7 downto 0), preferably from the package ieee.numeric_std. This is the accepted good practice to attribute numeric values to arrays of bits.
Technically, you could work around this and define your own "<=" function, but you would just be duplicating code from the VHDL standard IEEE library.
To expand on David's answer slightly: it's predefined for discrete arrays such that, basically, array elements are compared left to right (according to IEEE 1076-2008, 9.2.3), and each scalar array element is compared using its inherent order which, in the case of an enumeration like std_logic, is defined by its position (according to 5.2.2.1). '1' is "greater than" '0' only because its position in the std_ulogic declaration is higher (and 'Z' is "greater than" '1' for the same reason).
It should be clear from this that it's not treating the vectors as signed or unsigned. It happens to look like it's treating the vectors as unsigned if they're equal length and only contain '0' and '1', but you still shouldn't do it.

When to use what types

Questions:
Is there a more appropiate "supertype" to signed and unsigned than std_logic_vector (regarding my case)?
Is it ok to define an Input as (subtype of) Integer or is it better to define it as bitvector? (Are there any Issues with the Integer approach)
When should I use resolved or unresolved logic for the Inputs/Outputs off an Entity?
Resolved for Bus drivers (because of the "high Z drivers") otherwise unresolved?
Always resolved so a bus can be driven/used as input (this seems wrong, because when would I use unresolved then?)
Actual Case:
I am declaring an entity and am wondering for the right types for the inputs and outputs.
Lets assume I am constructing a dynamic width equal. It compares the first n Bits of two Inputs for equality.
The entity definition would be:
entity comparisonDynWidth is
generic(
width : positive;
min_width : positive;
-- when the tools suport vhdl2008 enough
-- reason for both signed/unsigned => std_logic inputs
--function compareFunc (x: in std_logic_vector; y: in std_logic_vector) return std_logic
);
port (
left, right : in std_logic_vector(width-1 downto 0);
widthControl: in natural range 0 to width-min_width;
result : out std_logic / std_ulogic ??
);
I chose std_logic_vector as Input since I want it to look the ports like a generic less than comparator as well, for which signedness matters and which can have signed and unsigned inputs.
since it is easier for me to define the width as an integer I did so.
Is there a more appropiate "supertype" to signed and unsigned than
std_logic_vector (regarding my case)?
Not sure what you mean, but you have no choice - signed and unsigned are defined in the standard.
Is it ok to define an Input as (subtype of) Integer or is it better to
define it as bitvector? (Are there any Issues with the Integer
approach)
Integers will flag errors if you go outside their range. vectors (signed and unsigned) will wrap around. Which is "correct" depends on what you want and how you feel about coding explicit wrap-around if you want it with integers.
When should I use resolved or unresolved logic for the Inputs/Outputs
off an Entity?
If you stick to:
only using resolved types for the top level IO ports (i.e. the actual pins of the device)
using unresolved types internally
you will be able catch errors involving multiple drivers on a signal with a detailed error-message at elaboration-time. This can be preferable to chasing down Xs in your waveforms at simulation-time.
There are no internal tri-state buses internally to most technologies these days, so you can't have multiple drivers, so there's no need for resolved signals inside the device. IO pins (almost?) always have tri-stateble drivers, so the use of a resolved type is appropriate, and the driving of a 'Z' can be used to infer that behaviour.
std_logic_vector is a good choice in your case (and in most cases in an entity, as it represents hardware situation best... e.g. with use of 'U' and 'Z' and so on)
the use of integer in an entity is ok as long as it is not the top-level entity. in top level entities, the exclusive use of std_logic(_vector) is recommended.
most tools report multi-driver situations anyway... the use of resolved types is therefore ok.

How to represent Integer greater than integer'high

Is there any way to use pre-defined types from STD_LOGIC_1164 or STD_NUMERIC to represent an integer ranging from 0 to 2^32-1 ? (considering the default integer type ranges from -2^31-1 to 2^31-1)
I need to implement 32-bit counter and was looking for some way to save code using integer type instead of std_logic_vector.. Any design pattern for this ?
Or, better asked: Whats the best way to declare a 32-bit (unsigned) integer supporting the operations >/<, =, +-/ ?
Tahnks in advance
Edit1: One option I found was to declare a signal as std_logic_vector(31 downto 0), and to perform conversions when doing comparisons or +- operations.. ex: counter <= counter + std_logic_vector(unsigned(value) + 1).. Still haven't found a way to do division though (in case,for example, 1/4 of the value of counter is needed)
Using the Integer types, you cannot (at least, not portably; there may be some VHDL tools that go beyond the minimum and offer a 64-bit integer)
Using IEEE.numeric_std, you can declare an Unsigned with a full 32-bit range (or 53-bit if you wish) and it should do everything you want.need, unless I misunderstand what you are asking.
use ieee.numeric_std.all;
and then use the unsigned data type - this operates as a bit vector with mathematical operations defined for it. You can choose how many bits you'd like. For example:
signal mynum : unsigned(234 downto 0)

downto vs. to in VHDL

I'm not sure I understand the difference between 'downto' vs. 'to' in vhdl.
I've seen some online explanations, but I still don't think I understand. Can anyone lay it out for me?
If you take a processor, for Little endian systems we can use "downto" and for Bigendian systems we use "to".
For example,
signal t1 : std_logic_vector(7 downto 0); --7th bit is MSB and 0th bit is LSB here.
and,
signal t2 : std_logic_vector(0 to 7); --0th bit is MSB and 7th bit is LSB here.
You are free to use both types of representations, just have to make sure that other parts of the design are written accordingly.
This post says something different:
"The term big endian (or little endian) designates the byte order in byte oriented processors and doesn't fit for VHDL bit vectors. The technical term is ascending and descending array range. Predefined numerical types like signed and unsigned are restricted to descending ranges by convention."
So, this answer can be confusing...
One goes up, one goes down:
-- gives 0, 1, 2, 3:
for i in 0 to 3 loop
-- gives 3, 2, 1, 0:
for i in 3 downto 0 loop
An interesting online reference I found is here, where among others, under the section "Array Assignments," you can read:
Two array objects can be assigned to each other, as long as they are of the same type and same size. It is important to note that the assignment is by position, and not by index number. There is no concept of a most significant bit defined within the language. It is strickly interpreted by the user who uses the array. Here are examples of array assignments:
with the following declaration:
....
SIGNAL z_bus: BIT_VECTOR (3 DOWNTO 0);
SIGNAL a_bus: BIT_VECTOR (1 TO 4);
....
z_bus <= a_bus;
is the same as:
z_bus(3) <= a_bus(1);
z_bus(2) <= a_bus(2);
z_bus(1) <= a_bus(3);
z_bus(0) <= a_bus(4);
Observations:
1) Any difference of "downto" and "to" appears when we want to use a bit-vector not just to represent an array of bits, where each bit has an independent behavior, but to represent an integer number. Then, there is a difference in bit significance, because of the way numbers are processed by circuits like adders, multipliers, etc.
In this arguably special case, assuming 0 < x < y, it is a usual convention that when using x to y, x is the most significant bit (MSB) and y the least significant bit (LSB). Conversely, when using y downto x, y is the MSB and x the LSB. You can say the difference, for bit-vectors representing integers, comes from the fact the index of the MSB comes first, whether you use "to" or "downto" (though the first index is smaller than the second when using "to" and larger when using "downto").
2) You must note that y downto x meaning y is the MSB and, conversely, x to y meaning x is the MSB are known conventions, usually utilized in Intellectual Property (IP) cores you can find implemented and even for free. It is, also, the convention used by IEEE VHDL libraries, I think, when converting between bit-vectors and integers. But, there is nothing even difficult about structural modeling of, e.g., a 32-bit adder that uses input bit-vectors of the form y downto x and use y as the LSB, or uses input bit-vectors of the form x to y where x is used as the LSB...
Nevertheless, it is reasonable to use the notation x downto 0 for a non-negative integer, because bit positions correspond to the power of 2 multiplied by the digit to add up to the number value. This seems to have been extended also in most other practice involving integers.
3) Bit order has nothing to do with endianness. Endianness refers to byte ordering (well, byte ordering is a form of bit ordering...). Endianness is an issue exposed at the Instruction Set Architecture (ISA) level, i.e., it is visible to the programmer that may access the same memory address with different operand sizes (e.g., word, byte, double word, etc). Bit ordering in the implementation (as in the question) is never exposed at the ISA level. Only the semantics of relative bit positions are visible to the programmer (e.g., shift left logical can be actually implemented by shifting right a register who's bit significance is reversed in the implementation).
(It is amazing how many answers that mention this have been voted up!)
In vector types, the left-most bit is the most significant. Hence, for 0 to n range, bit 0 is the msb, for a n downto 0 range bit n is the msb.
This comes in handy when you are combining IP which uses both big-endian and little-endian bit orderings to keep your head straight!
For example, Microblaze is big-endian and uses 0 as its msb. I interfaced one to an external device which was little-endian, so I used 15 downto 0 on the external pins and remapped them to 16 to 31 on the microblaze end in my interface core.
VHDL forces you to be explicit about this, so you can't do le_vec <= be_vec; directly.
Mostly it just keeps you from mixing up the bit order when you instantiate components. You wouldn't want to store the LSB in X(0) and pass that to a component that expects X(0) to contain the MSB.
Practically speaking, I tend to use DOWNTO for vectors of bits (STD_LOGIC_VECTOR(7 DOWNTO 0) or UNSIGNED(31 DOWNTO 0)) and TO for RAMs (TYPE data_ram IS ARRAY(RANGE NATURAL<>) OF UNSIGNED(15 DOWNTO 0); SIGNAL r : data_ram(0 TO 1023);) and integral counters (SIGNAL counter : NATURAL RANGE 0 TO max_delay;).
To expand on #KerrekSB's answer, consider a priority encoder:
ENTITY prio
PORT (
a : IN STD_LOGIC_VECTOR(7 DOWNTO 1);
y : OUT STD_LOGIC_VECTOR(2 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE seq OF prio IS
BEGIN
PROCESS (a)
BEGIN
y <= "000";
FOR i IN a'LOW TO a'HIGH LOOP
IF a(i) = '1' THEN
y <= STD_LOGIC_VECTOR(TO_UNSIGNED(i, y'LENGTH));
END IF;
END LOOP;
END PROCESS;
END ENTITY;
The direction of the loop (TO or DOWNTO) controls what happens when multiple inputs are asserted (example: a := "0010100"). With TO, the highest numbered input wins (y <= "100"). With DOWNTO, the lowest numbered input wins (y <= "010"). This is because the last assignment in a process takes precedence. But you could also use EXIT FOR to determine the priority.
I was taught that a good rule is to use "downto" for matters where maintaining binary order is important (for instance an 8 bit signal holding a character) and "to" is used when the signal is not necessarily interconnected for instance if each bit in the signal represents an LED that you are turning on and off.
connecting a 4 bit "downto" and a 4 bit "to" looks something like
sig1(3 downto 0)<=sig2(0 to 3)
-------3--------------------0
-------2--------------------1
-------1--------------------2
-------0--------------------3
taking part of the signal instead sig1(2 downto 1) <= sig2(0 to 1)
-------2--------------------0
-------1--------------------1
Though there is nothing wrong with any of the answers above, I have always believed that the provision of both is to support two paradigms.
First is number representation. If I write the number 7249 you immediately interpret it as 7 thousand 2 hundred and forty-nine. Numbers read from left to right where the most significant digit is on the left. This is the 'downto' case.
The second is time representation where we always think of time progressing from left to right. On a clock the numbers increase over time and 2 always follows 1. Here I naturally write the order of bits from left 'to' right in time ascending order regardless of the representation of the bits. In RS232 for instance we start with a start bit followed by 8 data bits (LSB first) then a stop bit. Here the MSB is on the right; the 'to' case.
As said the most important thing is not to mix them arbitrarily. In decoding an RS232 stream we may end up doing just that to turn bits received in time order into bytes which are MSB first but this is very much the exception rather than the rule.

Resources