FPGA 入门 (二)

verilog基本语法

常用可综合语法:

模块声明:module ... endmodule

端口定义:input,output,inout。

信号类型:wire,reg,tri等,integer常用于for语句中(reg,wire是最常用的,一般tri和integer用在测试脚本中)

参数定义:parameter。

运算符操作:各种逻辑操作符、移位操作符、算数操作符大多是可综合的(注:===与!==是不可综合的)。

比较判断:if ... else,case (casex, casez) ... default ... endcase。

连续赋值:assign,问号表达式(?:)。

always块:敏感列表可以为电平、沿信号posedge/negedge;通常和@连用。

begin ... end:通俗的说就是C语言里的{}。

任务定义:task ... endtask。

循环语句:for 跟C用法类似,但变量不能做++, 只能i=i+1这样。基本在可综合模块中不使用。

赋值符号:=和<=(阻塞赋值和非阻塞赋值)


小例子及testbench介绍

描述一个异步D触发器模块:


文件ex_module.v 定义可综合模块

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. module ex_module(                          //模块名字和文件名字要一样  紧接着接口列表  
  2.         input        wire                sclk,    //时钟命名 sclk  
  3.         input        wire                rst_n,   // reset_n  复位时低复位  
  4.         input        wire    [7:0]       d,       //模块声明的时候,输入必须是wire变量  
  5.         output       reg     [7:0]       q        //reg变量必须在always块里面来赋值,模块声明的时候,输出可以是wire变量也可以是reg    
  6. );  
  7. //异步D触发器  
  8. always @(posedge sclk or negedge rst_n) //敏感列表 可以包括电平触发或者沿触发  
  9.         if (rst_n == 1'b0) //条件表,这里是组合逻辑  还有其他表达方式 2'b01  8'b0000_1111     8'd10    8'h0f  
  10.                 q<=8'h00;              
  11.         else  
  12.                 q<=d;  
  13. //alway块中只能给reg类型变量赋值,wire会报错,如果是wire型变量 可以用assign 语句赋值  
  14. endmodule  

    可综合模块写完后,需要用仿真测试去验证设计的正确性。可以编写testbench模块,在结合modelsim仿真就可以看到前仿真的结果。

文件tb_ex_module.v 定义激励模块

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. `timescale 1ns/100ps  //单位时标声明 精度到100ps 小数点前是ns 例 10.1 就是10ns + 100ps 而10.11就达不到精度了  
  2. module tb_ex_module; //激励模块声明时不需要端口列表  
  3. reg  [7:0] d_r;  
  4. reg sclk_r, rst_n_r;//激励信号的声明  
  5. wire   [7:0] q; //原始模块输出信号连接线  
  6.       
  7. initial   //上电初始化过程  上电只只执行一次  
  8. begin //顺序执行  initial块内只能对寄存器变量赋值  
  9.     d_r <= 0;  
  10.     sclk_r <= 0;  
  11.     rst_n_r <= 0;  
  12.     #20  
  13.     rst_n_r <= 1;  
  14. end  
  15.   
  16. initial  
  17. begin  
  18.     #20  
  19.     send_d();  
  20. end  
  21.       
  22.       
  23. always #10 sclk_r <= ~sclk_r; //产生时钟,循环震荡周期 一个周期用时20ns  
  24.   
  25.     
  26.  //例化的方法  
  27.  //原始的名字 例化的名字(激励信号名字 可以自定义)  
  28.  ex_module ex_module_inst(  
  29.   .sclk (sclk_r),               //.后面是原模块的  ()里面是连接的当前模块的 这样通道就打开了  
  30.   .rst_n (rst_n_r),  
  31.   .d (d_r),  
  32.   .q  (q)  //如果是输出变量 ()中必须是wire变量  
  33.  );  
  34.       
  35. task send_d();  
  36.     integer i;  
  37.     begin  
  38.         for (i = 0; i < 255; i = i + 1)  
  39.         begin  
  40.             @(posedge sclk_r)//卡一个时钟拍子  
  41.             d_r <= d_r + 1;  
  42.         end  
  43.     end  
  44. endtask  
  45. endmodule  


modelsim仿真结果


testbench编写可以归纳为:

1)对被测试设计的顶层接口进行例化。

2)给被测试设计的输入接口添加激励。

3)判断被测试设计的输出响应是否满足设计要求。



有限状态机FSM

    硬件设计多是并行实现的,但对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这样就用到了状态机的思想。简单的说状态机就是通过不同的状态迁移来完成一些特定的顺序逻辑。

如何设计状态机

1)根据实际的工作流程画出状态迁移图。

2)根据状态迁移图来编写代码。

假如有两个开关K1和K2会随着条件A的值变化而变化。


ex_fsm.v 可综合模块

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. module ex_fsm(  
  2.     input       wire        sclk,  
  3.     input       wire        rst_n,  
  4.     input       wire        A,  
  5.     output      reg         k1,  
  6.     output      reg         k2  
  7. );  
  8.   
  9. parameter IDLE  =   4'b0001; //使用独热码来定义状态  
  10. parameter START =   4'b0010;  
  11. parameter STOP  =   4'b0100;  
  12. parameter CLEAR =   4'b1000;  
  13.   
  14. reg [3:0] state;  
  15.   
  16. //状态机只对状态进行处理,不对变量进行处理  
  17. always @(posedge sclk or negedge rst_n)  
  18.     if (rst_n == 1'b0)  
  19.         state <= IDLE;  
  20.     else begin  
  21.         case (state)  
  22.             IDLE: if (A == 1'b1)  
  23.                     state <= START;  
  24.             START: if (A == 1'b0)  
  25.                     state <= STOP;  
  26.             STOP: if (A == 1'b1)  
  27.                     state <= CLEAR;  
  28.             CLEAR: if (A == 1'b0)  
  29.                     state <= IDLE;  
  30.             default:  
  31.                 state <= IDLE;  
  32.             endcase  
  33.     end  
  34.   
  35. //变量单独写在一个always块中  
  36. always @(posedge sclk or negedge rst_n)  
  37.     if (rst_n == 1'b0)  
  38.         k1 <= 1'b0;  
  39.     else if (state == IDLE && A == 1'b1)  
  40.         k1 <= 1'b0;  
  41.     else if (state == CLEAR && A == 1'b0)  
  42.         k1 <= 1'b1;  
  43.   
  44. always @(posedge sclk or negedge rst_n)  
  45.     if (rst_n == 1'b0)  
  46.         k2 <= 1'b0;  
  47.     else if (state == STOP && A == 1'b1)  
  48.         k2 <= 1'b1;  
  49.     else if (state == CLEAR && A == 1'b0)  
  50.         k2 <= 1'b0;  
  51.       
  52. endmodule  

tb_ex_fsm.v 激励模块

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. `timescale 1ns/1ns  
  2. module tb_ex_fsm;  
  3.   
  4. reg     sclk_r;  
  5. reg     rst_n_r;  
  6. reg     in_A;  
  7. wire    k1;  
  8. wire    k2;  
  9.   
  10. initial  
  11. begin  
  12.     rst_n_r <= 1'b0;  
  13.     sclk_r <= 1'b0;  
  14.     #50  
  15.     rst_n_r <= 1'b1;  
  16. end  
  17.   
  18. initial  
  19. begin  
  20.     in_A <= 1'b0;  
  21.     #60  
  22.     send_A();  
  23. end  
  24.   
  25. always #10 sclk_r <= ~sclk_r;  
  26.   
  27. ex_fsm ex_fsm_inst(  
  28.     .sclk   (sclk_r),  
  29.     .rst_n  (rst_n_r),  
  30.     .A      (in_A),  
  31.     .k1     (k1),  
  32.     .k2     (k2)  
  33. );  
  34.   
  35. task send_A();  
  36.     integer i;  
  37.     begin  
  38.         for (i=0; i< 512; i=i+1)  
  39.         begin  
  40.             @(posedge sclk_r)  
  41.             if (i<40)  
  42.                 in_A <= 1'b0;  
  43.             else if (i<80)  
  44.                 in_A <= 1'b1;  
  45.             else if (i<120)  
  46.                 in_A <= 1'b0;  
  47.             else if (i<160)  
  48.                 in_A <= 1'b1;  
  49.             else if (i<200)  
  50.                 in_A <= 1'b1;  
  51.         end  
  52.     end  
  53. endtask  
  54.   
  55. endmodule  

如果每次用modelsim都手动添加仿真很麻烦,可以写一个run.do的自动仿真脚本

文件run.do 脚本

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #退出当前的仿真工程  
  2. quit -sim  
  3. #清空命令行  
  4. .main   clear  
  5. #创建库  
  6. vlib work  
  7. #将逻辑库的名字映射到实际物理路径上来  
  8. vmap    work ./work  
  9. #编译代码文件到逻辑库work中  
  10. vlog    -work   work    ./tb_ex_fsm.v  
  11. vlog    -work   work    ./../design/*.v  
  12. #启动仿真  
  13. vsim    -voptargs=+acc work.tb_ex_fsm  
  14. #添加波形  
  15. #定义宏  
  16. virtual type {  
  17.     {01 IDLE}  
  18.     {02 START}  
  19.     {04 STOP}  
  20.     {08 CLEAR}  
  21. } vir_new_signal  
  22. add wave    tb_ex_fsm/*  
  23. virtual function {(vir_new_signal)tb_ex_fsm/ex_fsm_inst/state} new_state  
  24. add wave -color yellow tb_ex_fsm/ex_fsm_inst/new_state  
  25. run 100us  

目录结构

modelsim在sim文件夹下建立工程,在modelsim的命令行中执行do run.do就可以自动仿真波形了。

modelsim仿真结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值