VerlogHDL语言
模组
- 针对阶层化的设计观念,在 Verilog 中提供一种模组 ( module ) 的架构。
- 模组中可以取用其他模组的别名,本身也可以被其他的模组所取用,所以可以先写基本元件线路的模组,在经由取用得到较大的模组,此符合由下到上的方法。
- 模组在取用时,所看到的只是其输出与输入的值,与内部的描述层次无关,可以先以行为层次来描述基本元件,并先取用,此符合上到下的设计方法。
- 在 Verilog 中模组的宣告是用关键字 module 和 endmodule。在 module 後需加一个用以识别的模组名称 ( module_name ),然後是宣告一个模组的输入与输出的埠列 ( module_terminal_list ),在模组的最後要加上 endmodule 。其架构如下所示:
-
module <module_name> (<module_terminal_list>);
...
<module internals>
...
...
endmodule
学习目标:
* 了解空白(Whitespace) ,
注解(Comments),
运算子(Operators),
数字(Number),
字串(Strings),
定义名称(Idntifers),
语法协定(Lexical Conventions)。
* 定义数值组(Value
Set),
接线(Nets),
暂存器(Registers),
向量(Vectors),
时间,
阵列(Arrays),
记忆体 (Memories)
参数(Parameters),
字串(Strings)的资料型态(Data Types)。
* 说明有用的系统任务(system tasks):
资讯显示(Displaying information),
资讯监视(Monitoring information),
中止 (Stopping)
完成(finishing)模拟。
* 说明简单的组译指令(Compiler Directives)。
3.1 语法协定(Lexical Conventions)
Verilog 的语法协定与 C 语言是非常类似的。
3.1.1 空白(Whitespace)
空白包含有: 空格 (blank spaces, \b),栏位 (tabs, \t),和换行(newlines, \n) ,除了分隔标记的空白和字串中的空白外,皆忽略。
3.1.2 注解(Comments)
注解是为了使程式易读
(readability)或文件化 (documentation)。
a=b && c; //这是一单行注解 /* 这是一 多行注解 */ /* 这是一 /*非法 */ 注解 */ |
3.1.3 运算子(Operators)
运算元有叁种形式:一元 (unary),二元(binary),和叁元 (ternary)。
a=~b; // ~ 是一元运算子. b是运算元 a=b && c; // && 是二元运算子. b和c是运算元 a=b ? c : d; // ?: 是叁元运算子. b,c和d是运算元 |
3.1.4 数字规格(Number Specification)
Verilog 有规定长度 (sized),不定长度 (unsized)二种数字规格.
规定长度之数字(Sized numbers)
规定长度之数字以 <size>'<base format><number>来表示.
<size>是以十进位来表示数字的位数(bits),<base format>是用以定义此数为十进位('d或'D),十六进位('h或'H),二进位('b或'B),八进位('o或'O)。
8'b11111111 // 这是一 8-bit 二进位数 16'habcd // 这是一 16-bit 十六进位数 16'd255 // 这是一 16-bit 十进位数 |
不规定长度之数字(Unsized numbers)
* 不规定长度之数字不使用<size>去规定数字之位元数大小,而是使用模拟器或硬体内定规格(必须大於32位元)。
* 若无<base format> 则定义为十进制。
2345 // 定义为 32 bits 十进位数 'hc3e // 32 bits 十六进位数 'o2 // 32 bits 八进位数 |
x或z值
x 是代表不确定的值,z 是代表高阻抗。
12'h1xx // 这是一 12-bit 十六进位数 ;最小8位元为不确定之值 6'hx // 这是一 6-bit 十六进位数 32'bz // 这是一 32-bit 高阻抗 |
负数(Negative numbers)
将负号放在<size>之前即代表该数之负数。
-8'd3 //用 8-bit二补数表示负叁 4'd-2 // 不正确的表示法 |
底线(Underscore characters)和问号(Question marks)
* 底线 "_"的功用在於增加可读性,并无特别的功用与功能。
* 但是需要注意的是,第一个字元不能使用底线。
* 问号 "?"是与 "z"是同义的,其目的是增加可读性。
12'b1111_0000_1010 // 与12'b111100001010同 4'b10?? // 与4'b10zz同 |
3.1.5 字串(Strings)
字串之所有字元必须在同一行上。
"Hello Verilog World" //是一个字串 "a/b" //是一个字串 |
3.1.6 定义名称(Identifers)与关键字(Keywords)
* 关键字是一组特殊的定义名称,其功用是为了定义程式语言架构。
* 定义名称是在程式语言中所给予物件的名称。
* 定义名称可由字母,数字,底线和钱号($)所组成。
* 定义名称的大小写是有分别的,且不能以钱号做开头。
wire value; // wire 是关键字 value是定义名称 output out; // output 是关键字 out是定义名称 |
3.2 数据型态(Data Types)
3.2.1 数值组(Value Set)
Verilog提供四种数值和八种强度(Strengths)。四种数值位准(value level)如下:
数值位准为0、1有八种强度如下:
* 其目的是为了解决在实际逻辑电路中,二个不同强度的驱动信号(driver)冲突(conflicts) 的问题。
* 如果strong1 和 weak0接在同一条线上,结果会是 strong1。
3.2.2 接点(Nets)
接点是连接硬体元件之点。在Fig3.1 接点 a是及闸gate1的输出,其值为接点b AND 接点c 的结果。
fig3.1
接点之最主要的关键字为wire。
wire a; //宣告上面电路中一个接线a wire b,c; //宣告上面电路中接线b,c wire d = 1'b0; //在宣告时设定接线d为一固定值0 |
3.2.3 暂存器(Registers)
在Verilog 中暂存器的功用与变数非常相近,可以直接给一个数值,不用像节点一样需要驱动才能改变数值。暂存器的关键字是 reg,内定值是 x。
reg reset; //宣告一个变数来持留(hold)数值 initial // 这一个架构将於後面章节讨论 begin reset = 1'b1; //设定reset之初始值为1来重设电路 #100 reset = 1'b0; // 在 100个模拟时间後,设定reset为0 end |
3.2.4 向量(Vectors)
节点和暂存器皆可定义为向量,若无定义位元长度,则以一个位元(纯量)计。
wire a; //定义为纯量接线变数 wire [7:0] bus; // 8-bit 汇流排 wire [31:0] busA,busB,busC; //3 个 32-bit 宽度的汇流排 reg clock; //定义为纯量暂存器变数 reg [0:40] virtual_addr; //向量暂存器变数, 41 bits宽度虚位址 |
向量可定义为[high#:low#] or [low#:high#],但是中括号左边者为最大位元。
busA[7] // 汇流排A之第七个位元 bus[2:0] // 汇流排之最末叁个位元,若使用bus[0:2]为非法的 virtual_addr[0:1] //虚位址之最高叁个位元 |
3.2.5 整数、实数、和时间暂存资料型态 (Integer、Real、and Time Register Data Types)
整数
整数是以关键字 integer做宣告,虽然我们可以用 reg来做一般变数的宣告,但是一些整数变数以 integer做宣告是较便利的,如计数(counting)。
integer counter; //一般用途的变数 initial counter = -2; //将负2存在 counter中 |
实数
实数是以关键字real做宣告。
real delta; //宣告一实数变数 delta inital begin delta = 4e10; //delta 被指定一科学表示式 delta = 2.13; //delta 被指定一数值 2.13 end integer i; //宣告一整数变数 i initial i = delat; //i 的数值为 2 (rounded value of 2.13) |
时间
时间是以关键字time做宣告,其功用是储存模拟时间(simulation time),最少要为64bits的资料。
time save_sim_time; //定义时间变数 save_sim_time initial save_sim_time = $time; //储存目前模拟时间 |
3.2.6 阵列(Arrays)
阵列之内容可以是整数、暂存资料、时间、和向量,但不能为实数。其表示法为<array_name>[<subscript>] ,且不能为多维阵列。
integer count[0:7]; // 8个 count 变数的阵列 reg bool[31:0]; // 32 个一位元布林暂存器变数的阵列 time chk_point[1:100]; //100 个时间核对点(checkpoint)变数的阵列 reg [4:0] port_id[0:7];// 8个 port_id的阵列;每一个 port_id 是 5 位元宽度 integer matrix[4:0][4:0];// 多维阵列为非法宣告 count[5]// count 变数的第五个元件 |
向量与阵列是不相同的,向量是一个多位元的元件(element),阵列是多个1bit或若干bits的元件。
3.2.7 记忆体(Memories)
在Verilog 中,记忆体像是一个暂存器的阵列,在阵列中的每一个物件,就像是个字元(word),每个字元可以是一个 bit或多个bits。
reg mem1bit[0:1023]; //记忆体 mem1bit 是 1k 个 一位元的字 reg [7:0] membyte[0:1023]; //记忆体 membyte 是 1k 个 八位元的字 membyte[511]// 提取位址为511的一位元组的字 |
3.2.8 参数(Parameters)
在模组中我们可以用关键字 parameter 定义一个固定常数(参数),这一个参数在每一次的编译时可以更改。
parameter port_id = 5; //宣告一常数 port_id parameter cache_line_width = 256; //定义一常数快取线的宽度(width of cache line) |
3.2.9 字串(Strings)
字串可以指定给暂存器 (reg)。
reg [8*18:1] string_value; //宣告一变数18个位元组的宽度 initial string_value = "Hello Verilog World"; // 将字串存於变数中 |
Table 3-3 是一些为了显示用的特殊字元
Table3-3 特殊字元
特殊字元 | 显示字元 |
\n | 换行 |
\t | 跳栏 |
%% | % |
\\ | \ |
\" | " |
\ooo | 1-3个八位元数 |
3.2.9 字串(Strings)
字串可以指定给暂存器 (reg)。
reg [8*18:1] string_value; //宣告一变数18个位元组的宽度 initial string_value = "Hello Verilog World"; // 将字串存於变数中 |
Table 3-3 是一些为了显示用的特殊字元
Table3-3 特殊字元
特殊字元 | 显示字元 |
\n | 换行 |
\t | 跳栏 |
%% | % |
\\ | \ |
\" | " |
\ooo | 1-3个八位元数 |
3.3 系统任务(System Tasks) 和 组译指令(Compiler Directives)
3.3.1 系统任务
系统任务包含有显示、监视数值、暂停、完成..等,其皆以$<keyword>表示。
资讯显示(Displaying information)
Usage: $display(p1,p2,p3,....,pn);
p1,p2,p3,....,pn可以是字串、变数、或说明。每一个 $display 命令後会自动跳行。由格式定义表(format specifications listed) 表格 3-4,可以做字串的格式。
表格 3-4 格式定义表
格式 | 显示 |
%d or %D | 十进制变数 |
%b or %B | 二进制变数 |
%s or %S | 字串 |
%h or %H | 十六进制变数 |
%c or %C | ASCII 字元 |
%m or %M | 阶层名(不需引数) |
%v or %V | 强度 |
%o or %O | 八进制变数 |
%t or %T | 目前时间 |
%e or %E | 实数科学记号 |
%f or %F | 十进制实数变数 |
%g or %G | 选择实数科学记号和十进制实数变数较短者 |
范例 3-2 显示任务
//显示双引号中之字串 %display("Hello Verilog World"); --Hello Verilog World //显示目前时间 //显示虚拟位址为1fe0000001c的值和目前时间 200 //使用二进制显示port_id其值为五 //显示 x 特性 //显示较高层次模组top的别名p1的阶层名,不需任何引数 |
范例 3-3 特殊字元
//跳行及显示特殊字元% $display("This is a \n multiline string with a %% sign") --This is a --multinline string with a % sign //显示其他特殊字元 |
资讯监视(Monitoring information)
Usage:$monitor(p1,p2,p3,....,pn);
p1,p2,....,pn 是与 $display 相同的,但是 $monitor 不仅仅是显示而已,其在每一次信号变化都能显示出来。
范例3-4 Monitor statement
// 监视信号 clock and reset的值和时间 //Clock 每 5 时间单位触发一次 和 reset在 10时间单位转为低电位 initial begin $monitor($time, "Value of signals clock = %b reset = %b, click, reset); end Partial output of the monitor statement: |
中止(Stopping) 和 完成(finishing)
Usage: $stop;
可以暂时中止模拟来检验信号的值是否正确。
Usage: $finish;
完成并退出模拟。
范例3-5 中止 和 完成
// 中止模拟在100时间单位并检验结果 // 在1000时间单位完成 initial // 模拟时间为0 begin clock = 0; reset = 1; #50 $stop; // 中止模拟在50时间单位 #900 $finish; // 完成模拟在950时间单位 end |
3.3.2 编译命令(Compiler Directives)
编译命令皆以`<keyword>来表示。
`define
定义文字巨集(text macro)。
范例3-6 `define Directive
//用文字巨集定义字的宽度 //在程式码中使用 `WORD_SIZE `difine WORD_SIZE 32 //定义一个别名,当 `s 出现时用 $stop取代 //定义一个经常使用的文字字串 |
`include
可以包含令一个Verilog file 一起编译。
范例3-7 `include 指令
//包含 header.v档案, 其包含一些在主程式design.v档案中之宣告 `include header.v ... ... <Verilog code in file design.v> ... ... |
3.4 总结
* Verilog 语法极类似C语言。
* 说明空白,注解,运算子,数字,字串,定义名称,语法协定。
* 在Verilog中有数种有用的资料型态可以使用。四种逻辑值,八种强度。可以使用资料型态,接线,暂存器,向量,时间,阵列,记忆体,参数,字串,资料型态。
* Verilog提供有用的系统任务
:资讯显示,资讯监视,中止和完成模拟。
* 编译指令 `define是用来定义一个文字巨集,`include 是用来包含其他的Verilog档案。