admin 管理员组

文章数量: 887021

Verilog 之并行,串行,数据类型,操作符号等相关基础归纳

本文为相关读书笔记,做个人理解之用

文章目录

    • 组合逻辑电路与时序逻辑电路
    • 同步时序逻辑和异步时序逻辑
    • Verilog并行语句
    • Verilog 串行语句
    • Verilog 数据类型
    • Verilog的操作符号

组合逻辑电路与时序逻辑电路

组合逻辑: 数字电路满足任意时刻的输出仅仅取决于该时刻的输入;

时序逻辑: 数字电路任意时刻的输出取决于当前输入以及电路原有的状态;

时序逻辑电路中肯定有组合逻辑的成分存在, 组合逻辑不能有时序逻辑的功能;

同步时序逻辑和异步时序逻辑

时序逻辑按信号间关系分为同步时序逻辑和异步时序逻辑,简称同步逻辑,异步逻辑;

异步逻辑中肯定由同步逻辑存在,

同步时序逻辑

狭义: 一个时钟信号驱动的设计, 所有的记忆元素(寄存器, RAM, Latch)都被同一个时钟信号驱动,输出同时变化;

广义: 允许数字电路中存在多个时钟,但其之间存在固定的因果关系,或其驱动的记忆单元在电路上完全隔离;

异步时序逻辑

异步时序逻辑电路 — 输入输出端口不全来自或导入一个时钟或若干具备因果的时钟所驱动的记忆元素;

Verilog并行语句

module中的语句部分都是并行的,并行语句如下:

module <module_name>(<port_list>);<verilog 连续赋值语句>;<verilog 程序块语句>;<verilog 实例化语句>;<verilog 生成语句>;<verilog 函数调用语句>;<verilog 模块说明语句>;
endmodule
  • 连续赋值语句

    assign a = 1'b1;
    //简写:
    wire a = 1'b1;assign a = sel ? b : c;
    //简写:
    wire a = sel ? b : c;
    
  • 程序块语句

    always@(<sensitive_list>)
    begin: <lable><statements>;
    end
    //<labe> : 程序块标号
    //敏感列表边沿事件:
    //寄存器的一个时钟端口决定一个always敏感量表只能有一个时钟的一个边沿事件********;
    //异步复位的边沿事件其实是电平敏感事件;
    
    • 纯组合逻辑always

      只使用非阻塞 “=” 赋值符号;

      敏感量表不能使用posedge / negedge 关键字;

      敏感量表可以为 “*”,交由编译器推断;

    • 纯时序always

      没有什么注意的,遵循正常使用语法即可;

      always@( <edge_type> clk)
      begin<statements>
      end
      //使用阻塞赋值 <=
      
    • 具有同步复位的always

      always@( <edge_type> clk)
      beginif(!rst_n)<statements>;else<statements>;
      end
    • 具有异步复位的always

      always@( <edge_type> clk,<edge_type> rst)
      beginif(rst)<statements>;else<statements>;
      end
      //注意敏感量列表中的异步复位信号必须注明为沿事件, 因为敏感量表一旦出现沿事件(时钟沿事件),就不允许出现描述组合逻辑的信号事件;
      
  • 实例化语句

    • 单独实例化

      正常的子模块例化语法,类似 类和对象的用法;

      模块输出只能连接线网, 输入连接 寄存器 和线网;

    • 数组实例化

      应用于一个模块多次的场景,语法如下:

      <module_name> <instance_name> <instance_array_range>
      (.<port_name_0> <variable_0>,.<port_name_1> <variable_1>,.<port_name_n> <variable_n>
      );//实例
      wire [3:0] a,b,c;
      module1 inst_module[3:0] 
      (.in0(a),.in1(b),.out(c)
      );
      //相当于:
      module1 inst_1 (.in0(a[3]),.in1(b[3]),out(c[3]));
      module1 inst_2 (.in0(a[2]),.in1(b[2]),out(c[2]));
      module1 inst_3 (.in0(a[1]),.in1(b[1]),out(c[1]));
      module1 inst_4 (.in0(a[0]),.in1(b[0]),out(c[0]));
      //上述端口也可公用信号

      使用数字实例化时要注意输入的变量位宽等于多有实例对应位宽之和或等于模块对应的位宽;

    • 实例参数重载

      对参数进行修改的动作;

      1. 内部重载

        实例化时进行对参数进行修改, 比较常用;

        module_1 #.(.<parameter_name> (name_value),...)
        inst_moudle_1(.a(a),.b(b));
        
      2. 外部重载

        允许才编译的时候在修改参数的值;

        module_1 inst_module_1(.a(a),.b(b));
        defparam inst_module_1.parameter_name = value;
        
    • 端口赋值形式

      1. 映射赋值

        常用使用形式

        wire a,b,c;
        module_0 inst(.in0(a),.in1(b),.out(c));
        
      2. 位置赋值

        wire a,b,c;
        module_0 inst(a,b,c);
        
      3. 部分赋值

        wire a,b,c;
        module_0 inst(.in0(a),.out(c));
        module_0 inst(a,,c); //此时必须按照端口位置使用","进行占位
        
      4. 常数赋值

        //只能应用于输入端口
        wire a,b,c;
        module_0 inst(.in0(a),.in1(1'b1),.out(c));
        
      5. 表达式赋值

        wire a,b,c;
        module_0 inst(.in0(a),.in1(~a),.out(c));
        
  • 生成语句

    • 循环生成

      genvar a;
      generatefor(a = 0; a < 100;a = a + 1)begin:<lable> //此处的begin 不能省略<statement>;//可以时实例化语句也可以是连续赋值语句end
      endgenerate
      //for 循环可以嵌套
      //举例:
      input [3:0] a,b;
      output [3:0] c,d;
      generate
      genvar i;for(i = 0;i < 4;i = i + 1)begin: test_genmodule_1 inst(.a(a[i]),.b(b[i]),.c(c[i]));assign d[i] = a[i];end
      endgenerate
      

      变量必须用genvar进行定义;

      必须给循环段起一个名字,

    • 条件生成

      作用于编译器行为,根据初始参数决定载入哪部分代码进行编译;参数再修改后必须进行重新编译并不支持动态选择;

      generateif(<condition>)begin:<lable_1><code>; 			           endelse if(<condition>)begin:<lable_2><code>;endelsebegin;<lable_3><code>;endend
      
  • 函数调用语句

    function [<lower>:<upper>] <output_name>;input <name>;<other inputs><variable declarations>begin<statements> end
    endfunction
    //<output_name>即是输出的变量名也是函数调用名, 其位宽由前面的范围决定;
    //<variable declarations>只能声明寄存器类型的变量
    //函数体中只能使用 阻塞赋值
    //函数调用中只能使用位置赋值, 并严格遵守input顺序
    //函数调用在串行语句和并行语句中均可;
    //函数中可以调用别的函数;
    //递归函数用于仿真;
    //函数不能调用task;
    //尽量在仿真中使用函数为不是功能模块中;
    
  • 模块说明语句

    specify<参数定义><时序检查选项><模块中的组合逻辑管教到管脚的时间延迟><模块中的时序逻辑时钟相关的时间延迟><条件延迟语句, 类似条件生成语句>
    endspecify
    

Verilog 串行语句

FPGA设计思路并行, module中仅支持并行语句的调用, 同时一些并行语句中的子语句可以顺序执行;

always@(...)
begin<verilog阻塞赋值语句>;<verilog非阻塞赋值语句>;<verilog条件语句>;<verilog循环语句>;<verilog等待语句>;<verilog函数调用语句>;<verilog任务调用语句>;
end
  • Verilog 阻塞赋值语句

    理解为变量对应FPGA硬件中的连线, 执行规则为等待赋值行为结束后在会开始执行下一条程序;

  • verilog非阻塞赋值语句

    理解为变量对应FPGA中寄存器等存储记忆单元,执行规则为赋值行为未完成之前就开始执行下一条程序;

  • Verilog 条件语句

    为典型串行语句

    • 带优先级语句

      if(<condition>) //逻辑门最少
      begin<statement>; 
      end
      else if(<condition>)
      begin<statement>;
      end
      else
      begin<statement>;
      end        
      

      优先级越高的分支应设置概率最大的条件仪优化仿真效率等;

    • 无优先级条件语句

      case(<expression>)<constant-valuel>:begin<statement>;end<constant-value2>:begin<statement>;end<constant-value3>:begin<statement>;end<other>default:begin<statement>;end
      //<constant_value> 值必须不同
      //分支必须完全覆盖
      //硬件实现为多路复用器, 数据路径等长
      //casex , casez可以实现不关心位   
      

verilog循环语句

除for循环之外的while , repeat, forever基本用于仿真激励;

integer <var>;
for(<var> = <initial_value>;<val> <= <final_value>,<val> = <val> + 1)
begin<statement>;
end
//一般别用, 使用时不要进行功能表述, 只进行结构描述,确保编译器能给出对应的实现电路;

verilog等待语句

  • 事件等待语句

    @(<edge> <variable> or <edge> <variable> or...)
    //每个always程序块必是一个事件等待语句;
    //事件等待语句可以存在于always块中, 主要用于仿真;
    
  • 直接时间等待语句

    # <time to delay>
    //只能用于仿真
    
  • 表达式等待语句

    wait (<expression>);
    //只能用于仿真 (该描述绝对化)
    

verilog函数调用语句

与并行语句中类似;

verilog任务调用语句

task <task_name>;
input <input_name>;
input <input_more>;
output <output_name>;
output <output_more>;<variable declarations>
begin<statements>;
end
//多输入, 多输出
//变量只能声明寄存器类型
//任务调用只能在串行语句中;
//任务可以调用别的任务;
//任务在仿真情况下可以进行递归;
//任务可以调用函数;

Verilog 数据类型

Verilog 四值逻辑系统

逻辑1 : 表示逻辑高电平;

逻辑0 : 表示逻辑低电平;

不确定逻辑X : 表示不可推断电平, 一般由于赋值冲突导致;

高组逻辑Z : 表示高阻态, 断路;

寄存器数据类型

凡在程序块中被赋值的变量,都必须是寄存器类型,寄存器类型及其子类型如下:

  • reg
reg <range> <variable_name>; //range 不写默认 1bit
  • integer 整数类型 , 对应32位二进制表示 real 实数类型,一般不用
integer a; real a;

线网数据类型

  • wire
wire <range> <variable_name>;
  • tri 用法同wire . 需定义被三态门驱动的硬件连线时,用tri定义.表示这根线上会出现 Z状态;

  • supply1/ supply0

    分别表示强行上拉到1, 或强行下拉到0. 理解为电源线和地线. verilog中常当做常数使用;

  • wand / triand

    表示线与逻辑, 二者区别类似wire与tri;

  • wor / trior

    表示线或逻辑, 二者区别类似wire与tri;

  • tri1 / tri0 / trireg

    分别表示当连线被置为高阻态时, 进行上拉 , 下拉 , 保持前值,;

参数数据类型

  • parameter 定义module里的一些常量参数

    parameter a = 100,b = 3'b100, c = a + 100;
    
  • localparam 定义module里的一些参数,与parameter参数不同在于上层模块不能访问此参数

    //如下的使用形式可以实现上层对下层模块的修改
    parameter N = 100;
    localparam M = N + 1;
    
  • specparam 用于specify用来定义模块的时序模型 ;

数组

<type> <type_range> <array_name> <array_range>;
//定义一个32bit宽,512个元素的存储器
reg [31:0] array[511:0];
//数组的访问, 不能使用C语言类似的访问
wire [31:0] out;
assign out = array[256];
//数组的bit访问
wire [0:0] out_bit;
assign out_bit = out[31];

常量

  1. 二进制表示法
<bit_width>'b <constant in binary>
wire a ;
assign a = 1'b1;
wire [7:0] b;
assign b = 8'b11110000;
//设置高阻状态
assign b = 8'bzzzzZZZZ;
//没有关于x的状态的常量赋值,因为X状态是由赋值冲突产生的,并不是由赋值产生;
  1. 八进制表示法
<bit_width>'o <constant in octonary>
wire [2:0] a;
assign a = 3'o5;  // o / O均可;
//高阻
wire [5:0] b;
assign b = 6'ozZ;//写两个,也可缺省
  1. 十进制表示法
<bit_width>'d <constant in decimal>
wire [7:0] a;
assign a = 8'd255;
//高阻
wire [15:0] b;
assign b = 16'dz;//只能写1个 
  1. 十六进制表示法
<bit_width>'d <constant in hexadecimal>
wire [5:0] a;
assign a = 6'hFA;
assign a = 6'b11_1010;

整数

integer //也可使用 wire 和 reg
wire [7:0] q;
assign q = 128;
//不同于十进制表示法,负数可以如下:
assign a = -128;
assign a = 16'd-128;// error

Verilog的操作符号

  • Verilog 赋值运算符

    • 连续赋值符号 ,应用于线网类型
    assign <variable_name> = <expression>;input a;
    wire b;assign a = b;// 1
    wire a = b;	//  2
    //1 和2等价, 1称作显示地连续赋值, 2称为隐式的连续赋值, 
    
    • 阻塞赋值符号 =

      应用于组合逻辑, 只能操作线网类型的变量;

      语句执行为顺序执行,下条语句必须等待上条语句完成赋值之后再执行;

    • 非阻塞复制符号 <=

      应用于时序逻辑, 只能操作寄存器类型的变量;

      执行为顺序执行, 但是上条语句未完成赋值操作时就开始执行下条语句的执行, 即其值得传递只能跨越一个寄存器;

    • 映射赋值符号 " . "

      两个变量之间建立一种连接的关系

    • 位置赋值

      没有显示操作符号, 别用;

  • Verilog 按位运算符

    ~  逻辑非, 按位取反; 单目;
    &  逻辑与, 按位取与; 双目; 
    |  逻辑或, 按位取或; 双目;
    ^  逻辑异或 , 按位异或; 双目;
    ~^ 逻辑同或 , 按位同或;
    
  • Verilog 归约运算符

    注意 : 规约运算所有结果均为 1bit

    &   : 归约与 , 按位从低到高相与;
    ~&  : 归约与非 , 按位从低到高相与后去反;
    |   : 归约或 ,按位从低到高进行逻辑或;
    ~|  : 归约或非,对归约或的结果进行逻辑反;
    ^   : 归约异或, 
    ~^  : 归约异或非;
    //与按位运算符区别在于(以异或为例):
    //按位运算符:
    wire [7:0] a,b,c;
    assign a = 8'hF1;
    assign b = 8'h1F;
    assign c = a ^ b; //c = 8'bEE;
    //归约运算符:
    wire [3:0] a
    wire b;
    assign a = 4'h7;
    assign b = ^a; // b =1'b1;
    
  • Verilog 算术运算符

    parameter a =  2 ** 3; //a = 8 ; 尽量别用
    // + - * / % 
    
  • Verliog 关系运算符

    ==  //相等
    === //全等 (包含 X, Z状态仅用于仿真)
    !=  //不等
    !== //不全等 (包含 X, Z状态仅用于仿真)
    <   //小于
    <=  //小于等于
    >   //大于
    >=  //大于等于
    
  • Verilog 逻辑运算符

    !  //逻辑反, 
    && //逻辑与,双目 , 同为true返回true, 否则false
    || //逻辑或 , 同为 false 返回 false, 否则 true
    
  • Verilog 迭代连接运算符

    显示符号为 : “{}”

    • 连接功能
    wire a = 1'b1;
    wire [2:0] b = 3'b011;
    wire [3:0] c = {a,b}; //c = 4'b1011
    
    • 迭代功能
    wire [1:0] a = 2'b10;
    wire [7:0] b = {4{a}}; // b = 8'b10101010 = {a,a,a,a}
    
    • 混合功能
    wire a = 1'b1;
    wire [2:0] b = 3'b011;
    wire [7:0] c = {{5{a}},b}; //c = 8'b11111011
    wire [7:0] d = {2{a,b}};   //c = 8'b10111011
    
  • Verilog 移位运算符

    <<  //(无符号) 左移
    <<< //带符号左移
    >>  //(无符号) 右移
    >>> //带符号右移//类似C语言规则, 默认的wire, reg都理解为无符号数
    //integer 为有符号数, 左移: 左抛右补0, 右移: 右抛左补符号位
    //通常利用迭代符号完成相同功能;
    //移位是乘除法的实现基础
    
  • Verilog 条件运算符

    //显示符号 : "? :"
    //类似C语言的使用
    
  • Verilog 操作符的优先级

    //必要时查阅优先级表格
    //但是个人习惯必须按照逻辑使用 "()"确保逻辑准确性
    

本文标签: Verilog 之并行 串行 数据类型 操作符号等相关基础归纳