前言
有个大神给我说,FPGA视频看完之后,不要写简单的代码,就有什么大项目,做一个就够了。
但是,我还是想练一练。于是就写了一个简单的状态机,并且发现了一些有趣东西:run.do脚本和force强制赋值语句
run.do脚本文件
这个脚本文件,通过modelsim在run.do脚本文件夹中新建一个工程,直接在运行窗口输入命令:do run.do,直接生成如下的波形图,简化了好多操作。
run.do文件
- 上图中的8-18行可以直接删去,剩下的作为最最简单的模板文件。为了大家方便使用,可以复制粘贴下面的代码
quit -sim
vlib work
vlog ./../testbench/fsm_tb.v
vlog ./../rtl/*.v
vsim -voptargs=+acc work.fsm_tb
virtual type {
{01 IDLE}
{02 WRITE}
{04 READ}
{08 CHECK}
{10 ERROR}
} virtual_new_signal
virtual function {(virtual_new_signal)fsm_tb/fsm_inst/state} new_state
add wave -colo red fsm_inst/new_state
add wave fsm_inst/*
run 100us
force强制改变波形数据
在仿真测试文件中,可以使用force语句强制改变波形数据,
这段代码的作用就是改变波形文件中的数据,从而测试某一功能,如下图所示:将red_cnt的值从0变为2,导致red_cnt和write_cnt的数不相等,进入ERROR状态。
附件(前面提到的设计文件)
fsm.v
module fsm(
Clk,
Rst_n,
write_start,
error_flag
);
input Clk ;
input Rst_n ;
input write_start ;
output error_flag;
reg [4:0] state;
assign error_flag = state[4];
localparam IDLE = 5'b00001,
WRITE = 5'b00010,
READ = 5'b00100,
CHECK = 5'b01000,
ERROR = 5'b10000;
reg [9:0] write_cnt;
reg write_end;
reg [9:0] read_cnt;
reg read_end;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
state <= IDLE;
else case(state)
IDLE:
if(write_start == 1'b1)
state <= WRITE;
WRITE:
if(write_end == 1'b1)
state <= READ;
READ:
if(read_end == 1)
state <= CHECK;
CHECK:
if((|write_cnt)==1'b0 && (|read_cnt)==1'b0)
state <= IDLE;
else
state <= ERROR;
ERROR:
state <= ERROR;
default:state <= IDLE;
endcase
//写的计数器
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
write_cnt <= 10'b0;
else if(state == WRITE)
write_cnt <= write_cnt + 1'b1;
else
write_cnt <= 10'b0;
//写的状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
write_end <= 1'b0;
else if(write_cnt == 10'd1022)
write_end <= 1'b1;
else
write_end <= 1'b0;
//读的计数器
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
read_cnt <= 10'b0;
else if(state == READ)
read_cnt <= read_cnt + 1'b1;
else
read_cnt <= 10'b0;
//读的状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
read_end <= 1'b0;
else if(read_cnt == 10'd1022)
read_end <= 1'b1;
else
read_end <= 1'b0;
endmodule
fsm_tb.v
`timescale 1ns/1ns
`define clock_period 20
module fsm_tb;
reg Clk,Rst_n,write_start;
wire error_flag;
fsm fsm_inst(
Clk,
Rst_n,
write_start,
error_flag
);
initial Clk = 1'b1;
always #(`clock_period/2) Clk = ~Clk;
initial begin
Rst_n = 1'b0;
#100
Rst_n = 1'b1;
end
initial begin
write_start = 1'b0;
#300
write_start = 1'b1;
#30
write_start = 1'b0;
end
//force强制赋值语句
initial begin
# 41280
force fsm_inst.read_cnt = 10'd2;
end
//initial #100_000 $stop;
endmodule
经验之谈
- 学会用run.do和makefile等类似的脚本文件
- modelsim中仿真时,要将参数定义放在那面,否则会报错