Verilog学习笔记

sky视频笔记:数字逻辑回顾&Hello World_哔哩哔哩_bilibili

一、数电基础

1.组合逻辑

  • 电路逻辑输出值只和当前的输入有关
  • 比如:AND/OR/XOR/NAND/NOR/MUX/Adder/Multiplier

2.时序逻辑

  • 电路逻辑输出值跟当前的输入和电路的当前状态有关
  • 保存当前状态的器件,如:触发器Flip-Flop,锁存器Latch 二者区别: Flip-Flop和Latch - 知乎

3.逻辑值

  • 逻辑状态

Verilog学习笔记_第1张图片

  • 逻辑 0:表示低电平,也就对应我们电路 GND;
    逻辑 1:表示高电平,也就是对应我们电路的 VCC;
    逻辑 X:表示未知,有可能是高电平,也有可能是低电平,仿真发生了不能解决的逻辑冲突
    逻辑 Z:表示高阻态,外部没有激励信号是一个悬空状态。相当于啥也没接,可以上拉或者下拉。

  • 对于没有进行初始化的信号,一般处于不确定态(x),高阻态表示该信号没有被其他信号驱动,经常用于有多个驱动源的总线型数据上。

  • 对于高阻态的理解:Verilog中三态门(高阻态)的理解与例子_CLL_caicai的博客-CSDN博客_verilog 高阻态

  • 反相器(非门)

Verilog学习笔记_第2张图片

  • 与门/或门/异或门

  • Verilog学习笔记_第3张图片

二、Verilog介绍

1.概述

  • 是一种硬件描述语言HDL,不是设计语言,先有电路,后有程序
  • 类似的有VHDL、SystemVerilog、Chisel(未来的方向,目前不好说)
  • 推荐书:国外的Verilog HDL 高级数字设计(第二版)—Miachael,D.Cilette和国内Verilog数字系统设计教程(第4版)夏宇闻。

2.可综合&不可综合

  • 可综合描述:综合tool能够把Verilog描述转化(Comlile)为基本的数字电路底层cell(与或非门,寄存器等)

    例如:assign y = a & b;—>

Verilog学习笔记_第4张图片

  • 不可综合描述:不能把Verilog描述转化为基本的数字电路底层cell的描述

    例如:$display("Hello world.\n");这种是需要串口。

3.Verilog设计仿真与实现

  • 何为仿真?

    从仿真器的角度理解Verilog语言:从仿真器的角度理解Verilog语言 - 知乎

  • 常用的仿真工具(所有verilog描述)

    • modelsim/Questasim (Mentor)
    • VCS                            (Synopsys)
    • NC-verilog                  (Candence)
  • Verilog设计的物理实现(可综合verilog描述)

    • 综合后在IC芯片上实现
    • 综合后在FPGA上实现

4.数字电路设计方法学

  • Top-Down:从顶层结构,算法/协议上开始。享下逐步划分功能模块;再细分各功能模块的功能和IO

Verilog学习笔记_第5张图片 

三.Verilog语法介绍

1.标识符

  • 首字母必须是字母/下划线
  • 区分大小写
  • 信号名字和信号功能对应

2.关键字

完整关键字定义,见verilog标准:IEEE Std 1364-2001

Verilog标识符与关键字_FPGA&IC设计导师的博客-CSDN博客_verilog标识符

initial一般是不可综合的,always是可综合的

3.数据物理类型

  • “线”性数据:用于连续赋值语句(assign)描述组合逻辑或module间的信号连接线
    • wire:线性,可综合
      • wire a; //1bit位宽
      • assign a=1'b0; //连续赋值语句
    • tri0/tri1:带下拉/上拉电阻的线性,没有驱动时,会有默认值0/1,一半可综合代码不用。
  • 寄存器类型:用于过程赋值语句(always,initial)描述组合逻辑/时序逻辑
    • reg d1;
    • d1<=din;//时序逻辑 d1 =din;//组合逻辑
    • 除了wire/tri0/tri1外的其他数据类型,基本都属于寄存器类型,只能用于过程赋值语句;
      • real 类似于float
      • interger //等价reg [31:0]
      • time/realtime

4.数据类型

  • 一维标量类型(常量)
    • 整数型(需要明确指定数据位宽):位宽代表转化为二进制数的位宽,达不到高位补0,多的,高位截断

      16'd100 //10进制表示的“100”

      16'h64 //16进制表示的“100”

      16'b0110_0100 //2进制表示的“100”

    • 实数型(可综合verilog不用)

    • 字符型(每个字符按8bit ASCII码的整型存储)

      “verilog” //占56bit

  • 一维标量类型(变量)
    • 整数型(需要明确指定数据位宽

Verilog学习笔记_第6张图片

 

  •          实数型(目前不可综合)
  • 多维标量类型(变量)

Verilog学习笔记_第7张图片

{}是用来合并的

  • 片选

在 assign 赋值操作中,如果等号左右两侧信号的位宽不同,那么就会进行截断或者补零操作。

  • 左侧信号位宽大于右侧信号位宽,右值的低位赋予左值对应的低位,左值高位的部分赋零
  • 左侧信号位宽小于右侧信号位宽,右值的低位赋予左值对应的低位,右值高位的部分直接被截断。即保留右值的低位。

使用 [] 可以对信号进行片选,选择信号中特定几位比特,以下是一些片选的例子。

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]    // Z 最低两位
b[3:0]      // 如果 b 在声明时 声明为 wire [0:3] b;则不能使用 b [3:0]进行选择
b[0:3]      // b的高四位.
assign w[3:0] = b[0:3];    // 将 b 的高位赋予 w 的低位 w[3]=b[0], w[2]=b[1], etc.

5. 运算符

  • 按bit位逻辑操作:&(and), |(or), ^(xor),~(inv)
  • 按整体运算:&&,||,!,==,! =, 返回值为0/1
  • 条件运算符(三目运算符) 描述MUX ?:
  • bit位选择[]/拼接{} a[0 +:8] 从0开始向上取8位,等价于a[7:0]
  • 算术运算符:+,-,*,<,>,< =,> =,**/,% (**慎用)

6.条件语句

  • if-else
if begin

end
  • case/casez/casex(casez/casex非必要不用)
case(*)
3'b001: out = 0;
...
end case

7.module 功能模块构建

  • 对于需要instance的模块,input 只能是wire,output可以是wire/reg

Verilog学习笔记_第8张图片

8.杂项

四、Verilog描述组合逻辑

1.MUX(多路选择器)

module mux4to1(s,d,y);
  input wire[1:0] s;
  input wire[3:0] d;
  output reg y;
  always @(*) begin
    case (s[1:0])
      2'd0:y = d[0];
      2'd1:y = d[1]; 
      2'd2:y = d[2];  
      default: y = d[3];
     endcase
   end
 endmodule

对应的电路图如下:

Verilog学习笔记_第9张图片

2.带有优先级的多路选择器(4选1)

module mux4to1(din,d,dout);
  input wire[1:0] din;
  input wire[3:0] d;
  output reg dout;
  always @(*) begin
     if(din[2])
       dout = d2;
     else if(din[1])
       dout = d1;
     else if(din[0])
       dout = d0;
      else dout= d3;
   end
 endmodule

Verilog学习笔记_第10张图片

3.译码器

  • N-2^N译码器

    独热码:每次只有一位输出。

  • 3-8译码器

module dec_3to8(
  din ,
  dout
 );
 input wire [2:0] din;
 ouput reg  [7:0] dout;

always @(*) begin
  case(din)
  3'b000:dout = 8'h01;
  3'b001:dout = 8'h02;
  3'b010:dout = 8'h04;
  3'b011:dout = 8'h08;
  3'b100:dout = 8'h10;
  3'b101:dout = 8'h20;
  3'b110:dout = 8'h40;
  3'b111:dout = 8'h80;
  endcase
  
end
endmodule

Verilog学习笔记_第11张图片

4.可综合常用语法:组合逻辑

//实现输出a+b-c
wire clk,rstn;
wire [15:0]a,b,c;
wire [17:0]out0;
reg [17:0[ out1;

assign out0 = {2'b0,a}+{2'b0,b}-{2'b0,c}; //连续赋值语句

always @(*) begin   //过程赋值语句
//always @(a or b or c) begin
  out1 = {2'b0,a}+{2'b0,b}-{2'b0,c};
end

Verilog学习笔记_第12张图片

  • CSA(Carry Save Adder,进位保存加法器)

Verilog学习笔记_第13张图片

【HDL系列】进位保存加法器原理与设计 - 知乎

5.有符号数符号位扩展

  • 有符号数符号位扩展

工具会默认把wire数当作有符号数

wire [15:0] a,b; //singned number
wire [16:0] out0;
wire [16:0] out1;

assign out0 = {a[15],a}-{b[15],b}; //
assign out1 = a-b;                 //这种会出错

五、Verilog描述时序逻辑

  • 可综合常用语法:时序逻辑
//实现输出a+b-c
wire clk,rstn;
wire [15:0]a,b,c;
reg [17:0[ out2,out3; 

//1.同步复位
always @(posedge clk) begin
  if(!rstn)
    out2 <= 'd0;
   else
    out2 <= {2'b0,a}+{2'b0,b}-{2'b0,c};
end

//2.异步复位
always @(posedge clk or negedge rstn) begin
  if(rstn)
    out3 <= {2'b0,a}+{2'b0,b}-{2'b0,c};
  else
    out3 <= 'd0;
end

[FPGA复位——同步复位和异步复位]https://www.jianshu.com/p/f2f78b4be64c

  • 同步复位等效电路

    顾名思义,同步复位就是指复位信号只有在时钟上升沿到来时,才能有效。否则,无法完成对系统的复位工作。

Verilog学习笔记_第14张图片

  • 异步复位等效电路

    它是指无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。

Verilog学习笔记_第15张图片

六、Verilog语句执行顺序

  • 连续赋值(assign)语句块,过程赋值(always,initial)语句块之间是并行执行的(只要触发条件满足,就开始执行)
连续赋值(assign x=y;):不能在过程块内使用;
过程阻塞性赋值(x=y;):只能在过程块中使用;
过程费阻塞性复制(x<=y):只能在过程块内使用。
  • 组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值,同一个模块中不要既用阻塞又用非阻塞

Verilog学习笔记_第16张图片

1.initial、always、assign

  • initial

    只能执行一次,在仿真一开始就执行,begin...end之间是顺序执行(非阻塞赋值除外)

initial
    begin
        语句1;
        语句2;
        ......
        语句n;
end
  • always

    always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。(非阻塞赋值除外)

    对于硬件综合来说,存在两种always块:

    组合逻辑:`always @(*)`
    
    时序逻辑:`always @(posedge clk)`
    

    时序always块也会像组合always块一样生成一系列的组合电路,但同时在组合逻辑的输出生成了一组触发器(或寄存器)。该输出在下一个时钟上升沿(posedge clk)后可见,而不是之前的立即可见。

always @ (event)
  [statement]

always @ (event) begin
  [multiple statements]
end
  • assign

    assign相当于连线,一般是将一个变量的值不间断地赋值给另一个变量,就像把这两个变量连在一起,所以习惯性的当做连线用,比如把一个模块的输出给另一个模块当输入。只能用于阻塞赋值。

    要更好的把握assign的使用,Verilog中有几个要点需要深入理解和掌握: - 在Verilog module中的所有过程块(如initial块和always块)、连续赋值语句(如assign语句)和实例引用都是并行的。在同一module中这三者出现的先后顺序没有关系。 - 只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于module的功能定义部分。 - 连续赋值assign语句独立于过程块,所以不能在always过程块中使用assign语句

2.非阻塞赋值的执行顺序

  • 所有过程赋值(always,initial)语句块中的非阻塞赋值(none blocking assignment:< =)是完全同时执行的
b<=a;
c<=b;
/*
clk0 b0=初值 c0也等于初值
clk1 b1=a c1=b0
clk2 b2=a c2=b1=a
*/

3.阻塞赋值的执行顺序

  • 在同一个过程赋值(always,initial)语句块中,阻塞赋值(blocking assignment:=)是顺序执行的。

Verilog学习笔记_第17张图片

  • 在同一个过程赋值(always,initial)语句块中,阻塞赋值的循序语法没有定义。

4.可综合code建议

  • 描述组合逻辑使用"="赋值;
  • 描述时序逻辑(DFF)使用"< ="赋值
  • #1(delay)可以用,但是综合会被忽略
  • 不要在多个语句块中,对同一个变量赋值
  • 在一个always块内,该块的一次触发,对同一个信号最多只赋值一次

七.实际用处的电路

1.Edge检测

  • 上升沿检测

    • 波形图:
      • Verilog学习笔记_第18张图片

    • 电路结构:

      • Verilog学习笔记_第19张图片

    • 代码

wire clk,rstn;
wire din;
reg  din_dly;
wire pulse;

assign pulse = din & (!din_dly);

always @(posedge clk or negedge rstn)
if(!rstn)
  din_dly <= 1'b0;
else
  din_dly <= din;

2.全加器

assign sum = a ^ b ^ cin;

assign cout = a&b | a&cin | b&cin;

<--> 
{cout,sum} = a + b + cin;

常见的错误来源

1.如何避免引入锁存器

在设计电路时,必须首先具体考虑电路:

1、我想实现一个逻辑门;

2、我想实现一个具有输入并产生输出的组合逻辑块;

3、我想实现一组组合逻辑,紧接着一组触发器。

不要上来就写代码,这样往往与你想象的电路相差很远。

除了你指定的情况以外,会发生些什么,答案是什么也不会发生,输出保持不变。而这往往就导致了电路的错误,所以说语法正确的代码不一定能产生合理的电路(组合逻辑+触发器)。

输出保持不变,这就意味着电路需要记住当前状态,从而产生锁存器。组合逻辑(比如逻辑门)不能记住任何状态。

你可能感兴趣的:(日常记录,IC,学习,fpga开发,单片机)