I have mostly worked on VHDL and I have recently started learning Verilog.
I wrote a Moore Finite State Machine (FSM). The FSM is not resetting properly as current state upon reset doesn't go into initial state as indicated by its value cstat = xx by simulator at t=0. Also the output which depends upon cstate is also shown as oup1 = x.
The design and testbench is on EDA playground (https://www.edaplayground.com/x/5Uwi). With Cadence Incisive 15.20 simulator invoked with command line options
-timescale 1ms/1us -sysv -disable_sem2009
I get following log output showing the simulation failed:
[2020年03月09日 15:12:36 EDT] irun -Q -unbuffered '-timescale' '1ms/1us' '-sysv' '-disable_sem2009' '-access' '+rw' design.sv testbench.sv
irun: 15.20-s038: (c) Copyright 1995-2017 Cadence Design Systems, Inc.
Top level design units:
moore_fsm_tb
Loading snapshot worklib.moore_fsm_tb:sv .................... Done
ncsim> source /incisiv/15.20/tools/inca/files/ncsimrc
ncsim> run
FAILED
Time=0, rst=0, inp1=0, inp2=0, current state = xx, next state = 00, oup1 = x
Expected current state = 00, next state = 00, oup1 = 0
Simulation complete via $finish(1) at time 0 FS + 4
./testbench.sv:70 $finish;
ncsim> exit
Done
Design
module moore_fsm_top ( input wire clk,
input wire rst,
input wire inp1,
input wire inp2,
output reg oup1,
output reg [1:0] cstat,
output reg [1:0] nstat
);
localparam MAX = 4000;
reg [11:0] ccnt;
reg [11:0] ncnt;
wire maxedout;
localparam INP_X = 1'b0;
localparam INP_Y = 1'b1;
localparam OUP_X = 1'b0;
localparam OUP_Y = 1'b1;
localparam UU = 2'b00;
localparam VV = 2'b01;
localparam WW = 2'b10;
localparam XX = 2'b11;
always @ ( posedge clk, posedge rst ) begin
if ( rst ) begin
cstat <= UU;
end else begin
cstat <= nstat;
end
end
always @ ( posedge clk, posedge rst ) begin
if ( rst ) begin
ccnt <= 12'b0;
end else begin
ccnt <= ncnt;
end
end
always @ ( * ) begin
case (cstat)
UU, WW: ncnt = 12'b0;
VV, XX: begin
if (ccnt == (MAX-1)) begin
ncnt = 12'b0;
end else begin
ncnt = ccnt+1;
end
end
endcase
end
assign maxedout = (ccnt == (MAX-1)) ? 1'b1 : 1'b0;
always @ ( * ) begin
case (cstat)
UU: begin
nstat = UU;
if (inp1 == INP_X) begin
nstat = UU;
end else if (inp1 == INP_Y) begin
nstat = VV;
end
end
VV: begin
nstat = VV;
if (inp2 == INP_X && !maxedout ) begin
nstat = VV;
end else if (inp2 == INP_X && maxedout) begin
nstat = UU;
end else if (inp2 == INP_Y && !maxedout) begin
nstat = WW;
end else if (inp2 == INP_Y && maxedout) begin
nstat = WW;
end
end
WW: begin
nstat = WW;
if (inp2 == INP_X) begin
nstat = WW;
end else if (inp2 == INP_Y) begin
nstat = XX;
end
end
XX: begin
nstat = XX;
if (inp1 == INP_X && maxedout == 1'b0 ) begin
nstat = XX;
end else if (inp1 == INP_X && maxedout == 1'b1) begin
nstat = WW;
end else if (inp1 == INP_Y && maxedout == 1'b0) begin
nstat = UU;
end else if (inp1 == INP_Y && maxedout == 1'b1) begin
nstat = UU;
end
end
default: nstat = UU;
endcase
end
always @ ( * ) begin
case (cstat)
UU, VV: oup1 = OUP_X;
WW, XX: oup1 = OUP_Y;
default: oup1 = OUP_X;
endcase
end
endmodule
Testbench
`timescale 1ms / 1us
module moore_fsm_tb;
reg clk;
reg rst;
reg inp1;
reg inp2;
wire oup1;
wire [1:0] cstat;
wire [1:0] nstat;
localparam TIME_PERIOD = 1;
localparam INP_X = 1'b0;
localparam INP_Y = 1'b1;
localparam OUP_X = 1'b0;
localparam OUP_Y = 1'b1;
localparam UU = 2'b00;
localparam VV = 2'b01;
localparam WW = 2'b10;
localparam XX = 2'b11;
moore_fsm_top dut(.clk(clk),
.rst(rst),
.inp1(inp1),
.inp2(inp2),
.oup1(oup1),
.cstat(cstat),
.nstat(nstat));
initial begin
clk = 1'b0;
forever #(TIME_PERIOD/2) clk = ~clk;
end
initial begin
rst = 1'b1;
@(negedge clk);
@(negedge clk);
rst = 1'b0;
end
initial begin
inp1 = INP_X;
inp2 = INP_X;
@(negedge rst);
checkifgood(UU, UU, OUP_X);
$display("PASS");
$finish;
end
task checkifgood;
input [1:0] exp_cstat;
input [1:0] exp_nstat;
input exp_oup1;
if (oup1 !== exp_oup1 || cstat !== exp_cstat || nstat !== exp_nstat) begin
$display("FAILED");
$display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
$time, rst, inp1, inp2, cstat, nstat, oup1 );
$display("Expected current state = %b, next state = %b, oup1 = %d",
exp_cstat, exp_nstat, exp_oup1 );
$finish;
end else begin
$display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
$time, rst, inp1, inp2, cstat, nstat, oup1 );
end
endtask
endmodule
I read Verilog gotcha that for asynchronous resets, if clocking and reset are in different initial blocks, than I should initialize clock and reset with non-blocking statement. If I make this change in above testbench, I get output from simulator saying:
Execution interrupted or reached maximum runtime.
What is going wrong here ?
1 Answer 1
I have modified your Test Bench and Design code, now u wont encounter the crash issue but i definitely think there is an issue in your stimulus in Test Bench.
`timescale 1ns / 1ns
module moore_fsm_tb;
reg clk;
reg rst;
reg inp1;
reg inp2;
wire oup1;
wire [1:0] cstat;
wire [1:0] nstat;
localparam TIME_PERIOD = 2;
localparam INP_X = 1'b0;
localparam INP_Y = 1'b1;
localparam OUP_X = 1'b0;
localparam OUP_Y = 1'b1;
localparam UU = 2'b00;
localparam VV = 2'b01;
localparam WW = 2'b10;
localparam XX = 2'b11;
moore_fsm_top dut(.clk(clk),
.rst(rst),
.inp1(inp1),
.inp2(inp2),
.oup1(oup1),
.cstat(cstat),
.nstat(nstat));
initial
clk = 1'b0;
always #(TIME_PERIOD/2) clk = ~clk;
initial begin
rst = 1'b0;
@(negedge clk);
@(negedge clk);
rst = 1'b1;
@(negedge clk);
@(negedge clk);
rst = 1'b0;
end
initial begin
inp1 = INP_X;
inp2 = INP_X;
@(negedge rst);
checkifgood(UU, UU, OUP_X);
$display("PASS");
$finish;
end
task checkifgood;
input [1:0] exp_cstat;
input [1:0] exp_nstat;
input exp_oup1;
if (oup1 !== exp_oup1 || cstat !== exp_cstat || nstat !== exp_nstat) begin
$display("FAILED");
$display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
$time, rst, inp1, inp2, cstat, nstat, oup1 );
$display("Expected current state = %b, next state = %b, oup1 = %d",
exp_cstat, exp_nstat, exp_oup1 );
$finish;
end else begin
$display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
$time, rst, inp1, inp2, cstat, nstat, oup1 );
end
endtask
endmodule
design code also modified ,but i am not sure u are trying to implement a priority encoders using the nested if-else-if structure in your design , but with initial glance i think u are not intended to do it.
module moore_fsm_top (
input wire clk,rst,inp1,inp2
,output reg oup1
,output reg [1:0] cstat,nstat
);
localparam MAX = 4000;
reg [11:0] ccnt;
reg [11:0] ncnt;
wire maxedout;
localparam INP_X = 1'b0;
localparam INP_Y = 1'b1;
localparam OUP_X = 1'b0;
localparam OUP_Y = 1'b1;
localparam UU = 2'b00;
localparam VV = 2'b01;
localparam WW = 2'b10;
localparam XX = 2'b11;
always @ ( posedge clk, posedge rst )
if ( rst ) begin
cstat <= #1 UU;
ccnt <= #1 12'b0;
end else begin
cstat <= #1 nstat;
ccnt <= #1 ncnt;
end
always @*
case (cstat)
UU, WW: ncnt = 12'b0;
VV, XX: if (ccnt == (MAX-1)) ncnt = 12'b0;
else ncnt = ccnt+1;
endcase
assign maxedout = (ccnt == (MAX-1)) ? 1'b1 : 1'b0;
always@* begin
nstat = cstat;
case (cstat)
UU: if (inp1 == INP_Y) nstat = VV;
VV: if (inp2 == INP_X && maxedout) nstat = UU;
else if (inp2 == INP_Y ) nstat = WW;
WW: if (inp2 == INP_Y) nstat = XX;
XX: if (inp1 == INP_X && maxedout) nstat = WW;
else if (inp1 == INP_Y ) nstat = UU;
endcase
end
always @*
case (cstat)
WW, XX: oup1 = OUP_Y;
default: oup1 = OUP_X;
endcase
endmodule
-
\$\begingroup\$ dear rama. I already found the problem and fixed it with help of @oldfart. The problem in design was not deliberate. I was obfuscating the code before I posted it here and it introduced the problem. The problem was there in Test-bench. It was basically that time period of 1 was not letting simulator proceed. Dividing time period of 1 (1 ms) by 2 in clock generation was perhaps causing it. Not sure why that is so because it should still work as time precision or step size is 1 us and so simulator should be able to generate 500 us clock edges \$\endgroup\$nurabha– nurabha2020年03月15日 01:54:32 +00:00Commented Mar 15, 2020 at 1:54
-
\$\begingroup\$ I think you have used localparam in the test bench by default localparam is an integer so if you divide 1 by 2 it might have rounded it to 0 so your test bench is not moving ahead and it is using up the memory, and regarding the current state is xxx, this is because in the initial block u are asserting the reset from timestamp 0 so design won't see as posedge in reset and your design won't get reset asynchronously.. So I modified the localparam,reset assertion and time precision in the Test Bench. \$\endgroup\$RAMA KRISHNA MEDA– RAMA KRISHNA MEDA2020年03月15日 03:35:59 +00:00Commented Mar 15, 2020 at 3:35
Explore related questions
See similar questions with these tags.
reset_n= 1'b0; #(TIME_PERIOD*10); reset_n= 1'b1;
I also prefer my TIME_PERIOD to be a nice big number 50 or 100 , not 1! OH! Just quickly scanning your code this is wrong:ncnt = ncnt+1;
That does not work in a combinatorial section. \$\endgroup\$ncnt
in different sections. You can't do that . 1/ It gives race conditions 2/ You can not synthesize that. \$\endgroup\$