How to make a simple 4 bit parity checker in VHDL? - 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

Related

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.

8 bit serial adder with accumulator

I am writing a VHDL code to impelemt 8 bit serial adder with accumulator.
When i do simulation, the output is always zeros! And some times it gives me the same number but with a shift !
I dont know what is the problem, i tried to put A,B as inout but didnt work as well. Can anybody help please.
This is the code:
entity SA is
Port ( st : in std_logic;
A,B: inout std_logic_vector ( 7 downto 0);
clk : in std_logic;
acc : out bit_vector(7 downto 0)); end SA;
architecture Behavioral of SA is
signal ps,ns: integer range 0 to 7;
signal C,D: bit_vector (7 downto 0);
signal ci,ciplus,si,sh:bit;
begin
si<=A(0) xor B(0) xor ci ;
ciplus <=(A(0) and B(0)) or (A(0) and ci ) or ( B(0) and ci );
process(ps,st)
begin
case ps is
when 0=> if(st='0')then
ns<=0;
else
ns<=1;
sh<='1';
end if;
when 1 to 6 => sh<='1';
ns<= ps+1;
when 7=> sh<='1';
ns <=0;
end case;
end process;
process(clk)
begin
if(clk 'event and clk ='1')then
ps <= ns;
ci<= ciplus;
end if;
if(sh='1') then
C<=si & A(7 downto 1) ;
D<=B(0) & B(7 downto 1);
end if;
end process;
acc<= C;
end Behavioral;
`
Your second process is written incorrectly. Prior to writing a process, you should always decide whether the process is sequential or combinatorial, and then write the process accordingly.
To help you write your code, especially when starting out with hardware description languages, please please please always draw a block diagram first, and then describe that block diagram using VHDL.
As it is, your second process:
Mixes combinatorial and sequential logic.
Is missing signals in the process sensitivity list.
Generates a latch because C and D are not assigned in all paths through the process.
Your first process has similar problems.
try initializing ps and ns see if that does the trick I am on my phone now so i cant simulate to help but usualy my problems in VHDL design are form uninitilized integers
signal ps,ns: integer range 0 to 7:=0;
you might want to check your warnings list see if that helps

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.

Resources