Verilog语言简介(数字逻辑课程笔记)

Verilog语言简介(数字逻辑课程笔记)

概述

Verilog是一种硬件描述语言:用形式化方法(文本形式)来描述和设计数字电路和数字系统的高级模块化语言。可编写设计文件、建立电路模型、编写测试文件进行仿真。

数据类型

1.变量值

  • 0:代表逻辑0或否条件;在电路中一般是低电平
  • 1:代表逻辑1或真条件;在电路中是高电平
  • X:代表未知的逻辑值(可能为0或1);一般是寄存器类型(reg)未初始化
  • Z:代表一个高阻态;是线型(wire)变量未接驱动

2.wire & reg

  • wire: 线网; 用来表示硬件单元之间的物理连线
wire a;
wire b;
wire c=1'b0;
  • reg: 寄存器; 用来表示存储单元
reg rstn;
initial begin
     rstn=1'b0;
     #100;
     rstn=1'b1;
 end

3.向量vector

  • 标量Scalar: 1-bit位宽的线网或寄存器类型
    wire n1;
    reg d1;
  • 向量Vector:n-bit位宽的线网或寄存器类型
    wire [3:0] n0;
    reg[3:0] d0;

4.数组Array

  • 在Verilog中允许声明reg, wire, integer, time, real及其向量类型的数组
// y is an scalar reg array of depth=12, each 1-bit wide
reg y1[11:0];
//y is an 8-bit vector net with a depth of 4
wire [0:7] y2 [3:0];
//y is a 2D array rows=2, cols=4 each 8-bit wide
reg [7:0] y3 [0:1][0:3];
  • 存储器:寄存器数组模拟存储器,可用来描述RAM或ROM的行为
module des();
//reg vector 8-bit wide
reg [7:0] mem1;
//8-bit wide vector array with depth=4;
reg [7:0] mem2 [0:3];
//16-bit wide vector 2D array with rows=4, cols=2
reg [15:0] mem3[0:3][0:1];

initial begin
 mem=8'ha9;
 $display("mem1 = 0x%0h", mem1);

5.其他类型

  • integer: 32位宽的通用整型变量,可在对硬件建模时用于其他目的(可综合)
  • time: 无符号64位宽,可用于存储仿真时间量以进行仿真调试,realtime变量时将时间存储为浮点数(不可综合)
  • real:实数变量,可存储浮点值, 可以与integer和reg相同的方式进行赋值(不可综合)
  • string:字符串,存储在reg中, reg变量的宽度必须足够大以容纳字符串(可综合)

模块构建

模块
操作符
赋值语句
generate
连续赋值
过程赋值
assign
always
initial
阻塞赋值
非阻塞赋值

Verilog的基本设计单元是模块。

模块由四个主要部分组成:

  • 端口定义:module 模块名(端口1,端口2,…)
  • I/O说明:包括输入(input)、输出(output)和双向(inout)
  • 信号类型声明:声明信号的数据类型和函数声明wire,reg,integer,real,time
  • 功能描述:用来描述设计模块的内部结构和模块端口间的逻辑关系。常用assign语句、always块语句等方法实现
module block1(a,b,c,d);
input a,b,c;
output d;
wire x;
assign d=a|x;
assign x=(b&~c);
endmodule

模块是一个具有特定功能的设计单元,在电路综合时模块会被转换为相应的数字电路
给定模块一组输入,模块会返回一组输出,这意味着模块可以被重复使用,由此来实现更复杂的电路
按照如下形式来实例化模块:

module mod1(input d,...);
//contents of the module
endmodule

module mod2;
   wire data;
   mod1 u0(.d(data),...);
   //contents of the module
endmodule

操作符

操作符也称运算符, 是Verilog HDL预定义的函数符号。

功能符号含义
算术运算符+,-,* , /,%, **加,减,乘,除,求模,求幂
逻辑运算符&&,II, !(单目)逻辑与,逻辑或,逻辑非
关系运算符<, >, <=, >=小于,大于,小于等于,大于等于
等值运算符= =, !=, = = =, != =等于,不等,全等,不全等
缩减运算符&,~ &,I,~ I,^ , ^ ~ /~ ^与,与非,或,或非,异或,同或(都为单目)
条件运算符信号 = 条件?表达式1:表达式2;条件为真时,信号取表达式1的值,为假,取表达式2的值
位运算符~(单目),&, I,^ ,^ ~ , ~ ^按位取反,按位与,按位或,按位异或,按位同或
移位运算符>>, <<右移,左移(后空位补0)
位拼接运算符{信号1的某几位,…,信号n的某几位}用于将两个或多个信号的某些位拼接起来
  • 在逻辑运算中,如果操作数不止一位,应将操作数作为一个整体来对待
  • 两个不同长度的操作数进行位运算时,将自动按右端对齐,位数少的操作数会在高位用0补齐。
  • 关系运算符优先级低于算术运算符,返回结果为逻辑值,0或1或x
  • 等于运算符(= =)和全等运算符(===)的区别: 使用等于运算符时,两个操作数必须逐位相等,结果才为1,若某些位为x或z,则结果为x;使用全等运算符时,若两个操作数的相应位形式上完全一致,则结果为1,否则为0.
操作数个数
单目运算符
双目运算符
三目运算符

在这里插入图片描述

赋值语句

连续赋值

连续赋值语句是 Verilog 数据流建模的基本语句,用于对 wire 型变量进行赋值。其格式如下:

assign <net_expression> = <expressiom of different signals or constant value>

➢ 等式左边必须是一个标量或者线性向量,而不能是寄存器类型
➢ 等式右边的类型没有要求,等式右边的值一旦发生变化,就会立刻重新计算并同时赋值给左侧

module xyz;
wire i1, i2;
wire out;
assign out=i1 & i2;
endmodule

在这里插入图片描述

过程赋值
  • 过程赋值是在 initial 或 always 语句块里的赋值,主要用于对寄存器类型变量进行赋值
  • 寄存器变量在被赋值后,其值将保持不变,直到重新被赋予新值
  • 过程赋值只有在语句执行的时候,才会起作用
  • Verilog 过程赋值包括 2 种语句:阻塞赋值与非阻塞赋值
过程赋值语句块:always语句块

➢ 通常带有触发条件
➢ 语句块中的语句会重复执行
➢ 一个变量不能在多个 always 块中被赋值
➢ 在 always 块中被赋值的只能是 register 型变量
➢ always 语句块即可以用来实现组合逻辑也可以用来实现时序逻辑

模块声明:

always @(event)
     [statement]
always @event begin
     [multiple statements]
end

不带有敏感信号的 always 语句块会一直
执行
➢ 可用于仿真时钟信号生成

always #10 clk= ~clk;

always设计组合电路
代码示例:

module combo (input a, b, c, d, e,
                             output reg z);
       always @ ( a or b or c or d or e) begin
          z= ((a & b) | (c ^ d) & ~e);
       end
       
endmodule

在这里插入图片描述

always设计时序逻辑电路

➢ 模N计算器,计数器从0开始,每个时钟周期上升沿自加1,计算器加到N-1之后重新从0开始计数。
➢ 模N计数器需要 log2 𝑁 个触发器来保存计数值

代码示例:

module mod10_counter(   input clk,
                        input rstn,
                        output reg[3:0] out);
   always @(posedge clk) begin
       if(!rstn) begin
          out<=0;
       end else begin
            if (out == 10)
                out<=0;
            else
                out <= out + 1;
           end
     end
endmodule
阻塞赋值

➢ 阻塞赋值属于顺序执行,即下一条语句执行前,当前语句一定会执行完毕
➢ 阻塞赋值语句使用等号 = 作为赋值符
➢ 仿真中,initial 里面的赋值语句都是用的阻塞赋值

reg_variable = expression
always @(posedge clk) begin
    b=a;
    c=b;
end

在这里插入图片描述

非阻塞赋值

➢ 非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行
➢ 非阻塞赋值语句使用小于等于号 <= 作为赋值符

reg_variable <= expression
always @ (posedge clk) begin
      b<=a;
      c<=b;

在这里插入图片描述

过程赋值语句块:initial语句块

➢ 仅用于仿真,沿时间轴只执行一次
➢ 用途主要是在仿真的初始状态对各变量进行初始化
➢ 不可综合,常用于测试文件中生成激励波形(如复位信号)作为电路的仿真信号

initial 
    [single statement]
initial begin
    [multiple statements]
end
module behave;
  reg rstn;
  reg [2:0] a;
  
initial begin
   rstn = 1'b0;
   #10 rstn = 1'b1;
     a=3'b001;
   #30 $finish;
   end
 endmodule
generate

generate 可以用来循环实例化模块或条件实例化模块
➢ generate 与 for loop,用来构造循环结构,多次实例化某个模块
➢ generate 与 if else 或 case,用来在多个块之间选择一个代码块

//Design for a half-adder
module ha (input a,b,
           output sum,cout);
   assign sum = a ^ b;
   assign cout = a & b;
endmodule

//A top level design that contains N instances of half adder
module my_design
   #(parameter N=4)
       ( input [N-1:0] a, b,
         output [N-1:0] sum, cout);
   //Declare a temporary loop variable to be used during           
   //generation and won't be available during simulation
   genvar i;
   //Generate for loop to instantiate N times
   generate
       for(i=0;i<N;i=i+1) begin
          ha u0 (a[i],b[i],sum[i],cout[i]);
       end
    endgenerate
endmodule

功能描述

结构描述
• 结构(Structural)描述是对设计电路的结构进行描述,即描述设计
电路使用的元件及这些元件之间的连接关系,属于低层次的描述方法
数据流描述
• 数据(Data Flow)流描述采用持续赋值语句,抽象级别位于结构描
述和行为描述之间
行为描述
• 行为(Behavioural)描述是对设计电路的逻辑功能的描述,并不用
关心设计电路使用哪些元件以及这些元件之间的连接关系,属于高层
次的描述方法

结构描述

◼ 基本逻辑门关键字是Verilog HDL预定义的逻辑门,包括and、or、not、
xor、nand、nor等
◼ Verilog HDL内置了26个基本元件,其中14个门级元件,12个开关级元件

调用门原语句法:

gate_keyword <instance> (output, input1,..., inputn );
module gates (input a,b,c,d,
              output o);
   //assign o=!(a&b&c&d)
   nand(o,a,b,c,d);//o is the input, a,b,c,and d are inputs
 endmodule
数据流描述

◼ 数据流描述方式要比结构化描述方式抽象级别要高一些,因为它不在需要清晰地刻画出具体的数字电路架构,而是可以比较直观地表达底层的逻辑行为
◼ 数据流描述方式又称为 RTL 级描述方式,即寄存器传输级描述
◼ 从数据的变换和传送的角度来描述设计模块,常用 assign 连续赋值语句实现,因此抽象级别没有行为描述方式高,纯数据流的描述方式只适用于小规模的电路设计

module combo (input a,b,c,d,
              output o);
   assign o= ~((a&b)|c^d);
endmodule

在这里插入图片描述

行为描述

◼ 行为描述是对设计电路的逻辑功能的描述,并不关心设计电路使用哪些元
件以及这些元件之间的连接关系
◼ 最能体现 EDA 风格的硬件描述方式,既可以描述简单的逻辑门,也可以描
述复杂的数字系统乃至微处理器;既可以描述组合逻辑电路,也可以描述
时序逻辑电路
◼ 属于高层次的描述方法,类似高级语言可以使用控制流循环语句等功能
◼ 语句块将一组语句组合在一起,这些语句在语法上等效于单个语句
◼ 顺序执行的语句常包装在 begin end 关键字中,并且将以给定的顺序依次
执行。出现多组 begin end 应注意其对应匹配。
◼ 并行执行的语句常包装在fork join关键字内,多用于仿真

initial begin
    #10 data =8'hfe;
    fork 
       #10 data=8'h11;
       begin
          #20 data=8'h00;
          #30 data=8'haa;
       end
     join
 end

在这里插入图片描述

◼ Control Flow 语句在 Verilog 中主要包括条件语句、循环语句。
◼ 其中条件语句主要为 if-else 和 case 两种关键字。

if-else语句

// if statement without else part
if(expression)
    [statement]

//if statement wirh an else part
if(expression)
    [statement]
else 
    [statement]

//if-else-if statement
if(expression)
   [statement]
else if(expression)
   [statement]
else
   [statement]
   

case语句

//Here 'expression' should match one of the items
case (<exoression>)
   case_item1:  <single statement>
   case_item2,
   case_item3:  <single statement>
   case_item4: begin
                  <multiple statements>
                  end
   default:   <statement>
endcase

循环语句

◼ repeat 语句——连续执行一条语句 n 次
◼ while 语句——执行一条语句直到某个条件不满足。首先判断循环执行条件表达式是否为真,若为真,则执行后面的语句或语句块,直到条件表达式不为真;若不为真,则其后的语句一次也不被执行
◼ forever 语句——无限连续地执行语句,可用 disable 语句中断.多用在initial 块中,以生成时钟等周期性波形
◼ task 语句
➢ 用来由用户定义任务,任务类似高级语言中的子程序,用来单独完成某项具体任务,并可以被模块或其他任务调用
➢ 当希望能够对多个信号进行一些运算并输出多个结果(即有多个输出变量)时,宜采用任务结构
◼ function 语句
➢ 用来定义函数,函数的目的是通过返回一个用于某表达式的值,来响应输入信号,适于对不同变量采取同一运算的操作
➢ 函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用,而 task 只能在同一模块内定义与调用

系统函数

◼ 在仿真时将一定内容显示出来是非常常用的,$ display 和$ write 函数就主要用于显示信息和调试信息,其区别是$ display 会在字符串末尾追加一个换行符,$write则不会

module tb;
  initial begin
      $display("This ends with a new line ");
      $write("This does not,");
      $write("like this.To start new line, use newline char");
      $display("This always start on a new line!");
   end
 endmodule
      

◼ Verilog 还提供一个连续监视器 $monitor 函数,每当其参数列表中的变量
或表达式发生更改时,会自动打印出变量或表达式的值。
◼ Verilog 也有系统函数来处理文件相关操作,包括打开文件,将值输
出到文件,从文件中读取值和关闭文件等。
➢ 打开和关闭文件
➢ 向文件中输入信息
➢ 读取文件
➢ 读取文件数据到存储器:

$readmemb (<数据文件名>,<存储器名>); 
$readmemh (<数据文件名>,<存储器名>);
module tb;
    reg[8*45:1] str;
    integer fd;

    initial begin
       fd = $fopen("my_file.txt","r");

       //keep reading lines until EOF is found
       while(! $feof(fd)) begin
          //Gey current line of the variable
          $fgets("%0s",str);
        
        //Display contents of the variable
        $display("%0s",str);
      end
      $fclose(fd);
     end
endmodule

代码示例

4-bit全加器

设计源码

`timescale 1ns/1ps

module full_adder_bit(
     input wire a,b,cin,
     output wire sum,cout
     );
    
     assign sum=(a^b)^cin;
     assign cout=(a&b)|((a^b)&cin);
endmodule

module full_adder_4bit(
     input wire[3:0],a,b,
     output wire[3:0] sum,
     output wire cout
     );
     
     wire[3:0] carry;
     full_adder_1bit bit0(a[0],b[0],1'b0,sum[0],carry[0]);
     full_adder_1bit bit1(a[1],b[1],carry[0],sum[1],carry[1]);
     full_adder_1bit bit2(a[2],b[2],carry[1],sum[2],carry[2]);
     full_adder_1bit bit3(a[3],b[3],carry[2],sum[3],carry[3]);
     
     assign cout=carry[3];
 end module

仿真源码

`timescale 1ns/1ps

module testbench();
reg[3:0] a,b;
wire[3:0] sum;
wire cout;

initial begin
    a=4'b0011;
    b=4'b0110;
    #10;
    a=4'b1001;
    b=4'b0111;
end

full_adder_4bit adder(a,b,sum,cout);

endmodule

➢ 初始a和b分别赋值4’b0011,4’b0110,计算结果sum和
cout分别是4’b1001,1’b0
➢ 经过10ns,a和b分别赋值4’b1001,4’b0111,计算结果
sum和cout分别是4’b0000,1’b1 ,即发生溢出

在这里插入图片描述

可读写存储器regfile

设计源码

`timescale 1ns/1ps

module regfile(
     input wire clk,
     input wire ren,
     input wire wen,
     input wire[31:0] wdata,
     input wire[4:0] addr,
     output wire[31:0] rdata
     );

     reg[31:0] regfile[31:0];
     
     initial begin
        $readmemh("C:\\ram_data.txt",regfile);
     end;

     assign rdata=(ren==1'b1) ? regfile[addr]: 32'b0;
    
     always @(posedge clk)begin
          if(wen)
             regfile[addr]=wdata;
      end
endmodule

     

➢ initial 语句在仿真开始时执行,不可综合!
➢ 通过$readmemh 系统函数,将文本文件中定义的值
加载到reg变量中,文本文件内容如下:

在这里插入图片描述
在这里插入图片描述

仿真源码

`timescale 1ns/1ps

module testbench();

reg clk;
reg ren;
reg wen;
reg[4:0] addr;
reg[31:0] wdata;
wire[31:0] rdata;

regfile regfile0(clk,ren,wen,wdata,addr,rdata);

initial begin
     clk=1'b0;
     ren=1'b0;
     wen=1'b0;
     addr=5'b00011;
     wdata=32'h0;
     #12
     wen=1'b1;
     wdata=32'h0a0a0a0a;
     #5
     wen=1'b0;
     #2
     ren=1'b1;
  end

  always #5 clk=~clk;

endmodule

在这里插入图片描述

  • 47
    点赞
  • 409
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数字逻辑课程设计中,通过Verilog语言设计自动洗衣机的原理,需要考虑到洗衣机的基本功能和控制流程。首先,洗衣机应该具有启动、停止、填充水、排出水、洗涤、漂洗、甩干等基本功能。 在Verilog设计中,可以使用状态机的方式来实现控制流程。首先,定义一个状态机包括各个状态:停止状态、填充水状态、洗涤状态、漂洗状态、甩干状态。在停止状态,洗衣机等待用户输入开始洗涤命令,然后进入填充水状态。这时,洗衣机的内部控制器接受到填充水的命令,并且检测到水位达到了指定高度后,就会进入洗涤状态。 在洗涤状态中,洗衣机的控制器控制摆杆和浸润器的动作,完成洗涤过程。当洗涤过程完成后,洗衣机将进入漂洗状态,并且重复上述操作。当所有的洗涤和漂洗都完成后,洗衣机进入甩干状态,启动电机来完成甩干操作。当甩干完成后,洗衣机返回到停止状态,等待下一次的洗涤命令。 在Verilog的设计中,还可以考虑到各种异常情况,如电机故障、过热等,设计相应的保护措施。此外,还可以添加一些延时等待操作,在洗涤、漂洗和甩干等阶段,增加适当的等待时间,保证洗衣机能够完成相应的操作。 总之,通过Verilog设计自动洗衣机,需要考虑到洗衣机的基本功能和控制流程,以及可能出现的异常情况。只有在充分的测试和验证后,才能实现一个稳定的自动洗衣机系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值