Comparing a long std_logic_vector to zeros - vhdl

In simulation this works perfect. Is this is the best way of checking for
zeros for a synthesisable code. What would be the resources generated?
signal vector_slv : std_logic_vector(2048 downto 0);
...
if (vector_slv = (vector_slv'range => '0')) then
-- do something...
Is there any other optimal way to implement this solution considering h/w mapping (with optimal resource utilization).
I would be more interested in understanding the resources used.

There's no way that makes more or less sense for synthesis. Write the code that best expresses your intention.
If you are comparing a vector for all zeros, the following should all produce the same results, or you should file a serious bug against the tool!
signal vector_slv : std_logic_vector(2048 downto 0);
constant zeros : std_logic_vector(vector_slv'range) := (others => '0');
...
if vector_slv = (vector_slv'range => '0') then
-- do something...
if vector_slv = zeros then
-- do something...
if unsigned(vector_slv) = to_unsigned(0, vector_slv'length) then
-- do something...
and indeed for shorter vectors which fit in an integer:
if intvar = 0 then
will be exactly the same as any 32-bit vector comparison.
(BTW, note there is no need for parentheses around the if condition - VHDL is not C :)

If the range is available, as in your example code, then the suggestion
solution looks fine, and I would expect that synthesis tools are made to handle
constructions like this.
If the range is not available, then compare with zero can be made like:
library ieee;
use ieee.numeric_std.all;
...
if unsigned( {std_logic_vector expression of any length} ) = 0 then
-- do something...
I would expect that synthesis tools handle this the same was as for compare
with (vector_slv'range => '0').

As far as synthesis is concerned, yes, such simple constructs are usually optimized fairly well by the tool. The exact hardware layout of course depends on what your target is (FPGA, ASIC, ...).
My suggestion is to take a look at the synthesis result (e.g. Technology Map Viewer for Altera FPGAs). If synthesis clobbers it, you can manually convert it into a binary tree of comparisons with zero, taking into account the technology primitives you have available. This can be a lot more tricky than it sounds, though, especially for FPGAs (there's more than LUTs to play with there), and shouldn't be necessary with a decent tool.

You can also separate predicate and assignment by doing this :
signal is_zero : boolean;
signal vector_slv : std_logic_vector(2048 downto 0);
...
process(clk)
begin
if rising_edge(clk) then
is_zero <= vector_slv = (vector_slv'range => '0');
if is_zero then
...
end if;
end if;
end process;
This should improve your Timing very much. Take into account that the predicate 'is_zero' is now a delayed version of your original comparison !

You could use the unary operators, e.g.:
and
nand
or
nor
signal vector_slv: std_logic_vector(2048 downto 0);
...
if and vector_slv then
-- Do something for all 1...
elsif nand vector_slv then
-- Do something for at least one 0...
elsif or vector_slv then
-- Do something for at least one 1...
elsif nor vector_slv then
-- Do something for all 0...
end if;
Or you could use the functions defined in std_logic_1164, e.g.:
function "and" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "nand" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "or" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "nor" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
use ieee.std_logic_1164.all;
...
signal vector_slv: std_logic_vector(2048 downto 0);
...
if and(vector_slv) then
-- Do something for all 1...
elsif nand(vector_slv) then
-- Do something for at least one 0...
elsif or(vector_slv) then
-- Do something for at least one 1...
elsif nor(vector_slv) then
-- Do something for all 0...
end if;

Related

Process or not to Process?

I have the below code in VHDL that I use in a project. I have been using a Process within the architecture and wanted to know if there were any other means which I'm sure there are of accomplishing the same goal.. in essence to take one number compare it to another and if there is a difference of +/- 2 reflect this in the output. I am using the following:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all, IEEE.std_logic_arith.all, IEEE.std_logic_signed;
ENTITY thermo IS
PORT (
CLK : in std_logic;
Tset, Tact : in std_logic_vector (6 DOWNTO 0);
Heaton : out std_logic
);
END ENTITY thermo;
ARCHITECTURE behavioral OF thermo IS
SIGNAL TsetINT, TactINT : integer RANGE 63 Downto -64; --INT range so no 32bit usage
BEGIN
Heat_on_off: PROCESS
VARIABLE ONOFF: std_logic;
BEGIN
TsetINT <= conv_integer (signed (Tset));--converts vector to Int
TactINT <= conv_integer (signed (Tact));--converts vector to Int
--If you read this why is it conv_integer not to_integer?? thx
ONOFF := '0'; --so variable does not hang on start
WAIT UNTIL CLK'EVENT and CLK = '1';
IF TactINT <= (TsetINT - 2) then
ONOFF := '1';
ELSIF TactINT >= (TsetINT + 2) then
ONOFF := '0';
END IF;
Heaton <= ONOFF;
END PROCESS;
END ARCHITECTURE behavioral;
I'm just after a comparison really and to know if there are any better ways of doing what I have already done.
Why convert Tact and Tset to an integer?
Why have the variable ONOFF? The variable initialization appears to remove any sense of hysteresis, is that what you intended? Based on your other code, I bet not. I recommend that you assign directly to the signal Heaton instead of using the variable ONOFF.
If I were to create TsetINT and TactINt, these would be good candidates to be variables. However, there is no need to do the integer conversion as you can simply do the following:
if signed(Tact) <= signed(Tset) - 2 then
...
elsif signed(Tact) >= signed(Tset) + 2 then
Please use numeric_std. Please ask your professor why they are teaching you old methodologies that are not current industry practice. Numeric_std is an IEEE standard and is updated with the standard, std_logic_arith is not an IEEE standard.
use ieee.numeric_std.all ;
In response to Jim's comment I wrote a simple thermal model test bench to test your design.
I only changed your design to use package numeric_std instead of the Synopsys packages. The rest is just prettifying and eliminating comments not germane to the question of whether or not Tact ever reaches Tset.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity thermo is
port (
CLK: in std_logic;
Tset, Tact: in std_logic_vector (6 downto 0);
Heaton: out std_logic
);
end entity thermo;
architecture behavioral of thermo is
signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process
variable ONOFF: std_logic;
begin
TsetINT <= to_integer (signed (Tset)); -- package numeric_std
TactINT <= to_integer (signed (Tact)); -- instead of conv_integer
ONOFF := '0'; -- AT ISSUE -- so variable does not hang on start
wait until CLK'event and CLK = '1';
if TactINT <= TsetINT - 2 then -- operator precedence needs no parens
ONOFF := '1';
elsif TactINT >= TsetINT + 2 then
ONOFF := '0';
end if;
Heaton <= ONOFF;
end process;
end architecture behavioral;
You have a comment in your process asking why conv_integer was required instead of to_integer. That prompted the change.
I removed superfluous parentheses based on operator order precedence (adding operators being higher precedence than relational operators), notice Jim's answer did the same.
So the simple model thermal model runs with a clock set to a 1 second period, and has two coefficients, relating to the temperature increase when Heaton is '1' or not. I arbitrarily set the heating up coefficient to 1 every 4 clocks, and the temperature decay coefficient to 1 every 10 clocks. Also set the ambient temperature (tout) to 10 and tset to 22. The numbers selected are severe to keep the model run time short enhancing portability without relying on setting a simulator resolution limit.
The thermal model was implemented using fixed signed arithmetic without using fixed_generic_pkg, allowing portability to -1993 tools without math packages and includes a fractional part, responsible for the different widths of Heaton true after reaching normal operating temperature. The model could just as easily have been implemented with two different precursor counters used to tell when to increment or decrement Tact.
Using REAL types is possible, not desirable because converting REAL to INTEGER (then to SIGNED) isn't portable (IEEE Std 1076-2008 Annex D).
The idea here is to demonstrate the lack of hysteresis and demonstrate the model doesn't reach Tset:
The lack of hitting Tset (22 + 2) is based on the lack of hysteresis. Hysteresis is desirable for reducing the number of heat on and off cycles The idea is once you start the heater you leave in on for a while, and once you stop it you want to leave it off for a while too.
Using Jim's modification:
-- signal TsetINT, TactINT: integer range 63 downto -64;
begin
HEAT_ON_OFF:
process (CLK)
begin
if rising_edge(CLK) then
if signed(Tact) <= signed(Tset) - 2 then
Heaton <= '1';
elsif signed(Tact) >= signed(Tset) + 2 then
Heaton <= '0';
end if;
end if;
end process;
gives us longer Heaton on and off cycles, decreasing how many times the heater starts and stops:
And actually allows us to see the temperature reach Tset + 2 as well as Tset - 2. where these thresholds provide the hysteresis which is characterized as a minimum on or minimum off time, depending on the efficiency of the heater and heat loss rate when the heater is off.
So what changed in the execution of the thermo model process? Look at the difference in the synthesis results for the two versions.

AND all elements of an n-bit array in VHDL

lets say I have an n-bit array. I want to AND all elements in the array. Similar to wiring each element to an n-bit AND gate.
How do I achieve this in VHDL?
Note: I am trying to use re-usable VHDL code so I want to avoid hard coding something like
result <= array(0) and array(1) and array(2)....and array(n);
Thanks
Oshara
Solution 1: With unary operator
VHDL-2008 defines unary operators, like these:
outp <= and "11011";
outp <= xor "11011";
outp <= and inp; --this would be your case
However, they might not be supported yet by your compiler.
Solution 2: With pure combinational (and traditional) code
Because in concurrent code you cannot assign a value to a signal more than once, your can create a temp signal with an "extra" dimension. In your case, the output is one-bit, so the temp signal should be a 1D array, as shown below.
-------------------------------------------
entity unary_AND IS
generic (N: positive := 8); --array size
port (
inp: in bit_vector(N-1 downto 0);
outp: out bit);
end entity;
-------------------------------------------
architecture unary_AND of unary_AND is
signal temp: bit_vector(N-1 downto 0);
begin
temp(0) <= inp(0);
gen: for i in 1 to N-1 generate
temp(i) <= temp(i-1) and inp(i);
end generate;
outp <= temp(N-1);
end architecture;
-------------------------------------------
The inferred circuit is shown in the figure below.
Solution 3: With sequential code
This is simpler than solution 2, though you are now using sequential code to solve a purely combinational problem (but the hardware will be the same). You can either write a code similar to that in solution 2, but with a process and loop (the latter, in place of generate) or using a function. Because in sequential code you are allowed to assign a value to a signal more than once, the temp signal of solution 2 is not needed here.
If you have VHDL-2008 available, then reduction and is build into the
language as David Koontz and Pedroni have explained.
If you only have VHDL-2003 and prior available, then you can use a function
like:
function and_reduct(slv : in std_logic_vector) return std_logic is
variable res_v : std_logic := '1'; -- Null slv vector will also return '1'
begin
for i in slv'range loop
res_v := res_v and slv(i);
end loop;
return res_v;
end function;
You can then use the function both inside and outside functions with:
signal arg : std_logic_vector(7 downto 0);
signal res : std_logic;
...
res <= and_reduct(arg);
My favorite, non-VHDL-2008 solution is:
use ieee.std_logic_unsigned.all ; -- assuming not VHDL-2008
. . .
result <= '1' when not MyArray = 0 else '0' ;
With VHDL-2008, I recommend that you use the "and" reduction built-in (see Pedroni's post) and use the IEEE standard package "ieee.numeric_std_unsigned.all" instead of the shareware package "std_logic_unsigned".

Non-recommended latches generated in VHDL

As part of a school project where we do genetics algorithm, I am programming something called "crossover core" in VHDL. This core is supposed to take in two 64-bit input "parents" and the two outputs "children" should contain parts from both inputs.
The starting point for this crossover is based on a value from an input random_number, where the 6 bit-value detemines the bit-number for where to start the crossover.
For instance, if the value from the random_number is 7 (in base 10), and the inputs are only 0's on one, and only 1's on the other, then the output should be something like this:
000.....00011111111 and 111.....11100000000
(crossover start at bit number 7)
This is the VHDL code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity crossover_core_split is
generic (
N : integer := 64;
R : integer := 6
);
port (
random_number : in STD_LOGIC_VECTOR(R-1 downto 0);
parent1 : in STD_LOGIC_VECTOR(N-1 downto 0);
parent2 : in STD_LOGIC_VECTOR(N-1 downto 0);
child1 : out STD_LOGIC_VECTOR(N-1 downto 0);
child2 : out STD_LOGIC_VECTOR(N-1 downto 0)
);
end crossover_core_split;
architecture Behavioral of crossover_core_split is
signal split : INTEGER := 0;
begin
split <= TO_INTEGER(UNSIGNED(random_number));
child1 <= parent1(N-1 downto split+1) & parent2(split downto 0);
child2 <= parent2(N-1 downto split+1) & parent1(split downto 0);
end Behavioral;
The code is written and compiled in Xilinx ISE Project Navigator 12.4.
I have tested this in ModelSim, and verified that it works. However, there is an issues with latches, and I get these warnings:
WARNING:Xst:737 - Found 1-bit latch for signal <child1<62>>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
WARNING:Xst:737 - Found 1-bit latch for signal <child1<61>>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
ETC ETC ETC...
WARNING:Xst:1336 - (*) More than 100% of Device resources are used
A total of 128 latches are generated, but appearantly they are not recommended.
Any advices in how to avoid latches, or at least reduce them?
This code is not well suited for synthesis: the length of the sub-vectors should not vary and maybe this is the reason for the latches.
For me the best solution is to create a mask from the random value: you can do that in many way (it's typically a binary to thermometric conversion). As example (it's not the optimal one):
process(random_number)
begin
for k in 0 to 63 loop
if k <= to_integer(unsigned(random_number)) then
mask(k) <= '1';
else
mask(k) <= '0';
end if;
end loop;
end process;
then once you have the mask value you can simply write:
child1 <= (mask and parent1) or ((not mask) and parent2);
child2 <= (mask and parent2) or ((not mask) and parent1);

synthesis of dynamic mux on std_logic_vector bytes

I have a FIFO who's size is determined according to a parameter in the package:
signal fifo : std_logic_vector(FIFO_SIZE*8 -1 downto 0);
I also have a 4 bit vector (numOfBytes) saying how many bytes are in the FIFO at any given time (up to 8).
I want the data out (a single byte) from the FIFO to be determined according the numOfBytes signal:
Do <= fifo(to_integer(unsigned(numOfBytes)*8 -1 downto to_integer(unsigned(numOfBytes)*8 -8) when numOfBytes /= x"0" else (others => '0');
when simulating, this works well, however when I try to synthesis it (using Synopsys DC) I get an elaboration error upon linking the design saying "Constant value required (ELAB-922)".
The ELAB code means "This error message occurs because an expression in the indicated line of your RTL description does not evaluate to a constant value, as required by the language."
How else can I make the output mux so it will undergo synthesis?
if not for the parameter i'd change the Do line to a regular mux, but it can't work with the parameters. (I can't call fifo(63 downto 54) when fifo is 4 byte...)
p.s.
I tried working with conv_integer in the beginning, but changed to to_integer(unsigned())due to answers found on the web.
Signal indexes used to construct a range have to be compile-time constants for synthesis to accept them.
There are two ways to solve this problem:
1) Change your FIFO to use an array. This is the standard way of declaring any form of memory, such as a FIFO.
type fifo_type is array(0 to FIFO_SIZE-1) of std_logic_vector(8-1 downto 0);
signal fifo : fifo_type;
...
Do <= fifo(to_integer(unsigned(numOfBytes))-1) when(numOfBytes/=0) else (others=>'0');
2) Use a loop to convert the variable into a constant. This is a common way to code a generic mux.
Do <= (others=>'0');
for i in 0 to FIFO_SIZE-1 loop
if(numOfBytes=i+1) then
Do <= fifo((i+1)*8-1 downto i*8);
end if;
end loop;
I would recommend the first approach for larger, memory-based FIFOs, and the second for smaller, register-based ones.
If the FIFO created with a number of bytes, instead of combining it into the same std_logic_vector then Synopsys DC may be able to handle it. Code could look like:
library ieee;
use ieee.numeric_std.all;
architecture syn of mdl is
... Declaration of FIFO_SIZE natural constant
type fifo_t is array(natural range <>) of std_logic_vector(7 downto 0);
signal fifo : fifo_t(FIFO_SIZE - 1 downto 0);
begin
... Handling FIFO insert and remove
Do <= fifo(to_integer(unsigned(numOfBytes))) when numOfBytes /= x"0" else (others => '0');
end architecture;
If you don't need a runtime-dynamic size to the FIFO, use a generic on your entity.
If you truly need a dynamic sized FIFO, you'll have to use a loop in a process as someone else said. But be very careful how you use such a FIFO, as if you change the size of it while someone is reading or writing, bad things may happen!

Mod-M counter Unsigned values have no signal

I am writing a RS232 module for my Nexys2 board. I am currently having issues with my baud rate controller which I want to set to 19200.
For this I am using a Mod-M counter, after many ISim simulations the problem with my code is in the mod-m counter as it is not producing any ticks.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity baud_rate is
generic (
N: integer := 8;
M: integer :=163);
Port (clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out STD_LOGIC_VECTOR(N-1 downto 0));
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : unsigned(N-1 downto 0);
signal r_next : unsigned(N-1 downto 0);
begin
process(clk,reset)
begin
if (reset ='1') then
r_reg <= (others=>'0');
elsif(clk'event and clk='1') then
r_reg <= r_next;
end if;
end process;
r_next <= (others =>'0') when r_reg=(M-1) else r_reg+1;
tick <='1' when r_reg=(M-1) else '0';
q <= std_logic_vector(r_reg);
end Behavioral;
I have tested and all the clk inputs and run fine and the issue seems to be with the r_reg and r_next registers. In ISim when outputing either of these on q I get UUUUUUUU, so it seems they are not generating signal. From this i can infer that the two r_reg and r_next registers aren't being created or storing values, is there an issue when using unsigned?
To make triple sure I have even copied the mod-m counter from the book FPGA Prototyping with VHDL (which is the code shown) BUT still this does not work and q output is UUUUUUUU.
If there are any better ways of creating a baud rate from the nexys2 50mz clock that would also be appreciated!
Cheers
Frankly I am horrified if people are expected to learn VHDL from a book where examples like this are presented. I know the author has a similar book on Verilog : do people end up thinking VHDL is just a more verbose Verilog?
Specific criticisms (actually 7,8 are more observations):
1) Spurious type conversions.
Q represents an unsigned number. So make it unsigned!
The baud generator isn't the only thing in your FPGA so Q isn't likely to be an off-chip port. There are good arguments for making top level, off-chip ports std_logic_vector but even that isn't compulsory. However, if your customer's specification or coding style insists on spurious type conversions on ports; follow it.
2) the DRY principle:
package CPU_types is
subtype baud_count is unsigned(7 downto 0);
end CPU_types;
Spot the simplification in maintenance.
If you are using a subtype in several places, put it in a package; the universal code reuse tool.
3) Indentation, formatting. (I recognise that may have become garbled by editor settings). It adds to the brain load reading it. What I've done here isn't The One Way though.
4) Spurious brackets round logical expressions. Harmless, but look like crutches for C programmers.
5) Antique clk'event style. Next year, the rising_edge function will be old enough to drink (in America. In Britain it's been getting plastered every Saturday night for a couple of years now...)
6) The "two process" style with r_reg and r_next. Does he also write state machines with a separate combinational process on next_state? Given this, I'm guessing so. Single process state machines are easier, smaller (to write : they don't generate smaller hardware) and safer.
7) I cheated and my tick is one cycle later than in the original. If that is critical, restore the external "tick" assignment. I also made it synchronous vhich will help performance. Some people would prefer tick <= '0' in an else clause; however the default assignment I used is safe, and prevents a lot of mistakes (and unnecessary else clauses) in larger designs.
8) The assignment to Q can be brought into the process too; if you made r_reg a process variable you'd have to. There is room for other variations and preferences.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use CPU_types.all;
entity baud_rate is
generic (
M: integer := 163);
Port (
clk, reset : in STD_LOGIC;
tick : out STD_LOGIC;
q : out baud_count);
end baud_rate;
architecture Behavioral of baud_rate is
signal r_reg : baud_count;
begin
process(clk,reset)
begin
if reset ='1' then
r_reg <= (others=>'0');
elsif rising_edge(clk) then
tick <= 0;
r_reg <= r_reg+1;
if r_reg = M then
tick <= '1';
r_reg <= (others=>'0');
end if;
end if;
end process;
-- tick <='1' when r_reg = M-1 else '0';
-- or simpler, when r_reg = 0
q <= r_reg;
end Behavioral;

Resources