如何将TileLink节点导出为LazyModule输出并生成对应Verilog文件
如何正确导出TileLink客户端节点并解决Diplomacy报错?
我尝试创建一个带有TileLink客户端并连接到模块输出的简单模块,耗时20小时仍无法实现,以下是我的代码:
class ArmleoCoreTop extends Module { implicit val p = Parameters.empty val acore = LazyModule(new ArmleoCore()) val macore = Module(acore.module) val io = IO(acore.io_node.cloneType) acore.io_node <> io } class ArmleoCore()(implicit p: Parameters) extends LazyModule { val client = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( name = "ArmleoCore", sourceId = IdRange(0, 4), requestFifo = true, visibility = Seq(AddressSet(0x0000_0000, (BigInt(1) << 64) - 1))) )))) val io_node = InModuleBody { client.makeIOs() } lazy val module = new ArmleoCoreImpl(this) } class ArmleoCoreImpl(outer: ArmleoCore) extends LazyModuleImp(outer) { val (tl, edge) = outer.client.out(0) val (legal, a) = edge.Get(0.U, "h1000".U, 0x4.U) tl.a.bits := a val io = IO(new Bundle() { val legal = Output(Bool()) }) io.legal := legal } object ArmleoCoreDriver extends App { (new chisel3.stage.ChiselStage).emitVerilog(new ArmleoCoreTop(), args) }
运行后出现如下报错:
(run-main-29) java.lang.IllegalArgumentException: requirement failed: Diplomacy has detected a problem with your graph: [error] At the following node, the number of outward ports should equal the number of produced outward parameters. [error] source acore.client node: [error] parents: acore [error] locator: (src/main/scala/armleocpu/ArmleoCore.scala:11:25) [error] [error] 0 outward ports connected: [] [error] 0 inward ports connected: [] [error] [error] Downstreamed inward parameters: [] [error] Produced outward parameters: [TLMasterPortParameters(List(TLMasterParameters(ArmleoCore, IdRange(0,4), List(), List(AddressSet(0x0, 0xffffffffffffffff)), Set(), false, true, , TBALGFPH, false)), TLChannelBeatBytes(None,None,None,None), 0, List(), List(), List())]
问题原因
报错核心是TLClientNode声明了对外提供的Master参数,但既没有连接到下游节点,也没有正确导出为顶层IO,Diplomacy的图检查机制发现参数与实际连接端口数量不匹配,因此抛出错误。同时原代码的层级结构不符合LazyModule的使用规范(普通Module嵌套LazyModule)。
修正方案
以下是调整后的完整代码,关键修改点已标注:
import chisel3._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ // 顶层改为LazyModule,适配内部嵌套的LazyModule实例 class ArmleoCoreTop(implicit p: Parameters) extends LazyModule { val acore = LazyModule(new ArmleoCore()) // 将client节点转换为可导出的Sink端口 val tlSink = acore.client.makeSink() lazy val module = new Impl(this) class Impl(outer: ArmleoCoreTop) extends LazyModuleImp(outer) { // 导出顶层TileLink IO端口 val io = IO(new Bundle { val tl = Flipped(TLClientPort(tlSink.params)) }) // 连接Sink端口与顶层IO io.tl <> tlSink.node.io } } class ArmleoCore()(implicit p: Parameters) extends LazyModule { val client = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( name = "ArmleoCore", sourceId = IdRange(0, 4), requestFifo = true, visibility = Seq(AddressSet(0x0000_0000, (BigInt(1) << 64) - 1))) )))) lazy val module = new ArmleoCoreImpl(this) } class ArmleoCoreImpl(outer: ArmleoCore) extends LazyModuleImp(outer) { val (tl, edge) = outer.client.out(0) // 生成Get请求示例 val (legal, a) = edge.Get(0.U, "h1000".U, 0x4.U) tl.a.bits := a tl.a.valid := legal // 仅当请求合法时置位valid // 必须处理响应通道,避免未连接信号报错 tl.d.ready := true.B } object ArmleoCoreDriver extends App { implicit val p = Parameters.empty // 正确生成LazyModule对应的硬件模块 (new chisel3.stage.ChiselStage).emitVerilog(LazyModule(new ArmleoCoreTop()).module, args) }
关键修改说明
- 层级结构修正:
ArmleoCoreTop改为LazyModule,因为它内部包含LazyModule类型的acore,Diplomacy要求LazyModule必须嵌套在LazyModule中。 - 节点导出方式:使用
client.makeSink()将TLClientNode转换为可导出的端口节点,解决参数与端口数量不匹配的问题。 - 信号完整性:在
ArmleoCoreImpl中必须处理tl.d通道(设置ready),否则会出现未连接的硬件信号错误。 - 顶层生成规范:生成Verilog时需调用
LazyModule(...).module,获取LazyModule对应的实际硬件模块实例。
内容的提问来源于stack exchange,提问作者armleo
相关产品推荐
相关产品推荐

