diff --git a/junctions/src/main/scala/addrmap.scala b/junctions/src/main/scala/addrmap.scala index 808ef5ee..5fa34483 100644 --- a/junctions/src/main/scala/addrmap.scala +++ b/junctions/src/main/scala/addrmap.scala @@ -30,14 +30,13 @@ trait HasAddrMapParameters { val pgLevelBits = p(PgLevelBits) val asIdBits = p(ASIdBits) - val addrMap = new AddrHashMap(p(GlobalAddrMap)) + val addrMap = new AddrHashMap(p(GlobalAddrMap), p(MMIOBase)) } abstract class MemRegion { def size: BigInt } case class MemSize(size: BigInt, prot: Int) extends MemRegion case class MemSubmap(size: BigInt, entries: AddrMap) extends MemRegion -case class MemChannels(size: BigInt, nchannels: Int, prot: Int) extends MemRegion object AddrMapConsts { val R = 0x1 @@ -68,7 +67,6 @@ class AddrMap(entries: Seq[AddrMapEntry]) extends scala.collection.IndexedSeq[Ad this map { entry: AddrMapEntry => entry.region match { case MemSize(_, _) => 1 case MemSubmap(_, submap) => submap.countSlaves - case MemChannels(_, nchannels, _) => nchannels }} reduceLeft(_ + _) } } @@ -77,12 +75,12 @@ object AddrMap { def apply(elems: AddrMapEntry*): AddrMap = new AddrMap(elems) } -class AddrHashMap(addrmap: AddrMap) { +class AddrHashMap(addrmap: AddrMap, start: BigInt) { val mapping = new HashMap[String, AddrHashMapEntry] - private def genPairs(am: AddrMap): Seq[(String, AddrHashMapEntry)] = { + private def genPairs(am: AddrMap, start: BigInt): Seq[(String, AddrHashMapEntry)] = { var ind = 0 - var base = BigInt(0) + var base = start var pairs = Seq[(String, AddrHashMapEntry)]() am.foreach { case AddrMapEntry(name, startOpt, region) => region match { @@ -94,32 +92,21 @@ class AddrHashMap(addrmap: AddrMap) { } case MemSubmap(size, submap) => { if (!startOpt.isEmpty) base = startOpt.get - val subpairs = genPairs(submap).map { + val subpairs = genPairs(submap, base).map { case (subname, AddrHashMapEntry(subind, subbase, subsize, prot)) => (name + ":" + subname, - AddrHashMapEntry(ind + subind, base + subbase, subsize, prot)) + AddrHashMapEntry(ind + subind, subbase, subsize, prot)) } pairs = subpairs ++ pairs ind += subpairs.size base += size } - // every channel gets the same base and size - case MemChannels(size, nchannels, prot) => { - if (!startOpt.isEmpty) base = startOpt.get - val subpairs = (0 until nchannels).map { i => - val chname = name + ":" + i.toString - (chname, AddrHashMapEntry(ind + i, base, size, prot)) - } - pairs = subpairs ++ pairs - ind += nchannels - base += size - } } } pairs } - for ((name, ind) <- genPairs(addrmap)) { mapping(name) = ind } + for ((name, ind) <- genPairs(addrmap, start)) { mapping(name) = ind } def nEntries: Int = mapping.size def apply(name: String): AddrHashMapEntry = mapping(name) @@ -133,15 +120,18 @@ class AddrHashMap(addrmap: AddrMap) { } def isValid(addr: UInt): Bool = { - sortedEntries().map { case (_, base, size, _) => - addr >= UInt(base) && addr < UInt(base + size) + addr < UInt(start) || sortedEntries().map { + case (_, base, size, _) => + addr >= UInt(base) && addr < UInt(base + size) }.reduceLeft(_ || _) } def getProt(addr: UInt): AddrMapProt = { - Mux1H(sortedEntries().map { case (_, base, size, prot) => - (addr >= UInt(base) && addr < UInt(base + size), - new AddrMapProt().fromBits(Bits(prot, 3))) - }) + val protBits = Mux(addr < UInt(start), + Bits(AddrMapConsts.RWX, 3), + Mux1H(sortedEntries().map { case (_, base, size, prot) => + (addr >= UInt(base) && addr < UInt(base + size), Bits(prot, 3)) + })) + new AddrMapProt().fromBits(protBits) } } diff --git a/junctions/src/main/scala/nasti.scala b/junctions/src/main/scala/nasti.scala index 0baa463d..579ef6f4 100644 --- a/junctions/src/main/scala/nasti.scala +++ b/junctions/src/main/scala/nasti.scala @@ -479,26 +479,6 @@ class NastiCrossbar(nMasters: Int, nSlaves: Int, routeSel: UInt => UInt) } } -object NastiMultiChannelRouter { - def apply(master: NastiIO, nChannels: Int)(implicit p: Parameters): Vec[NastiIO] = { - if (nChannels == 1) { - Vec(master) - } else { - val dataBytes = p(MIFDataBits) * p(MIFDataBeats) / 8 - val selOffset = log2Up(dataBytes) - val selBits = log2Ceil(nChannels) - // Consecutive blocks route to alternating channels - val routeSel = (addr: UInt) => { - val sel = addr(selOffset + selBits - 1, selOffset) - Vec.tabulate(nChannels)(i => sel === UInt(i)).toBits - } - val router = Module(new NastiRouter(nChannels, routeSel)) - router.io.master <> master - router.io.slave - } - } -} - class NastiInterconnectIO(val nMasters: Int, val nSlaves: Int) (implicit p: Parameters) extends Bundle { /* This is a bit confusing. The interconnect is a slave to the masters and @@ -517,10 +497,8 @@ abstract class NastiInterconnect(implicit p: Parameters) extends NastiModule()(p } class NastiRecursiveInterconnect( - val nMasters: Int, - val nSlaves: Int, - addrmap: AddrMap, - base: BigInt = 0) + val nMasters: Int, val nSlaves: Int, + addrmap: AddrMap, base: BigInt) (implicit p: Parameters) extends NastiInterconnect()(p) { var lastEnd = base var slaveInd = 0 @@ -530,13 +508,16 @@ class NastiRecursiveInterconnect( addrmap.zipWithIndex.foreach { case (AddrMapEntry(name, startOpt, region), i) => val start = startOpt.getOrElse(lastEnd) val size = region.size - realAddrMap(i) = (start, size) - lastEnd = start + size require(bigIntPow2(size), s"Region $name size $size is not a power of 2") require(start % size == 0, f"Region $name start address 0x$start%x not divisible by 0x$size%x" ) + require(start >= lastEnd, + f"Region $name start address 0x$start%x before previous region end") + + realAddrMap(i) = (start, size) + lastEnd = start + size } val routeSel = (addr: UInt) => { @@ -567,10 +548,6 @@ class NastiRecursiveInterconnect( o <> s slaveInd += subSlaves } - case MemChannels(_, nchannels, _) => - require(nchannels == 1, "Recursive interconnect cannot handle MultiChannel interface") - io.slaves(slaveInd) <> xbarSlave - slaveInd += 1 } } } @@ -585,69 +562,37 @@ class ChannelHelper(nChannels: Int) val blockOffset = selOffset + chanSelBits def getSelect(addr: UInt) = - addr(blockOffset - 1, selOffset) + if (nChannels > 1) addr(blockOffset - 1, selOffset) else UInt(0) def getAddr(addr: UInt) = - Cat(addr(nastiXAddrBits - 1, blockOffset), addr(selOffset - 1, 0)) + if (nChannels > 1) + Cat(addr(nastiXAddrBits - 1, blockOffset), addr(selOffset - 1, 0)) + else addr } -/** NASTI interconnect for multi-channel memory + regular IO - * We do routing for the memory channels differently from the IO ports - * Routing memory banks onto memory channels is done via arbiters - * (N-to-1 correspondence between banks and channels) - * Routing extra NASTI masters to memory requires a channel selecting router - * Routing anything to IO just uses standard recursive interconnect - */ -class NastiPerformanceInterconnect( - nBanksPerChannel: Int, - nChannels: Int, - nExtraMasters: Int, - nExtraSlaves: Int, - addrmap: AddrMap)(implicit p: Parameters) extends NastiInterconnect()(p) { +class NastiMemoryInterconnect( + nBanksPerChannel: Int, nChannels: Int) + (implicit p: Parameters) extends NastiInterconnect()(p) { val nBanks = nBanksPerChannel * nChannels - val nMasters = nBanks + nExtraMasters - val nSlaves = nChannels + nExtraSlaves - - val split = addrmap.head.region.size - val iomap = new AddrMap(addrmap.tail) - - def routeMemOrIO(addr: UInt): UInt = { - Cat(addr >= UInt(split), addr < UInt(split)) - } + val nMasters = nBanks + val nSlaves = nChannels val chanHelper = new ChannelHelper(nChannels) - def connectChannel(outer: NastiIO, inner: NastiIO) { outer <> inner outer.ar.bits.addr := chanHelper.getAddr(inner.ar.bits.addr) outer.aw.bits.addr := chanHelper.getAddr(inner.aw.bits.addr) } - val topRouters = List.fill(nMasters){Module(new NastiRouter(2, routeMemOrIO(_)))} - topRouters.zip(io.masters).foreach { - case (router, master) => router.io.master <> master - } - val channelRouteFunc = (addr: UInt) => UIntToOH(chanHelper.getSelect(addr)) - val channelXbar = Module(new NastiCrossbar(nExtraMasters, nChannels, channelRouteFunc)) - channelXbar.io.masters <> topRouters.drop(nBanks).map(_.io.slave(0)) - for (i <- 0 until nChannels) { /* Bank assignments to channels are strided so that consecutive banks * map to different channels. That way, consecutive cache lines also * map to different channels */ - val banks = (i until nBanks by nChannels).map(j => topRouters(j).io.slave(0)) - val extra = channelXbar.io.slaves(i) + val banks = (i until nBanks by nChannels).map(j => io.masters(j)) - val channelArb = Module(new NastiArbiter(nBanksPerChannel + nExtraMasters)) - channelArb.io.master <> (banks :+ extra) + val channelArb = Module(new NastiArbiter(nBanksPerChannel)) + channelArb.io.master <> banks connectChannel(io.slaves(i), channelArb.io.slave) } - - val ioslaves = Vec(io.slaves.drop(nChannels)) - val iomasters = topRouters.map(_.io.slave(1)) - val ioxbar = Module(new NastiRecursiveInterconnect( - nMasters, nExtraSlaves, iomap, split)) - ioxbar.io.masters <> iomasters - ioslaves <> ioxbar.io.slaves }