Diplomacyを使ってOCPのバスを作成するプロジェクト。PatternPusherウィジェットの次はSRAMを作成する。SRAMを定義することでクライアントとマネージャの両方を定義することで、やっと回路を構築することができるようになる。OCPのSRAMを定義してみよう。
SRAMはスレーブノードなので、OCPManegerNode
を使用することになる。TileLinkのSRAMをまずはそのまま流用する。
chisel-hw/src/main/scala/ocp/SRAM.scala
class OCPRAM( address: AddressSet, parentLogicalTreeNode: Option[LogicalTreeNode] = None, cacheable: Boolean = true, executable: Boolean = true, atomics: Boolean = false, beatBytes: Int = 4, ecc: ECCParams = ECCParams(), val devName: Option[String] = None, val dtsCompat: Option[Seq[String]] = None )(implicit p: Parameters) extends DiplomaticSRAM(address, beatBytes, devName, dtsCompat) { val node = OCPManagerNode(Seq(OCPManagerPortParameters( Seq(OCPManagerParameters( address = List(address), resources = device.reg("mem"), regionType = if (cacheable) RegionType.UNCACHED else RegionType.IDEMPOTENT, executable = executable, supportsGet = TransferSizes(1, beatBytes), supportsPutPartial = TransferSizes(1, beatBytes), supportsPutFull = TransferSizes(1, beatBytes), supportsArithmetic = if (atomics) TransferSizes(1, beatBytes) else TransferSizes.none, supportsLogical = if (atomics) TransferSizes(1, beatBytes) else TransferSizes.none, fifoId = Some(0))), // requests are handled in order beatBytes = beatBytes, minLatency = 1))) // no bypass needed for this device
supportsGet
とか全然使わないけど、とりあえずそのままTileLinkから持ってきて定義している。
中身の実装は以下のようになっている。ガバガバで全然OCPのプロトコルを守っていないが(それどころか連続でリクエストを持ってこられると普通にデータを失ってしまう)、まずはVerilogが生成できるところまで持って行きたい。
lazy val module = new LazyModuleImp(this) { val (in, edge) = node.in(0) val sram = Reg(Vec(256, UInt(32.W))) val cmd_addr = Reg(UInt(8.W)) when (in.cmd.valid && in.cmd.bits.mcmd === OCPMessages.Write) { cmd_addr := in.cmd.bits.address(7, 0) } when (in.cmd.valid && in.cmd.bits.mcmd === OCPMessages.Read) { in.resp.valid := true.B in.resp.bits.data := sram(in.cmd.bits.address) } .otherwise { in.resp.valid := false.B } when (in.data.valid) { sram(cmd_addr) := in.data.bits.data } in.cmd.ready := true.B in.data.ready := true.B }
スレーブノードを作成したので、次にマスターとスレーブを接続してOCPタイルを作ってみる。
chisel-hw/src/main/scala/ocp/OCPUnitTest.scala
class OCPUnitTest()(implicit p: Parameters) extends LazyModule { val pusher = LazyModule(new OCPPatternPusher("pat1", Seq( new WritePattern(0x100, 0x2, 0x012345678L), new WritePattern(0x500, 0x2, 0x0abcdef01L), new ReadExpectPattern(0x100, 0x2, 0x012345678L), new ReadExpectPattern(0x500, 0x2, 0x0abcdef01L) ))) val ram = LazyModule(new OCPRAM(AddressSet(0x0, 0x3ff))) ram.node := pusher.node lazy val module = new LazyModuleImp(this) with UnitTestModule { pusher.module.io.run := true.B io.finished := pusher.module.io.done } }
単純にOCPPatternPusher
とOCPSRAM
を接続しただけである。GraphMLを生成してみよう。
良さそうだ。しかし、Verilogを生成してみるとバスごと消されてしまっていた。。。これは要解析。
module OCPUnitTest( input clock, input reset, output io_finished ); wire pusher_clock; // @[OCPUnitTest.scala 18:26] wire pusher_reset; // @[OCPUnitTest.scala 18:26] wire pusher_io_done; // @[OCPUnitTest.scala 18:26] OCPPatternPusher pusher ( // @[OCPUnitTest.scala 18:26] .clock(pusher_clock), .reset(pusher_reset), .io_done(pusher_io_done) ); assign io_finished = pusher_io_done; // @[OCPUnitTest.scala 30:17] assign pusher_clock = clock; assign pusher_reset = reset;