6.2. SoCs with NoC-based Interconnects

The primary way to integrate a network-on-chip into a Chipyard SoC is to map one of the standard TileLink crossbar-based buses (System Bus, Memory Bus, Control Bus, etc.) to a Constellation-generated NoC.

The interconnect can be mapped as a “private” interconnect for the TileLink bus, in which case a dedicated interconnect to carry the bus traffic will be generated. Alternatively, the interconnect can be mapped to a shared global interconnect, in which case multiple TileLink buses can be transported over a single shared interconnect.

6.2.1. Private Interconnects

An example of integrating dedicated private interconnects for the System Bus, Memory Bus, and Control Bus can be seen in the MultiNoCConfig of generators/chipyard/src/main/scala/config/NoCConfigs.scala.

class MultiNoCConfig extends Config(
  new constellation.soc.WithCbusNoC(constellation.protocol.SimpleTLNoCParams(
    constellation.protocol.DiplomaticNetworkNodeMapping(
      inNodeMapping = ListMap(
        "serial_tl" -> 0),
      outNodeMapping = ListMap(
        "error" -> 1, "ctrls[0]" -> 2, "pbus" -> 3, "plic" -> 4,
        "clint" -> 5, "dmInner" -> 6, "bootrom" -> 7, "clock" -> 8)),
    NoCParams(
      topology = TerminalRouter(BidirectionalLine(9)),
      channelParamGen = (a, b) => UserChannelParams(Seq.fill(5) { UserVirtualChannelParams(4) }),
      routingRelation = NonblockingVirtualSubnetworksRouting(TerminalRouterRouting(BidirectionalLineRouting()), 5, 1))
  )) ++
  new constellation.soc.WithMbusNoC(constellation.protocol.SimpleTLNoCParams(
    constellation.protocol.DiplomaticNetworkNodeMapping(
      inNodeMapping = ListMap(
        "L2 InclusiveCache[0]" -> 1, "L2 InclusiveCache[1]" -> 2,
        "L2 InclusiveCache[2]" -> 5, "L2 InclusiveCache[3]" -> 6),
      outNodeMapping = ListMap(
        "system[0]" -> 0, "system[1]" -> 3,  "system[2]" -> 4 , "system[3]" -> 7,
        "serial_tl_0" -> 0)),
    NoCParams(
      topology        = TerminalRouter(BidirectionalTorus1D(8)),
      channelParamGen = (a, b) => UserChannelParams(Seq.fill(10) { UserVirtualChannelParams(4) }),
      routingRelation = BlockingVirtualSubnetworksRouting(TerminalRouterRouting(BidirectionalTorus1DShortestRouting()), 5, 2))
  )) ++
  new constellation.soc.WithSbusNoC(constellation.protocol.SimpleTLNoCParams(
    constellation.protocol.DiplomaticNetworkNodeMapping(
      inNodeMapping = ListMap(
        "Core 0" -> 1, "Core 1" -> 2,  "Core 2" -> 4 , "Core 3" -> 7,
        "Core 4" -> 8, "Core 5" -> 11, "Core 6" -> 13, "Core 7" -> 14,
        "serial_tl" -> 0),
      outNodeMapping = ListMap(
        "system[0]" -> 5, "system[1]" -> 6, "system[2]" -> 9, "system[3]" -> 10,
        "pbus" -> 3)),
    NoCParams(
      topology        = TerminalRouter(Mesh2D(4, 4)),
      channelParamGen = (a, b) => UserChannelParams(Seq.fill(8) { UserVirtualChannelParams(4) }),
      routingRelation = BlockingVirtualSubnetworksRouting(TerminalRouterRouting(Mesh2DEscapeRouting()), 5, 1))
  )) ++
  new freechips.rocketchip.rocket.WithNBigCores(8) ++
  new freechips.rocketchip.subsystem.WithNBanks(4) ++
  new freechips.rocketchip.subsystem.WithNMemoryChannels(4) ++
  new chipyard.config.AbstractConfig
)

Note that for each bus (Sbus / Mbus / Cbus), the configuration fragment provides both a parameterization of the private NoC, as well as a mapping between TileLink agents and physical NoC nodes.

For more information on how to construct the NoC parameters, see the Constellation documentation.

6.2.2. Shared Global Interconnect

An example of integrating a single global interconnect that supports transporting multiple TileLink buses can be seen in the SharedNoCConfig of generators/chipyard/src/main/scala/config/NoCConfigs.scala.

class SharedNoCConfig extends Config(
  new constellation.soc.WithGlobalNoC(GlobalNoCParams(
    NoCParams(
      topology        = TerminalRouter(HierarchicalTopology(
        base     = UnidirectionalTorus1D(10),
        children = Seq(HierarchicalSubTopology(1, 2, BidirectionalLine(5)),
                       HierarchicalSubTopology(7, 2, BidirectionalLine(5))))),
      channelParamGen = (a, b) => UserChannelParams(Seq.fill(22) { UserVirtualChannelParams(4) }),
      routingRelation = NonblockingVirtualSubnetworksRouting(TerminalRouterRouting(HierarchicalRouting(
        baseRouting = UnidirectionalTorus1DDatelineRouting(),
        childRouting = Seq(BidirectionalLineRouting(),
                           BidirectionalLineRouting()))), 10, 2)
    )
  )) ++
  new constellation.soc.WithMbusNoC(constellation.protocol.GlobalTLNoCParams(
    constellation.protocol.DiplomaticNetworkNodeMapping(
      inNodeMapping = ListMap(
        "Cache[0]" -> 0, "Cache[1]" -> 2, "Cache[2]" -> 8, "Cache[3]" -> 6),
      outNodeMapping = ListMap(
        "system[0]" -> 3, "system[1]" -> 5,
        "ram[0]" -> 9))
  )) ++
  new constellation.soc.WithSbusNoC(constellation.protocol.GlobalTLNoCParams(
    constellation.protocol.DiplomaticNetworkNodeMapping(
      inNodeMapping = ListMap(
        "serial_tl" -> 9, "Core 0" -> 2,
        "Core 1" -> 10, "Core 2" -> 11, "Core 3" -> 13, "Core 4" -> 14,
        "Core 5" -> 15, "Core 6" -> 16, "Core 7" -> 18, "Core 8" -> 19),
      outNodeMapping = ListMap(
        "system[0]" -> 0, "system[1]" -> 2, "system[2]" -> 8, "system[3]" -> 6,
        "pbus" -> 4))
  )) ++
  new freechips.rocketchip.rocket.WithNBigCores(8) ++
  new freechips.rocketchip.subsystem.WithNBanks(4) ++
  new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++
  new chipyard.config.AbstractConfig
)

Note that for each bus, the configuration fragment provides only the mapping between TileLink agents and physical NoC nodes, while a separate fragement provides the configuration for the global interconnect.

For more information on how to construct the NoC parameters, see the Constellation documentation.