downto vs. to in VHDL
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.
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...
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!)
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