1

背景:大约一个月前,我开始使用 Chipyard,以便在 VCU118 上使用 RISC-V 内核构建快速原型。Chipyard 是完美的,但需要我加强并学习 Chisel 和 Rocket-chip 工具,以将互连扩展到我的设计。

第一个连接的硬件是赛灵思提供的 PCIe 到 AXI 桥接 IP,称为 XDMA。fpga-shells已经为这个 IP 提供了包装器、外壳和覆盖层,因此通过对 Chipyard 系统、HarnessBinders 和 IOBinders 的一些研究,我设法将它连接起来。叠加层是这样放置的:

val overlayOutput = dp(PCIeOverlayKey).last.place(PCIeDesignInput(wrangler=dutWrangler.node, corePLL=harnessSysPLL)).overlayOutput
    val (pcieNode: TLNode, pcieIntNode: IntOutwardNode) = (overlayOutput.pcieNode, overlayOutput.intNode)
    val (pcieSlaveTLNode: TLIdentityNode, pcieMasterTLNode: TLAsyncSinkNode) = (pcieNode.inward, pcieNode.outward)

有两个从站,但我只展示一个的 IOBinders 和 HarnessBinders。我假设我的另一个 Port mixin 运行正常,因为它与CanHaveMasterTLMMIO端口完全相同,但具有单独的键和不同的地址范围。我意识到这效率低下,但比创建外部总线更容易。这是 IOBinder,它利用CanHaveMasterTLMMIOPort将主 MMIO 端口引入系统总线。

class WithXDMASlaveIOPassthrough extends OverrideIOBinder({
    (system: CanHaveMasterTLMMIOPort) => {
        val io_xdma_slave_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mmio_tl)).suggestName("tl_slave_mmio")
        io_xdma_slave_pins_temp <> system.mmio_tl 
        (Seq(io_xdma_slave_pins_temp), Nil)

    }
})

我检索并连接 TestHarness 中的从节点,如下所示:

 val inParamsMMIOPeriph = topDesign match { case td: ChipTop => 
        td.lazySystem match { case lsys: CanHaveMasterTLMMIOPort => 
              lsys.mmioTLNode.edges.in(0)
        }
    }
 val inParamsControl = topDesign match {case td: ChipTop => 
        td.lazySystem match { case lsys: CanHaveMasterTLCtrlPort => 
            lsys.ctrlTLNode.edges.in(0)
        }
    }

 val pcieClient = TLClientNode(Seq(inParamsMMIOPeriph.master))
 val pcieCtrlClient = TLClientNode(Seq(inParamsControl.master))
 val connectorNode = TLIdentityNode()


 // pcieSlaveTLNode should be driven for both the control slave and the axi bridge slave
 connectorNode := pcieClient 
 connectorNode := pcieCtrlClient 
 pcieSlaveTLNode :=* connectorNode

最后,我将节点连接到线束绑定器。在这一步中,我遵循了在 Chipyard 中连接 DDR 的方式。

class WithPCIeClient extends OverrideHarnessBinder({
    (system: CanHaveMasterTLMMIOPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[HeterogeneousBag[TLBundle]]) => {
        require(ports.size == 1)
        th match { case vcu118th: FCMVCU118FPGATestHarnessImp => {
            val bundles = vcu118th.fcmOuter.pcieClient.out.map(_._1)
            val pcieClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
            pcieClientBundle <> DontCare // Some signals aren't being driven to this bundle, but it's hard to know how critical that is. Only happens when myPeripheral is on. 
            bundles.zip(pcieClientBundle).foreach{case (bundle, io) => bundle <> io}
            pcieClientBundle <> ports.head 
        } }
    }
})

我添加了pcieClientBundle <> DontCare以抑制这些未驱动的信号。这个问题只影响驱动到两个从机的信号。

信号如:

a.bits.user.amba_prot.fetch

a.bits.user.amba_prot.secure

a.bits.user.amba_prot.modifiable

a.bits.user.amba_prot.privileged

在两根电线中都没有被驱动(导致$RefNotInitializedExceptionFIRRTL 通过)。我知道这些来自,TLToAXI4但奇怪的是,只有当我将另一个外围设备连接到总线时,它们才会被驱动。该外设不会离开 ChipTop。它有三个主 AXI 总线连接到系统,如下所示:

( peirpheralMasterNode1         
        := TLBuffer(BufferParams.default)
        := TLWidthWidget(8) 
        := AXI4ToTL()
        := AXI4UserYanker(capMaxFlight=Some(16)) 
        := AXI4Fragmenter()
        := AXI4IdIndexer(idBits=3)
        := AXI4Buffer()
        := peripheralTop.Master1)
fbus.fromPort(Some("PERIPHERAL_MASTER_1"))() := peripheralMasterNode1

外围设备的 AXI Lite 从站是我怀疑问题所在。它的节点声明如下:

 val regCfgSlv = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
    slaves = Seq(AXI4SlaveParameters(
      address       = AddressSet.misaligned(0xf000E0000L, 0x1000L),
      resources     = regCfgDevice.reg("config"),
     // executable    = true, // Determines whether processor can execute from this memory.
      supportsWrite = TransferSizes(1, 4),
      supportsRead  = TransferSizes(1, 4),
      interleavedId = Some(0))),
  beatBytes = 4
  )))

它连接到系统总线使用toSlave

 sbus.toSlave(Some(portName)){
      (peripheralTop.regCfgSlv 
        := AXI4Buffer() 
        := AXI4UserYanker(capMaxFlight=Some(2))
        := TLToAXI4()
        // := TLWidthWidget(sbus.beatBytes))
        := TLFragmenter(4, 
                        p(CacheBlockBytes),
                       // sbus.beatBytes,
                        holdFirstDeny = true) 
        := TLWidthWidget(sbus.beatBytes))
    }

当我通过设置 myPeripheral 的密钥将这个 mixin 外围设备包含在我的配置中时,我收到关于两个 HarnessBinders 客户端捆绑 [ ]a.bits.user.amba_prot都没有驱动信号的错误。val pcieClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))当我只使用 myPeripheral 或 XDMA 之一时,它就$RefNotInitializedException消失了。

这是我的配置。我试过WithMyPeripheral四处走动无济于事。

class CustomRocketConfig extends Config(
  new WithPCIeMMIOPort ++  // add default external master port
  new WithControlPort ++ // add control port for pcie cfg. // TODO: Crossbar this on MMIO Port? Move both MMIO and Control to a port on System Bus?
  new freechips.rocketchip.subsystem.WithDefaultSlavePort ++ // add default external slave port
  new WithMyPeripheral(MyPeripheralParams()) ++ // Link up myPeripheral
  new freechips.rocketchip.subsystem.WithNBigCores(2) ++
  new freechips.rocketchip.subsystem.WithNExtTopInterrupts(3) ++
  new chipyard.config.AbstractConfig)
class WithPCIeTweaks extends Config (

    new WithPCIeClient ++ 
    new WithPCIeManager ++
    new WithPCIeCtrlClient ++  // Same for these harness binders - ME
    new WithXDMAMasterIOPassthrough ++ 
    new WithXDMASlaveIOPassthrough ++ 
    new WithXDMACtrlIOPassthrough  // I imagine these three IOBinders can be combined into one - ME



    //TODO: Probably need harness binder and io binder for interrupt if we use it
    )
class myRocketConfig extends Config (
    // new WithMyPeripheral(MyPeripheralParams()) ++ // Link up myPeripheral
    new WithPCIeTweaks ++ 
    new WithVCU118Tweaks ++
    new WithMyVCU118System ++ 
    new CustomRocketConfig 
)

我希望我的问题清晰而有趣。什么是a.user.amba_prot信号,为什么当我连接 XDMA 和外围设备时它们没有被驱动?为什么我可以声明其中之一myPeripheralXDMA,但是,当我连接两者时,这些信号没有驱动程序?我意识到这是一个困难的问题,在一个已经很少被查看的标签中有很多活动部件。如果您花时间阅读本文并提出建议,我们将非常感谢您的善意和专业知识。


编辑:我认为问题可能是 Test Harness 的外交区域和 ChipTop 的外交区域之间的参数协商失败。这是 XDMA 中的控制节点。

val control = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
    slaves = Seq(AXI4SlaveParameters(
      address       = List(AddressSet(c.control, c.ecamMask)),
      resources     = device.reg("control"),
      supportsWrite = TransferSizes(1, 4),
      supportsRead  = TransferSizes(1, 4),
      interleavedId = Some(0))), // AXI4-Lite never interleaves responses
    beatBytes = 4)))

这是系统看到的端口。

  val mmioTLNode = TLManagerNode(
    mmioPortParamsOpt.map(params =>
      TLSlavePortParameters.v1(
        managers = Seq(TLSlaveParameters.v1(
          address            = AddressSet.misaligned(params.base, params.size),
          resources          = device.ranges,
          executable         = params.executable,
          supportsGet        = TransferSizes(1, sbus.blockBytes),
          supportsPutFull    = TransferSizes(1, sbus.blockBytes),
          supportsPutPartial = TransferSizes(1, sbus.blockBytes))),
        beatBytes = params.beatBytes)).toSeq)

  mmioPortParamsOpt.map { params =>
    sbus.coupleTo(s"port_named_$portName") {
      (mmioTLNode
        := TLBuffer()
        := TLSourceShrinker(1 << params.idBits)
        := TLWidthWidget(sbus.beatBytes)
        := _ )
    }
  }

param.beatBytes当前设置为 8 ( site(MemoryBusKey).beatBytes)。但控制配置从节点为4。

4

1 回答 1

0

我已经确定了解决此错误的一种令人满意的方法。我对外交的理解在这里可能存在缺陷,所以如果这有助于某人制定更好的答案,我很想听听。

什么是a.user.amba_prot信号?

这些信号是 TL 和 AXI4 之间桥接协议的结果。如果主设备最初是 AXI4,则它具有标记为prot和的 ar 和 aw 通道信号cache

  • AxCACHE[0],可缓冲 (B) 位

  • AxCACHE[1],可缓存 (C) 位(这是“可修改”位)

  • AxCACHE[2],读取分配 (RA) 位

  • AxCACHE[3],写分配 (WA) 位

  • AxPROT[0],特权访问位

  • AxPROT[1],安全访问位

  • AxPROT[2],数据/指令访问位

这些信号从 AXI 主设备驱动到 AXI 从设备。

为什么我可以声明 myPeripheral 或 XDMA,但是,当我连接两者时,这些信号没有驱动程序?

使用 Chipyard 时需要牢记以下几点:Chipyard 系统是一个外交区域。测试工具是另一个。所以从Chipyard系统的角度来看,XDMA完全表现为TL连接。它有一个 TL 主机驱动它的从端口和一个 TL 从机在它的主端口上。这是因为XDMA在 PCIeOverlay 中使用外交将 AXI 节点连接到 Test Harness 外交区域内的 TileLink。系统的外交区域只能看到这些TileLink主从端口。当 AXI 主设备和从设备连接时,TileLink 客户端包现在需要amba_prot信号,因为系统可以看到它需要连接到 AXI 从设备。

解决方法是直接为XDMA. 通过这种方式,系统可以从 XDMA 看到 AXI 从属和主控,并且可以在系统端建立到 TL 的桥接。

于 2021-09-17T14:22:48.357 回答