Verilog for Design

设计人员知道写的RTL可以综合成么样的电路
设计人员对于硬件系统进行描述
验证人员搭建验证环境对设计人员描述的硬件系统进行验证
对Standcell,模拟/定制IP(USB PHY/SRAM等)进行行为级描述

1.寄存器

1.1 简单的寄存器

reg q

always @(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    q<=1'b0;
  else
    q<=d;
end

1.2 复杂寄存器

reg q;

always @(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    q <= 1'b0;
  else
    begin
      if(sel)
        q <= 1'd0;
      else
        q <= 1'd1;
    end
end

2.组合电路与时序电路

  • assign语句起到连接作用,当等号左侧数据变化的时候,等号右端的数据也会发生变化;与时序逻辑不同,时序逻辑需要在时钟上升沿的时候,才会进行数据同步

2.1 Module

  • module可以表示一个cell,一个单元甚至一个芯片
  • 每一个模块以module开始,有一个模块名,以endmodule结束
  • module中包含端口声明,数据类型定义,底层模块实例,行为描述等
  • 一个文件可以出现多个module/endmodule(不推荐使用这种方式,最好一个文件写一个module)

2.2 端口

  • 端口是模块与外界环境交互的接口(input,output,inout用的非常少)
  • 对于外部环境来讲,模块内部是不可见的,对于模块的调用只能通过端口进行
  • 端口需要进行声明,芯片内部一般不会使用inout

module dff(
  input wire clk;
  input wire rst_n;
  input wire d;
  output reg q;
  output reg qb; q端取反信号
);

加法器端口

2.3 数据类型

  • wire -- assign
  • reg -- always
    always@(posedge clk or negedge restn)产生的一定是寄存器,如果是always @(*) 产生的可能是组合逻辑不是寄存器
  • parameter -- 常量,通用模块的位宽,可以定义为参数
wire d;
wire [1:0] a_in;   // [MSB,LSB] -- [最高位,最低位]
reg q;
reg [1:0] sumout;

reg [1:0] mem[3:0];  // 四个存储位置,每个位置存2bit数据

2.4 实例化:instance

  • U_modulename作为例化名
  • 在使用例化的时候,以其作用进行命名,方便进行区分
  • 在实例化的时候,信号有两种方式,位置关联和名称关联,推荐使用名称关联的方式

  • 通过名称关联的方式进行例化,与位置没有关系

parameter

  • 多个parameter传递参数
module addr #(
parameter DW = 4
)(
  input wire [DW-1:0] a,
  input wire [DW-1:0] b,
  input wire [DW-1:0] c,
);

assign c = a + b;

endmodule

// 例化的时候

add #(.DW(16)) u_addr_exp(
  .a(),
  .b(),
  .c()
);

2.5 assign

  • 生成组合逻辑,连接输入与输出的关系
  • 对wire进行赋值,不定义数据类型默认为wire类型
  • 支持各种逻辑运算
assign c = a & b;
assign c = a + b;
assign c = sel ? (a & b) : (a + b);


module adder(
  input [1:0] a_in,
  input [1:0] b_in,
  output [1:0] sum_out,
  output c_out,
)

assign {c_out,sum_out} = a_in + b_in;

endmodule

2.5 always

  • 生成时序逻辑和组合逻辑
  • 对reg变量进行赋值
  • 支持各种逻辑运算
  • 与for,if..else,case.begin..end等同时使用
  • 在使用always语句写组合逻辑的时候,注意将敏感列表写全,将所有影响结果的变量都写到敏感列表中,推荐使用always @ (*)
// always 实现与时钟无关的逻辑-组合逻辑
assign c = sel ? (a & b) : (a + b);

always @ (*)
begin
  if(sel)
    c = a & b;
  else 
    c = a + b;
end


always @ (*)
begin
  case(sel)
    1'b1:c = a & b;
    1'b0:c = a + b;
  endcase
end

// 与时钟相关的逻辑,体现为寄存器

2.6 可综合性

  • 综合:基于特定的约束,把设计的高层次描述转换成门级网表的过程
  • 可描述:数据流,协议数据,运算;什么时候打拍,什么时候运算,控制流:协议控制,运算的控制等(FSM)

2.7 阻塞赋值和非阻塞赋值

  • = 阻塞赋值,在执行a = b,c = a的语句的时候,语句一局一局执行,将b的值给a之后,a的值改变之后,才能赋值给c
  • <= 非阻塞赋值,a<=b,c<=a,b赋值给a是非阻塞的,b的值还没有赋值给a的时候,a的值就会赋值给c,当某个时间点的时候一起赋值,假设开始a = 2,b = 1,执行结果后c = 2,a = 1,b赋值给a和a赋值给c同时进行,可以描述寄存器
  • 时序电路-->非阻塞赋值;逻辑电路-->阻塞赋值

3.常见错误

(1)多驱动(Multiple drives)
在不同的always和assign语句中,对与同一个变量,赋值了不同变量,同一时间,变量在等式左边只能出现一次

assign a = c + b;
assign a = c - b;   // assign 语句是并发执行的,产生多驱动问题

always @(*) begin  // always语句也是并发的,会产生多驱动问题
  if(sel)
    d = a;
  else
    d = b;
end

always @(*) begin
  if(sel)
    d = a1;
  else
    d = b1;
end

(2) 端口未定义(Port not declare)

adder u_addr_exp(
  .a(),
  .b(),
  .c(),
  .d()   // 没有声明d端口会进行报错
);

(3)阻塞赋值和非阻塞赋值进行混用
时序逻辑使用非阻塞赋值(<=)
组合逻辑使用阻塞赋值(=)

(4)变量未声明Object not be declared

(5)缺失分号Miss ;

(6)缺少endmodule
(7)Procedure assignment error
(8)Continuous assignment error:wire/reg定义不匹配
(9)Previously declared:多次定义
(10)Too few instance port connextion:例化时少了一些port
(11)Wire has no fanin/fanout:信号不驱动来源或者不驱动任何信号

wire a1;  // wire has no fanin
// assign a1 = a;  

(12)Width mismatch:信号位宽不匹配

4.APB_Slave design

  • ARM研发的AMBA提供一种机制实现RISC处理器与其他IP核和外设的集成,AMBA2.0标准定义了APB AHB ASB,AHB用于高性能,高时钟频率的系统模块,APB用于低速外设
    13-Verilog for  Design-小白菜博客
    13-Verilog for  Design-小白菜博客
    13-Verilog for  Design-小白菜博客

4.1 接口

13-Verilog for  Design-小白菜博客
13-Verilog for  Design-小白菜博客

4.2 读写使能

4.3 行为描述

13-Verilog for  Design-小白菜博客
13-Verilog for  Design-小白菜博客

总结

从Design的视角来解读Verilog:硬件思维VS软件思维

  • always块之间是并发执行的,没有先后顺序
  • assign也是并发执行的,没有先后顺序

AHB中为什么需要使用mux将master的输出选出来?
AHB在同一时间只有一个master获得总线控制权,在Arbiter仲裁之后,只有一个Master发送请求,那么为什需要mux选通master,master1输出信号,并且不是三态(0,1,z(高阻))的信号,AHB不是三态总线,虽然master2没有被授权控制总线,但是输出的信号仍然存在,所有一定需要使用mux
13-Verilog for  Design-小白菜博客
三态总线
输出可以有三种状态0,1,z(高阻),对于三态总线不需要使用mux,如果master没有授权,就输出一个高阻