Verilog永无止境

Verilog语法简介

@author: 紫金港小李

@mail: [email protected]

一、门级建模

1.基本定义

(1)模块定义

模块定义以关键字module开始,以关键字endmodule结束。基本语法结构如下:

module 模块名 (端口名1,端口名2,...);
...
endmodule

(2)端口声明

模块定义中的端口列表中仅仅列出了本模块具有哪些端口,但是并不标明输入or输出。这就需要在模块中进行声明:

output Y;
input A,B,C,D;

顾名思义,端口声明就是声明端口的类型,宽度等信息。类型有三种.

Verilog HDL 关键字 端口类型
input 输入端口
output 输出端口
inout 双向端口

Tips:
也可以端口声明放入模块定义中,举个栗子:

module top_module (
    input in,
    output out);
    ...
endmodule

(3)门级调用

端口声明后的部分就是门级调用,语法格式

逻辑门类型 <实例名称(可选)> (端口连接)

实例名称部分在门级建模一般不适用。逻辑门类型指的是常用的基本逻辑门,例如

not (S1n,S1);
not (En_n,En);
and (and1,En_n,S1n,S0n,A);
or (Y,and1,and2,and3);
门的名称 门的功能
buf 缓冲器
not 非门
and 与门
nand 与非门
or 或门
nor 或非门
xor 异或门
xnor 同或门

(4)模块实例化

把当前模块(module)中调用其他模块来完成设计的过程称之为模块的实例化。语法结构如下:

模块名称 实例名称 (端口连接);
  • 模块名称即已经定义好的其他模块的模块名
  • 实例名称时在本模块内定义的新名称
  • 端口连接是在当前模块中把实例化的模块所包含的端口进行连接,有两种连接方式
    • 按顺序连接
    • 按名称连接

下面是一个以16位全加器通过实例化得到32位全加器的例子:

module fadd32b(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cout,x;
    //add16,16 bits full adder
    add16 inst1 (a[15:0],b[15:0],1'b0,sum[15:0],cout);
    add16 inst2 (a[31:16],b[31:16],cout,sum[31:16],x);
endmodule

二、数据流级建模

1. assign(类似于赋值语句)

(1) 最简单的例子莫过于导线了~~

Exams m2014q4h.png

assign 线网信号名 = 运算表达式
module top_module (
    input in,
    output out);
	assign out = in;//这里是连续赋值,意即在仿真结束前,out恒等于in
endmodule

(2) 与或非门

Verilog 有两种非,一种是bitwise-NOT (~),另一种是logical-NOT (!) , like C. 对于一位的运算,这两种并无区别。

module Inverter(
    input in,
    output out
);

    assign out = ~in;//inverter gate

endmodule

Verilog有两种与,bitwise-AND (&) and logical-AND (&&) operators, like C. 对于一位的运算,这两种并无区别。

module AND( 
    input a, 
    input b, 
    output out );
    assign out = a&b;//and gate
endmodule

同样,bitwise-OR (|) and logical-OR (||) operators, like C.

module OR( 
    input a, 
    input b, 
    output out );
    assign out = a|b;//or gate
endmodule

2. 操作数

  • 操作数有很多数据类型,如parameter,wire等19种,这里介绍常用的4种。
数据类型 功能
parameter 用于参数的描述
wire型 用于描述线网
reg型 用于描述寄存器
integer型 用于描述整数类型

(1)数字

在操作数中首先要介绍的是数字,数字的基本表示格式如下:

<位宽>'<进制><数值>

在这个格式中,数值是唯一不可缺少的。

  • Verilog支持四种进制形式,二进制,八进制,十进制和十六进制,分别用B,O,D,H表示(不区分大小写)。
  • 位宽表示一个数字到底包含几位信息,指明了数字的精确位数,这个位数是以它华为二进制数之后所具有的宽度来表示的。

还是一样的,举一个栗子。

2'b01	//二进制,相当于十进制:1
4'd11	
6'o37	//八进制,相当于十进制:3*8+7=31
8'hab
  • 位宽缺少或者进制缺少
'o37	//位宽采用默认宽度(一般32位),相当于00000000000000000000000000011111
37		//相当于十进制的37

(2)参数

有时候某些数字或字符需要多次使用,Verilog中可用关键字parameter来定义一个参数,用于指代某个常用的数值、字符串或表达式。

parameter 参数1 = 表达式1,参数2 = 表达式2

在语法结构中,parameter是关键字,后面的参数名是设计者自己定义的一个标识符。

parameter size = 8;
parameter a=4,b=16;
parameter width = size-1;
parameter clock = a+b;

(3)线网

线网类型采用关键字wire来定义,用于描述模块中可能是连线的情况。其语法如下

wire [宽度申明] 线网名1,线网名2

Example:

wire x;
wire [3:0] y;
wire [7:1] m,n;

(4)寄存器

在数字电路中有一类器件可以存储数据值,在Verilog中定义为reg类型

reg x;
reg [3:0] y;
reg [7:1] m,n;

除了表示一位或多位的寄存器,reg还可以用来定义存储器,语法如下:

reg [n-1:0] 存储器名称 [0:m-1];
reg [7:0] mema [0:255];	//这里定义了一个宽度为8位的存储器,共有256个存储单元
		//每个单元用0~255的数字进行编号
mema[1] 就是指第一个的8位储存单元。

进行初始化时,初始化的过程中要对每个存储器单元进行初始化赋值,而不能采用整个存储器直接赋值的方法.

reg memb [0:255];
memb = 0;(错误)
memb[100] = 0;(正确)

整数是一种特殊的数据类型,使用关键字integer进行申明。

integer i;
i=-1;

做个题目放松放松?Wiredecl2.png

`default_nettype none//这句的意思是,不允许未定义的变量参与运算,这与C语言类似,必须要先定义变量
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out,
    output out_n   ); 

    wire and_1,and_2,or_1;//define three wire
    
    assign and_1 = a&b;
    assign and_2 = c&d;
    assign or_1 = and_1|and_2;

    assign out = or_1;
    assign out_n = ~or_1;
endmodule

3. 操作符

操作类型 操作符 执行的操作 操作数的个数
算术 *
/
+
-
%
**




取余
求幂
2
按位 ~
&
|
^
^~
按位求反
按位与
按位或
按位异或
按位同或
1
2
2
2
2
逻辑
&&
||
逻辑求反
逻辑与
逻辑或
1
2
2
关系 >
<
>=
<=
大于
小于
大于等于
小于等于
2
等式 ==
!=
===
!==
相等
不等
相等
不等
2
移位 >>
<<
>>>
<<<
右移
左移
算术右移
算术左移
2
拼接 { } 拼接 任意个数
缩减 &
~&
|
|~
^
^~
缩减与
缩减与非
缩减或
缩减或非
缩减异或
缩减同或
1
条件 ? : 条件 3

(1) 详解拼接

拼接操作符可以完成几个信号的拼接,用大括号{}表示。使用如下:

reg [3:0] a,b,c;
a=4'b0000;
b=4'b1111;
c=4'b0101;
x1={a,b,c};					//0000_1111_0101
x2={a[3],b,c};				//0_1111_0101
x3={a[2:0],b[0],c};			//000_1_0101
x4={a[0],b[0],c[0],2'b00};	//01100	

拼接符不仅可以处理上述问题,还可以重复某个信号 assign a = {b,b,b,b,b,b};. 为了简化表达,语法如下:

{num{vector}}

Examples:

   {
   
   5{
   
   1'b1}}           // 5'b11111 (or 5'd31 or 5'h1f)
   {
   
   2{a,b,c}}          // The same as {a,b,c,a,b,c}
   {
   
   3'd5, {2{3'd6}}}   // 9'b101_110_110. It's a concatenation of 101 with
                       // the second vector, which is two copies of 3'b110.

4. Vector (可以理解成数组)

  • Declaring Vectors(定义)

Vectors must be declared:

   type [upper:lower] vector_name;
   //for example:
   wire [7:0] w;         // 8-bit wire
   reg  [4:1] x;         // 4-bit reg(register:寄存器变量)
   output reg [0:0] y;   // 1-bit reg that is also an output port (this is still a vector)
   input wire [3:-2] z;  // 6-bit wire input (negative ranges are allowed)
   output [3:0] a;       // 4-bit output wire. Type is 'wire' unless specified otherwise.
   wire [0:7] b;         // 8-bit wire where b[0] is the most-significant bit.
  • Implicit nets(如果变量未定义即出现,可能出bug)

   wire [2:0] a, c;    // Two vectors 
   assign a = 3'b101;  // a = 101 
   assign b = a;       // b =   1  implicitly-created wire
   assign c = b;       // c = 001  <-- bug 
   my_module i1 (d,e); // d and e are implicitly one-bit wide if not declared.                    			  // This could be a bug if the port was intended to be a vector. 

Adding ``default_nettype none` would make the second line of code an error, which makes the bug more visible.(建议加上这条语句,使得直接报ERROR便于查找错误)

  • Accessing Vector Elements: Part-Select(数组寻址?)

   assign w = a;//a:4-bits,w:8-bits.
   //the lower 4 bits in w is a ,while the higher 4 bits in zero.
   //w的低位是a,高位为0.

takes the entire 4-bit vector a and assigns it to the entire 8-bit vector w (declarations are taken from above). If the lengths of the right and left sides don’t match, it is zero-extended or truncated as appropriate.

  The part-select operator can be used to access a portion of a vector:
   
   w[3:0]      // Only the lower 4 bits of w
   x[1]        // The lowest bit of x
   x[1:1]      // ...also the lowest bit of x
   z[-1:-2]    // Two lowest bits of z,like python
   b[3:0]      // Illegal. Vector part-select must match the direction of the declaration.
   b[0:3]      // The *upper* 4 bits of b.
   assign w[3:0] = b[0:3];    // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.

在学了,在学了。
萌

猜你喜欢

转载自blog.csdn.net/zjg_lizheng/article/details/109758521