以下の内容はhttps://msyksphinz.hatenablog.com/entry/2020/02/22/040000より取得しました。


Diplomacyを使ってOCPバスを作成する (8. PatternPusherの改良)

前回はDiplomacyを使ったOCPバスの作成で、Bundleを作成してValid/Readyの信号をCmd/Readyに変換した。次はこれに基づいてテスト環境を構築する。テスト環境ではまずはPatternPusherを使ってコマンドを挿入する。まずはPatternPusherを改造しなければ始まらない。

PatternPusherでは、これまでValid信号の判定に使っていた信号を、Cmdを使う方式に切り替える。

  • chisel-hw/src/main/scala/ocp/PatternPusher.scala
val (plegal, pcmds,   pbits) = pattern.map(_.bits  (edgeOut).getOrElse(edgeOut.NopCmd ())).unzip3
val (wlegal, wvalids, wbits) = pattern.map(_.wrdata(edgeOut).getOrElse(edgeOut.NopData())).unzip3

cmd.mcmd   := Mux(pcmds(step) =/= OCPMessages.NopCmd && io.run && !flight && ready && !end, pcmds(step), OCPMessages.NopCmd)
cmd.bits   := pbits(step)

pcmd(step)の作り方だが、パタンのビットフィールドから構築している。コマンドは以下の4種類を用意した。

  • WriteReqPattern : 書き込み要求。アドレスとデータサイズを指定する。データは含まれない。Cmdチャネルを使用する。
case class WriteReqPattern(address: BigInt, size: Int) extends Pattern
{
  def bits (edge: OCPEdgeOut) = Some(edge.Write(0.U, address.U))
  def wrdata (edge: OCPEdgeOut) = None
}
  • WriteDataPattern : 書き込みデータ要求。書き込みデータを指定する。Dataチャネルを使用する。
case class WriteDataPattern(data: BigInt) extends Pattern
{
  override def address = 0
  override def size = 0
  def bits (edge: OCPEdgeOut) = None
  def wrdata (edge: OCPEdgeOut) = Some(edge.WriteData(0.U, data.U))
}
  • ReadPattern : 読み込み要求。コマンドチャネルを指定する。
case class ReadPattern(address: BigInt, size: Int) extends Pattern
{
  def bits(edge: OCPEdgeOut) = Some(edge.Read(0.U, address.U))
  def wrdata (edge: OCPEdgeOut) = None
}
  • ReadExpectPattern : 読み込み要求。コマンドチャネルとレスポンスチャネルを使用する。データの比較を行う。
case class ReadExpectPattern(address: BigInt, size: Int, data: BigInt) extends Pattern
{
  def bits(edge: OCPEdgeOut) = Some(edge.Read(0.U, address.U))
  def wrdata (edge: OCPEdgeOut) = None
  override def dataIn = Some(data)
}

このedge.Write, edge.WriteData, edge.Readの作り方だが、これはEdges.scalaで記述している。

  • chisel-hw/src/main/scala/ocp/Edges.scala
class OCPEdgeOut(
  client:  OCPClientPortParameters,
  manager: OCPManagerPortParameters,
  params:  Parameters,
  sourceInfo: SourceInfo)
  extends OCPEdge(client, manager, params, sourceInfo)
{
  // Nop
  def NopCmd(): (Bool, UInt, OCPBundleCmd) = {
    val cmd = Wire(new OCPBundleCmd(bundle))
    cmd.tagId   := 0.U
    cmd.address := 0.U
    (true.B, OCPMessages.NopCmd, cmd)
  }

  // Accesses
  def Read(fromTagId: UInt, toAddress: UInt): (Bool, UInt, OCPBundleCmd) = {
    val cmd = Wire(new OCPBundleCmd(bundle))
    cmd.tagId  := fromTagId
    cmd.address := toAddress
    (true.B, OCPMessages.Read, cmd)
  }

  def Write(fromTagId: UInt, toAddress: UInt): (Bool, UInt, OCPBundleCmd) = {
    val cmd = Wire(new OCPBundleCmd(bundle))
    cmd.tagId   := fromTagId
    cmd.address := toAddress
    (true.B, OCPMessages.Write, cmd)
  }

  def NopData(): (Bool, Bool, OCPBundleData) = {
    val data = Wire(new OCPBundleData(bundle))
    data.tagId := 0.U
    data.data  := 0.U
    (true.B, false.B, data)
  }

  def WriteData(fromTagId: UInt, data: UInt): (Bool, Bool, OCPBundleData) = {
    val d = Wire(new OCPBundleData(bundle))
    d.tagId := fromTagId
    d.data  := data
    (true.B, true.B, d)
  }
}

コマンドチャネルを使用するメソッドの戻り値は、

  • Bool : 命令が有効か
  • UInt : コマンドを使用するか
  • OCPBundleCmd : コマンド発行に使用するビット群

データチャネルを使用するメソッドの戻り値は、

  • Bool : 命令が有効か
  • Bool : そのチャネルを本当に使用するか
  • OCPBundleData : データチャネルに使用するビット群

これに基づいてSRAMとDelayerの実装を変更して、テストを実行した。

  val pusher = LazyModule(new OCPPatternPusher("pat1", Seq(
    new WriteReqPattern(0x100, 0x2),
    new WriteDataPattern(0x012345678L),
    new WriteReqPattern(0x104, 0x2),
    new WriteDataPattern(0x0abcdef01L),
    new WriteReqPattern(0x108, 0x2),
    new WriteDataPattern(0x0deadbeefL),
    new WriteReqPattern(0x10c, 0x2),
    new WriteDataPattern(0x087654321L),
    new ReadExpectPattern(0x100, 0x2, 0x012345678L),
    new ReadExpectPattern(0x104, 0x2, 0x0abcdef01L),
    new ReadExpectPattern(0x108, 0x2, 0x0deadbeefL),
    new ReadExpectPattern(0x10c, 0x2, 0x087654321L)
  )))
  val ram = LazyModule(new OCPRAM(AddressSet(0x0, 0x3ff)))

  ram.node := OCPDelayer(0.01) := pusher.node

実行結果は、ただしく動作しているようだ。

./tilelink
Started UnitTest OCPUnitDelayerTest
Count = 1000
Resp Fired : same as expected. 12345678
Resp Fired : same as expected. abcdef01
Count = 2000
Resp Fired : same as expected. deadbeef
Resp Fired : same as expected. 87654321
f:id:msyksphinz:20200208141659p:plain
図. OCPでコマンドを発行し、SRAMから読みだした様子。



以上の内容はhttps://msyksphinz.hatenablog.com/entry/2020/02/22/040000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14