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 定义可综合模块
- module ex_module( //模块名字和文件名字要一样 紧接着接口列表
- input wire sclk, //时钟命名 sclk
- input wire rst_n, // reset_n 复位时低复位
- input wire [7:0] d, //模块声明的时候,输入必须是wire变量
- output reg [7:0] q //reg变量必须在always块里面来赋值,模块声明的时候,输出可以是wire变量也可以是reg
- );
- //异步D触发器
- always @(posedge sclk or negedge rst_n) //敏感列表 可以包括电平触发或者沿触发
- if (rst_n == 1'b0) //条件表,这里是组合逻辑 还有其他表达方式 2'b01 8'b0000_1111 8'd10 8'h0f
- q<=8'h00;
- else
- q<=d;
- //alway块中只能给reg类型变量赋值,wire会报错,如果是wire型变量 可以用assign 语句赋值
- endmodule
可综合模块写完后,需要用仿真测试去验证设计的正确性。可以编写testbench模块,在结合modelsim仿真就可以看到前仿真的结果。
文件tb_ex_module.v 定义激励模块
- `timescale 1ns/100ps //单位时标声明 精度到100ps 小数点前是ns 例 10.1 就是10ns + 100ps 而10.11就达不到精度了
- module tb_ex_module; //激励模块声明时不需要端口列表
- reg [7:0] d_r;
- reg sclk_r, rst_n_r;//激励信号的声明
- wire [7:0] q; //原始模块输出信号连接线
-
- initial //上电初始化过程 上电只只执行一次
- begin //顺序执行 initial块内只能对寄存器变量赋值
- d_r <= 0;
- sclk_r <= 0;
- rst_n_r <= 0;
- #20
- rst_n_r <= 1;
- end
-
- initial
- begin
- #20
- send_d();
- end
-
-
- always #10 sclk_r <= ~sclk_r; //产生时钟,循环震荡周期 一个周期用时20ns
-
-
- //例化的方法
- //原始的名字 例化的名字(激励信号名字 可以自定义)
- ex_module ex_module_inst(
- .sclk (sclk_r), //.后面是原模块的 ()里面是连接的当前模块的 这样通道就打开了
- .rst_n (rst_n_r),
- .d (d_r),
- .q (q) //如果是输出变量 ()中必须是wire变量
- );
-
- task send_d();
- integer i;
- begin
- for (i = 0; i < 255; i = i + 1)
- begin
- @(posedge sclk_r)//卡一个时钟拍子
- d_r <= d_r + 1;
- end
- end
- endtask
- endmodule
modelsim仿真结果
testbench编写可以归纳为:
1)对被测试设计的顶层接口进行例化。
2)给被测试设计的输入接口添加激励。
3)判断被测试设计的输出响应是否满足设计要求。

有限状态机FSM
硬件设计多是并行实现的,但对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这样就用到了状态机的思想。简单的说状态机就是通过不同的状态迁移来完成一些特定的顺序逻辑。
如何设计状态机
1)根据实际的工作流程画出状态迁移图。
2)根据状态迁移图来编写代码。
假如有两个开关K1和K2会随着条件A的值变化而变化。
ex_fsm.v 可综合模块
- module ex_fsm(
- input wire sclk,
- input wire rst_n,
- input wire A,
- output reg k1,
- output reg k2
- );
-
- parameter IDLE = 4'b0001; //使用独热码来定义状态
- parameter START = 4'b0010;
- parameter STOP = 4'b0100;
- parameter CLEAR = 4'b1000;
-
- reg [3:0] state;
-
- //状态机只对状态进行处理,不对变量进行处理
- always @(posedge sclk or negedge rst_n)
- if (rst_n == 1'b0)
- state <= IDLE;
- else begin
- case (state)
- IDLE: if (A == 1'b1)
- state <= START;
- START: if (A == 1'b0)
- state <= STOP;
- STOP: if (A == 1'b1)
- state <= CLEAR;
- CLEAR: if (A == 1'b0)
- state <= IDLE;
- default:
- state <= IDLE;
- endcase
- end
-
- //变量单独写在一个always块中
- always @(posedge sclk or negedge rst_n)
- if (rst_n == 1'b0)
- k1 <= 1'b0;
- else if (state == IDLE && A == 1'b1)
- k1 <= 1'b0;
- else if (state == CLEAR && A == 1'b0)
- k1 <= 1'b1;
-
- always @(posedge sclk or negedge rst_n)
- if (rst_n == 1'b0)
- k2 <= 1'b0;
- else if (state == STOP && A == 1'b1)
- k2 <= 1'b1;
- else if (state == CLEAR && A == 1'b0)
- k2 <= 1'b0;
-
- endmodule
tb_ex_fsm.v 激励模块
- `timescale 1ns/1ns
- module tb_ex_fsm;
-
- reg sclk_r;
- reg rst_n_r;
- reg in_A;
- wire k1;
- wire k2;
-
- initial
- begin
- rst_n_r <= 1'b0;
- sclk_r <= 1'b0;
- #50
- rst_n_r <= 1'b1;
- end
-
- initial
- begin
- in_A <= 1'b0;
- #60
- send_A();
- end
-
- always #10 sclk_r <= ~sclk_r;
-
- ex_fsm ex_fsm_inst(
- .sclk (sclk_r),
- .rst_n (rst_n_r),
- .A (in_A),
- .k1 (k1),
- .k2 (k2)
- );
-
- task send_A();
- integer i;
- begin
- for (i=0; i< 512; i=i+1)
- begin
- @(posedge sclk_r)
- if (i<40)
- in_A <= 1'b0;
- else if (i<80)
- in_A <= 1'b1;
- else if (i<120)
- in_A <= 1'b0;
- else if (i<160)
- in_A <= 1'b1;
- else if (i<200)
- in_A <= 1'b1;
- end
- end
- endtask
-
- endmodule
如果每次用modelsim都手动添加仿真很麻烦,可以写一个run.do的自动仿真脚本
文件run.do 脚本
- #退出当前的仿真工程
- quit -sim
- #清空命令行
- .main clear
- #创建库
- vlib work
- #将逻辑库的名字映射到实际物理路径上来
- vmap work ./work
- #编译代码文件到逻辑库work中
- vlog -work work ./tb_ex_fsm.v
- vlog -work work ./../design/*.v
- #启动仿真
- vsim -voptargs=+acc work.tb_ex_fsm
- #添加波形
- #定义宏
- virtual type {
- {01 IDLE}
- {02 START}
- {04 STOP}
- {08 CLEAR}
- } vir_new_signal
- add wave tb_ex_fsm/*
- virtual function {(vir_new_signal)tb_ex_fsm/ex_fsm_inst/state} new_state
- add wave -color yellow tb_ex_fsm/ex_fsm_inst/new_state
- run 100us
目录结构

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