抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

记录一下上课和平时积累的

语法

verilog的语法相比其他语言比较少,用于描述硬件,要实现功能主要还是模块之间的组合

基本结构和语句要求

每个.v文件就是一个module,代码写再moduleendmoudule之间,moudule后跟模块名,以及模块的输入输出,模块内部实现功能。输入输出有两种写法,看自己习惯:

  • 放在括号内
1
2
3
module a(input a, b, output c, d);
...
endmodule
  • 放在括号外
1
2
3
4
5
module a(a,b,c,d);
input a,b;
output c,d;
...
endmodule

数据类型

  1. parameter:常量

    • 常量位宽和进制设置
    1
    parameter a = 3'b101
  2. reg:寄存器,主要在时序逻辑电路中,生成出来主要是D触发器

  3. wire:可以理解为线

  4. 设置位宽

1
reg [3:0] a

逻辑功能描述

  1. assign:如果逻辑能用一句话描述清楚可以使用assign语句

    1
    assign x = (b & ~c)
  2. always:如果逻辑比较复杂,使用always块描述

    • 敏感列表:在always @()中的括号里面,也就是该always块触发条件,常见的条件有:
      • posedge:信号上升沿
      • negedge:信号下降沿
      • *:所有,一般描述组合逻辑
    1
    2
    3
    4
    5
    6
    always @(posedge clk) begin // 每当时钟上升沿到来时执行
    if (load)
    out = data;
    else
    out = data + 1 + cin;
    end

关键字

关键字是实现定义好的符号

  1. 门结构

    • and/xand:与/与非
    • not:非
    • or/xor:或/或非
    • buf:
  2. 选择结构

    • if-else结构:综合出来一般带优先级,多级的选择结构
    1
    2
    3
    4
    if (load)
    out = data;
    else
    out = data + 1 + cin;
    • case结构

    • casex结构

  3. 其他

    • assign、always、while。。。等等

运算符

运算符 符号 功能
关系运算符 <,>,<=,>=... 和c语言一样
归约运算符和按位运算符 &、^、|、~| 一元运算符,归约运算,所有bit项相与;二元时,按位与
逻辑运算符 !、&&、|| 和c语言一样
位运算符 ~、&、|、^ 和c语言一样
移位运算 <<、>> 和c语言一样
条件运算符 ?: 和c语言一样(一般在assign语句中使用)
位拼接运算符 {,} 实现增长位宽的作用,将多个数据拼接,eg:d = {a, b, c};
算数运算 +、-、*、/、% 和c语言一样

模块化设计

常用的一些模块往往设计成一个module,其他模块里面可以直接调用,使用方法如下:

  1. 写好需要的module

  2. 在要用的模块里面实例化:对input和output进行连线,output只能连到wire类型的线上

    1
    2
    3
    4
    5
    6
    7
    /* 实例化,将线连接到自己的例程 */ 
    key_filter u_key_filter( // 模块名
    .clk (clk) , // 时钟输入信号
    .key (key) , // 复位信号,低电平有效
    .rst_n (rst_n) ,
    .key_out (key_out)
    );
  3. 如果当前文件是最终的,设置为顶层后再全部编译

技巧

  1. 可以把输出定义为wire,赋值使用reg,在外面用assignwire赋值

  2. 同步复位和异步复位:

    • 同步复位:复位信号和时钟同步(复位信号不在敏感列表)
    • 异步复位:只要有reset就复位,不和时钟同步,代码如下所示:
    1
    2
    3
    always @(negedge clk or posedge reset) begin
    ...
    end
  3. 找到公用电路,尽早实现(如选择)

其他默认规则

  1. ifcase语句:最好把所有状态描述完(写全),不然综合会出现锁存器(有些状态没描述,锁存上一次状态)

  2. always中赋值的变量,一定要定义为reg类型

  3. if-elseswitch-case更占空间,没优先级最好用switch-case

  4. 组合逻辑中一般用非阻塞赋值,也就是<=赋值

  5. 产生触发器不取决于reg,取决于敏感列表negedge clk

  6. D触发器的产生,敏感列表有edge,非阻塞赋值时,左边就是Q,右边就是D

    image-20220923160417850

常见模块

状态机

状态机可以实现基本所有功能

  1. 一般至少两个always块,实现组合和时序

多路复用器Multiplexer

  1. 画出原理图

    image-20220921151541434

  2. 写输入输出

    1
    2
    3
    module Mux8 (input sel, input [7:0] data1, data0, output [7:0] bus1);

    endmodule
  3. 写逻辑

    • 简单的
    1
    assign bus1 = sel ? data1: data0;
    • 复杂的
    1
    2
    3
    4
    5
    6
    7
    8
    always @(*)
    begin
    case(sel)
    0:
    1:
    default:
    endcase
    end
  4. 其他结构(带优先级的)

    image-20220921152341565

    • 代码实现
    1
    2
    3
    4
    5
    6
    always @(*)
    begin
    if();
    else if();
    else;
    end

编码器和译码器Encoder/Decoder

  1. 确定输入输出关系

  2. 代码实现

    • 确定输入输出
    1
    2
    3
    4
    5
    6
    7
    module Code42(F, I, en);
    output [1:0] F;
    input [3:0] I;
    input en;
    reg [1:0] t;
    assign F = en ? t : 2‘bz;
    endmodule;
    • 普通
    1
    2
    3
    4
    5
    6
    7
    8
    always @(I)
    begin
    case(I)
    1: t = 0;
    2: t = 1;
    default: t=0;
    endcase
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
       
    * 带优先级的(`if-else`)

    ```verilog
    always @ (I)
    begin
    if(I[3]) t = 2'b11;
    else if(I[2]) t = 2'b10;
    else t = 2'b00;
    end
  • 带优先级的(switch-case

    1
    2
    3
    4
    5
    6
    7
    8
    always @ (I)
    begin
    casex(Data)
    3'b1xx: t = 2'b11;
    3'b01x: t = 2'b10;
    default: t = 2'bx;
    endcase
    end

加法器

  1. 写真值表

  2. 代码描述

    • 普通
    1
    2
    3
    4
    module fulladder(input a, b, cin, output sum, cout);
    assign sum = a ^ b ^ cin;
    assign cout = (a & b) | (a & cin) | (b & cin);
    endmodule
    • 知道结构(结构化描述)

    image-20220921160512260

    1
    2
    3
    4
    5
    6
    module Add_half(sum, c_out, a, b);
    output sum, c_out;
    input a, b;
    xor(sum, c, b);
    and(c_out, a, b);
    endmodule
    • 用库实现
    1
    2
    3
    4
    5
    6
    7
    module Adder4(A, B, Cin, S, Cout);
    input [3:0] A, B;
    input Cin;
    output [3:0] S;
    output Cout;
    assign {Cout, S} = A + B + Cin;
    endmodule
    • 溢出(对有符号的数,判断最高位,也就是符号位是否出错)
    1
    2
    3
    4
    5
    6
    7
    8
    module Adder4(A, B, Cin, S, Cout, Ovout);
    input [3:0] A, B;
    input Cin;
    output S;
    output Cout, Ovout;
    assign {cout,S} = A + B + Cin;
    assign Ovout = (A[3]==B[3]) && (S[3]!=A[3]);
    endmodule

ALU

  1. 确定功能(四则运算?)

  2. 代码实现

    • 基本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    module ALU8(left, right, mode, ALUout);
    input [7:0] left, right;
    input [1:0] mode;
    output reg [7:0] ALUout;
    always @(left, right, mode)
    begin
    case (mode)
    2'b00: ALUout = A + B;
    2'b01: ALUout = A - B;
    2'b10: ALUout = A & B;
    2'b11: ALUout = A | B;
    default: ALUout = 8'bX;
    endcase
    end
    endmodule

触发器

  1. 确定功能
  2. 代码实现
1
2
3
4
5
6
7
8
9
module Flop (reset, clk, din, qout)
input reset, clk, din;
output qout;
reg qout;
always @(negedge clk) begin
if (reset) qout <= 1'b0;
else qout <= din;
end
endmodule

计数器

  1. 确定计数器的大小
  2. 代码实现
1
2
3
4
5
6
7
8
9
module Counter4 (reset, clk, count);
input reset, clk;
output [3:0] cout;
reg [3:0] cout;
always @(negedge clk) begin
if (reset) count <= 4'b00_00;
else count <= count + 1;
end
endmodule

移位寄存器

  1. 确定位数

  2. 代码实现

    • D触发器实现

      image-20220923160620707

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    module ShiftReg(A, E, clk, rst);
    output A;
    input E, clk, rst;
    reg B, C, D;
    always @(posedge clk or posedge rst) begin
    if (rst) begin
    A<=0; B<=0; C<=0; D<=0;
    end
    else begin
    A<=B; B<=C; C<=D; D<=E;
    end
    end
    endmodule
    • 通用移位寄存器(移位时,输出可以用bit0bit7
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    module ShiftRegister8(input s1, sr, clk,
    input [7:0] ParIn,
    input [1:0] m,
    output reg [7:0] Parout);
    always @(negedge clk) begin
    case (m)
    0: ParOut <= ParOut;
    1: ParOut <= {ParOut [6:0], sl};
    2: ParOut <= {sr, ParOut [7:1]};
    3: ParOut <= ParIn;
    default: ParOut <= 8'bX;
    endcase
    end
    endmodule

序列检测器

  1. 确定功能

    image-20220928144538311

  2. 代码实现

    • 状态机实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    module Detector (input a, clk, reset,
    output w);
    parameter [1:0] s0=2'b00, s1=2'b01, s2=2'b10, s3=2'b11; // 定义状态
    reg [1:0] current, next;
    always @(posedge clk) begin // 更新状态,时序逻辑
    if (reset) current <= s0;
    else current <= next;
    end
    always @(*) begin // 更新激励,组合逻辑
    next = s0; // 相当于defalut,覆盖所有情况(高阻之类的)
    case (current)
    s0: if (a) next = s1; else next = s0;
    s1: if (a) next = s2; else next = s0;
    s2: if (a) next = s2; else next = s3;
    s3: if (a) next = s1; else next = s0;
    endcase
    end
    assign w = (current == s3) ? 1 : 0; // 输出
    endmodule
    • 移位寄存器(检测111)

      • moore(输出是同步的)

        image-20220928150643255

      1
      2
      3
      4
      5
      6
      7
      8
      9
      module Seq_Rec_3_1s_Moore_Shft_Reg(output D_out, input clk, reset, Din, En);
      reg [2:0] current;
      always @(posedge clk) begin
      if (reset) current <= 3'b000;
      else if (En)
      else current <= {Din, current[2:1]};
      end
      assign D_out = (current == 3'b111) ? 1 : 0;
      endmodule
      • mealy(输出跟输入有关)

        image-20220928150735235

      1
      2
      3
      4
      5
      6
      7
      8
      module Seq_Rec_3_1s_Mealy_Shft_Reg(output D_out, input clk, reset, Din);
      reg [1:0] current;
      always @(posedge clk) begin
      if (reset) current <= 2'b00;
      else current <= {Din, current[1]};
      end
      assign D_out = ((current==2'b11) && Din) ? 1 : 0;
      endmodule

同步器

  1. 功能:将不同时钟域的时钟同步

    image-20220928153509576

    • 中间毛刺可能是竞争冒险导致的,一般不需要考虑(glitch)

    • 亚稳态:锁信号时,adata刚好发生改变,解决:

      • 低时钟域到高时钟域

      image-20220928154519566

      • 高时钟域到低时钟域(把输入当clk,保证了信号都能采到

      image-20220928154650892

  2. 实现

    • 普通同步器(采样一次)
    1
    2
    3
    4
    5
    module Synchronizer (input clk, adata,
    output reg synched);
    always @(posedge clk)
    synched <= adata;
    endmodule

vivado使用

创建工程和添加文件

  1. 打开vivado软件,可以看首页的Quick Start,点击Create Project进入创建工程界面

  2. 进入后选择路径,进入下一步,选择RTL Project,选择Do not ...(一般建好工程再添加文件)

    image-20220930142227230

  3. 选择芯片型号后,选择Finish,可以看到如下界面:

    image-20220930142714080

综合和分析

  1. Design Sources中添加源文件,完成代码编写

  2. 在右边框的综合中选择Run Synthesis

    image-20220930142936563

  3. Launch Runs弹窗选择ok即可

  4. Synthesis Completed看情况选择,如果不实施选择View Reports即可

  5. 完成后点击综合中的Schematic可以查看原理图

    image-20220930143349129

仿真

约束的输入

评论