Adder in VHDL
1. Inside always block on the left-hand side never use wire. Only assign values to reg inside always block.
Eg. Consider this
reg [3:0] answer_reg;
always @* begin
answer_reg = a + c;
end
OR
wire [3:0] answer_wire;
assign answer_wire = a + c;
2. Never use the same reg on both sides (Left & Right) inside always @ (*) block.
WRONG WAY: This will lead simulator to race as right side count+1 updates the left side count value which triggers the * block again and keeps going. It will result in infinite loop and simulation stuck.
always @ (*)
begin
if (pushin)
count = count +1;
if (count)
$display(“Hi”);
end
THIS IS CORRECT WAY TO USE COUNTER:
always @ (*)
begin
count_d=count; // This part work as a else part for if (pushin1), important to make sure no latches created
if(pushin1) begin
count_d= count+1;
end
if (count)
$display(“Hi”);
end
always @ (posedge clock)
begin
count <= #1 count_d;
end
Always write $finish statement in your testbench if you are dumping signals on .vcd or .vpd file. It creates a massive database for your waveform file and blocks all allocated memory resources given to you. You may result in disk quota exceed if you are not careful. Always write $finish statement in the testbench.
Never use reg on left side in assign statement. You can only use wire for assigning values using assign statement which results in a combinational logic for your wire.
Use always @ (*) block for combinational logic and use blocking statements in always @ (*) blocks. Use always @ (posedge clock) for sequential part of the design (Flip-Flop) with non-blocking statements.
Do not use blocking and non-blocking both assignments for a particular signal at different places. Bad coding practice. It results in hardware ambiguity.
Avoid multiple driver errors. Avoid driving the same signal in two different always blocks. It results in racing when one tries to simulate code. One never knows which block will execute first during simulation.
BAD CODING:
always @ ( posedge clock)
a <= #1 0;
always @ ( posedge clock)
a <= #1 1;
Default data type is wire: this means that if you declare a variable without specifying reg or wire, it will be a 1-bit wide wire.
Always use #1 delay in always @ (posedge clock) block for easy debug and better waveform view. You can clearly see where exactly the signal gets sampled. It reduces debug efforts a lot.
GOOD WAY:
always @ (posedge clock)
D <= #1 Q;
Never call module inside always or initial blocks. Module calls must be outside any procedural blocks.
WRONG WAY:
module conditional_adder(input wire [31:0] a_input,input wire [31:0] b_input,input wire cin,output wire [31:0]
sum_out,output wire carry_out);
wire [31:0] a;
wire [15:0] b;
always @ (posedge clock)
bit2_adder x1(.a(a_input[1:0]), .b(b_input[1:0]),.cin(cin), .sum(a[1:0]), .cout(b[0]));
assign sum_out = a;
assign carry_out = b[(`BITS/2)1];
endmodule
CORRECT WAY:
module conditional_adder(input wire [31:0] a_input,input wire [31:0] b_input,input wire cin,output wire [31:0]
sum_out,output wire carry_out);
wire [31:0] a;
wire [15:0] b;
bit2_adder x1(.a(a_input[1:0]), .b(b_input[1:0]),.cin(cin), .sum(a[1:0]), .cout(b[0]));
assign sum_out = a;
assign carry_out = b[(`BITS/2)1];
endmodule
always @ (posedge clock1, posedge clock2, negedge reset) this may simulate but does not synthesize. There is no Hardware (Flip-flop) which has two or multiple clocks in Toshiba synthesis library. you may use any of the followings in your HDL:
always @ (posedge clock)
always @ (negedge clock)
always @ (posedge clock or negedge reset)
always @ (posedge clock or posedge reset)
always @ (negedge clock or negedge reset)
always @ (negedge clock or posedge reset)
There are FFs with preset though if you want to use preset signal, you can include it in.
Try to avoid using different clock edge (posedge and negedge) in same design. It makes STA and SCAN difficult to perform. Either use only always @ (posedge clock) or only always @ (negedge clock) everywhere in your design.
Make sure you understand the concurrent behavior of Verilog. Always write synthesizable code. Make sure you work on synthesis as early as possible. Do not synthesize entire design at once at the end of the whole design. Synthesis small partition of design as you write over the time to make sure that you are writing correctly. If you will write entire code and later try to synthesize you may find it difficult to make it synthesizable at the end. Synthesis as early as possible and always after you add a small-small portion of HDL code in your design. Always remember we are writing HDL, synthesis has a lot more importance over simulation. You should see the evolving circuit behind every line of Verilog you add. No one is perfect!
Make sure you have no latches in your design. There should be only Flip-flops and combinational hardware in your design. You may use always_ff instead always to make sure that you are getting desired hardware from synthesis.
There is nothing like always @ (posedge clock and posegde reset), you can not use and keyword in this sense in always block. There is just or keyword. Make sure you know how to write code to make correct FFlop hardware for any sequential circuits.
If you are using a loop, for example for loop in your code make sure it has fix numbers on iteration at compile time as you can not keep variable numbers of iterations as it does not result in hardware. A number of loop iterations must be fixed values to make sure that it synthesize.
Think about how that loop might be implemented, given that the hardware doesn’t know how loops work. Because of that, loops get unrolled completely – if you have ten loop iterations, VCS will produce ten copies of the hardware within the loop. If in your code you have an unknown number of iterations (varying or infinite #’s of iterations), It can not produce a fixed hardware.
Solution
— inputs: X[7..0], Y[7..0]
— outputs: S[7..0]
— carry_in and carry_out not used!!! (do not intend to extend on 16-bit!)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
entity CSA8 is
PORT (X, Y: in bit_vector(7 downto 0);
S: out bit_vector(7 downto 0));
end CSA8;
architecture logic of CSA8 is
component CSA4 is
PORT( C_in: in bit;
X, Y: in bit_vector(3 downto 0);
S: out bit_vector(3 downto 0);
C_out: out bit);
end component;
component MUX10_5 is
PORT( sel: in bit;
X, Y: in bit_vector(4 downto 0);
m: out bit_vector(4 downto 0));
end component;
constant c: bit := ‘1’;
signal msel: bit;
signal mx, my: bit_vector(4 downto 0);
begin
csa4_inst0 : CSA4
PORT MAP( C_in => ‘0’, X => X(3 downto 0), Y => Y(3 downto 0),
S => S(3 downto 0), C_out =>msel);
csa4_inst1 : CSA4
PORT MAP( C_in => c, X => X(7 downto 4), Y => Y(7 downto 4),
S => mx(3 downto 0), C_out => mx(4));
csa4_inst2 : CSA4
PORT MAP( C_in => not c, X => X(7 downto 4), Y => Y(7 downto 4),
S => my(3 downto 0), C_out => my(4));
mux10_5_inst0 : MUX10_5
PORT MAP( sel =>msel, X => mx, Y => my,
m(3 downto 0) => S(7 downto 4));
end logic;
”
Test codes
– CSA8_test.vhdl
—
— test vector for CSA8.vhdl
— A testbench has no ports.
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture behav of test is
— Declaration of the component that will be instantiated.
component CSA8
port(A, B: in bit;
SUM, CARRY: out bit);
end component;
— Specifies which entity is bound with the component.
for adder_0: CSA8 use entity work.CSA8;
signal i0, i1, s, co, ci : bit;
begin
— Component instantiation.
adder_0: CSA8 port map (A => i0, B => i1, SUM => s, CARRY => co);
— This process does the real job.
process
type pattern_type is record
— The inputs of the adder.
i0, i1, ci : bit;
— The expected outputs of the adder.
s, co : bit;
end record;
— The patterns to apply.
type pattern_array is array (natural range <>) of pattern_type;
constant patterns : pattern_array :=
((‘0’, ‘0’, ‘0’, ‘0’, ‘0’),
(‘0’, ‘0’, ‘1’, ‘1’, ‘0’), — not use
(‘0’, ‘1’, ‘0’, ‘1’, ‘0’),
(‘0’, ‘1’, ‘1’, ‘0’, ‘1’), — not use
(‘1’, ‘0’, ‘0’, ‘1’, ‘0’),
(‘1’, ‘0’, ‘1’, ‘0’, ‘1’), — not use
(‘1’, ‘1’, ‘0’, ‘0’, ‘1’),
(‘1’, ‘1’, ‘1’, ‘1’, ‘1’)); — not use
begin
report ” A , B : C ,SUM”;
— Check each pattern.
for i in patterns’range loop
— Set the inputs.
i0 <= patterns(i).i0;
i1 <= patterns(i).i1;
ci <= patterns(i).ci;
— Wait for the results.
wait for 1 ns;
report bit’image(i0) & “,” &bit’image(i1) & “:” &bit’image(co) & “,” &bit’image(s);
— Check the outputs.
–assert s = patterns(i).s
–report “bad sum value” severity error;
–assert co = patterns(i).co
–report “bad carray out value” severity error;
end loop;
assert false report “end of test” severity note;
— Wait forever; this will finish the simulation.
wait;
end process;
end behav;
Raw
result.txt
$ghdl -a CSA8.vhdl; ghdl -a CSA8_test.vhdl; ghdl -e test; ghdl -r test
CSA8_test.vhdl:44:5:@0ms:(report note): A , B : C ,SUM
CSA8_test.vhdl:53:7:@1ns:(report note): ‘0’,’0′:’0′,’0′
CSA8_test.vhdl:53:7:@2ns:(report note): ‘0’,’0′:’0′,’0′
CSA8_test.vhdl:53:7:@3ns:(report note): ‘0’,’1′:’0′,’1′
CSA8_test.vhdl:53:7:@4ns:(report note): ‘0’,’1′:’0′,’1′
CSA8_test.vhdl:53:7:@5ns:(report note): ‘1’,’0′:’0′,’1′
CSA8_test.vhdl:53:7:@6ns:(report note): ‘1’,’0′:’0′,’1′
CSA8_test.vhdl:53:7:@7ns:(report note): ‘1’,’1′:’1′,’0′
CSA8_test.vhdl:53:7:@8ns:(report note): ‘1’,’1′:’1′,’0′
CSA8_test.vhdl:60:5:@8ns:(assertion note): end of test
$ghdl -a CSA8.vhdl CSA8.vhdl; ghdl -a CSA8_test.vhdl; ghdl -e ftest; ghdl -r ftest
CSA8_test.vhdl:41:5:@0ms:(report note): A , B ,CI :CO ,SUM
CSA8_test.vhdl:50:7:@1ns:(report note): ‘0’,’0′,’0′:’0′,’0′
CSA8_test.vhdl:50:7:@2ns:(report note): ‘0’,’0′,’1′:’0′,’1′
CSA8_test.vhdl:50:7:@3ns:(report note): ‘0’,’1′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@4ns:(report note): ‘0’,’1′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@5ns:(report note): ‘1’,’0′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@6ns:(report note): ‘1’,’0′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@7ns:(report note): ‘1’,’1′,’0′:’1′,’0′
CSA8_test.vhdl:50:7:@8ns:(report note): ‘1’,’1′,’1′:’1′,’1′
CSA8_test.vhdl:57:5:@8ns:(assertion note): end of test
$ghdl -a CSA82.vhdl; ghdl -a CSA8_test.vhdl; ghdl -e ftest; ghdl -r ftest
CSA8_test.vhdl:41:5:@0ms:(report note): A , B ,CI :CO ,SUM
CSA8_test.vhdl:50:7:@1ns:(report note): ‘0’,’0′,’0′:’0′,’0′
CSA8_test.vhdl:50:7:@2ns:(report note): ‘0’,’0′,’1′:’0′,’1′
CSA8_test.vhdl:50:7:@3ns:(report note): ‘0’,’1′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@4ns:(report note): ‘0’,’1′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@5ns:(report note): ‘1’,’0′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@6ns:(report note): ‘1’,’0′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@7ns:(report note): ‘1’,’1′,’0′:’1′,’0′
CSA8_test.vhdl:50:7:@8ns:(report note): ‘1’,’1′,’1′:’1′,’1′
CSA8_test.vhdl:57:5:@8ns:(assertion note): end of test
$ghdl -a CSA82b.vhdl; ghdl -a CSA8_test.vhdl; ghdl -e ftest; ghdl -r ftest
CSA8_test.vhdl:41:5:@0ms:(report note): A , B ,CI :CO ,SUM
CSA8_test.vhdl:50:7:@1ns:(report note): ‘0’,’0′,’0′:’0′,’0′
CSA8_test.vhdl:50:7:@2ns:(report note): ‘0’,’0′,’1′:’0′,’1′
CSA8_test.vhdl:50:7:@3ns:(report note): ‘0’,’1′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@4ns:(report note): ‘0’,’1′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@5ns:(report note): ‘1’,’0′,’0′:’0′,’1′
CSA8_test.vhdl:50:7:@6ns:(report note): ‘1’,’0′,’1′:’1′,’0′
CSA8_test.vhdl:50:7:@7ns:(report note): ‘1’,’1′,’0′:’1′,’0′
CSA8_test.vhdl:50:7:@8ns:(report note): ‘1’,’1′,’1′:’1′,’1′
CSA8_test.vhdl:57:5:@8ns:(assertion note): end of test