Verilog 学习笔记

目录

数据类型:

1.wire类型

2.reg类型 、integer整数、real实数 

3.向量(数组)

4.parameter 参数

赋值语句:

1.过程赋值 

2.连续赋值

常用语句

1.if 语句

2.case 语句

testbench仿真模块

1.注意事项

2.代码示例


数据类型:

1.wire类型

用于表示硬件电路单元之间的物理连线。未声明信号类型默认为wire类型wire不允许在always块内部赋值, 但可以在always块中被用作非阻塞赋值(<=)的一个源。可对wire类型在always块外部用assign连续赋值。

module d_flip_flop(      //以D触发器为例:输出信号有reg,wire两种类型,以说明其赋值操作区别
    input wire clk,      //时钟
    input wire rst_n,    //复位低有效
    input wire D,        //输入
    output reg Q         //reg 类型输出
    output wire Q_n      //wire类型输出
);
reg Q_n_reg = 1'd0;      //定义内部变量

always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
      Q <= 1'd1 ;        //复位
      Q_n_reg <= 1'd0 ;
   end 
   else begin
      Q       <=  D ;    //wire类型可作为源进行非阻塞赋值
      Q_n_reg <= !D ;
   end
   end
   
assign Q_n = Q_n_reg;    //对wire类型的赋值需在外部进行
endmodule

2.reg类型 、integer整数、real实数

verilog中数字表达形式为:(位宽)'(进制)(数值) 。其中,进制b、o、d、h分别为二、八、十、十六进制。比如:2'b10表示2位二进制数10,即十进制2。4'hA表示4位十六进制数A,即十进制10。

(注意:位宽为二进制的位宽,比如1'd2就是错误表达因为二进制2至少两位)

module xxx(   
    input reg a,b, 
    input reg c
); 
reg      d = 4'b0001 ; 
real     e = 3.14    ; 
interger f = 3e2     ;//即3*10^2=300 
......

3.向量(数组)

module xxx(
    input wire [7:0]  a,      //8位宽的输入
    output reg [15:0] b,      //16位宽的输出
    output reg [7:0]  c       //8位宽的输出
);
reg [7:0] d[3:0]   //4个8位的向量

//向量的拼接
always @* begin
    b = {a, a};    //将a重复拼接组成16位的向量b
end

//向量的按位截取
always @* begin
    c = b[15:8];  //截取b的高8位输出
end
endmodule

4.parameter 参数

用于声明设计参数,是一个常量,不支持小数

parameter time_count = 26'd24_999_999;
parameter width = 8;

当代码多次使用同一个参数时(比如计时器的计数上限值),一个个修改起来较为麻烦,可以通过定义为 parameter 参数,需要修改直接在定义位置修改

还可在例化模块时用 defparam 进行参数设置,例如例化同一模块使用不同的参数:

timer timer_l(          
  .clk    (clk),
  .rst_n  (rst_n),
  .flag   (flag)
)
defparam timer_l.time_count = 26'd24_999_999;

timer timer_2(
  .clk    (clk),
  .rst_n  (rst_n),
  .flag   (flag)
)
defparam timer_2.time_count = 25'd24_999_99;

此外还有另外一种例化参数的方法:

timer
#(
	.count(24_999_99)
)
	timer_1(
		.clk   (clk),
		.rst_n (rst_n),
		.flag  (flag)
);	

赋值语句:

左侧必须是变量数据类型,可以是reg、integer或real。右侧可以是任何有效的表达式或信号。

1.过程赋值 

=  阻塞赋值   (前面的赋值语句阻塞后面的,即按顺序执行,a值给b后,b值再给c)

always @(posedge clk) begin
	b = a;
	c = b;
end

<=  非阻塞赋值   (不会阻塞,即同时执行)

always @(posedge clk)begin
	b <= a;
	c <= b;
end

2.连续赋值

用于表示组合逻辑,左侧必须是wire或tri。始终处于活动状态即右侧一变化即会使左侧值被更新

assign  a = b&c;

常用语句

1.if 语句

当 if/ else if/ else 满足条件时只执行一条语句时,可以省略begin end.

当执行多条语句时,用begin end括起来,例如:if(条件1) begin   执行1;执行2; 执行3;end

if     (条件1)    执行1;
else if(条件2)    执行2;
else if(条件3)    执行3;
else             执行4;

2.case 语句

用一个四选一数据选择器为例,当sel信号分别为0123时对应输出abcd。

满足当前情况只执行一条语句时,可以省略begin end,当执行多条语句时,用begin end括起来

两种情况执行内容一样时可以用逗号省略,例如:2'd0 ,2'd1 : dout = a;

case(sel)
    2'd0 : dout = a;
    2'd1 : dout = b;
    2'd2 : dout = c;
    2'd3 : dout = d;
    default : ;        //其他情况,即使条件列完也需要写default: ;(相当于什么都不执行)
endcase

testbench仿真模块

1.注意事项

(1)`timescale 接时间单位/精度,#10即表示延时10个时间单位

(2)仿真模块一般没有端口列表(input/output),因为通常输入信号为自定义为reg类型,而输           出则定义为wire类型

(3)模块例化:仿真模块相当于顶层文件,将待仿真模块例化后再进行验证,例化名可自定义。

(4)若使用linux操作系统,跑仿真需要生成fsdb波形文件,需在代码内直接加入以下代码:

initial begin
    $fsdbDumpfile("test.fsdb");
    $fsdbDumpvars;
    $fsdbDumpMDA;
end 

2.代码示例

    以验证D触发器功能为例编写一段tb文件代码(dff_tb.v)

`timescale 1ns / 1ps           //timescale 时间单位/精度
module dff_tb( );              //仿真一般无端口列表
reg  clk_sim;
reg  d_sim;
wire q_sim;
wire q_n_sim;
 
always #10 clk_sim = ~clk_sim; //每10个时间单位对clk进行翻转,即周期为20个单位
initial begin
    clk_sim = 0;
    d_sim   = 0;
    #20;                       //延时20个时间单位(20ns)
    d_sim = 1;
    #40;
    d_sim = 0;
    #100;
    $stop;                     //停止仿真 也可以写$finish;
end 
 
dff dff_1(                     //模块例化:  原模块名----在顶层文件中命名为
   .clk (clk_sim),             //原模块端口名----要连接的端口名
   .d   (d_sim),
   .q   (q_sim),
   .q_n (q_n_sim)
);
endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值