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

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.

Related

signal statement must use <= to assign value to signal

I've got this error in the expression "individuos(x):=cout" of the following code. What I'm trying to do is assign to each array of individuos a different random "cout" input sequentially. If I change the expression to "individuos <= cout", it'll asign the same "cout" to all "individuos", the same will happen if i trie to build a sequential statement with the assert function. How do I fix this?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_TEXTIO.ALL;
use ieee.numeric_std.all;
--package genetica_type is
--type genetica is array(0 to 49) of unsigned(7 downto 0);
--type fitness is array(0 to 49) of unsigned (2 downto 0);
--end package genetica_type;
use work.genetica_type.all;
entity conexao is
Port (
clk : in bit;
cout: in unsigned (7 downto 0);
individuos: out genetica
);
end entity;
architecture Behavioral of conexao is
--type genetica is array (0 to 49) of std_logic_vector (7 downto 0);
--signal s_individuos : genetica;
--signal i: genetica;
begin
process (clk)
begin
If (clk 'event and clk = '1') then
for x in 0 to 49 loop
individuos(x) := cout;
end loop;
end if ;
end process;
end Behavioral;
I've got this error in the expression "individuos(x):=cout" of the following code.
That is a syntax error. Use <= exactly as the compiler says.
What I'm trying to do is assign to each array of individuos a different random "cout" input sequentially. If I change the expression to "individuos <= cout", it'll asign the same "cout" to all "individuos"
That is exactly what you ask it to do :
If (clk 'event and clk = '1') then
for x in 0 to 49 loop
individuos(x) <= cout;
end loop;
end if ;
On every rising clock edge, loop 50x performing 50 assignments, each of the same data, to all 50 addresses.
What I think you want to do, is, on every clock, perform ONE assignment, and increment the address to point to the next location.
signal x : natural range 0 to individuos'high;
...
if rising_edge(clk) then
individuos(x) <= cout;
x <= x + 1 mod individuos'length;
end if;
This code has several other differences from yours:
It uses the simpler rising_edge(clk) function
It will still work when you change the size of the input array.
It still has a bug : if you change the array lower bound to something other than 0, it will fail... for example:
type genetica is array(3 to 49) of ...
Easy to catch this with an assert:
Assert individuos'low = 0 report "Array Individuos bound error" severity failure;
It also runs continuously. If you want to start and stop it, or reset the address counter, or stop when it reaches 50, that takes additional logic.

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".

PRBS Generator module in VHDL

Here i am posting a snapshot of prbs
My code for prbs module is
-- Module Name: prbs - Behavioral
-- Project Name: modulator
-- Description:
--To make it of N bit replace existing value of N with desired value of N
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity prbs is
Port ( pclock : in STD_LOGIC;
preset : IN std_logic := '0';
prbsout : out STD_LOGIC);
end prbs;
architecture Behavioral of prbs is
COMPONENT dff is
PORT(
dclock : IN std_logic;
dreset : IN std_logic;
din : IN std_logic ;
dout : OUT std_logic
);
END COMPONENT;
signal dintern : std_logic_vector (4 downto 1); --Change value of N to change size of shift register
signal feedback : std_logic := '0';
begin
instdff : dff port map (pclock , preset , feedback , dintern(1));
genreg : for i in 2 to 4 generate --Change Value of N Here to generate that many instance of d flip flop
begin
instdff : dff port map ( pclock , preset , dintern(i-1) , dintern(i));
end generate genreg;
main : process(pclock)
begin
if pclock'event and pclock = '1' then
if preset = '0' then
if dintern /= "0" then
feedback <= dintern(1) xor dintern(3); -- For N equals four;
--feedback <= dintern(4) xor dintern(5) xor dintern(6) xor dintern(8); -- For N equals eight;
--feedback <= dintern(11) xor dintern(13) xor dintern(14) xor dintern(16); -- For N equals sixteen;
--feedback <= dintern(1) xor dintern(2) xor dintern(22) xor dintern(32); -- For N equals thirty two
else
feedback <= '1';
end if;
end if;
end if;
end process main;
prbsout <= dintern(4) ; --Change Value of N Here to take output to top entity
end Behavioral;
In it i am instantiating a d flip flop module
d ff module code
----------------------------------------------------------------------------------
-- Module Name: dff - Behavioral
-- Project Name:
-- Description:
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity dff is
Port ( dclock : in STD_LOGIC ;
dreset : in STD_LOGIC ;
din : in STD_LOGIC;
dout : out STD_LOGIC);
end dff;
architecture Behavioral of dff is
begin
process(dclock)
begin
if dclock'event and dclock = '1' then
if dreset = '0' then
dout <= din;
else
dout <= '1';
end if;
end if;
end process;
end Behavioral;
But i am not getting desired output.
In top level entity i am getting always 1 at prbsout signal.
When i try to simulate then prbsout signal becomes undefined.
What i am missing?
The prbs module reset at preset does not apply to the feedback signal,
probably because the intention was to use the initial value of 0 assigned in
the declaration of the feedback signal. However, since the dff modules
uses synchronous reset, and the dintern signal will be undriven U at start,
and since then next value for feedback is calculated using dintern(1) in an
xor, the feedback will get undefined right after start, and can't recover,
even if a lengthy reset is applied. See waveform from ModelSim below.
An immediate fix for the reset issue is to apply reset for feedback also in
the main process:
...
else -- preset /= '0'
feedback <= '0';
...
Now at least reset works, and can make the prbs generate a sequence. See
waveform below.
Just a few additional comments to the code, while at it:
Instead of dclock'event and dclock = '1' you can use rising_edge(dclock),
which I think must reader will find easier to understand, and it is less
error prone
For most tools, it is unnecessary to make a separte module just for a
flip-flop, like the dff module, since the tools can infer flip-flop
directly from the process even when advanced expressions are used for signal
assignments are used.
But, I don't think the output is what you actually want. Based on your
design, and the selected taps for the LFSR, it looks like you want to generate
maximum length LFSR sequences, that is sequences with a length of 2 ** N - 1
for a LFSR register being N bits long.
The principles of LFSR and the taps to for feedback generation is described
on Wikipedia: Linear feedback shift
register.
However, since the feedback signal is generated as a flip-flop, it becomes
part of the LSFR shift register, thus adds a bit to the length, but the tap
values are based on the dintern part of the LFSR only, the taps will be
wrong. Selecting the wrong bits will result in a LFSR sequence that is less
than then maximum sequence, and you can also see that in the simulation output,
where the sequence is only 6 cycles long, even through the dintern(4 downto
1) + feedback together makes a 5 bit register.
So a more thorough rewrite of the prbs module is required, if what you want
is to generate maximum length PRBS sequences, and below is an example of how
the prbs module can be written:
library ieee;
use ieee.std_logic_1164.all;
entity prbs_new is
generic(
BITS : natural);
port(
clk_i : in std_logic;
rst_i : in std_logic;
prbs_o : out std_logic);
end entity;
library ieee;
use ieee.numeric_std.all;
architecture syn of prbs_new is
signal lfsr : std_logic_vector(BITS downto 1); -- Flip-flops with LFSR state
function feedback(slv : std_logic_vector) return std_logic is -- For maximum length LFSR generation
begin
case slv'length is
when 3 => return slv( 3) xor slv( 2);
when 4 => return slv( 4) xor slv( 3);
when 8 => return slv( 8) xor slv( 6) xor slv( 5) xor slv(4);
when 16 => return slv(16) xor slv(15) xor slv(13) xor slv(4);
when 32 => return slv(32) xor slv(22) xor slv( 2) xor slv(1);
when others => report "feedback function not defined for slv'lenght as " & integer'image(slv'length)
severity FAILURE;
return 'X';
end case;
end function;
begin
process (clk_i, rst_i) is
begin
if rising_edge(clk_i) then
if unsigned(lfsr) /= 0 then
lfsr <= lfsr(lfsr'left - 1 downto lfsr'right) & feedback(lfsr); -- Left shift with feedback in
end if;
end if;
if rst_i = '1' then -- Asynchronous reset
lfsr <= std_logic_vector(to_unsigned(1, BITS)); -- Reset assigns 1 to lfsr signal
end if;
end process;
prbs_o <= lfsr(BITS); -- Drive output
end architecture;
Comments to ´prbs_new´ module
Generic BITS is added so diffrent LFSR length can be made from the same code.
Ports are named with "_i" for inputs and "_o" for outputs, since this naming
convension is very useful when tracing signals at a toplevel with multiple
modules.
The VHDL standard package ieee.numeric_std is used instead of
the non-standard package ieee.std_logic_unsigned.
Asynchronous reset is used instead of synchronous reset and initial value in
the signal declaration.
The advantage over synchronous reset is that asynchronous reset typical
applies to a dedicated input on the flip-flops in FPGA and ASIC
technology, and not in the potentially timing critical data path, whereby
the design can be faster.
The advantage over initial value in the signal declation is that FPGA and
ASIC technologies are more likely to be able to implement this; there are
cases where initial values are not supported. Also functional reset
makes restart possible in a test bench without having to reload the
simulator.
There is no check for an all-0 value of the lfsr signal in the process,
since the lfsr will never get an all-0 value if proper maximum length taps
are used, and the lfsr signal is reset to a non-0 value.
It looks like you are never setting your internal state (dintern) to a known value. Since all subsequent states are calculated from your initial dintern value, they are unknown as well. Try assigning an initial state to dintern, or fixing your preset code to actually do something when preset is high (and then assert it at the start of your testbench).

Binary serial adder - VHDL

I'm trying to design a 32bit binary serial adder in VHDL, using a structural description. The adder should make use of a full adder and a d-latch. The way I see it is:
Full adder:
architecture Behavioral of FullAdder is
begin
s <= (x xor y) xor cin;
cout <= (x and y) or (y and cin) or (x and cin);
end Behavioral;
D-Latch:
architecture Behavioral of dLatch is
begin
state: process(clk)
begin
if(clk'event and clk = '1') then
q <= d;
end if;
end process;
end Behavioral;
Serial adder:
add: process ( clk )
variable count : integer range 0 to 31;
variable aux : STD_LOGIC;
variable aux2 : STD_LOGIC;
begin
if(clk'event and clk = '1') then
fa: FullAdder port map(x(count), y(count), aux, s(count), aux2);
dl: dLatch port map(clock, aux2, aux);
count := count + 1;
end if;
end process;
However, it doesn't seem to work.
Also, what would be the simplest way to pipeline the serial adder?
"It doesn't seem to work" is pretty general, but one problem I see is that you are trying to instantiate the component fa: FullAdder within a process. Think about what component instantiation means in hardware, and you will realize that it makes no sense to instantiate the module on the rising_edge of clk...
Move the instantiation out of the process, and it should at least remove the syntax error you should be seeing ("Illegal sequential statement." in ModelSim).
For pipelining the serial adder, the best way is to connect the adders and d flip-flops one after the other. So, you would have the cout of the first adder be the input of a flip-flop. The output of that flip-flop will be the cin of the next adder and so on. Be careful though, because you will also have to pipeline the s of each adder, as well as each bit of the input, by essentially putting several d flip-flops in a row to copy them through the various pipeline stages.

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

Resources