Combinational division in HDL - vhdl

I am trying to come up with a way to estimate the gate count if I were to implement a purely combinational 64-bit division.
I can't get my synthesis tool to generate a combinational 64-bit/64-bit integer division.

a 64bit/64bit divider fully combinational is leading to a huge design. this will use a lot of resources and lead to poor speed achievements. I'd suggest to implement the division with several register stages instead of fully combinational.
however, if you'd like to try, the following code would be synthesisable (as "/" operation is given by numeric_std library). check with a synthesis tool the recources needed for it (for synthesis the use of std_logic_vector in entities is suggested):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity divideComb is
Port ( a : in STD_LOGIC_VECTOR (63 downto 0);
b : in STD_LOGIC_VECTOR (63 downto 0);
c : out STD_LOGIC_VECTOR (63 downto 0));
end divideComb;
architecture Behavioral of divideComb is
begin
c<=std_logic_vector(signed(a)/signed(b));
end Behavioral;
the above code leads to the following synthesis results with Xilinx ISE 13.4:
inferred 131 Adder/Subtractor(s)
inferred 65 Comparator(s)
inferred 4036 Multiplexer(s)
when using Spartan 6 architecture, this leads to 6982 Slice LUTs (and 0 FlipFlops, of course!)

Related

should signals in vhdl be signed/unsigned to perform arithmetic operations?

I am practising some basic vhdl programs.Now i came across arithmetic operations.I used bit_vector and multiplied the input signals directly but it errors "No feasible entries for infix operator".The program is below:
entity multiplier is
port(a,b : in bit_vector(3 downto 0);
c: out bit_vector(7 downto 0));
end multiplier;
architecture ar of multiplier is
begin
c<=(a*b);
end ar;
But i came across this program which works fine with std_logic_vector
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Multiplier_VHDL is
port(
Nibble1, Nibble2: in std_logic_vector(3 downto 0);
Result: out std_logic_vector(7 downto 0)
);
end entity Multiplier_VHDL;
architecture Behavioral of Multiplier_VHDL is
begin
Result <= std_logic_vector(unsigned(Nibble1) * unsigned(Nibble2));
end ;
My questions are:
1.cant we simply add 2 signal bits c<=a+b as we do in verilog?
2.should a signal be signed/unsigned to perform arithmetic operations?
3.like c which is signed by default,what about vhdl/verilog?
4.are signed & unsigned present in use ieee.std_logic_arith.all and use IEEE.NUMERIC_STD.ALL same?
1. Cant we simply add 2 signal bits c <= a + b as we do in verilog?
VHDL is a strongly typed language, which means it is strict when it comes to assigning things of different types to each other. Verilog might let you multiply a simple bit vector; you know what the types of the operands are and the format of the result, and that's fine for your design process. In VHDL, it's not good enough that you as the designer know what formats the numbers are in, the compiler wants to know this as well. In your example, the compiler doesn't know if your vectors represent an unsigned number, signed, fixed point, etc. By casting them to unsigned, you are explicitly telling it what the number format is. An even better solution would be to have these as type unsigned throughout, to avoid the type casts.
Another advantage of VHDL strongly typed is that this can help to catch bugs caused by errors in number format storage at the compilation stage instead of under simulation or on an FPGA device. In general it saves time to catch bugs earlier in the design cycle. If you search online for "strongly typed" you will find more discussion on this topic.
2. Should a signal be signed/unsigned to perform arithmetic operations?
As above, if you want to stick to standard libraries, then yes it is a good idea to give your signals a meaningful type. Think about the guy trying to understand your code in 10 years time (it might even be you), if it's clear what the number formats are, their life will be made easier.
3. Like c which is signed by default, what about vhdl/verilog?
c in your example code is not signed by default in VHDL, it has whatever type you declared it as. If you are multiplying using unsigned, the result would also be unsigned, so this would be the type that I would use for the result. If the type of the result signal does not match the return type of the operation, this will be a compiler error.
4. Are signed & unsigned present in use ieee.std_logic_arith.all and use IEEE.NUMERIC_STD.ALL same?
No, it is not recommended to use std_logic_arith, as this library is not part of the VHDL standard. If you familiarise yourself with the number formats in numeric_std, you should not need to use any other libraries for integer arithmetic.
The usual vector type to use in VHDL is std_logic_vector from the package ieee.std_logic_1164, instead of bit_vector.
However, this vector type is just a collection of std_logic elements, without defined arithmetic operations. So the standard VHDL package that can be used to get arithmetic operations is numeric_std.
Using these for VHDL-2002 compatible code for unsigned arithmetic, it will look:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity multiplier is
port(a, b : in std_logic_vector(3 downto 0);
c : out std_logic_vector(7 downto 0));
end multiplier;
architecture ar of multiplier is
begin
c <= std_logic_vector(unsigned(a) * unsigned(b));
end ar;
However, you could choose to define a, ´b´, and ´c´ as unsigned to simplify the code like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity multiplier is
port(a, b : in unsigned(3 downto 0);
c : out unsigned(7 downto 0));
end multiplier;
architecture ar of multiplier is
begin
c <= a * b;
end ar;
There are also signed types defined in the numeric_std package.
In VHDL-2008, a numeric_std_unsigned package is provided, which provides arithmetic operations for the std_logic_vector type, thus the code can be like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;
entity multiplier is
port(a, b : in std_logic_vector(3 downto 0);
c : out std_logic_vector(7 downto 0));
end multiplier;
architecture ar of multiplier is
begin
c <= a * b;
end ar;
To answer the 4 questions:
Arithmetic operations must be defined for the operands, and this can be done either through use of conversion to unsigned type in numeric_std package, or through use of operators in numeric_std_unsigned package.
For VHDL-2002 yes, and for VHDL-2008 the numeric_std_unsigned package can be used.
See above.
The std_logic_arith package is a Synopsys package, so use numeric_std and numeric_std_unsigned instead.

In VHDL is there a difference between declaring one large vector and using slices of it verses declaring multiple small vectors?

--Example 1:
signal x : STD_LOGIC_VECTOR(15 downto 0);
--do something with x(15 downto 8);
--do soemthing else with x(7 downto 0);
--Example 2:
signal x0 : STD_LOGIC_VECTOR(7 downto 0);
signal x1 : STD_LOGIC_VECTOR(7 downto 0);
--do something with x0(7 downto 0);
--do something else with x1(7 downto 0);
Is there any difference in the above with regards to how it would be implemented inside the FPGA, gate/LUT usage, performance, etc.
And what about when an alias is used like.
--Example 3:
signal x : STD_LOGIC_VECTOR(15 downto 0);
alias x0 is x(15 downto 8);
alias x1 is x(7 downto 0);
--do something with x0(7 downto 0);
--do something else with x1(7 downto 0);
I am new to this so couldn't figure out how to verify it myself, because in Xilinx ISE even if I regenerate the bit file on the same exact source code twice, the check-sum of the resulting bit file always changes. I guess it adds a time-stamp or some random number to the bit file?
The VHDL language does not specify how a design is to be implemented in a device, e.g. FPGA, so a synthesis tool can use whatever resources it wants, as long as the resulting implementation is equivalent with the VHDL source.
Tool vendors, e.g. Xilinx or Altera, does usually not specify the implementation method, but the tools are usually very good at optimizing the design, thus resulting in the smallest possible implementation.
The result is that equivalent VHDL designs will usually result in the same optimal implementation, in special if the design is simple so the synthesis algorithm can build complete internal design structures. Based on these reservations, the short answer is:
All 3 designs are assumed to be equivalent, so they will have the same implementation.
The consequence of this is that you can usually prioritize a design structure that is easy to write, read, review, and test, so you minimize the number of bugs and time spend, and then let the synthesis tool handle the implementation.
Finally, the art is then to understand when usually does not apply, and you therefore have write the design to fit the tool and device in order to get maximum performance and fill.

VHDL - Xilinx ISE crashing during synthesis

I'm new to VHDL and am having a bit of an issue with the synthesis tool crashing when I have certain stuff in my code (developing in Xilinx ISE).
Below is the gist of what is making the program crash.
signal enteredDigit1 : std_logic_vector(3 downto 0);
begin
u3: entity work.module port map (x,y, enteredDigit1)
process(asyncClock, enteredDigit1) begin
ssegDigit <= enteredDigit1
end process
If I do the ssegDigit <= enteredDigit1 outside that process, its fine. However due to me needing to write an asynchronous bit of code, I figured it would be easier to keep track of states and such in a process.
Any ideas why it would just crash? I get no indication from the program console.
EDIT: It seems to be crashing because I'm assigning ssegDigit a new value. If I instead give enteredDigit1 to a variable in the process it compiles
Without seeing the error message and/or the declaration for ssegDigit it may be impossible to provide a definitive answer.
This analyzes:
library ieee;
use ieee.std_logic_1164.all;
entity module is
port (
signal x: in std_logic_vector (3 downto 0);
signal y: in std_logic_vector (3 downto 0);
signal enteredDigit1: out std_logic_vector (3 downto 0)
);
end entity;
architecture foo of module is
begin
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity ssegDigit_tb is
end entity;
architecture foo of ssegDigit_tb is
signal asyncClock: std_logic;
signal x: std_logic_vector(3 downto 0);
signal y: std_logic_vector(3 downto 0);
signal ssegDigit: std_logic_vector(3 downto 0);
signal enteredDigit1 : std_logic_vector(3 downto 0);
begin
u3: entity work.module port map (x,y, enteredDigit1);
process(asyncClock, enteredDigit1)
begin
ssegDigit <= enteredDigit1;
end process;
end architecture;
Notice that ssegDigit has the same index range of enteredDigit1, and I corrected the declaration for enteredDigit1 which was:
signal enteredDigit1 : std_logic_vector(3 down 0);
Where the VHDL reserved word downto was not complete and should be:
signal enteredDigit1 : std_logic_vector(3 downto 0);
Without knowing your exact methodology for causing the ISE tool to crash there's an outside possibility that it's parser isn't robust enough.
In general a simulator's analyzer is going to be more robust than one found in a synthesis tool. Synthesizers are written anticipating a valid VHDL design specification, which also points to the utility of validating your design before synthesis.
If neither the declaration for ssegDigit having a matching element for each element in enteredDigit1 nor fixing the reserved word downto in declaration for enteredDigit1 is your problem, by definition you haven't provided enough information. Also notice the semicolon following the assignment statement in the process and after end process.
Let us know, and elaborate the question if needed.
Noted you corrected the downto in your example but not the missing semicolons.
After your comment:
... The sseg digits are declared as you expected, and port mapped to the same range. I was thinking maybe its a case of the synthesizer flipping out because the signal enteredDigit1 is being modified in a few places. Any idea why it would work outside the process? synchronous issues?
It appears that ssegDigit is declared as a signal and connected to a port. This points to the futility of playing twenty questions in comments, where each time around a bit more information is revealed (we'd eventually get a message suggesting moving dialogs to a wiki chat if nothing else).
Perhaps you could show port declarations including mode, signal declarations for the involved elements and any assignment statements for the signals particularly enteredDigit1.
It might also be useful for you to demonstrate the indications leading you to conclude the synthesis tool 'crashing'.
See How do I ask a good question? , Help others reproduce the problem, "Include just enough code to allow others to reproduce the problem. For help with this, read How to create a Minimal, Complete, Valid Example" (How to create a Minimal, Complete, and Verifiable example).

Error adding std_logic_vectors

I wanna have a simple module that adds two std_logic_vectors. However, when using the code
below with the + operator it does not synthesize.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
entity add_module is
port(
pr_in1 : in std_logic_vector(31 downto 0);
pr_in2 : in std_logic_vector(31 downto 0);
pr_out : out std_logic_vector(31 downto 0)
);
end add_module;
architecture Behavior of add_module is
begin
pr_out <= pr_in1 + pr_in2;
end architecture Behavior;
The error message I get from XST
Line 17. + can not have such operands in this context.
Do I miss a library? If possible, I do not wanna convert the inputs into natural numbers.
Many thanks
How do you want the compiler to know if your std_logic_vectors are signed or unsigned ? Adder implementation is not the same in these two cases, so you need to explicitly tell the compiler what you want it to do ;-)
Note: VHDL syntax highlighting in StackOverflow is crappy. Copy/paste this code in your preferred VHDL editor to read it more easily.
library IEEE;
use IEEE.std_logic_1164.all;
-- use IEEE.std_logic_arith.all; -- don't use this
use IEEE.numeric_std.all; -- use that, it's a better coding guideline
-- Also, never ever use IEEE.std_unsigned.all or IEEE.std_signed.all, these
-- are the worst libraries ever. They automatically cast all your vectors
-- to signed or unsigned. Talk about maintainability and strong typed language...
entity add_module is
port(
pr_in1 : in std_logic_vector(31 downto 0);
pr_in2 : in std_logic_vector(31 downto 0);
pr_out : out std_logic_vector(31 downto 0)
);
end add_module;
architecture Behavior of add_module is
begin
-- Here, you first need to cast your input vectors to signed or unsigned
-- (according to your needs). Then, you will be allowed to add them.
-- The result will be a signed or unsigned vector, so you won't be able
-- to assign it directly to your output vector. You first need to cast
-- the result to std_logic_vector.
-- This is the safest and best way to do a computation in VHDL.
pr_out <= std_logic_vector(unsigned(pr_in1) + unsigned(pr_in2));
end architecture Behavior;
Don't use std_logic_arith - I've written about this (at some length :).
Do use numeric_std - and do use the right type on your entity ports. If you are doing arithmetic, use numerical types (either integers, or (un)signed vectors, as appropriate). They'll synthesise perfectly well.
std_logic_vectors are good for
when you don't care about numerical values (a set of control bits, some random data bits)
when you don't know about the type of the input (say an adder which can operate on both signed and unsigned numbers based on a control flag).
Good advice from #Aurelien to use numeric_std.
Bear in mind that adding two 32 bit values can result in a 33 bit value and decide how you want to handle the overflow.
You cannot do an arithmetic operation with just std_logic_vector. Either you have to convert the std_logic_vector to signed/unsigned (depending on your code requirements) (see 1 below) or else convert them to integers (see 2 below)
pr_out = std_logic_vector(unsigned(pr_in1) + "01")
pr_out = std_logic_vector(integer(pr_in1) + 99)
These are just examples. You can change them based on your requirements.
The easy way to solve this error is:
Add library of unsign,
After that your code starts to work.
Use
ieee.std_logic_unsigned.all;
pr_out <= pr_in1 + pr_in2;

adding '1' to LOGIC_VECTOR in VHDL

I'm trying to add '1' to an N-Length STD_LOGIC_VECTOR in VHDL
This is the very first time I'm using VHDL so I'm not at all sure how to add this 1 without bulding a Full-Adder which seems kinda of redundent
We are not allowed to use any more liberaries then then one in the code.
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY cnt IS
GENERIC (n: natural :=3);
PORT( clk: IN std_logic; -- clock
rst: IN std_logic; -- reset
cntNum: IN std_logic_vector(n-1 DOWNTO 0); -- # of counting cycles
cntOut: OUT std_logic_vector(n-1 DOWNTO 0) -- count result
);
END cnt;
architecture CntBhvArc OF cnt IS
signal counta : std_logic_vector(n-1 DOWNTO 0);
begin
process (clk, rst)
begin
if rst='1' then
counta<="0";
elsif (clk'event) and (clk='0') then
counta<= counta+'1';
end if;
cntOut<=counta;
end process;
END CntBhvArc
Also... can anyone point to a VHDL totrial for someone who has very little experince in programing?
Thanks
You should not use library IEEE.STD_LOGIC_UNSIGNED.ALL
This library is deprecated (see VHDL FAQ); use ieee.numeric_std.all instead.
To answer your last point - don't think of it as programming. HDL stands for "hardware description language". You're describing hardware, always keep it in mind when writing your code :)
I've also written at length about not using STD_LOGIC_UNSIGNED, but using NUMERIC_STD instead. If this is homework and you're being taught to use STD_LOGIC_UNSIGNED, then I despair of the educational establishments. It's been years since that made sense.
VHDL is strongly-typed, so if count is representing a number (and with a name like that, it better had be :), use either a signed or unsigned vector, or an integer. Integers don't wrap around in simulation unless you make them (if you add 1 to them when they are at their max value, the simulator will terminate). The vector types do. Sometimes you want one behaviour, sometimes the other.
Finally, I just noted this:
elsif (clk'event) and (clk='0') then
which is better written as:
elsif falling_edge(clk) then
again, this has been so for about a decade or two. Were you intending to use the falling edge - rising edge is more usual.
You need to cast the std_logic_vector to an unsigned value so you can add one, then cast it back so you can assign it to your output.
This looks like a homework assignment, so I'll leave you to figure out exactly how to do the implementation.

Resources