Verilog语法总结

本文介绍了Verilog语言中的核心概念,包括整数数据类型(integer)的使用,四值逻辑(0、1、x、z)的意义,以及函数(function)和任务(task)的定义和区别。此外,还讲解了编译指令如`timescale`、`define`、`include`和`ifdef`的用法,以及系统任务`$display`、`$stop`和`$finish`在仿真控制中的作用。
摘要由CSDN通过智能技术生成

1、整数 integer

  • 整数(正数 0 负数)是一种通用的寄存器数据类型,用于对数量进行操作,整数的默认位宽为宿主机的字的位数,与具体实现有关,最小为32位。

  • reg和integer:reg的寄存器类型变量为无符号数
           integer的寄存器类型变量为有符号数

  • 举例

     integer counter; //作为计数器定义
       counter = -1;  //将-1存储到计数器中
    //说明:counter[8] 和 counter[16:2]是非法的
    

2、verilog的四值逻辑(0、1、x、z)

值的级别硬件电路中的条件
0逻辑0,条件为假
1逻辑1,条件为真
x逻辑值不确定
z高阻,浮动状态

3、task和function的区别

函数任务
函数能调用另一个函数,不能调用另一个任务任务能调用另一个任务,也能调用另一个函数
函数在仿真0时刻就开始执行任务可以在非0时刻执行
函数一定不能包含任何延迟、事件或者控制声明语句任务可以包含任何延迟、事件或者控制声明语句
函数至少有一个输入变量,可以有多个输入变量任务可以没有输入变量;或者有多个输入、输出、双向变量
函数只能返回一个值,函数不能有(output)和(inout)变量任务不返回任何值,通过输出变量(output)和(inout)传递多个值

4、函数:关键字 function-----endfunction

使用函数的前提条件:

  • 子程序内不含有延迟、时序或者控制结构
  • 子程序只有一个返回值
  • 至少有一个输入变量
  • 没有输出或者双向变量
  • 不含有非阻塞赋值语句

注意:

  • 函数中不能调用任务
  • 函数中可以调用其他函数

说明:关于函数function—endfunction有两种编码风格

基础语法:

function [返回值类型/位宽范围] [函数名称] ([参数1],[参数2]);  
 

endfunction 

//[函数名称]在verilog内部被隐含地声明为一个寄存器类型变量
//如果没有指定[返回值类型/位宽范围],则默认位宽为1

编码风格1:

module fun (
    input  integer data_in,
    output [8:0]   data_out
);

//定义一个计算二进制位宽的函数---可以用来计算模块中地址总线的宽度  
function [8:0] clogb2;     
   input    bit_depth ; 
   integer  bit_depth ;         
  begin                                                           
    for(clogb2 = 0; bit_depth > 0; clogb2 = clogb2 + 1)                   
	    bit_depth = bit_depth >> 1;                                 
   end                                                           
endfunction 

  assign data_out = clogb2(data_in);  //函数的调用:指明函数名clogb2()和输入变量 i_in

endmodule

编码风格2:

module fun (
    input  integer data_in,
    output [8:0]   data_out
);

//定义一个计算二进制位宽的函数---可以用来计算模块中地址总线的宽度  
function [8:0] clogb2(input integer bit_depth);            
  begin                                                           
    for(clogb2 = 0; bit_depth > 0; clogb2 = clogb2 + 1)                   
	     bit_depth = bit_depth >> 1;                                 
    end                                                           
endfunction 

  assign data_out = clogb2(data_in);  //函数的调用:指明函数名clogb2()和输入变量 i_in

endmodule

5、任务:关键字 task-----endtask

如果子程序满足下面任意一个条件,则必须使用任务而不是函数:

  • 子程序中包含有延迟、时序或者事件控制结构
  • 没有输出或者输出变量的数目大于1
  • 没有输入变量

注意:

  • 任务可以调用另一个任务,也可以调用另一个函数

基础语法:

task  [函数名称] ([参数1],[参数2]);  
 

endtask 

举例: 以仿真apb slave总线上的外设为例

`timescale 1ns / 1ps 
module apb_master_tb;
  reg pclk;
  reg presetn;
  reg psel;
  reg penable;
  reg pwrite;
  reg  [31:0] paddr;
  reg  [31:0] pwdata;
  reg  [3:0]  pstrb = 4'b1111;
  wire [31:0] prdata;
  wire pready;
 
// 时钟生成
always #50 pclk = ~pclk;

reg [31:0] rdata;
initial begin
  pclk = 0;
  presetn = 0;
  #100;
  presetn = 1;

  #500;
  apb_write(32'h0,32'h45af);
  apb_write(32'h4,32'h45af);
  apb_write(32'h8,32'h45af);
  apb_write(32'hc,32'h45af);

  #600;
  apb_read(32'h0,rdata);
  apb_read(32'h4,rdata);
  apb_read(32'h8,rdata);
  apb_read(32'hc,rdata);

  #10000;
  $finish;
end

// APB write
task apb_write(input [31:0] addr,input [31:0] data); begin
  @(posedge pclk) begin
    paddr   <= addr;  // 设置地址
    pwdata  <= data;  // 设置写数据
    pwrite  <= 1;     // 设置为写操作
    psel    <= 1;     // 选中设备
    penable <= 0;     // 使能信号
  end
  @(posedge pclk) begin
    pwrite  <= 1;     // 设置为写操作
    psel    <= 1;     // 选中设备
    penable <= 1;     // 使能信号
  end
  @(posedge pclk) begin
    pwrite  <= 1;     // 设置为写操作
    psel    <= 0;     // 结束
    penable <= 1;     // 使能信号
  end
end
endtask 

// APB read
task apb_read(input [31:0] addr,output [31:0] data); begin
  @(posedge pclk) begin  
    paddr   <= addr;     // 设置地址
    pwrite  <= 0;        // 设置为读操作
    psel    <= 1;        // 选中设备
    penable <= 0;        // 使能信号
  end
  @(posedge pclk) begin
    pwrite  <= 0;       // 设置为读操作
    psel    <= 1;       // 选中设备
    penable <= 1;       // 发起读操作 
    data <= prdata;     // 设置读数据
  end
  @(posedge pclk) begin
    pwrite  <= 0;       // 设置为读操作
    psel    <= 0;       // 结束
    penable <= 1;       // 发起读操作 
  end
end
endtask

// APB 设备例化
apb_slave u_apb_slave (
  .pclk    (pclk),
  .presetn (presetn),
  .psel    (psel),
  .paddr   (paddr),
  .penable (penable),
  .pstrb   (pstrb),
  .pwrite  (pwrite),
  .pwdata  (pwdata),
  
  .pready  (pready),
  .prdata  (prdata)
);

endmodule

6、编译指令–形式:`keyword

(1) `timescale

用法: `timescale <reference_time_unit>/<time_precision>

说明: <reference_time_unit> (参考时间单位):指定时间和延迟的测量单位。
   <time_precision>(时间精度):指定仿真过程中延迟值进位取整的精度。
   只有1,10,100才是合法的说明时间单位和时间精度的整数。

举例
`timescale 1ns / 1ps
#10      表示延迟10ns
#6.231678   因为精度为1ps,在6.232时赋值语句生效

(2) `define

说明: 定义Verilog中的文本宏,类似C语言中的#define

举例:

a. 规定子长的文本宏: `define WORD_SIZE 32            //代码中用`WORD_SIZE表示
b. 定义别名:        `define S $stop                 //代码中用`S来代替$stop
c.定义字符串:       `define WORD_REG reg [31:0]     //用`WORD_REG reg 32来定义一个32位的寄存器变量

(3) `include

说明: 可以在编译期间将一个Verilog源文件包含在另一个Verilog文件中,作用类似于C语言中的#include结构

举例
可以提前将VGA数据,比如颜色的数据存放在一个源文件中(起名为VGA_Para.v或者VGA_Para.h)在VGA的driver和display模块可以直接调用这个文件VGA_Para.v

`include "VGA_Para.v"	

module VGA_Dispaly(
  input port1,
  
  output port2
    );

endmodule

(4) `ifdef–条件编译

说明: 条件编译指令可以根据指定条件来生成对应的电路,可以减少电路面积并提高代码的复用性。

用法: 在Verilog文件中,条件编译标志可以用`define语句设置。

举例一:有条件的编译模块

`ifdef XOR            //若设置NOR标志,则编译design_xor模块  
module design_xor;
······
endmodule  
`elsif AND           //若设置AND标志,则编译design_and模块
module design_and;
······
endmodule 	
`else                //默认执行design_or模块
module design_or;
······
endmodule 		
`endif
 

举例二:有条件的编译语句

`define	XOR			    //执行该语句
//`define	AND			 
//`define	OR  
 
module test(
	input		i_data_a,
	input		i_data_b,
	output	o_data_result	
);
 
`ifdef XOR
	assign o_data_result = i_data_a ^ i_data_b;	
`elsif AND
	assign o_data_result = i_data_a & i_data_b;	
`else 
	assign o_data_result = i_data_a | i_data_b;		
`endif
 
endmodule

举例三:`ifndef的用法

它的作用和`ifdef 是相反的----当其后的标识符未被定义时,则编译后续的代码段

//`define	XOR       //注释掉,相当于标识符未被定义
 
module test(
	input		i_data_a,
	input		i_data_b,
	output	o_data_result	
);
 
`ifndef XOR                                       
	assign o_data_result = i_data_a ^ i_data_b;	   //XOR未被定义,执行该语句
`else 
	assign o_data_result = i_data_a | i_data_b;		
`endif
 
endmodule

7、系统任务–形式:$keyword

(1) $display

用法: $display(P1,P2,P3,…,Pn);

说明: P1,P2,P3,…,Pn是双引号括起来的 字符串变量或者表达式;同时$display会自动在字符串的结尾处插入一个换行符。

举例:

$display("Hello Verilog"); //显示小括号中的字符串

$display($time); //显示当前仿真时间

reg[0:40] virtual_addr;//在时间为200的时刻,显示41位虚拟地址1fe0000001c
$display("At time %d virtual address is %h", $time, virtual_addr);
---显示为:At time 200 virtual address is 1fe0000001c

$display("ID of the port is %d", port_id); //二进制数显示port_id 5
---显示为:ID of the port is 00101

字符串格式说明:

格式显示
%d或%D用十进制显示变量
%b或%B用二进制显示变量
%s或%S显示字符串
%h或%H用十六进制显示变量
%c或%C显示ASCII字符
%m或%M显示层次名
%v或%V显示强度
%o或%O用八进制显示变量
%t或%T显示当前时间格式
%e或%E用科学计数法格式显示实数(如3e10)
%f或%F用十进制浮点数格式显示实数
%g或%G用科学计数法或十进制格式显示实数,显示较短的格式

(2) $stop

用法: $stop;

说明:$stop 暂停仿真,使仿真进入一种交互模式,设计者可以在此模式下对设计进行调试

(3) $finish

用法: $finish;

说明:$finish 结束仿真

(4) $random

随机数生成,满足随机测试向量集的需求

举例

$random;      //返回一个32位带符号的随机整数,每次仿真。随机序列相同
$random(seed);//seed是一个整数,可指定随机数的取值范围。
               //seed可以是reg、integer、time变量
               //seed-种子,这一参数由仿真时间决定;seed参数不变,既同一时刻都在调用相同的seed,所以生成的随机序列是相同的。

$random % b;  //得到(-b+1)~(b-1)范围内的随机数
$random % 60; //得到 -59 ~ 59范围内的随机数

{$random} % b;  //得到 0 ~(b-1)范围内的随机数
{$random} % 60; //得到 0 ~ 59范围内的随机数

8、generate-----endgenerate

可综合的语法,有助于设计通用性强的逻辑电路,综合工具在对代码进行编译时,会将电路展开生成完整的设计代码,然后进行电路综合

举例一:模块设计

//Gray2Bin 格雷码转二进制(8bit)
generate
   genvar i; //声明一个正整数变量

   for(i=0;i<8;i=i+1) begin :gen_binary

      assign binary_value[i] = binary_value[i+1] ^ gray_value[i];

   end
endgenerate

举例二:多次例化

//Gray2Bin 格雷码转二进制(8bit)
generate
   genvar i; //声明一个正整数变量

   for(i=0;i<3;i=i+1) begin :port_inst
       
       port u_port(
          .port1    (in[i]),
          .port2    (in[i]),
          .port3    (in[i]),

          .port4    (out[i]),
       );
     
   end
endgenerate

该博客为博主记录学习所用,如有错误,请评判指正。博客内容大多来自《Verilog HDL数字设计与综合(第二版)》 -夏宇闻译

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值