AND all elements of an n-bit array in VHDL - 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".

Related

Combining `others` expression with `signed` cast

Let var stand for a signed vector (library IEEE.NUMERIC_STD.ALL) of size m.
Let foo be another variable of type std_logic_vector(n-1 downto 0), where n is smaller than m.
I want to concatenate a '0' left of foo, then pad it with zeroes in its right until it size is m and then store the result in var.
I tried
rdsor <= signed('0' & divisor & others=>'0');
But Xilinx complains with the following message on synthesis:
Syntax error near "others".
How do I do what I want?
Assuming rdsor is equivalent to your theoretical var and divisor equivalent to foo you could use two assignments in a process statement:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity jsevillamol is
end entity;
architecture fum of jsevillamol is
constant M: natural := 42;
constant N: natural := 23;
signal rdsor: signed (M - 1 downto 0);
signal divisor: std_logic_vector (N - 1 downto 0);
begin
-- rdsor <= signed('0' & divisor & others=>'0');
process (divisor)
begin
rdsor <= (others => '0');
rdsor (rdsor'LEFT downto rdsor'LEFT - divisor'LENGTH)
<= signed('0' & divisor);
end process;
end architecture;
This works because each element of rdsor is a separate signal and there is only one value for any particular time in a projected output waveform. By not providing an after time_expression in the waveform element of the second assignment the elements of rdsor slice will be assigned the second assignments expression values. (The elements of the first assignment are supplanted by the second). This method of overwriting the projected output waveform is commonly used in providing default values prior to incomplete condition coverage with if statements.
This example analyzes, elaborates and simulates, while doing nothing interesting it demonstrates index ranges are constructed properly.
Notice it avoids the issue of concatenation versus aggregation brought up by Matthew Taylor's answer.
For a single signal assignment in a method not sensitive to tool VHDL revision:
architecture fie of jsevillamol is
constant M: natural := 42;
constant N: natural := 23;
signal rdsor: signed (M - 1 downto 0);
signal divisor: std_logic_vector (N - 1 downto 0);
subtype other is signed (rdsor'LEFT - divisor'LENGTH - 1 downto 0);
begin
-- rdsor <= signed('0' & divisor & others=>'0');
rdsor <= '0' & signed(divisor) & other'(others => '0');
end architecture;
This uses concatenation and subsumes the others into an aggregate. There's a subtype declaration for the trailing '0's portion to allow the aggregate expression to be the target of a qualified expression.
This architecture also analyzes, elaborates and simulates proving index arithmetic is correct.
You would need to use others as part of an aggregate not part of a concatenation. Here's a solution using an aggregate and attributes (which relies on you using VHDL 2008):
rdsor <= (rdsor'LEFT => '0', (rdsor'LEFT-1) downto (rdsor'LEFT-divisor'LENGTH) => signed(divisor), others => '0');
https://www.edaplayground.com/x/5Yuw

Why does my implementation of an XOR-reduction has multiple drivers?

I have a binary string like "11000110".
I'm trying to XOR all bits together.
I have this code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity e_circuit is
generic(n : INTEGER:=8);
port(
d1:in std_logic_vector(n-1 downto 0);
result:out std_logic
);
end e_circuit;
architecture structure of e_circuit is
signal temp:std_logic;
begin
temp<=d1(0);
loop1:for i in 1 to n-1 generate
temp<= d1(i) or d1(i-1);
end generate;
result<=temp;
end structure;
But, when I try to compile it, I get the error below:
ERROR:Xst:528 - Multi-source in Unit <e_circuit> on signal <result>;
this signal is connected to multiple drivers.
What does it mean? How can I fix it?
This means that you are assigning to a signal (temp) multiple times (tying their outputs together directly) without any combinational circuit or if clause. When the synthesizer synthesizes the resulting circuit, all of the statements in the for...generate statement get executed simultaneously. Here are some solutions you can try:
First, you can use the VHDL-2008 reduction operator:
result <= xor d1;
Or, if your synthesizer doesn't support that, create a function to do it for you:
function xor_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 xor slv(i);
end loop;
return res_v;
end function;
And call it in your corresponding architecture:
result <= xor_reduct(d1);
Or do the circuit manually, (with temp being a std_logic_vector of the same size as d1:
temp(0) <= d1(0);
gen: for i in 1 to n-1 generate
temp(i) <= temp(i-1) xor d1(i);
end generate;
result <= temp(n-1);
What does it mean?
You have concurrently assigned the signal temp at several locations in your code (and none of them is masked by an if ... generate). Each concurrent assignment makes up a driver.
The for generate repeats the concurrent statements inside the block for each value of i within the given range. Thus, for n = 8, your code is similar to:
temp <= d1(0);
temp <= d1(1) or d1(1-1);
temp <= d1(2) or d1(2-1);
temp <= d1(3) or d1(3-1);
temp <= d1(4) or d1(4-1);
temp <= d1(5) or d1(5-1);
temp <= d1(6) or d1(6-1);
temp <= d1(7) or d1(7-1);
Thus, you have connected 8 drivers to temp. The first is the input d1(0) and the others or the outputs of 7 OR gates.
The posted error message is reported only with the old parser of ISE for Spartan-3 like devices. You should switch to the new one. Right click on Synthesize -> Properties -> Synthesis Options. The set option "Other XST Command Line Options" to
-use_new_parser YES
Then, you get a more meaningful error message:
ERROR:HDLCompiler:636 - "/home/zabel/tmp/xor_reduction/e_circuit.vhdl" Line 23: Net is already driven by input port .
Line 23 is the one within the for ... generate statement.
How can I fix it?
At first, your code has to use an XOR instead of OR. ISE does not support the XOR reduction operator from VHDL'08, thus, you have to describe it manually. One solution is to use sequential statements within a process, which has also been suggested by #user1155120 in the comments:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity e_circuit is
generic(n : INTEGER := 8);
port(d1 : in std_logic_vector(n-1 downto 0);
result : out std_logic);
end e_circuit;
architecture structure of e_circuit is
begin
process(d1)
variable temp : std_logic;
begin
temp := d1(0);
for i in 1 to n-1 loop
temp := temp xor d1(i);
end loop;
result <= temp;
end process;
end structure;
Here, the variable temp is updated sequentially during the execution of the process (like in an imperative software programming language). The final value is then assigned to the signal result.
I have also omitted all VHDL packages which are not required.

Comparing a long std_logic_vector to zeros

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;

How to make a simple 4 bit parity checker in VHDL?

I am trying to learn VHDL and I'm trying to make 4-bit parity checker. The idea is that the bits come from one input line (one bit per clock pulse) and the checker should find out if there is odd number of 1s in the 4-bit sequence (i.e 1011 , 0100 , etc.) and send an error output(e.g error flag: error <=´1´) if there is.
Would someone give me an example how it´s done, so that I can study it?
I have tried searching the web, but all the discussions I found were related to something way more complicated and I could not understand them.
VHDL 2008 standard offers a new xor operator to perform this operation. Much more simple than the traditional solution offered by Aaron.
signal Data : std_logic_vector(3 downto 0) ;
signal Parity : std_logic ;
. . .
Parity <= xor Data ;
This assumes "invec" is your input std_logic_vector:
parity <= invec(3) xor invec(2) xor invec(1) xor invec(0);
If it got any larger than 4 inputs, a loop would probably be best:
variable parity_v : std_logic := '0';
for i in invec'range loop
parity_v := parity_v xor invec(i);
end loop;
parity <= parity_v;
That loop would be converted into the proper LUT values at synthesis time.
(I did this from memory; may be slight syntax issues.)
small syntax error in the code. should remove ":" after loop.
library ieee;
use ieee.std_logic_1164.all;
entity bus_parity is
generic(
WPARIN : integer := 8
);
port(
parity_in : in std_logic_vector(WPARIN-1 downto 0);
parity_out : out std_logic
);
end entity;
architecture rtl of bus_parity is
begin
process(parity_in)
variable i : integer;
variable result: std_logic;
begin
result := '0';
for i in parity_in'range loop
result := result xor parity_in(i);
end loop;
parity_out <= result;
end process;
end architecture;
Or in Verilog:
`timescale 1ns/10ps
`default_nettype none
module bus_parity #(
parameter WPARIN = 8
) (
input wire [WPARIN-1:0] parity_in,
output reg parity_out
);
always #* begin : parity
integer i;
reg result;
result = 1'b0;
for(i=0; i < WPARIN-1; i=i+1) begin
result = result ^ parity_in[i];
end
parity_out = result;
end
endmodule
`default_nettype wire

Shift Right And Shift Left (SLL/SRL)

so, I'm developing an ALU for MIPS architecture and I'm trying to make a shift left and a shift right so that the ALU can shift any amount of bits.
the Idea I had is to convert the shift value to an integer and select the piece of the entry that'll be on the result(the integer is stored in X) but Quartus doesn't accept a variable value, only constants.
What could I do to make this?
(Cases are on lines "WHEN "1000" =>..." and "WHEN "1001" =>...")
Thanks.
PROCESS ( ALU_ctl, Ainput, Binput, X )
BEGIN
-- Select ALU operation
--ALU_output_mux <= X"00000000"; --padrao
CASE ALU_ctl IS
WHEN "1000" => ALU_output_mux(31 DOWNTO X) <= (Ainput( 31-X DOWNTO 0 ));
WHEN "1001" => ALU_output_mux(31-X DOWNTO 0) <= (Ainput( 31 DOWNTO X ));
WHEN OTHERS => ALU_output_mux <= X"00000000";
END CASE;
END PROCESS;
If Quartus doesn't like it you have two choices:
Write it some way that Quartus does like - you're trying to infer a barrel shifter, so you could write one out longhand and then instantiate that. Potentially expensive in time
Get a different synthesizer that will accept it. Potentially expensive in money.
I have had issues with this in Quartus as well, although your code also has some implicit latches (you are not assigning all bits of the output in your two shift cases).
The work-around I use is to define an intermediate array with all the possible results, then select one of those results using your selector. In your case, something like the following:
subtype DWORD_T is std_logic_vector( 31 downto 0);
type DWORD_A is array (natural range <>) of DWORD_T;
signal shift_L : DWORD_A(31 downto 0);
signal shift_R : DWORD_A(31 downto 0);
signal zero : DWORD_T;
...
zero <= (others=>'0');
process (Ainput)
begin
for index in Ainput'range loop
shift_L(index) <= Ainput(31 - index downto 0) & zero(index - 1 downto 0);
shift_R(index) <= zero(index - 1 downto 0) & Ainput(31 downto index);
end loop;
end process;
ALR_output_mux <= shift_L(to_integer(X)) when ALU_ctl="1000",
shift_R(to_integer(X)) when ALU_ctl="1001",
(others=>'0') when others;
You could work around this by using generate or for to create each shift/rotate level, or you can use the standard functions ({shift,rotate}_{left,right}) for shifting and rotating.

Resources