VHDL - creating a variable number of signals - for-loop

I'm creating a full adder with a variable number of bits. I've got a component that is a half-adder which takes in three inputs (the two bits to add, and a carry in bit) and gives 2 outputs (one bit output and a carry out bit).
I need to tie the carry out of one half-adder to the carry in of another. And I need to do this a variable number of times (if I'm adding 4 digit numbers, I'll need 4 half adders. If I'm doing 32 bit numbers, I'll need 32 half adders).
I was going to tie the carry outs of one half-adder to the carry in of another using signals, but I don't know how to create a variable number of signals.
I can instantiate a variable number of half-adders using a for-loop in a process, but since signals are defined outside of processes, I can't use a for loop for it. I don't know how I should tie the half-adders together.

The easiest way to write an adder in VHDL is not to worry about full adders and half adders, but just type:
a <= b + c;
where a,b and c are signed or unsigned
95% of the time, the synthesis tools will do a better job than you would.

I think you want variable-width signals not variable numbers of signals
Your signals need to be std_logic_vector(31 downto 0) for example - and then you wire up the bits of those signals to your half-adders appropriately.
Of course, as those signals are numbers, then don't use std_logic_vector use signed or unsigned (and the ieee.numeric_std lib).
And (as Philippe rightly points out) unless this is a learning exercise, just use the + operator.

Related

In Verilog and VHDL, what exactly is the difference between `logic[19:4]` and `logic[15:0]`?

and of course the equivalent syntax in VHDL?
Is the lower index a minimum bound for indexing? What happens in assignments between signals with differing bounds but the same width?
Assuming you meant the widths to be the same...
...so, in Verilog let's assume you meant
logic [19:4] v19_4;
logic [15:0] v15_0;
In a Verilog simulation, you will not experience any difference unless to try to index the bits.
If you index the bits, you will find that
in the first case, the left hand bit is bit 19 (ie v19_4[19]), whereas in the second case, the left hand bit is bit 15 (ie v15_0[15]);
in the first case, the right hand bit is bit 4 (ie v19_4[4]), whereas in the second case, the right hand bit is bit 0 (ie v15_0[0]).
In Verilog, it is valid to call the left hand bit "the MSB" and the right hand bit "the LSB".
You will experience exactly the same behaviour in VHDL. In VHDL let's assume you meant
signal v19_4 : std_logic_vector(19 downto 4);
signal v15_0 : std_logic_vector(15 downto 0);
Again, in a VHDL simulation, you will not experience any difference unless to try to index the bits. If you index the bits, you will find that
in the first case, the left hand bit is bit 19 (ie v19_4(19)), whereas in the second case, the left hand bit is bit 15 (ie v15_0(15));
in the first case, the right hand bit is bit 4 (ie v19_4(4)), whereas in the second case, the right hand bit is bit 0 (ie v15_0(0)).
With synthesis you might see a difference. It is generally recommended to index vectors from 0 for synthesis to remove the possibility of synthesising more bits than you need. However, I would think that most synthesisers would optimise away the excess logic.

Most efficient VHDL for large vector?

I want to be able to have a shift register that does an XOR against another register loaded with some value. The issue is that I wish to do this with a large scale vector, something on the order of thousands of bits wide.
The obvious way to do this in VHDL would be something like
generic( length : integer := 15);
signal shiftreg : std_logic_vector(length downto 0);
process(clk)
begin
if rising_edge(clk) then
shiftreg<= shiftreg(length-1 downto 0) & input;
endif;
end process;
However, if length here is set to some very high number, attempting to synthesize this becomes a massive undertaking. Since this is a relatively simple structure I imagine it is taking so long because the length is far beyond the number of registers in a single block.
My question is if there is some way to implement a large vector like this in a way that would be quicker to synthesize. For example, is it quicker to use something like
array(length downto 0) of std_logic;
or does a synthesis tool recognize those are equivalent?
Synthesis time is not typically relevant in FPGA design, although area utilization and timing usually is. If your shift register takes most of the resources that your target FPGA has, synthesis will take a long time trying to figure out a way to make it work, and likewise builds take longer as you fill up larger parts. For some ballpark, an 80% full design with tight timing in a modern midrange FPGA usually takes about 30 minutes to synthesize and 3 hours to place&route. This will not be significantly affected by coding style if you're still describing the same functionality.
If you describe a shift register (with the same functional features) in VHDL using std_logic_vector, a type you defined as an array of std_logic, or anything else, it will synthesize into the same thing.
In recent-ish Xilinx parts at least, a single LUT can be used for a 64-deep shift register as long as you haven't described a reset (synchronous OR asynchronous). You can likewise produce a 1000 deep shift register with just a handful of LUTs.
Now if you're looking to use the whole thousand+ bits of this shift register to xor against some other register, you can't use SRLs (LUT used as a shift register) because only the final bit is accessible as an output. This makes it put the whole thing in registers which may be rather large, and could require more registers than your part has. The key thing here is that you have to think about the scale of the hardware you describe, and whether that's feasible in your target part.
If you want a really deep shift register, block rams can be used to act like shift registers at depths exceeding 100,000 but these have the same issue where you only access the final output.

What is the minimum number of bits I need to express a n-bit, signed std_logic_vector in VHDL?

I'm new to VHDL and am trying to find a way to take a n bit (stored as a generic) signed number and truncate it to a form that requires the minimum number of bits.
For example, if I have 5 as its 8 bit signed number (stored in a std_logic_vector of length 8) 00000101, I'd like to make a function to return 0101 as a std_logic_vector. Any ideas on how I can accomplish this?
Since you have specified that you're using a signed value, you may want to use the signed type (from the numeric_std library) instead of the more generic std_logic_vector.
If your number is a compile time constant, you can write a function starting from the leftmost bit (in a for loop for example) that counts how many identical bits it sees, then returns signed_input(8-result downto 0). The issue with this is that as a compile time constant, there isn't much advantage in removing the redundant bits. The whole vector will be optimized away in synthesis.
You might want to include special cases to make the result at least 1 bit (0 technically doesn't need any bits to represest) or 2 bits (-1 only needs the sign bit to distinguish it from 0) depending on how you want to use your signed type value.
If your number is a real signal (the value changes during operation), you can still count the number of identical bits from the left, but variable location slicing of the vector will be iffy. Are you trying to pack the most of several numbers into a fixed bit width? Doing that will synthesize into multiplexers for each bit as well as the LUTs used for calculating the number of redundant bits for each of the numbers.

Trouble having Implement Shift Operator (sll) in VHDL

I am trying to make a BCD converter to show numbers from 0 to 9999, I need to implement Double Dabble Algorithm using the shift operators. But I just cannot start coding without running into warnings i dont really know about, I am still a beginner so please ignore any stupid mistakes that I make. I started off by first implementing the algorithm. I have never used shift operators so I am probably not doing it right, please help, here is my code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity algorithm is
Port (x: in unsigned (15 downto 0);
y: out unsigned (15 downto 0));
end algorithm;
architecture Behavioral of algorithm is
begin
y <= x sll 16;
end Behavioral;
And the error
Xst:647 - Input <x> is never used. This port will be preserved and left unconnected
if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of
this sub-block is preserved.
Even if I implement this
y <= x sll 1;
I get this error
Xst:647 - Input <x<15>> is never used. This port will be preserved and left
unconnected if it belongs to a top-level block or it belongs to a sub-block
and the hierarchy of this sub-block is preserved.
What am I doing wrong here?
What you are doing wrong is, firstly, attempting to debug a design via synthesis.
Write a simple testbench which, first, exercises your design (i.e. given the code above, feeds some data into the X input port).
Later you can extend the testbench to read the Y output port and compare the output with what you would expect for each input, but you're not ready for that yet.
Simulate the testbench and add the entity's internal signals to the Wave window : does the entity do what you expect? If so, proceed to synthesis. Otherwise, find and fix the problem.
The specific lines of code above, y <= x sll 16; and y <= x sll 1; work correctly and the synthesis warnings (NOT errors) are as expected. Shifting a 16 bit number by 16 bits and fitting the result into a 16 bit value, there is nothing left, so (as the warning tells you) port X is entirely unused. Shifting by 1 bit, the MSB falls off the top of the result, again exactly as the warning says.
It is the nature of synthesis to warn you of hundreds of such things (often most of them come from the vendor's own IP, strangely enough!) : if you have verified the design in simulation you can glance at the warnings and ignore most of them. Sometimes things really do go wrong, then one or two of the warnings MAY be useful. But they are not a primary debugging technique; most of them are natural and expected, as above.
As David says, you probably do want a loop inside a clocked process : FOR loops are synthesisable. I have recently read a statement that WHILE loops are often also synthesisable, but I have found this to be less reliable.

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