Diplomacyを使ったデザインでは、クロスバーを使って自由にバスを構成することができる。この場合のバスのIDは自動的に計算されるようになっている。例えば、クロスバーに対して4つのマスターが接続される場合、そしてそのマスターのIDのビット幅が最大で3ビットである場合、
- マスター0 :
2'b00, sourceId_0[ 2: 0]
- マスター1 :
2'b01, sourceId_1[ 2: 0]
- マスター2 :
2'b10, sourceId_2[ 2: 0]
- マスター3 :
2'b11, sourceId_3[ 2: 0]
のようにバスが構成される。この計算を行っているのはXbar.scalaである。さっそく解析してみる。
rocket-chip/src/main/scala/tilelink/Xbar.scala
class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parameters) extends LazyModule { val node = TLNexusNode( clientFn = { seq => seq(0).copy( minLatency = seq.map(_.minLatency).min, clients = (TLXbar.mapInputIds(seq) zip seq) flatMap { case (range, port) => port.clients map { client => { client.copy(sourceId = client.sourceId.shift(range.start) ) }} } ) },
このsourceId
にはそれぞれのマスターが取りうるIDの範囲が指定される。それぞれsourceId
の値を出力してみると以下のようになる。下記はTLPatternPusherによる例。TLPatternPusherはIDを使わないので、1つのIDしか使用されない。
sourceId = IdRange(3,4) sourceId = IdRange(2,3) sourceId = IdRange(1,2) sourceId = IdRange(0,1)
そしてTLXbarの出力側に付加するIDの計算を行う。
class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parameters) extends LazyModule { ... // Transform input bundle sources (sinks use global namespace on both sides) val in = Wire(Vec(io_in.size, TLBundle(wide_bundle))) for (i <- 0 until in.size) { val r = inputIdRanges(i) if (connectAIO(i).exists(x=>x)) { in(i).a <> io_in(i).a in(i).a.bits.source := io_in(i).a.bits.source | UInt(r.start) } else { in(i).a.valid := Bool(false) io_in(i).a.ready := Bool(true) } ...
このときのr.start
とin(i).a.bits.source
の値を出力してみる。
TLXbar A channel r.start = 3 TLXbar A channel after = UInt<2>(Wire in TLXbar) TLXbar A channel r.start = 2 TLXbar A channel after = UInt<2>(Wire in TLXbar) TLXbar A channel r.start = 1 TLXbar A channel after = UInt<2>(Wire in TLXbar) TLXbar A channel r.start = 0 TLXbar A channel after = UInt<2>(Wire in TLXbar)
2ビットのsourceId
が生成され、さらにIDがr.start
により割り当てられる。
さらに、多くのIDを扱うためのTLFuzzerを接続するとどうなのか?
sourceId = IdRange(96,128) sourceId = IdRange(64,96) sourceId = IdRange(32,64) sourceId = IdRange(0,32) TLXbar A channel r.start = 96 TLXbar A channel after = UInt<7>(Wire in TLXbar) TLXbar A channel r.start = 64 TLXbar A channel after = UInt<7>(Wire in TLXbar) TLXbar A channel r.start = 32 TLXbar A channel after = UInt<7>(Wire in TLXbar) TLXbar A channel r.start = 0 TLXbar A channel after = UInt<7>(Wire in TLXbar)
r.start
はinputIdRanges(i)
から生成されている。
... for (i <- 0 until in.size) { val r = inputIdRanges(i) ...