阿扣的Verilog HDL学习笔记③

第3章 基本概念

注释、分隔符、数字、字符串、标识符、关键字……;逻辑值集合和数据类型(线网、寄存器、向量、数字、仿真时间、数组、参数、存储器、字符串……);用于显示和监视信息、暂停和结束仿真的系统任务;宏定义、文件包含的基本编译指令

3.1词法约定

  • 空白符:空格( \b )、制表符( \t )、换行符。
  • 仅用于分隔标识符,编译时忽略(字符串中的空白符除外)
  • 注释:单行注释( //… )、多行注释( /* … */)。
  • 单行注释可以嵌套在多行注释中多行注释不可嵌套。即( /* …此处可用//… */ )。
  • 操作符:单目操作符、双目操作符、三目操作符。
  • 单目操作符优先级>操作数;三目操作符含两个单独操作符,用以分隔3个操作数。

a = ~ b ; // 单目操作符 ~

a = b && c ; // 双目操作符 &&

a = b ? c : d ; // 三目操作符 ?:

  • 数字声明
    • 指明位数的数字( <size>'<base format><number>):<size>用十进制数表示位宽;<base format>基数格式包括十进制()、十六进制()、二进制()、八进制();<number> 0~1、a/A~f/F 。
    • 不指明位数的数字:不指定基数格式时默认为十进制数;默认位宽与计算机有关(最小32位)。

4'b1111 // 4位二进制数

12'habc // 12位十六进制数

16'd255 // 16位十进制数

23456 // 32位十进制数

'hc3 // 32位十六进制数

'021 // 32位八进制数

  • X和Z值:不确定值X、高阻值Z。
  • X和Z代表的位数:十六进制--4位;八进制--3位;二进制--1位
  • 数的最高位是X、Z或0时,自动复制扩展剩余更高位;数的最高位是1时,用0扩展剩余更高位。

12'h12x // 12位十六进制数,四个最低位不确定

6'hx // 6位十六进制数,所有位都不确定

32'bz // 32位高阻值

  • 负数:位宽前加负号表示常数负数;用一个可选的带符号说明符表示带符号算术运算的负数。

-6'd3 //  6位 用二进制补码形式储存的 (3)10,表示负数

-6'sd3 // 6位 用于带符号算数运算的负数

4'd-2 // 非法

  • 下划线和问号:下划线( _ )可出现在数字中任何位置(第一个字符除外),提高可读性,编译时忽略;问号()同 Z,表示高阻抗,增强casez和casex语句的可读性(表示“不必关心”的情况)。

12'b1111_0000_1010 // 提高可读性

4'b10?? // 相当于 4'b10zz

  • 字符串:字符串()相当于一个单字节ACSII字符队列。必须一行写完,不能包含回车符。

"a / b"

  • 关键字和标识符:关键字(全小写)是Verilog中预留的定义语言结构的特殊标识符,包括关键字、系统任务和编译指令。标识符(区分大小写)是程序代码中对象的名字。
  • 标识符由字母、数字字符、下划线_、美元符$组成。首字符不能是数字或$。$开始的标识符为系统函数。

reg value; // reg是关键词;value是标识符

imput clk; // input是关键字;clk是标识符

  • 转义标识符:“\”开始,空白符(空格、制表符、换行符)结束。
  • \...空白符之间的字符逐个处理,可为所有可打印字符,\和空白符除外。

\a+b-c   //同a+b-c

\**my_name** //同**my_name**

3.2数据类型

  • 四值电平逻辑:0(假)、1(真)、x(不确定)、z(高阻/浮动)  按值的级别排序
  • 强度值:supply(驱动)、strong(驱动)、pull(驱动)、large(存储)、weak(驱动)、medium(存储)、small(存储)、highz(高阻) 按程度由强到弱排序
  • 各类线网中,只有trireg类型可以存储强度(large、medium、small三等级)
  • 强度值解决不同强度驱动源之间的赋值冲突。
  • 不同强度信号驱动同一个线网,结果服从高强度信号。同强度多个信号竞争,结果为不确定值。
  • 线网net:硬件单元间的连接。由连接器件输出端连续驱动。
  • net不是关键词。包括wire、wand、wor、tri、triand、trior、trireg…数据类型。
  • 线网用wire声明,值由驱动源决定。默认值为z(trireg类型线网默认值为x),默认位宽为1。

wire a; // 声明a是wire类型

wire b, c; // 声明b和c是wire类型

wire d = 1'b0; //  声明时赋值:逻辑值0

  • 寄存器register:存储元件,被改写前保持原数值。
  • Verilog的寄存器是一个保存数值的变量,不需要驱动源和时钟信号。仿真中随时可以赋值改变。
  • 寄存器用reg声明,默认值为x。声明为带符号类型的变量时可用于带符号的算术运算。

reg reset; // 声明保持数值的变量reset

initial

begin

    reset = 1'b1; // 初始化,使数字电路复位

    #100  reset = 1'b0; // 100个时间单位后,reset置逻辑0

end

 

reg signed [63:0] m; // 64位带符号的值

integer i; // 32位带符号的值。integer为整数

  • 向量:线网和寄存器类型数据默认位宽为1,是标量;可声明为向量(位宽大于1)。
  • 向量用[high#:low#]或[low#:high#]来说明。:边为向量的最有效位。不能直接对整个数组赋值。

wire a; // 标量线网变量,默认

wire [7:0] bus; // 8位总线

wire [31:0] busA, busB, busC; // 3条32位宽的总线

reg clock; // 标量寄存器,默认

reg [0:40] virtual_addr; // 向量寄存器,41位宽的虚拟地址

  • 向量域选择:可指定向量的某一位或若干相邻位。

busA[7] // busA的第7位

bus[2:0] // bus的最低三位

virtual_addr[0:1] // 向量virtual_addr的两个最高位

  • 可变的向量域选择:可通过for循环动态选取向量的各个域。
  • [<starting_bit.+ : width]  从起始位(可为变量)开始递增,位宽为width(常量)
  • [<starting_bit.- : width]  从起始位(可为变量)开始递减,位宽为width(常量)

reg [255:0] data1; // data1[255]是最高有效位

reg [0:255] data2; //data2[0]是最高有效位

reg [7:0' byte;

 

//用变量选择向量的一部分

byte = data1[31-:8]; //从第31位算起,宽度为8位,相当于data1[31:24]

byte = data1[24+:8]; //从第24位算起,宽度为8位,相当于data1[31:24]

byte = data2[31-:8]; //从第31位算起,宽度为8位,相当于data2[31:24]

byte = data2[24+:8]; //从第31位算起,宽度为8位,相当于data2[31:24]

 

//起始位可以为变量,宽度必须为常数。可通过可变域选择

//用循环语句选取一个很长的向量的所有位

for (j=0; j<=31; j=j+1)

    byte = data1[(j*8)+:8]; //

//初始化向量的一个域

data1[(byteNum*8)+:8] = 8'b0; // 若byteBum = 1,共有8位被清零,[15:8]

  • 整数:一种通用的寄存器数据类型,用integer声明。
  • 默认位宽是宿主机的位数,域具体实现有关,最小32位。
  • reg类型寄存器变量为无符号数,整数类型变量为有符号数

integer counter; // 一般用途的变量没座位计数器

initial

counter = -1; // 把-1存储到计数器中

  • 实数:用real声明,用十进制或科学计数法(eg. 3e6代表3000000)表示。
  • 实数不带范围,默认值为0。
  • 将实数赋值给整数时,取整为最接近的整数。

real delta; //定义一个实型变量delta

initial

begin

delta = 4e10; // delta被赋值40000000000

delta = 2.13; // delta被赋值2.13

end

integer i; //定义一个整型变量i

initial

i = delta; // i被赋值2

  • 时间寄存器:用以保存仿真时间的寄存器数据类型。
  • 时间寄存器用time来声明,宽度与具体实现有关,最小为64位。
  • 调用系统函数$time得到当前的仿真时间。

time save_sim_time; //定义时间类型变量save_sim_time

initial

save_sim_time = $time; //记录当前仿真时间

  • 数组:Verilog中可声明reg、integer、time、real、realtime及其向量类型的数组,任意维数均可。
  • 线网数组可用于连接实例的端口,其每个元素可作为一个标量或向量。<数组名>[<下标>]。
  • 对于多维数组要说明每一维的索引。

integer count[0:7]; //8个计数变量组成的数组

 

reg bool[31:0]; //32个boolean布尔寄存器变量组成的数组

 

time chk_point[1:100]; //100个时间检查变量组成的数组

 

reg [4:0] port_id[0:7]; //8个 位宽为5的端口标识变量组成的数组

 

integer matrix[4:0][0:255]; //二维整数型数组

 

reg [63:0] array_4d [15:0][7:0][7:0][255:0]; //四维64位寄存器型数组

 

wire [7:0] w_array2 [5:0]; //6个 8位线型向量的数组

 

wire w_array1[7:0][5:0]; //1位线型变量的二维数组

 

count[5] = 0; //count数组中第5个整数型单元(32位)复位

chk_point[100] = 0; //chk_point数组中的第100个时间型单元(64位)复位

port_id[3] = 0; //port_i数组中第3个寄存器型单元(5位)复位

 

matrix[1][0] = 33559; //数组中第1行第0列整数型单元(32位)置为33559

array_4d[0][0][0][0][15:0] = 0; //思维数组中索引号位[0][0][0][0]的寄存器型单元的0~15位置0

 

port_id = 0; //非法,不能写入整个数组

matrix[1] = 0; //非法,不能写入整行(matrix[1][0]~matrix[1][255])

 

  • 注意分辨数组和线网/寄存器向量。向量是一个单独元件,位宽为n;数组是多个元件,每个元件位宽为n或1。
  • 存储器:用寄存器的一维数组表示存储器。
  • 每个元素称为一个元素或一个字(word),位宽为1位或多位,由一个数组索引来指定。
  • n个1位寄存器不等于一个n位寄存器

reg mem1bit[0:1023]; //1K的1位存储器mem1bit

reg [7:0] membyte[0:1023]; //1K的字节(8位)存储器membyte

membyte[511] //

出存储器membyte中地址511处存储的字节

  • 参数:用关键字parameter在模块内定义常数。
  • 参数代表常数,每个模块实例的参数值可在编译阶段被重载,其类型和范围可以定义(不能像变量一样赋值)。
  • 通过模块实例化或使用defparam语句来改变参数值(重定义)
  • 局部参数:用localparam来定义,不能改变值,不能用参数重载语句(defparam)或通过有序参数列表或命名参数赋值来直接修改。

parameter port_id = 5; //定义常数port_id为5

parameter cache_line_width =256; //定义告诉缓冲器总线宽度为常数256

parameter signed[15:0] WIDTH; //参数WIDTH有正负号,16位

 

localparam  state1 = 4'b0001,

          state2 = 4'b0010,

 state3 = 4'b0100,

 state4 = 4'b1000; //定义状态机的状态编码为局部参数,避免被意外修改

  • 字符串:保存在reg类型的变量中,每个字符占8位(一个字节)。(寄存器变量的宽度应足够大,稍宽于字符串位长)
  • 寄存器变量的宽度大于字符串的位宽,则用0填补左边的空余位。
  • 寄存器变量的宽度小于字符串的位宽,则截去字符串的最左位。

reg [8*18:1] string_value; //声明18个字节的变量string_value

initial

string_value = "Hello Verilog Worlk"; //字符串可存储在变量中

  • 在字符串中显示特殊字符时必须加前缀转义字符:

转义字符

显示内容

\n

换行

\t

tab(制表空格)

%%

%

\\

\

\"

"

\ooo

1~3个八进制数字字符

3.3系统任务和编译指令

 

$display("Hello Verilog World"); //显示:Hello Verilog World

 

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

 

//在时间为200的时刻显示41位虚拟地址1fe0000001

reg [0:40] virtual_addr;

$display("At time %d virtual address is %h", $time, virtual_addr); //显示:At time 200 virtual address is 1fe0000001

 

//用二进制数显示port_id 5

$display("ID of the port is %b", port_id); //显示:ID of the port is 00101

 

//显示x字符;用二进制数显示4位总线bus的信号10xx

reg [3:0] bus;

$display("Bus value is %b", bus); //显示:Bus value is 10xx

 

//在名为top的最高层模块中显示在盖层被调用的实例p1的层次名

$display("This string is diaplayed from %m level of hierachy"); //显示:This string is diaplayed from top.p1 level of hierachy

 

//显示特殊字符:换行和%号

$diaplay("This is a \n multiline string with a %% sign"):

//显示:

//This is a

//multiline string with a % sign

 

格式

显示

%d或%D

用十进制表示变量

%b或%B

用二进制表示变量

%s或%S

显示字符串

%h或%H

用十六进制表示变量

%c或%C

显示ASCII字符

%m或%M

显示层次名

%v或%V

显示强度

%o或%O

用八进制表示变量

%t或%T

显示当前时间格式

%e或%E

用科学计数法格式显示实数(eg. 3e10)

%f或%F

用十进制浮点数格式显示实数

%g或%G

用科学计数法或十进制格式显示实数(取较短的格式)

 

//监视时钟和复位信号的时间和值

//时钟每5个时间单位翻转一次,复位信号10个时间单位后变低

initial

begin

$monitor($time, "Value of signals clock = %b reset = %b', clock, reset);

end

 

/*监视语句部分输出:

0 Value of signals clock = 0 reset = 1

5 Value of signals clock = 1 reset = 1

10 Value of signals clock = 0 reset = 0

 

initial

begin

clock = 0;

reset = 1;

#100 $stop;

#900 $finish;

end

 

//规定字长的文本宏

//用'WORD_SIZE表示

'define WORD_SIZE 32

 

//别名。用'S来代替$stop

'define S $stop;

 

//定义经常使用的字符串

'define WORD_REG reg [31:0]

//之后可用'WORD_REG 32 来定义一个32位寄存器变量

 

'include "header.v"

...

<design.v文件中的Verilog代码>

...

  • 系统任务(系统函数):$<keyword>形式;包括屏幕显示、线网值丰台监视、暂停、结束仿真……
  • 详见《IEEE Standard Verilog Hardware Description Language》
  • 显示信息$display:显示变量、字符串、表达式……;
  • 用法:$display(p1, p2, p3, … , pn);
  • p1, p2, p3, … , pn 是双引号括起来的变量、字符串、表达式;字符串结尾自动插入换行符(参数列表位空时光标换行;x和z以“x”“z”的形式显示。
  • 字符串格式说明:
  • 监视信息$monitor:对信号值变化进行动态监视
  • 用法:$monitor(p1, p2, p3, … , pn);
  • p1, p2, p3, … , pn 是变量、信号名或双引号括起来的字符串,
  • 暂停仿真$stop: 暂停仿真,进入交互模式,方便设计者检查和调试。
  • 结束仿真$finish
  • 编译指令:用法:'<keyword>
  • 'define:定义文本宏。编译时,编译器遇到'<宏名>时,用预定义的文本宏进行替换(类似于C中的#define)。使用时加前缀'
  • 'include:将一个Verilog源文件包含在另一个Verilog文件中(类似于C中的#define)。常用语将内含全局或公用定义的头文件包含在设计文件中。
  • 'ifdef
  • 'timescale
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值