I have the following code for implementing a GCD system in Verilog, but the TB doesn't produce the result it has to. The problem may be from other modules, but I have triple-checked everything, but couldn't find the reason:
`timescale 1ns / 1ps
module comparator(a_gt_b,a_lt_b,a_eq_b,a,b);
input [31:0] a,b;
output reg a_gt_b,a_lt_b,a_eq_b;
always @(a or b)
begin
if(a>b)
{a_gt_b,a_lt_b,a_eq_b}<=3'b100;
else if(a<b)
{a_gt_b,a_lt_b,a_eq_b}<=3'b010;
else
{a_gt_b,a_lt_b,a_eq_b}<=3'b001;
end
endmodule
`timescale 1ns / 1ps
module controller(a_ld,b_ld,a_sel,b_sel,output_en,done,clk,rst,go,a_gt_b,a_lt_b,a_eq_b);
input clk,rst,go;
input a_gt_b,a_lt_b,a_eq_b;
output reg a_ld,b_ld,a_sel,b_sel;
output reg output_en,done;
reg [2:0] cState,nState;
parameter a=3'b000;
parameter b=3'b001;
parameter c=3'b010;
parameter d=3'b011;
parameter e=3'b100;
parameter f=3'b101;
parameter g=3'b110;
parameter h=3'b111;
initial nState<=a;
always @(posedge clk)
begin
if(rst==1)
cState<=a;
else
cState<=nState;
end
always @(go or a_gt_b or a_lt_b or a_eq_b or cState)
begin
case(cState)
a:begin
if(go==0) nState<=a;
else nState <=b;
end
b:nState<=c;
c:nState <=d;
d:begin
if({a_gt_b,a_lt_b,a_eq_b}==3'b100)
nState <=e;
else if({a_gt_b,a_lt_b,a_eq_b}==3'b010)
nState <=f;
else if({a_gt_b,a_lt_b,a_eq_b}==3'b001)
nState <= h;
//else nState <= h;////edited
end
e:nState <= g;
f:nState <= g;
g:nState <= d;
h:nState <= a;
default : nState<=a;
endcase
end
always @(go or a_gt_b or a_lt_b or a_eq_b or cState)
begin
case(cState)
a:
begin
a_sel<=0;
b_sel<=0;
a_ld<=0;
b_ld<=0;
output_en<=0;
done<=0;
end
b:
begin
a_sel<=0;
b_sel<=0;
a_ld<=1;
b_ld<=1;
output_en<=0;
done<=0;
end
c:
begin
a_sel<=1;
b_sel<=1;
a_ld<=0;
b_ld<=0;
output_en<=0;
done<=0;
end
d: //compare state
begin
a_sel<=0;// a=0 b=0
b_sel<=0;
a_ld<=0;
b_ld<=0;
output_en<=0;
done<=0;
end
e: //a=a-b state
begin
a_sel<=1;
b_sel<=0;
a_ld<=1;
b_ld<=0;
output_en<=0;
done<=0;
end
f: //b=b-a state
begin
a_sel<=0;
b_sel<=1;
a_ld<=0;
b_ld<=1;
output_en<=0;
done<=0;
end
g: //waiting state
begin
a_sel<=0;
b_sel<=0;
a_ld<=0;
b_ld<=0;
output_en<=0;//en=1
done<=0;
end
h: //
begin
a_sel<=0;
b_sel<=0;
a_ld<=0;
b_ld<=0;
output_en<=1; //en=0
done<=1;
end
default:
begin
a_sel<=0;
b_sel<=0;
a_ld<=0;
b_ld<=0;
output_en<=0;
done<=0;
end
endcase
end
endmodule
`timescale 1ns / 1ps
module datapath(a_gt_b,a_lt_b,a_eq_b,out,output_en,clk,rst,a_ld,b_ld,a_sel,b_sel,in1,in2);
input clk,rst;
input a_ld,b_ld,a_sel,b_sel;
input [31:0]in1,in2;
input output_en;
output [31:0]out;
output a_gt_b,a_lt_b,a_eq_b;
wire [31:0] ta,tb,ts1,ts2,tm1,tm2;
substractor s1(ts1,ta,tb);
substractor s2(ts2,tb,ta);
mux m1(tm1,in1,ts1,a_sel);
mux m2(tm2,in2,ts2,b_sel);
register ra(ta,clk,rst,a_ld,tm1);
register rb(tb,clk,rst,b_ld,tm2);
register rout(out,clk,rst,output_en,tb);
comparator com(a_gt_b,a_lt_b,a_eq_b,ta,tb);
endmodule
`timescale 1ns / 1ps
module GCD(out,done,clk,rst,in1,in2,go);
input [31:0]in1,in2;
input clk,rst,go;
output [31:0]out;
output done;
wire a_gt_b,a_lt_b,a_eq_b;
wire a_ld,b_ld,a_sel,b_sel;
wire output_en;
controller c1(a_ld,b_ld,a_sel,b_sel,output_en,done,clk,rst,go,a_gt_b,a_lt_b,a_eq_b);
datapath d1(a_gt_b,a_lt_b,a_eq_b,out,output_en,clk,rst,a_ld,b_ld,a_sel,b_sel,in1,in2);
endmodule
`timescale 1ns / 1ps
module mux(mout,i0,i1,sel);
input [31:0]i0,i1;
input sel;
output reg [31:0]mout;
always @(i0 or i1 or sel)
begin
if(sel==0)
mout<=i0;
else
mout<=i1;
end
endmodule
`timescale 1ns / 1ps
module register(rnout,clk,rst,load,rin);
input [31:0] rin;
input clk,rst,load;
output reg [31:0] rnout;
always @(posedge clk)
begin
if(rst==1)
rnout<=0;
else if(load==1)
rnout<=rin;
//else
// rnout <= 0;////edited
end
endmodule
`timescale 1ns / 1ps
module substractor(s1,a,b);
input [31:0] a,b;
output reg [31:0]s1;
always @(a or b)
begin
s1=a-b;
end
endmodule
module fp_testbench_GCD;
reg clk;
reg rst;
reg [31:0] in1;
reg [31:0] in2;
reg go;
wire [31:0] out;
wire done;
//integer i;
initial clk=0;
always@(clk) #20 clk <= ~clk;
GCD uut (
.out(out),
.done(done),
.clk(clk),
.rst(rst),
.in1(in1),
.in2(in2),
.go(go)
);
task initialize;
begin
in1=0;
in2=0;
go=0;
end
endtask
task reset;
begin
@(negedge clk)
rst <=1;
go<=0;
@(negedge clk)
rst <=0;
go <=1;
end
endtask
task calculate(input [31:0]a,input [31:0]b);
begin
@(negedge clk)
go<=1;
in1 <= a;
in2 <= b;
#50 go<=0;
#10000;
end
endtask
initial begin
$monitor($time," %d %d %d",in1,in2,out);
reset;
initialize;
calculate(48123,628163);
reset;
calculate(45,90);
reset;
calculate(2000,10000);
reset;
calculate(35,49);
end
endmodule
What happens after adding a wave to the simulation is this:
It is not even close to what it should be.
You have a Verilog simulation race condition in the testbench code, which means that the simulation results are often unpredictable. This is the problematic line of code:
always@(clk) #20 clk <= ~clk;
Here is a better way to generate the clock that avoids the race:
always #20 clk = ~clk;
To end the simulation cleanly, I also added a $finish
to the initial
block:
initial begin
$monitor($time, " %d %d %d", in1, in2, out);
reset;
initialize;
calculate(48123, 628163);
reset;
calculate(45, 90);
reset;
calculate(2000, 10000);
reset;
calculate(35, 49);
#5 $finish;
end