结构化数字设计

结构化数字设计

层次建模的概念

设计方法学

两种基本的设计方法:自底向上自顶向下设计

1.自底向上

自底向上

2.自顶向下

自顶向下

通常情况下,两种方法混合使用。

 

 

模块

​ Verilog使用模块(module)的概念来代表一个基本的功能块。

​ 一个模块可以是一个元件,也可以是低层次模块的组合

1.模块声明

​ 在Verilog中,模块声明是由关键字module开始,关键字endmodule必须出现在模块定义的结尾。每个模块必须有一个模块名,由它唯一的标志这个模块。模块的端口列表则描述这个模块的输入和输出端口

module <模块名>(<模块端口列表>);
...
<模块的内容>
...
...
endmodule

例如在脉动进位计数器的例子中,T触发器可以定义为:

module T_FF (q, clock ,reset);
...
...
<T触发器的功能描述>
...
...
endmodule

​ 使用Verilog可以在每个模块内4个抽象层次进行描述,定义如下:

  1. 行为或算法级:注重实现的算法,并不注重硬件实现的细节
  2. 数据流级:说明数据的流程对模块进行描述,数据如何在各个寄存器之间流动,以及如何处理这些数据。
  3. 门级:从组成电路的逻辑门及其之间的相互关系的角度设计模块。
  4. 开关级:通过开关,储存节点及其互连关系来设计模块。

 

2.模块实例

​ 模块声明类似于一个模板,使用这个模板就可以创建实际的对象。当一个模块被调用的时候,Verilog会根据模板创建一个唯一的模块对象,每个对象都有其各自的名字、变量、参数和输入/输出(I/O)接口。

​ 从模板创建对象的过程称为实例化(instantiation),创建的对象称为实例(instance)

 

​ 在Verilog中,不允许在模块声明中嵌套模块,也就是在模块声明的module和endmodule关键字之间不能再包含模块声明。模块之间的相互调用是通过实例引用来完成的。

//它引用了4个触发器。它们之间的连接参见2.2节
//定义名为ripple_carry_counter(脉动进位计数器)的模块
module ripple_carry_counter(q,clk,reget);
    output[3:0]q;//输人输出端口的信号和向量声明,以后会讲解
input clk,reset;//输入/输出端口的信号声明,以后会讲解
//生成了4个触发器TEF的实例,每个实例都有自己的名字,每个实例都传递一组信号
//注意每个实例都是FF模块的副本
    TFF tff0 (q[0],clk,reset);
    TFF tff1 (q[1],q[0],reset);
    TFF tff2 (q{2},q[1],reset);
    TFF tff3 (q[3],q[2],reset);
endmodule
//定义名为TFF(触发器)的模块。它引用了一个D触发器。我们在本模块中假设
//D触发器(DEF)已经在该设计中的别处定义了,参见图2.4,看它们之间的互相连接
moaule TFF (q,clk,reset);
//以后将对下列语句做进一步的解释
output q;0
input clk,reset;
wire d;
DFF dff0(q,d,clk,reset);//调用(实例引用)DFF,取名为dffo
not n1(d,q);//非门(not)是veri1og语言的内部原语部件(primitive),以后会讲解
endmodule

ps:关键字必须是小写字母

 

 

基本概念

Verilog中的基本词法约定与c语言类似。

数字声明

  1. 指明位数的数字

    指明位数的数字表现形式为

    <size>'<base format><number>
    

    < s i z e > <size> <size>用来指明数字的宽度(二级制的个数),只能用十进制表示。Base format表示用什么进制

    4'b1111//这是一个4位的二进制数
    12'habc//这是一个12位的十六进制数
    16'd255//这是一个16位的十进制数
    
  2. 不指明位数的数字

    没有指定基数默认为十进制数。如果没有指定宽度,则默认为32位

    234566//这是一个32位的十进制数
    'hc3//这是一个32位的十六进制数
    'o21//这是一个32位的八进制数
    
  3. X和Z值

    x表示不确定值,z表示高阻值;不区分x,y的大小写。

    12'h13x//这是一个12位的十六进制数,四个最低位不确定6'hx//这是一个6位的十六进制数,所有位都不确定
    32'bz//这是一个32位的高阻值
    

    ​ 16进制为基数的表示中x或z表示4位,在8进制,x,z表示3位,在2进制中x,z代表1位。如果某数的最高位是0,x或z,verilog语言约定将分别使用0,x,z自动对这个数进行扩展,填满余下的更高位。如果最高位是1,余下的更高位用0来扩展。

  4. 复数

    对于常数,我们可以通过在表示位宽的数字前面增加一个减号来表示它是一个负数,因为表示大小的常数总是正的。

    -6'd3//这是一个6位的用二进制补码形式存储的十进制数3,表示负数
    -6'sd3//这是一个6位的用于带符号算术运算的负数
    4'd-2//非法说明
    
  5. 下划线和问号

    除了第一个字符,下划线可以出现在数字中的任何位置,它的作用只是提高可读性,在编译阶段会被忽略,?是z的另一种表示。

    12'b1111_0000_1010//用下划线符号来提高可读性4'b10??//相当于4'b10zz
    
  6. 转义标识符

    转义标识符以反斜线“\”开始,以空白符(空格、制表符和换行符)结束。Verilog将反斜线和空白符之间的字符逐个进行处理。

    \a+b-C //译者注:与a+b-c等同
    \**my_name** //译者注:如果作为标识符则与**my_name**等同
    

数据类型

  1. 值的种类

    Verilog使用四值逻辑和八种信号强度来对实际的硬件电路建模。

    值的级别硬件电路中的条件
    0逻辑0,条件为假
    1逻辑0,条件为假
    x逻辑值不确定
    z高阻,浮动状态
    强度等级类型程度
    supply驱动最强
    strong驱动
    pull驱动
    large储存
    weak驱动
    medium储存
    small储存
    highz高阻最弱
  2. 线网

    1. 线网(net:代表了一类数据类型,包括wire,wand,wor,tri,trireg等)标识硬件单元之间的连接。

    2. 就像在真实的电路中一样,线网由其连接器件的输出连续驱动。

    3. 线网一般使用关键字wire进行声明。如果没有明显说明向量,则默认线网的位宽为1

    4. 线网的默认值为z(trireg类型的线网例外,其默认值为x),线网的值由驱动源确定,如果没有驱动源,则线网的值为z

      wire a;//声明上面的电路中a是wrie(连线)类型
      wire b,c;//声明上面的电路中b和c也是wire(连线)类型
      wire d = 1'b0;//连线d在声明时,d被赋值为逻辑值0
      

      在这里插入图片描述

  3. 寄存器

    1. 寄存器用来表示储存元件,它保持原有的树脂,直到被改写。

    2. 寄存器数据类型一般通过关键字reg来声明,默认值为X

      reg reset;//声明能保持数值的变量reset
      initia1 //这个结构将在以后讨论
      begin
      	reset = 1'b1;//把reset初始化为1,使数字电路复位
      	#100 reset=1'b0;//经过100个时间单位后,reset置逻辑0
      end
      
  4. 向量

    1. 线网和寄存器类型的数据均可以声明为向量(位宽大于1)。若在声明中没有指定位宽,则默认为标量(1位)

      wire a;//标量线网变量,默认
      wire [7:0] bus;//8位的总线
      wire [31:0] busA,busB,busC;//3条32位宽的总线
      reg clock;//标量寄存器,默认
      reg [0:40] virtual_addr;//向量寄存器,41位宽的虚拟地址
      
      1. 向量域选择

        对于上面例子中声明的向量,我们可以指定它的某一位或若干个相邻位。

        busA[7] //向量busA的第7位
        bus[2:0]//向量bus的最低3位
        //如果写成bus[0:2]是非法的,因为高位应该写在范围说明的左侧
        virtual_addr[0:1]//向量virtual_addr的两个最高位
        
      2. 可变的向量域选择

        [+:width]:从起始位开始递增,位宽为width。

        [-:width]:从起始位开始递减,位宽为width。

    起始位可以是一个变量,但是位宽必须是一个常量。下面的例子说明了可变的向量域选择的使用方法:

    reg[255:0]data1;//data1【255】是最高有效位
    reg[0:255]data2;//data2【0】是最高有效位
    reg[7:0]byte;
    //用变量选择向量的一部分
    byte=data1[31-:8];//从第31位算起,宽度为8位,相当于data131:24】
    byte=data1[24+:8];//从第24位算起,宽度为8位,相当于data1【31:24】
    byte=data2[31-:8];//从第31位算起,宽度为8位,相当于data2【24:31】
    byte=data2[24+:8];//从第24位算起,宽度为8位,相当于data2【24:311//超始位可以是变量,但宽度必须是常数。因此可以通过可变域选择,//用循环语句选取一个很长的向量的所有位
    for(j=0;j<=32;j=j+1)
        byte=data1[(j*8)+8];//次序是【7:0】,【15:81..【255:248】
    //用于初始化向量的一个域
    data1[(byteNum*8)+:8] = 8'b0;//如果byteNum=1,共有8位被清零,【15:8】
    
  5. 数字,实数和时间寄存器的数据类型

    除reg类型之外,Verilog还支持integer,real和time寄存器数据类型。

    1. 整数

      用关键字integer进行声明,虽然可以用reg类型的寄存器作为通用变量,但声明一个整体类型的变量来完成计数会更为方便。

      整数默认位宽为宿主机的字的位数,最小应为32位。

      integer counter;//一般用途的变量,作为计数器initial
      	coumter=-1;//把-1存储到计数器中
      
    2. 实数

      用real来声明,实数声明不能带有范围,默认值为0。

      real delta;//定义一个名为delta的实型变量
      initial
      begin
      	delta = 4e10;//delta被赋值,用科学记数法表示
      	delta = 2.13;//delta被赋值为2.13
      end
      integer i;//定义一个名为的整型变量
      initial
      	i = delta;//1得到值2(2.13取整数部分)
      
    3. 时间寄存器

      仿真是按仿真时间进行的,其宽度与具体实现有关,最小为64位。用time来声明。通过调用系统函数$time可以得到当前的仿真时间。

      time save_simtime;//定义时间类型的变量savesim time initial
      	save sim time=$time;//把当前的仿真时间记录下来
      
    4. 数组

      在Verilog中允许声明reg,integer,time,real,realtime及其向量类型的数组,对数组的维数没有限制。

      形如<数组名><下标>。对于多维数组来讲,用户需要说明其每一维的索引。举例如下:

      integer count[0:7];//由8个计数变量组成的数组
      reg boo1[31:0];//由32个1位的布尔(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];//声明8位向量的数组
      wire w_array1[7:0][5:0];//声明1位线型变量的二维数组
      

      不要将数组和线网或寄存器向量混淆起来,向量是一个单独的元件,它的位宽是n;数组由多个元件组成,其中每个元件元素的赋值位n或1。

      下面的例子显示了对数组元素的赋值:

      count[5]=0;//把count数组中的第5个整数型单元(32位)复位
      chk_point[100]=0;//把chk_point数组中的第100个时间型单元(64位)复位
      port_id[3]=0;//把port_id数组中的第3个寄存器型单元(5位)复位
      matrix[1][0]=33559;//把数组中第1行第0列的整数型单元(32位)置为33559
      array_4d[0][0][0][0][15:0]=0;//把四维数组中索引号为【o】【O】【0】【O】的寄存器型单元
      //的0-15位都置为0
      port_id=0;//非法,企图写整个数组
      matrix[1] = 0;//非法,企图写数组的整个第2行,即从matrix【1】【0】直到matrix【1】【255】
      
  6. 寄存器

    在数字电路仿真中,需要对寄存器文件ROM和RAM建模。如果需要访问储存器中的一个特定字,可以将字的地址作为数组的下标来完成。

    reg memibit[0:1023];//1K的1位存储器mem1bit
    reg[7:0] membyte[0:1023];//1K的字节(8位)存储器membyte 
    membyte[511]//取出存储器membyte中地址511处所存的字节
    
  7. 参数

    Verilog允许使用关键字parameter在模块内定义常数。参数代表常数,不能像变量那样赋值,但是每个模块实例的参数值可以在编译阶段被重载。

    parameter port_id=5;//定义常数portid为5
    parameter cache_1ine_width=256;//定义高速缓冲器总线宽度为常数256
    parameter signed[15:0] WIDTH;//把参数WIDTH规定为有正负号,宽度为16位
    

    Verilog中的局部参数使用关键字localparam来定义,其作用等同于参数,区别在于它的值不能改变。

    localparam  state1 = 4'b0001,
    			state2 = 4'b0010,
    			state3 = 4'b0100,
    			state4 = 4'b1000;
    
  8. 字符串

    1. 字符串保存在reg类型的变量中,每个字符占用8位(一个字节),因此寄存器变量的宽度应足够大。

    2. 如果寄存器变量的宽度大于字符串的大小,则Verilog使用0来填充左边的空余位;如果寄存器变量的宽度小于字符串的大小,则Verilog截去字符串最左边的位。

      reg[8*18:1] string_value;//声明变量string_vaiue,其宽度为18个字节
      initial
      	string_value = "Hello Verilog World";//字符串可以存储在变量中
      
    3. 有一些特殊字符在显示字符串时有特定的意义,例如换行符,制表符和显示参数值。如果需要在字符串中显示这些特殊字符,则必须加前缀转义字符。

转义字符显示的字符
\n换行
\ttab(制表空格)
%%%
\\\
\""
\0001到3个八进制数字字符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y江江江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值