Chisel/FIRRTL DefnameDifferentPortsException
Chisel/FIRRTL DefnameDifferentPortsException
我最近将我的一个大项目的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
中的测试中了解到它应该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:
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
。更改解决了问题。
此检查应该在引用特定 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))
我最近将我的一个大项目的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
中的测试中了解到它应该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:
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
。更改解决了问题。
此检查应该在引用特定 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))