作为一名极其低产的一名“作者”,2021年也要写上一篇文章吧。作为今年的第一篇博文,想和大家聊聊 FSM 仿真时可能遇到的一些问题。
具体的 FSM 如何书写,这里送上“十二点过九分”的一篇文章的链接。
十二点过九分:【划水】怎么写一个有限状态机?zhuanlan.zhihu.com下面言归正传,在编写 FSM 测试程序时,经常需要检查 FSM 的“状态”,常规的做法是:
- 在利用 Modelsim 仿真时,我们将次级目录下的定义的 state 单独拉出来,查看状态跳转情况。这样的作法虽然可以看到,但是仿真的波形上都是所定义子状态的 0/1 二进制编码。不会直观的显示当前的状态名(如何你的记忆力足够强大,则可以直接忽略笔者的这篇文章)
- 采用打印的方式,例如利用 $display 函数,在命令行中显示,但是波形中又无法体现。
因此,有这么一种“奇淫技巧”(至少笔者是这么认为的),那便是在 testbench 中直接引用该状态变量,并通过 case 语句将 state 转换为自然语言表述。
下面给出具体的操作步骤,操作步骤参考[1]。
第一步:在 testbench 中定义 reg 型变量,用于存储ASCII字符串。例如,下面定义了最大长度为5字符串。
reg [5*8-1:0] current_state_name ;
第二步:利用模块变量的直接引用,并通过case将状态机的各个状态与自然语言一一对应起来
always@(tb_ASCII_state.UUU.current_state or tb_ASCII_state.UUU.next_state)begin
case(tb_ASCII_state.UUU.current_state)
IDLE :test_current_state = "IDLE" ;
PROCESS :test_current_state = "PROCESS" ;
END_S :test_current_state = "END_S" ;
default :test_current_state = "ERROR" ;
endcase
case(tb_ASCII_state.UUU.next_state)
IDLE :test_next_state = "IDLE" ;
PROCESS :test_next_state = "PROCESS" ;
END_S :test_next_state = "END_S" ;
default :test_next_state = "ERROR" ;
endcase
end
第三步:在Modelsim的波形窗口界面中,将前面定义的reg型变量转换为ASCII显示。
下面给出本次所用的完整的测试用例
工程文件
module ASCII_state(
input sys_clk ,
input rst_n ,
output reg state_out
);
reg [2:0] current_state,next_state ;
localparam IDLE = 3'b001 ,
PROCESS = 3'b010 ,
END_S = 3'b100 ;
always@(posedge sys_clk or negedge rst_n)begin
if(!rst_n)begin
current_state <= IDLE ;
end
else begin
current_state <= next_state ;
end
end
always@(*)egin
case(current_state)
IDLE:begin
state_out = 1'b1 ;
next_state = PROCESS ;
end
PROCESS:begin
state_out = 1'b1 ;
next_state = END_S ;
end
END_S:begin
state_out = 1'b0 ;
next_state = IDLE ;
end
default:begin
state_out = 1'b0 ;
next_state = IDLE ;
end
endcase
end
endmodule
仿真文件
module tb_ASCII_state;
reg sys_clk ;
reg rst_n ;
wire state_out ;
initial sys_clk = 1 ;
always#5 sys_clk = ~sys_clk;
initial begin
rst_n = 0 ;
#50;
rst_n = 1 ;
end
ASCII_state UUU(
.sys_clk (sys_clk ),
.rst_n (rst_n ),
.state_out (state_out)
);
reg [8*8-1:0] test_current_state,test_next_state;
localparam IDLE = 3'b001 ,
PROCESS = 3'b010 ,
END_S = 3'b100 ;
always@(tb_ASCII_state.UUU.current_state or tb_ASCII_state.UUU.next_state)begin
case(tb_ASCII_state.UUU.current_state)
IDLE :test_current_state = "IDLE" ;
PROCESS :test_current_state = "PROCESS" ;
END_S :test_current_state = "END_S" ;
default :test_current_state = "ERROR" ;
endcase
case(tb_ASCII_state.UUU.next_state)
IDLE :test_next_state = "IDLE" ;
PROCESS :test_next_state = "PROCESS" ;
END_S :test_next_state = "END_S" ;
default :test_next_state = "ERROR" ;
endcase
end
波形仿真
从仿真波形上来看,功能基本正确。
基于以上操作,面对状态跳转的问题,就不存在对一连串的0101...而发愁了 。
参考
[1] 李庆华著《通信IC设计》.机械工业出版社