【工程源码】基于FPGA在Modelsim仿真中显示状态机名称的3种方法

经过网上的搜索及自己的实验,总结在Modelsim仿真中显示状态机名称的三种方法。下面以一个具体的实例进行讲解。
实例功能:引入状态机实现2分频,这里使用状态机完全只是为了说明如何在仿真中显示状态机名称。
状态转移图:

设计文件代码:

1         module fsm(
    2                 input clk,
    3                 input reset_n,
    4                 output reg clkout
    5         );
    6 
    7         parameter ONE  = 2'b01,
    8                ZERO = 2'b10;
    9                                  
    10        reg [1:0]state;
    11
    12        always@(posedge clk or negedge reset_n)
    13        if(!reset_n)begin
    14                state <= ONE;
    15                clkout <= 1'b1;
    16        end
    17        else begin
    18                case(state)
    19                        ONE:begin
    20                                state <= ZERO;
    21                                clkout <= 1'b0;
    22                        end
    23                        ZERO:begin
    24                                state <= ONE;
    25                                clkout <= 1'b1;
    26                        end
    27                endcase
    28        end
    29
    30        endmodule


testbench文件代码:

1         `timescale 1ns/1ns
2         `define CLK_PRIOD 20
3 
4         module tb_fsm();
5 
6                 reg clk;
7                 reg reset_n;
8                 wire clkout;
9 
10                fsm inst_fsm(
11                        .clk(clk),
12                        .reset_n(reset_n),
13                        .clkout(clkout)
14                );
15                
16                initial clk = 1;
17                always #(`CLK_PRIOD/2) clk = ~clk;
18                
19                initial begin
20                        reset_n = 0;
21                        #201
22                        reset_n = 1;
23                        #500;
24                        $stop;
25                end
26
27        endmodule

仿真波形:

 

 在波形图中,看到状态机状态只能以各种进制的数进行显示,当状态比较多的时候不太便于查看波形查找一些问题,下面将用3种不同的方式对状态机状态以名称的形式显示在波形图中。

 

 

方法一:在testbench文件中对设计文件中的各种状态进行映射
实现过程:
   在tb文件加入一个reg变量monitor_state,将设计文件中的状态state映射到monitor_state,通过映射将不同的状态state在tb文件中通过monitor_state用字符串表示,具体实现代码如下。与开始相比,tb文件增加了9~16行的代码,在modelsim波形显示窗口将信号monitor_state添加进行,将数据显示格式设置为ASCII码,这样就能看到monitor_state信号名称就显示为状态机名了,并且与state是一一对应的。


注:这里的monitor_state的位宽设置是根据状态名称最长字符的个数确定的,一个ASCII码字符要用8bit表示,这里最长的是4个字符,所以这里设置的位宽是32位。

1         `timescale 1ns/1ns
    2         `define CLK_PRIOD 20
    3         module tb_fsm();
    4                 reg clk;
    5                 reg reset_n;
    6                 wire clkout;
    7                 reg [31:0]monitor_state;
    8                 
    9         parameter ONE  = 2'b01,
    10              ZERO = 2'b10;
    11
    12                always@(inst_fsm.state)
    13                case(inst_fsm.state)
    14                        ONE:  monitor_state = "ONE ";
    15                        ZERO: monitor_state = "ZERO";
    16                endcase
    17
    18                fsm inst_fsm(
    19                        .clk(clk),
    20                        .reset_n(reset_n),
    21                        .clkout(clkout)
    22                );
    23                
    24                initial clk = 1;
    25                always #(`CLK_PRIOD/2) clk = ~clk;
    26                
    27                initial begin
    28                        reset_n = 0;
    29                        #201
    30                        reset_n = 1;
    31                        #500;
    32                        $stop;
    33                end
    34        endmodule 

仿真波形:

 

 

方法二:在testbench文件中对设计文件中的状态机编码进行重定义
实现过程:
   在tb文件中将设计文件中的状态机编码用 defpara 进行重定义,具体可见下面代码8、9行,这里就涉及到重定义前后状态机状态寄存器的位宽发生了变化,重定义后的位宽变成了32位,这样就需要在设计文件中将状态寄存器state的位宽也设置成32bit。即将设计文件代码的第10行代码更改为 “reg [31:0]state;” 。这种情况不需要在波形文件额外添加信号,直接让状态机状态寄存器显示状态名。仿真波形见下面。

1         `timescale 1ns/1ns
    2         `define CLK_PRIOD 20
    3         module tb_fsm();
    4                 reg clk;
    5                 reg reset_n;
    6                 wire clkout;
    7 
    8         defparam        inst_fsm.ONE  = "ONE ";
    9         defparam        inst_fsm.ZERO = "ZERO";
    10
    11                fsm inst_fsm(
    12                        .clk(clk),
    13                        .reset_n(reset_n),
    14                        .clkout(clkout)
    15                );
    16                
    17                initial clk = 1;
    18                always #(`CLK_PRIOD/2) clk = ~clk;
    19                
    20                initial begin
    21                        reset_n = 0;
    22                        #201
    23                        reset_n = 1;
    24                        #500;
    25                        $stop;
    26                end
    27        endmodule

 仿真波形:

方法三:使用虚拟对象显示状态机名称
实现过程:
   该种方法不需要对设计代码和tb代码进行更改,这个只需要在modelsim软件上进行一些Tcl命令的操作,首先使用ModelSim的virtual type命令定义一个新的枚举类型(FSM_TYPE),该枚举类型可以在随后的仿真中使用,其命令格式为:virtual type { {val1 s1} { val2 s2} … { valn sn} } newVirtualType,其中val表示枚举值,s表示枚举名。而newVirtualType表示新的枚举类型名称。


注:virtual type与 { 之间,里面的 {} 与 {} 之间,} 与newVirtualType 一定要有空格。
   具体在本实例中在使用最开始的tb文件进行仿真后,然后再modelsim软件的tcl console窗口依次输入如下命令:

1  virtual type { {2‘b01 ONE} { 2'b10 ZERO} } state_type
     
2 virtual function {(state_type)/inst_fsm/state} fsm_state
     
3 add wave -color pink /inst_fsm/fsm_state 

 

 

3条命令的作用分别为:
1、使用ModelSim的virtual type命令定义一个新的枚举类型state_type
2、将需要显示的信号(/inst_fsm/state,设计文件中状态寄存器)进行类型转换,转换成一个新的信号fsm_state
3、将新的信号fsm_state加入到wave窗口中
仿真波形:

总结:
   以上三种方法均能实现在Modelsim仿真中显示状态机名称,各有特点,读者可以根据自己的习惯选择其中一种方法即可,这个就是能让在仿真波形时更加直观的看到状态转移的跳转情况

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个基本的FPGA对正弦AD采样的Verilog程序样例,供您参考: ``` module sin_adc( input clk, // 时钟信号 input rst, // 复位信号 input [7:0] sin_in, // 正弦信号输入 output reg [7:0] adc_out // ADC输出 ); reg [7:0] adc_cnt = 0; // 计数器 reg [7:0] adc_data = 0; // ADC数据 always @(posedge clk) begin if (rst) begin adc_cnt <= 0; adc_data <= 0; end else begin adc_cnt <= adc_cnt + 1; if (adc_cnt == 10) begin adc_cnt <= 0; adc_data <= sin_in; end end end assign adc_out = adc_data; endmodule ``` 这个程序实现了一个简单的ADC采样模块,可以对8位正弦信号进行采样,并将采样结果输出到8位ADC输出端口。在这个模块,时钟信号和复位信号需要外部提供,正弦信号输入需要用户通过其他方式提供,这里直接使用了一个8位的输入端口。 为了仿真这个模块,可以使用ModelSim进行仿真。以下是一个简单的仿真测试程序: ``` `timescale 1ns / 1ns module sin_adc_tb(); reg clk; reg rst; reg [7:0] sin_in; wire [7:0] adc_out; sin_adc dut ( .clk(clk), .rst(rst), .sin_in(sin_in), .adc_out(adc_out) ); initial begin clk = 0; rst = 1; sin_in = 0; #10 rst = 0; #100 $finish; end always #5 clk = ~clk; initial begin $dumpfile("sin_adc.vcd"); $dumpvars(0, sin_adc_tb); #10 sin_in = 100; #100 sin_in = 200; #100 sin_in = 50; #100 sin_in = 150; end endmodule ``` 这个测试程序实例化了sin_adc模块,并对其进行了简单的测试。在测试过程,时钟信号和复位信号由测试程序提供,正弦信号输入则在仿真过程动态改变。仿真结果可以通过ModelSim的波形查看功能进行观察和分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值