我最近将我的一个大项目的 Chisel 版本从 3.1.1 更新到 3.4.0;但是,我得到了一堆 firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException
:
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 的定义及其依赖项:
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 实例化模板之一:
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
中的测试中了解到,如果 ExtModules 具有匹配的端口名称和宽度,但顺序不同,它应该抛出异常
,所以我试图使 Chisel BlackBox 中的输入顺序与 Verilog 模块中的输入顺序相同,但我仍然遇到异常。
测试 如果无参数 ExtModules 具有相同的端口但宽度不同则抛出异常
让我认为具有不同端口宽度的多个实例化可能是异常的原因,但还有另一个测试表明如果 ExtModules 有参数、匹配的端口名称但宽度不同,它应该不抛出异常
,这里就是这种情况,因为端口宽度由参数控制。
出现此异常的原因可能是什么?
更新:根据要求,这里是黑盒的两个实例化的 FIRRTL IR:
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
类型而不是 重置
。更改解决了问题。
最佳答案
此检查应该在引用特定 BlackBox 时禁止不可能的情况。即,以下必须为真:
- 如果BlackBox没有参数,那么所有端口必须有相同的名称、相同的宽度、相同的顺序
- 如果 BlackBox 有参数,那么所有端口必须有相同的名称和相同的顺序(但可以有不同的宽度)
听起来您的示例生成的 BlackBox 违反了后一个条件(因为您的 BlackBox 有参数),或者这暴露了 FIRRTL 编译器检查中的错误。
实际的 Verilog 模块从未经过检查,因此不会在此处造成任何问题。
您能否更新您的问题以提供产生这些错误的 FIRRTL IR?具体来说,XilinxSimpleDualPortNoChangeBRAM
和 XilinxSimpleDualPortNoChangeBRAM_1
的 FIRRTL IR 是什么样的?这应该在像“Foo.fir”这样的文件中。或者,您可以执行以下操作:
import chisel3.stage.ChiselStage
/* Note: this is emitChirrtl ("chirrtl") as you want the FIRRTL emitted from Chisel. */
println(ChiselStage.emitChirrtl(new MyTopModule))
关于凿子/FIRRTL DefnameDifferentPortsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64440617/