如何使 Chisel 生成带启用的触发器?

Posted

技术标签:

【中文标题】如何使 Chisel 生成带启用的触发器?【英文标题】:How to make Chisel generate flip flops with enable? 【发布时间】:2017-01-12 11:32:02 【问题描述】:

我们正在实现一个处理器管道,并且想要一种有效的方法来停止它。如果我们可以控制电路,那么我们将使用具有启用输入的锁存器。要停止,只需禁用锁存器,然后它们不会在下一个时钟沿更新,它们将保持不变,直到再次启用。

但是,如何在 Chisel 中做到这一点?目前尚不清楚“何时”声明将转化为什么。对于幕后黑魔法的帮助,以及如何控制末端电路的提示将不胜感激。

【问题讨论】:

【参考方案1】:

when 语句本质上只是帮助构建多路复用树的简写方式。例如:

class SimpleWhen extends Module 
  val io = IO(new Bundle 
    val cond = Input(Bool())
    val a = Input(UInt(32.W))
    val b = Input(UInt(32.W))
    val z = Output(UInt(32.W))
  )

  when (io.cond)  io.z := io.a 
  .otherwise  io.z := io.b 

如果我们由此生成 Verilog,我们会得到(在 Chisel 3 中):

module SimpleWhen(
  input   clock,
  input   reset,
  input   io_cond,
  input  [31:0] io_a,
  input  [31:0] io_b,
  output [31:0] io_z
);
  wire  _T_11;
  wire [31:0] _GEN_1;
  assign io_z = _GEN_1;
  assign _T_11 = io_cond == 1'h0;
  assign _GEN_1 = _T_11 ? io_b : io_a;
endmodule

正如人们所预料的那样,这个模块基本上只是根据条件condab 之间多路复用。

关于启用寄存器的更有趣用例:

class RegEnableTest extends Module 
  val io = IO(new Bundle 
    val en = Input(Bool())
    val a = Input(Valid(UInt(32.W)))
    val b = Input(Valid(UInt(32.W)))
    val out = Output(UInt(32.W))
  )

  val regNext = Wire(UInt(32.W))
  val myReg = Reg(UInt(32.W))
  when (io.en)  myReg := regNext 
  regNext := myReg

  when (io.a.valid)  regNext := io.a.bits 
  when (io.b.valid)  regNext := io.b.bits 

  io.out := myReg

这里我们有一个寄存器myReg,它仅在输入en 为高电平时更新。生成的 Verilog 为:

module RegEnableTest(
  input   clock,
  input   reset,
  input   io_en,
  input   io_a_valid,
  input  [31:0] io_a_bits,
  input   io_b_valid,
  input  [31:0] io_b_bits,
  output [31:0] io_out
);
  wire [31:0] regNext;
  reg [31:0] myReg;
  reg [31:0] _GEN_1;
  wire [31:0] _GEN_0;
  wire [31:0] _GEN_2;
  assign io_out = myReg;
  assign regNext = _GEN_2;
  assign _GEN_0 = io_en ? regNext : myReg;
  assign _GEN_2 = io_b_valid ? io_b_bits : io_a_bits;
// ... Randomization removed for clarity ...
  always @(posedge clock) begin
    if (io_en) begin
      myReg <= regNext;
    end
  end
endmodule

myReg 仅在 io.en 为高电平时更新。使用 RegEnable (https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.RegEnable$) 可以使这段代码更加简洁

【讨论】:

这些捕获了功能,但问题是关于其他的。有使能触发器的本机电路实现。在这些中,启用是通过晶体管以更紧凑、更快速和更节能的方式实现的。问题是关于强制 Chisel 在综合过程中从代工厂库中选择这些特定的电路元件。如果 Chisel 使用多路复用器实现该功能,那么综合工具将无法发现它们可以使用更好的原生电路版本。 Chisel 以这样一种方式生成 Verilog,以便综合工具 可以 推断诸如启用的触发器之类的事情。在最近的rocket-chip (DefaultConfig) 运行中,我们发现 99% 的寄存器被合成(在教育过程中)作为门控寄存器。【参考方案2】:

这里是如何使用 RegEnable 来实现的,RegEnable 是构建启用寄存器的辅助对象: https://github.com/ucb-bar/chisel3/blob/master/src/main/scala/chisel3/util/Reg.scala

import chisel3._
import chisel3.util._

class RegEnableTest extends Module 
  val io = IO(new Bundle 
    val en = Input(Bool())
    val a = Input(Valid(UInt(32.W)))
    val b = Input(Valid(UInt(32.W)))
    val out = Output(UInt(32.W))
  )

  val regNext = Wire(UInt(32.W))
  val myReg = RegEnable(regNext,io.en)

  when (io.a.valid)  regNext := io.a.bits 
  when (io.b.valid)  regNext := io.b.bits 

  io.out := myReg

这会产生以下verilog(经过编辑以删除不需要的宏)

module RegEnableTest(
  input   clock,
  input   reset,
  input   io_en,
  input   io_a_valid,
  input  [31:0] io_a_bits,
  input   io_b_valid,
  input  [31:0] io_b_bits,
  output [31:0] io_out
);
  wire [31:0] regNext;
  reg [31:0] myReg;
  reg [31:0] _GEN_1;
  wire [31:0] _GEN_0;
  wire [31:0] _GEN_2;
  assign io_out = myReg;
  assign regNext = _GEN_2;
  assign _GEN_0 = io_en ? regNext : myReg;
  assign _GEN_2 = io_b_valid ? io_b_bits : io_a_bits;

  always @(posedge clock) begin
    if (io_en) begin
      myReg <= regNext;
    end
  end
endmodule

【讨论】:

【参考方案3】:

或者你可以这样做:

  val regNext = Wire(UInt(32.W))

  when (io.a.valid)  regNext := io.a.bits 
  when (io.b.valid)  regNext := io.b.bits 

  io.out := RegEnable(regNext,io.en)

但是状态在verilog代码中没有一个好名字

  assign io_out = _T_30;
  assign regNext = _GEN_1;
  assign _GEN_1 = io_b_valid ? io_b_bits : io_a_bits;
  assign _GEN_2 = io_en ? regNext : _T_30;

  always @(posedge clock) begin
    if (io_en) begin
      _T_30 <= regNext;
    end
  end
  endmodule

【讨论】:

以上是关于如何使 Chisel 生成带启用的触发器?的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL:如何启用模式中的所有触发器?

SQL Server:检查触发器是启用还是禁用?

Android pushwoosh:从通知(带触发器)启动应用程序时,如何避免显示“使用完成操作”对话框

启用文本框时如何触发新的验证?

如何使触发器与两个源表一起工作?

Sql Server 2016数据库生成带数据的脚本