FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

A short User Guide to Chisel勉強中(4)

f:id:msyksphinz:20170806234951p:plain

前回の続き。Chisel勉強中。

このページから。

github.com

パラメータ付き関数

Polymorphism and Parameterization · freechipsproject/chisel3 Wiki · GitHub

より一般的なMuxを定義するために、ビット長をパラメータ化する。

def Mux[T <: Bits](c: Bool, con: T, alt: T): T = { ... }

この場合、TはBitsのサブクラスである必要がある。

Mux(c, UInt(10), UInt(11))

パラメータ付きクラス

Polymorphism and Parameterization · freechipsproject/chisel3 Wiki · GitHub

パラメータ付き関数のように、クラスもパラメータ化することにより、再利用しやすくすることができる。 例えば、Filterクラスを一般化する。

class FilterIO[T <: Data](gen: T) extends Bundle { 
  val x = Input(gen)
  val y = Output(gen)
}

Filterクラスを、Linkの型をコンストラクタとして受け取るクラスとして定義することができる。

class Filter[T <: Data](gen: T) extends Module { 
  val io = IO(new FilterIO(gen))
  ...
}

一般化したFIFOは以下のように定義することができる。

class DataBundle extends Bundle {
  val a = UInt(32.W)
  val b = UInt(32.W)
}

class Fifo[T <: Data](gen: T, n: Int) extends Module {
  val io = IO(new Bundle {
    val enqVal = Input(Bool())
    val enqRdy = Output(Bool())
    val deqVal = Output(Bool())
    val deqRdy = Input(Bool())
    val enqDat = Input(gen)
    val deqDat = Output(gen)
  })
  val enqPtr     = Reg(init = 0.asUInt(sizeof(n).W))
  val deqPtr     = Reg(init = 0.asUInt(sizeof(n).W))
  val isFull     = Reg(init = false.B)
  val doEnq      = io.enqRdy && io.enqVal
  val doDeq      = io.deqRdy && io.deqVal
  val isEmpty    = !isFull && (enqPtr === deqPtr)
  val deqPtrInc  = deqPtr + 1.U
  val enqPtrInc  = enqPtr + 1.U
  val isFullNext = Mux(doEnq && ~doDeq && (enqPtrInc === deqPtr),
                         true.B, Mux(doDeq && isFull, false.B,
                         isFull))
  enqPtr := Mux(doEnq, enqPtrInc, enqPtr)
  deqPtr := Mux(doDeq, deqPtrInc, deqPtr)
  isFull := isFullNext
  val ram = Mem(n)
  when (doEnq) {
    ram(enqPtr) := io.enqDat
  }
  io.enqRdy := !isFull
  io.deqVal := !isEmpty
  ram(deqPtr) <> io.deqDat
}

kここで、DataBundle型を受け取る8要素を格納できるFIFOを以下のようにインスタンスすることができる。

val fifo = Module(new Fifo(new DataBundle, 8))

Ready/Validのインタフェースを以下のようにして一般化することができる。

class DecoupledIO[T <: Data](data: T) extends Bundle {
  val ready = Input(Bool())
  val valid = Output(Bool())
  val bits  = Output(data)
}

以下のようにデータのハンドシェークを定義する。

class DecoupledDemo extends DecoupledIO(new DataBundle)

こうして、FIFOインタフェースを以下のようにして簡単かすることができる。

class Fifo[T <: Data](data: T, n: Int) extends Module {
  val io = IO(new Bundle {
    val enq = Flipped(new DecoupledIO(data))
    val deq = new DecoupledIO(data)
  })
  ...
}

複数クロックドメイン

Multiple Clock Domains · freechipsproject/chisel3 Wiki · GitHub

Chisel3では、以下のように複数クロックをサポートすることができるようになった。 以下のように非同期のFIFOでデータの受け渡しを行うことができる。

class MultiClockModule extends Module {
  val io = IO(new Bundle {
    val clockB = Input(Clock())
    val stuff = Input(Bool())
  })

  // This register is clocked against the module clock.
  val regClock = RegNext(stuff)

  withClock (io.clockB) {
    // In this withClock scope, all synchronous elements are clocked against io.clockB.

    // This register is clocked against io.clockB.
    val regClockB = RegNext(stuff)
  }

  // This register is also clocked against the module clock.
  val regClock2 = RegNext(stuff)
}

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com