首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >凿/FIRRTL DefnameDifferentPortsException

凿/FIRRTL DefnameDifferentPortsException
EN

Stack Overflow用户
提问于 2020-10-20 07:40:55
回答 1查看 140关注 0票数 3

我最近更新了我的一个大型项目的Chisel版本,从3.1.1升级到3.4.0;但是,我得到了一堆firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException

代码语言:javascript
复制
firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException: : ports of extmodule XilinxSimpleDualPortNoChangeBRAM with defname XilinxSimpleDualPortNoChangeBRAM are different for an extmodule with the same defname
firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException: : ports of extmodule XilinxSimpleDualPortNoChangeBRAM_1 with defname XilinxSimpleDualPortNoChangeBRAM are different for an extmodule with the same defname
// and so on 241 times

下面是XilinxSimpleDualPortNoChangeBRAM的定义及其依赖关系:

代码语言:javascript
复制
class XilinxSimpleDualPortNoChangeBRAM(width: Int,
                                       depth: Int,
                                       performance: String="HIGH_PERFORMANCE",
                                       initFile: String="",
                                       ramStyle: String="block",
                                       val useReset: Boolean=false)
                                       extends BlackBox(Map("RAM_WIDTH" -> width,
                                                            "RAM_DEPTH" -> depth,
                                                            "RAM_PERFORMANCE" -> performance,
                                                            "INIT_FILE" -> initFile,
                                                            "RAM_STYLE" -> ramStyle))
                                       with HasBlackBoxResource with Memory {
    val io = IO(new XilinxSimpleDualPortBRAMBlackBoxIO(log2Ceil(depth), width))
    val acceptedRamStyles = Seq("block", "distributed", "registers", "ultra")
    require(acceptedRamStyles contains ramStyle)
    def write(wrAddr: UInt, wrData: UInt, wrEn: Bool): Unit = {
      io.wea := wrEn
      io.addra := wrAddr
      io.dina := wrData
    }

    def read(rdAddr: UInt, rdEn: Bool): UInt = {
      io.addrb := rdAddr
      io.regceb := rdEn
      io.enb := rdEn
      io.doutb
    }

    def defaultBindings(clock: Clock, reset: core.Reset): Unit = {
      io.clock := clock
      if(useReset)
        io.reset := reset
      else
        io.reset := false.B
    }
    setResource("/XilinxSimpleDualPortNoChangeBRAM.v")
}

trait Memory extends BaseModule {
  def read(rdAddr: UInt, rdEn: Bool): UInt
  def write(wrAddr: UInt, wrData: UInt, wrEn: Bool): Unit
  val latency: Int = 2
}

class XilinxSimpleDualPortBRAMIO(addrWidth: Int, dataWidth: Int) extends Bundle {
    val addra  = Input(UInt(addrWidth.W))
    val addrb  = Input(UInt(addrWidth.W))
    val dina   = Input(UInt(dataWidth.W))
    val wea    = Input(Bool())
    val enb    = Input(Bool())
    val regceb = Input(Bool())
    val doutb  = Output(UInt(dataWidth.W))

    override def cloneType = (new XilinxSimpleDualPortBRAMIO(addrWidth, dataWidth)).asInstanceOf[this.type]
}
class XilinxSimpleDualPortBRAMBlackBoxIO(addrWidth: Int, dataWidth: Int) extends XilinxSimpleDualPortBRAMIO(addrWidth, dataWidth) {
    val clock  = Input(Clock())
    val reset  = Input(Reset())

    override def cloneType = (new XilinxSimpleDualPortBRAMBlackBoxIO(addrWidth, dataWidth)).asInstanceOf[this.type]
}

Verilog资源XilinxSimpleDualPortNoChangeBRAM.v是Vivado中可用的BRAM实例化模板之一:

代码语言:javascript
复制
module XilinxSimpleDualPortNoChangeBRAM #(
  parameter RAM_WIDTH = 64,                       // Specify RAM data width
  parameter RAM_DEPTH = 512,                      // Specify RAM depth (number of entries)
  parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY"
  parameter INIT_FILE = "",                       // Specify name/location of RAM initialization file if using one (leave blank if not)
  parameter RAM_STYLE = "block"                   // Target memory type. Accepted values: block, distributed, registers, ultra (UltraScale+ only)
) (
  input [clogb2(RAM_DEPTH-1)-1:0] addra, // Write address bus, width determined from RAM_DEPTH
  input [clogb2(RAM_DEPTH-1)-1:0] addrb, // Read address bus, width determined from RAM_DEPTH
  input [RAM_WIDTH-1:0] dina,          // RAM input data
  input wea,                           // Write enable
  input enb,                           // Read Enable, for additional power savings, disable when not in use
  input regceb,                        // Output register enable
  output [RAM_WIDTH-1:0] doutb,         // RAM output data
  input clock,                          // Clock
  input reset                          // Output reset (does not affect memory contents)
);

  (* ram_style = RAM_STYLE *) reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0];
  reg [RAM_WIDTH-1:0] ram_data = {RAM_WIDTH{1'b0}};

  // The following code either initializes the memory values to a specified file or to all zeros to match hardware
  generate
    if (INIT_FILE != "") begin: use_init_file
      initial
        $readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1);
    end else begin: init_bram_to_zero
      integer ram_index;
      initial
        for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1)
          BRAM[ram_index] = {RAM_WIDTH{1'b0}};
    end
  endgenerate

  always @(posedge clock) begin
    if (wea)
      BRAM[addra] <= dina;
    if (enb)
      ram_data <= BRAM[addrb];
  end

  //  The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register)
  generate
    if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register

      // The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing
       assign doutb = ram_data;

    end else begin: output_register

      // The following is a 2 clock cycle read latency with improve clock-to-out timing

      reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}};

      always @(posedge clock)
        if (reset)
          doutb_reg <= {RAM_WIDTH{1'b0}};
        else if (regceb)
          doutb_reg <= ram_data;

      assign doutb = doutb_reg;

    end
  endgenerate

  //  The following function calculates the address width based on specified RAM depth
  function integer clogb2;
    input integer depth;
      for (clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
  endfunction

endmodule

我试图查看抛出此异常的文件,CheckHighForm.scala,但是我很快就迷路了,因为我不知道应该寻找什么。

我从CheckSpec.scala中的测试中了解到,它应该是throw an exception if ExtModules have matching port names and widths, but a different order,所以我试图使Chisel BlackBox中的输入顺序与Verilog模块中的输入顺序相同,但我仍然得到了一个异常。

测试throw an exception if parameterless ExtModules have the same ports, but different widths使我认为具有不同端口宽度的多个实例化可能是异常的原因,但是还有另一个测试表明它应该NOT throw an exception if ExtModules have parameters, matching port names, but different widths,这是因为端口宽度是由参数控制的。

这一例外的原因是什么?

更新:根据请求,这是黑匣子的两个实例化的FIRRTL IR:

代码语言:javascript
复制
  extmodule XilinxSimpleDualPortNoChangeBRAM : 
    input addra : UInt<14>
    input addrb : UInt<14>
    input dina : UInt<1>
    input wea : UInt<1>
    input enb : UInt<1>
    input regceb : UInt<1>
    output doutb : UInt<1>
    input clock : Clock
    input reset : Reset
    
    defname = XilinxSimpleDualPortNoChangeBRAM
    parameter RAM_STYLE = "block"
    parameter RAM_WIDTH = 1
    parameter RAM_DEPTH = 16384
    parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE"
    parameter INIT_FILE = ""

  extmodule XilinxSimpleDualPortNoChangeBRAM_1 : 
    input addra : UInt<6>
    input addrb : UInt<6>
    input dina : UInt<518>
    input wea : UInt<1>
    input enb : UInt<1>
    input regceb : UInt<1>
    output doutb : UInt<518>
    input clock : Clock
    input reset : Reset
    
    defname = XilinxSimpleDualPortNoChangeBRAM
    parameter RAM_STYLE = "distributed"
    parameter RAM_WIDTH = 518
    parameter RAM_DEPTH = 64
    parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE"
    parameter INIT_FILE = ""

更新2:很明显,一些XilinxSimpleDualPortNoChangeBRAM正在选择一个较旧版本的XilinxSimpleDualPortBRAMBlackBoxIO,其中重置仍然是Bool类型而不是Reset类型。改变它解决了这个问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-20 14:29:22

当引用特定的BlackBox时,这种检查应该不允许出现不可能的情况。也就是说,以下情况必须是正确的:

如果

  • 没有参数,那么所有端口都必须具有相同的名称、相同的宽度,并且如果BlackBox有参数,则必须保持相同的
  • 顺序,那么所有端口都必须具有相同的名称和相同的顺序(但可能有不同的宽度)

听起来,您的示例要么生成违反后一个条件的BlackBoxes (因为您的BlackBoxes有参数),要么在FIRRTL编译器检查中暴露了一个错误。

实际的Verilog模块从未被检查过,在这里也不会造成任何问题。

您能否更新您的问题,以提供产生这些错误的FIRRTL IR?具体来说,用于XilinxSimpleDualPortNoChangeBRAMXilinxSimpleDualPortNoChangeBRAM_1的FIRRTL是什么样子的?这应该在像"Foo.fir“这样的文件中。或者,您也可以这样做:

代码语言:javascript
复制
import chisel3.stage.ChiselStage

/* Note: this is emitChirrtl ("chirrtl") as you want the FIRRTL emitted from Chisel. */
println(ChiselStage.emitChirrtl(new MyTopModule))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64440617

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档