Home Chisel笔记(二):使用Rocket-chip的TLXbar
Post
Cancel

Chisel笔记(二):使用Rocket-chip的TLXbar

Rocket-chip提供了非常多TileLink协议相关的模块,可以直接使用,但是rocket-chip并没有提供比较完善的文档可以参考。本节以Xbar为例,用一个小例子来说明如何使用rocket-chip中TileLink的模块。

本节参考的文档如下:

  1. Chipyard文档第9节:TileLink and Diplomacy Reference

  2. Rocket-chip中diplomacy相关的文档

我们首先创建主设备,如下所示。主设备每隔8个周期发送一次Get请求,且每次请求的地址递增8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyClient(implicit p: Parameters) extends LazyModule {
  val node = TLClientNode(
    Seq(
      TLMasterPortParameters.v1(
        clients = Seq(
          TLMasterParameters.v1(
            name        = "my-client"
          )
        )
      )
    )
  )

  lazy val module = new LazyModuleImp(this) {
    val (tl, edge) = node.out(0)
    dontTouch(tl)

    val cycle = RegInit(0.U(32.W))
    cycle := cycle + 1.U

    tl.a.valid := (cycle(2, 0) === 0.U)
    tl.d.ready := true.B

    val base       = RegInit("h20000".U(32.W))
    val (_, gbits) = edge.Get(0.U, base + cycle, 2.U)

    tl.a.bits := gbits
  }
}

接下来创建从设备,如下所示。从设备的地址基址作为一个参数传入,但范围固定。在TLSlaveParameters参数中我们可以指定从设备的一些性质,如地址范围、支持的请求类型等。该从设备只能接受Get请求,且d通道内返回的数据就是a通道内传过来的地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class MyManager(val base: BigInt)(implicit p: Parameters) extends LazyModule {
  val device    = new SimpleDevice("my-device", Seq("my-device0"))
  val beatBytes = 8
  val node = TLManagerNode(
    Seq(
      TLSlavePortParameters.v1(
        Seq(
          TLSlaveParameters.v1(
            address     = Seq(AddressSet(base, 0xff)),
            resources   = device.reg,
            regionType  = RegionType.UNCACHED,
            executable  = true,
            supportsGet = TransferSizes(1, beatBytes)
          )
        ),
        beatBytes = beatBytes
      )
    )
  )

  lazy val module = new LazyModuleImp(this) {
    val (tl, edge) = node.in(0)
    dontTouch(tl)

    tl.d.valid := tl.a.valid
    tl.a.ready := tl.d.ready

    tl.d.bits := edge.AccessAck(tl.a.bits, tl.a.bits.address)
  }
}

最后我们创建Top模块,演示如何使用Xbar,如下所示。我们有一个主设备和两个从设备,从设备地址范围分别为0x20000-0x200ff0x20100-0x201ff

1
2
3
4
5
6
7
8
9
10
11
12
13
class Top()(implicit p: Parameters) extends LazyModule {
  val xbar     = LazyModule(new TLXbar)
  val client0  = LazyModule(new MyClient)
  val manager0 = LazyModule(new MyManager(0x20000))
  val manager1 = LazyModule(new MyManager(0x20100))

  xbar.node := client0.node

  manager0.node := xbar.node
  manager1.node := xbar.node

  lazy val module = new LazyModuleImp(this) {}
}

以下是生成verilog与DAG的代码,生成的graphml文件可以通过yED打开查看,或者直接用yED Live在线平台查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
import chipsalliance.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util.HasRocketChipStageUtils

object Elaborate extends App with HasRocketChipStageUtils {
   override def main(args: Array[String]): Unit = {
    implicit val config = Parameters.empty
    val top = LazyModule(new Top())
    val verilog = chisel3.stage.ChiselStage.emitVerilog(top.module)
    writeOutputFile(".", "Top.v", verilog)
    writeOutputFile(".", "Top.graphml", top.graphML)
  }
}

测试方便起见,我们可以创建对应的Tester,在src/test/scala/Tester.scala,如下所示。之后我们只需要通过sbt test就可以直接进行仿真并生成波形,不过这种方式只适用于简单的测试,之后进一步的测试可能仍然需要自己写Verilator的测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import chipsalliance.rocketchip.config.Parameters
import chiseltest._
import freechips.rocketchip.diplomacy.LazyModule
import org.scalatest.flatspec.AnyFlatSpec

class Tester extends AnyFlatSpec with ChiselScalatestTester {
  it should "test" in {
    val annotation = Seq(
      VerilatorBackendAnnotation,
      WriteVcdAnnotation
    )

    test(LazyModule(new Top()(Parameters.empty)).module).withAnnotations(annotation) { tb =>
      tb.clock.step(400)
    }
  }
}
This post is licensed under CC BY 4.0 by the author.

Chisel笔记(一):Diplomacy

CMU 18-643可重构计算笔记-1:FPGA的三个时代