数据计算

时钟频率是 50MHz 对应着每个周期是1s/50MHz = 0.02us(20ns)
1us = 10^(-6)s0.02us = 2*10^(-8)s = 0.2*10^(-7)s

  1. 如果要计时0.2s的话,就是0.2s = 0.02us*10^7也就是要计数10^7个数,即10_000_000,需要占24位
  2. 如果要计时1s的话,就是5*10_000_000,需要占26位

image.pngimage.png

代码编写

  1. /***************************************
  2. File Name: flow_led.v
  3. Description: LED流水灯,时间间隔1秒
  4. Author: ZHJ0125
  5. Date: 2022-04-05
  6. ***************************************/
  7. module flow_led(
  8. input sys_clk, //系统时钟
  9. input sys_rst_n, //系统复位,低电平有效
  10. output reg [3:0] led //4个LED灯
  11. );
  12. //reg define
  13. reg [25:0] counter;
  14. /***************************************
  15. // main code
  16. ***************************************/
  17. //计数器对系统时钟计数,计时1秒
  18. always @(posedge sys_clk or negedge sys_rst_n) begin
  19. if(!sys_rst_n)
  20. counter <= 26'd0;
  21. else if(counter < 26'd50_000_000) // 1s
  22. //else if(counter < 24'd10) // 24'd10 for modelsim
  23. counter <= counter + 1'b1;
  24. else
  25. counter <= 26'd0;
  26. end
  27. //通过移位寄存器控制IO口的高低电平,从而改变LED的显示状态
  28. always @(posedge sys_clk or negedge sys_rst_n) begin
  29. if(!sys_rst_n)
  30. led <= 4'b0001;
  31. else if(counter == 26'd50_000_000)
  32. //else if(counter == 24'd10) // 24'd10 for modelsim
  33. led[3:0] <= {led[2:0], led[3]};
  34. // else
  35. // led <= led;
  36. end
  37. endmodule

程序固化

.sof文件转换成.jic文件,使之可以被烧录至片外Flash。image.png

SignalTap仿真

设置counter等于49999990时触发,软件会截取触发前256周期至触发后1792周期的状态。
image.png
image.png

实际效果

每1秒变换一次状态,实现流水灯效果。已将代码烧录至Flash,掉电后数据不会丢失。

flow_led.mp4 (9.25MB)

ModelSim 手动仿真

image.png
添加Verilog文件:
image.png image.png
创建Testbanch文件:
image.png image.png
工程文件目录:
image.png
编写Testbanch文件flow_led_tb.v
image.png

  1. `timescale 1ns/1ns // 定义仿真时间单位1ns,仿真时间精度为1ns
  2. module flow_led_tb(); // 测试模块
  3. // parameter define
  4. parameter T = 20; // 时钟周期20ns
  5. // reg define
  6. reg sys_clk; // 时钟信号
  7. reg sys_rst_n; // 复位信号
  8. // wire define
  9. wire [3:0] led;
  10. //***********************************
  11. // main code
  12. //************************************
  13. // 给输入信号初始值
  14. initial begin
  15. sys_clk = 1'b0;
  16. sys_rst_n = 1'b0; // 复位
  17. #(T+1) sys_rst_n = 1'b1; // 在第21ns的时候复位信号拉高
  18. end
  19. // 50MHz的时钟,周期为1/50MHz=20ns,所以每10ns取反一次
  20. always #(T/2) sys_clk = ~sys_clk;
  21. // 例化flow_led模块
  22. flow_led u0_flow_led (
  23. .sys_clk (sys_clk ),
  24. .sys_rst_n (sys_rst_n),
  25. .led (led )
  26. );
  27. endmodule

修改源文件时间间隔:

  1. //计数器对系统时钟计数,计时1秒
  2. always @(posedge sys_clk or negedge sys_rst_n) begin
  3. if(!sys_rst_n)
  4. counter <= 26'd0;
  5. //*******修改此处语句,将定时时间改为10*0.02us=0.2us=200ns
  6. //else if(counter < 26'd50_000_000) // 1s
  7. else if(counter < 26'd10) // 26'd10 for modelsim
  8. counter <= counter + 1'b1;
  9. else
  10. counter <= 26'd0;
  11. end
  12. //通过移位寄存器控制IO口的高低电平,从而改变LED的显示状态
  13. always @(posedge sys_clk or negedge sys_rst_n) begin
  14. if(!sys_rst_n)
  15. led <= 4'b0001;
  16. //*******修改此处语句,将定时时间改为10*0.02us=0.2us=200ns
  17. //else if(counter == 26'd50_000_000)
  18. else if(counter == 26'd10) // 26'd10 for modelsim
  19. led[3:0] <= {led[2:0], led[3]};
  20. // else
  21. // led <= led;
  22. end

修改完成后,在ModelSimCompileCompile All 进行全编译。
image.png
开始仿真,点击SimulateStart Simulation ...,选择Workflow_led_tb,会自动跳转至仿真界面。
image.png
添加信号源
image.png
设置仿真时间为2 us,并开始运行:
我们在源代码里设置的计数器个数为10,计时时间为0.2us(200ns)。仿真时间为2us,理论上我们可以看到2us/0.2us = 10次LED状态改变。
image.png
仿真结果如下:
image.png
image.png
从上面第一张图可以看出:

  1. 复位信号sys_rst_n在第21ns,由低电平跳转至了高电平。
  2. 时钟信号sys_clk在第10ns开始跳转至高电平,并以20ns为周期进行高低电平的转换。
  3. 在第230ns,即时钟信号sys_clk的第11个上升沿,LED状态发生改变,由初始的0001变为0010。
  4. 以后每隔220ns,即每次满10个时钟周期,就会在下一次时钟上升沿发生LED状态跳转。

从上面第二张图可以看出:

  1. 每隔220ns,LED状态就会发生跳转,一直持续了整个仿真时间2us。
  2. 在整个仿真时间2us内,发生了9次LED状态跳变。

我们原本预计在整个仿真时间2us内,可以发生2us/0.2us=10次LED状态改变,但实际上,由于在第21ns复位信号才被拉高,所以第一次LED状态跳转是在第230ns,一共只能发生9次LED状态跳变。

ModelSim 联合仿真

相关配置

联合仿真就是将Quartus和ModelSim联合,使得在Quartus软件中就可以调用ModelSim的仿真功能。
在Quartus软件的ToolsOptionsGerenalEDA Tool Options选项界面中,设置ModelSim Altera的路径为<Quartus软件安装路径>\modelsim_ase\win32aloem以我的安装路径为例,需要将目录设置为D:\Quartus\install\modelsim_ase\win32aloem
image.png
另外还需要在AssignmentsSettingsEDA Tool SettingSimulation界面进行如下配置:
image.png

编写TestBanch

找到ProcessingStartStart TestBench Template Writer,它会自动创建一个Testbanch模板,创建的模板位置可以在控制台看到。
image.png 我们直接在Quartus软件中打开这个flow_led.vt文件:
image.png
我们在此模板基础上进行修改,以下是我修改的文件内容:

  1. /***************************************
  2. // File Name: flow_led.vt
  3. // Description: Verilog Test Bench template for design : flow_led
  4. // Author: ZHJ0125
  5. // Date: "04/05/2022 20:26:52"
  6. ***************************************/
  7. `timescale 1 ns/ 1 ns // 声明仿真时间单位(左)和仿真精度(右)
  8. module flow_led_tb(); // 模块名称为flow_led_tb
  9. reg sys_clk; // 时钟信号
  10. reg sys_rst_n; // 复位信号
  11. // wires
  12. wire [3:0] led;
  13. // 例化设计模块,例化被测模块的目的是把被测模块和激励模块实例化起来,
  14. // 并且把被测模块的端口与激励模块的端口进行相应的连接,使得激励可以输入到被测模块。
  15. // 左侧带'.'的信号为flow_led模块定义的端口信号,右侧括号内的信号为激励模块中定义的信号。
  16. flow_led i1 (
  17. // port map - connection between master ports and signals/registers
  18. .led(led),
  19. .sys_clk(sys_clk),
  20. .sys_rst_n(sys_rst_n)
  21. );
  22. initial begin
  23. // code that executes only once
  24. // insert code here --> begin
  25. sys_clk = 1'b0; // 时钟信号初始值
  26. sys_rst_n = 1'b0; // 复位信号初始值
  27. #100 sys_rst_n = 1'b1; // 在第100ns的时候复位信号拉高
  28. #1000 $stop; // 在第1000ns的时候停止仿真,仿真时间为1000ns
  29. // --> end
  30. //$display("Running testbench");
  31. end
  32. // 使用initial或always语句产生激励波形
  33. always begin
  34. // code executes for every event on sensitivity list
  35. // insert code here --> begin
  36. #10 sys_clk = ~sys_clk;
  37. // --> end
  38. end
  39. endmodule

接着需要回到AssignmentsSettingsEDA Tool SettingSimulation配置界面,配置Testbanch文件:
image.png
image.png
image.png
需要注意的是:

  1. Test bench name填写的内容需要与模板中写的模块名字一致。
  2. Top level module in test bench会自动生成,默认与模块名字一致。
  3. 文件名是模板自动生成的flow_led.vt文件,不是我们之前手动编写的flow_led_tb.v

    开始仿真

    准备就绪后,点击ToolsRun Simulation ToolRTL Simulation按钮,会自动打开ModelSim的仿真界面。
    image.png
    可以看到:

  4. 在第100ns时,复位信号sys_rst_n拉高

  5. LED状态共跳变4次,并且符合流水灯的预期(循环移位)效果。

参考资料

正点原子开拓者FPGA开发指南V1.5.pdf第四和第五章节