FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Diplomacyを使ってOCPバスを作成する(6. Delayerの実装)

Diplomacyを使ってOCPバスを作成している。OCP SRAMの動作を確認しつつ、OCPのDelayerを実装しようと思う。DelayerというのはバスのReady信号を遅らせて、信号を遅らせてバスの問題を検出するための機能だ。

TileLinkのDelayerはすでに実装されている。これはLFSRを使ってReady信号を遅らせる機構となっている。

  • chisel-hw/src/main/scala/ocp/Delayer.scala
    def feed[T <: Data](sink: DecoupledIO[T], source: DecoupledIO[T], noise: T) {
      val allow = UInt((q * 65535.0).toInt) <= LFSRNoiseMaker(16, source.valid)
      sink.valid := source.valid && allow
      source.ready := sink.ready && allow
      sink.bits := source.bits
      when (!sink.valid) { sink.bits := noise }
    }

このfeed関数を使ってOCPの3つのチャネルを接続する。Valid信号が立ち上がっていないときは、Noise信号を挿入してバスをわざと乱すことでデバッグを行う。

    (node.in zip node.out) foreach { case ((in, _), (out, _)) =>
      val cmd_noise = Wire(in.cmd.bits)
      cmd_noise.mcmd    := LFSRNoiseMaker(3)
      cmd_noise.tagId   := LFSRNoiseMaker(cmd_noise.params.tagidBits)
      cmd_noise.address := LFSRNoiseMaker(cmd_noise.params.addressBits)

      val data_noise = Wire(in.data.bits)
      data_noise.tagId  := LFSRNoiseMaker(data_noise.params.tagidBits)
      data_noise.data   := LFSRNoiseMaker(data_noise.params.dataBits)

      val resp_noise = Wire(out.resp.bits)
      resp_noise.tagId := LFSRNoiseMaker(resp_noise.params.tagidBits)
      resp_noise.data  := LFSRNoiseMaker(resp_noise.params.dataBits)

      feed(out.cmd,  in.cmd,   cmd_noise)
      feed(out.data, in.data,  data_noise)
      feed(in.resp,  out.resp, resp_noise)
    }

これを使ってテストコードを作ってみよう。これまで通りMasterとSlaveの間に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
f:id:msyksphinz:20200205001425p:plain:w300
Delayerを挿入したOCP Diplomacy回路図

シミュレーションを実行して波形を表示してみた。上手く動作しているようだ。

make tilelink CONFIG=OCPUnitDelayerTestConfig
./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:20200205001502p:plain
Delayerを挿入したOCP回路 シミュレーション結果