Get rid of NASTI memory interconnects
These were made for a previous Hurricane tapeout, but we are now doing all of the memory routing in TileLink, so they are no longer needed.
This commit is contained in:
		| @@ -1,109 +0,0 @@ | ||||
| package junctions | ||||
|  | ||||
| import Chisel._ | ||||
| import cde.Parameters | ||||
|  | ||||
| class NastiDemuxDriver(n: Int)(implicit p: Parameters) extends Module { | ||||
|   val io = new Bundle { | ||||
|     val start = Bool(INPUT) | ||||
|     val finished = Bool(OUTPUT) | ||||
|     val nasti = new NastiIO | ||||
|     val select = UInt(OUTPUT, log2Up(n)) | ||||
|   } | ||||
|  | ||||
|   val (s_idle :: s_write_addr :: s_write_data :: s_write_resp :: | ||||
|        s_read_addr :: s_read_resp :: s_done :: Nil) = Enum(Bits(), 7) | ||||
|   val state = Reg(init = s_idle) | ||||
|  | ||||
|   val select = Reg(init = UInt(0, log2Up(n))) | ||||
|  | ||||
|   when (state === s_idle && io.start) { state := s_write_addr } | ||||
|   when (io.nasti.aw.fire()) { state := s_write_data } | ||||
|   when (io.nasti.w.fire()) { state := s_write_resp } | ||||
|   when (io.nasti.b.fire()) { state := s_read_addr } | ||||
|   when (io.nasti.ar.fire()) { state := s_read_resp } | ||||
|   when (io.nasti.r.fire()) { | ||||
|     when (select === UInt(n - 1)) { | ||||
|       state := s_done | ||||
|     } .otherwise { | ||||
|       select := select + UInt(1) | ||||
|       state := s_write_addr | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   io.nasti.aw.valid := (state === s_write_addr) | ||||
|   io.nasti.aw.bits := NastiWriteAddressChannel( | ||||
|     id = UInt(0), | ||||
|     addr = UInt(0), | ||||
|     size = UInt("b011")) | ||||
|   io.nasti.w.valid := (state === s_write_data) | ||||
|   io.nasti.w.bits := NastiWriteDataChannel(data = select) | ||||
|   io.nasti.b.ready := (state === s_write_resp) | ||||
|   io.nasti.ar.valid := (state === s_read_addr) | ||||
|   io.nasti.ar.bits := NastiReadAddressChannel( | ||||
|     id = UInt(0), | ||||
|     addr = UInt(0), | ||||
|     size = UInt("b011")) | ||||
|   io.nasti.r.ready := (state === s_read_resp) | ||||
|  | ||||
|   io.finished := (state === s_done) | ||||
|   io.select := select | ||||
|  | ||||
|   assert(!io.nasti.r.valid || io.nasti.r.bits.data === select, | ||||
|     "NASTI DeMux test: Read data did not match") | ||||
| } | ||||
|  | ||||
| class NastiDemuxSlave(implicit p: Parameters) extends NastiModule()(p) { | ||||
|   val io = (new NastiIO).flip | ||||
|  | ||||
|   val (s_write_wait :: s_write_data :: s_write_resp :: | ||||
|        s_read_wait :: s_read_resp :: s_done :: Nil) = Enum(Bits(), 6) | ||||
|   val state = Reg(init = s_write_wait) | ||||
|  | ||||
|   val value = Reg(UInt(width = 64)) | ||||
|   val id = Reg(UInt(width = nastiXIdBits)) | ||||
|  | ||||
|   when (io.aw.fire()) { | ||||
|     id := io.aw.bits.id | ||||
|     state := s_write_data | ||||
|   } | ||||
|  | ||||
|   when (io.w.fire()) { | ||||
|     value := io.w.bits.data | ||||
|     state := s_write_resp | ||||
|   } | ||||
|  | ||||
|   when (io.b.fire()) { state := s_read_wait } | ||||
|  | ||||
|   when (io.ar.fire()) { | ||||
|     id := io.ar.bits.id | ||||
|     state := s_read_resp | ||||
|   } | ||||
|  | ||||
|   when (io.r.fire()) { state := s_done } | ||||
|  | ||||
|   io.aw.ready := (state === s_write_wait) | ||||
|   io.w.ready := (state === s_write_data) | ||||
|   io.b.valid := (state === s_write_resp) | ||||
|   io.b.bits := NastiWriteResponseChannel(id = id) | ||||
|   io.ar.ready := (state === s_read_wait) | ||||
|   io.r.valid := (state === s_read_resp) | ||||
|   io.r.bits := NastiReadDataChannel(id = id, data = value) | ||||
| } | ||||
|  | ||||
| class NastiMemoryDemuxTest(implicit p: Parameters) extends unittest.UnitTest { | ||||
|   val nSlaves = 4 | ||||
|  | ||||
|   val driver = Module(new NastiDemuxDriver(nSlaves)) | ||||
|   driver.io.start := io.start | ||||
|   io.finished := driver.io.finished | ||||
|  | ||||
|   val demux = Module(new NastiMemoryDemux(nSlaves)) | ||||
|   demux.io.master <> driver.io.nasti | ||||
|   demux.io.select := driver.io.select | ||||
|  | ||||
|   for (i <- 0 until nSlaves) { | ||||
|     val slave = Module(new NastiDemuxSlave) | ||||
|     slave.io <> demux.io.slaves(i) | ||||
|   } | ||||
| } | ||||
| @@ -553,171 +553,6 @@ class NastiRecursiveInterconnect(val nMasters: Int, addrMap: AddrMap) | ||||
|   } | ||||
| } | ||||
|  | ||||
| class ChannelHelper(nChannels: Int) | ||||
|     (implicit val p: Parameters) extends HasNastiParameters { | ||||
|  | ||||
|   val dataBytes = p(MIFDataBits) * p(MIFDataBeats) / 8 | ||||
|   val chanSelBits = log2Ceil(nChannels) | ||||
|   val selOffset = log2Up(dataBytes) | ||||
|   val blockOffset = selOffset + chanSelBits | ||||
|  | ||||
|   def getSelect(addr: UInt) = | ||||
|     if (nChannels > 1) addr(blockOffset - 1, selOffset) else UInt(0) | ||||
|  | ||||
|   def getAddr(addr: UInt) = | ||||
|     if (nChannels > 1) | ||||
|       Cat(addr(nastiXAddrBits - 1, blockOffset), addr(selOffset - 1, 0)) | ||||
|     else addr | ||||
| } | ||||
|  | ||||
| class NastiMemoryInterconnect( | ||||
|     nBanksPerChannel: Int, nChannels: Int) | ||||
|     (implicit p: Parameters) extends NastiInterconnect()(p) { | ||||
|  | ||||
|   val nBanks = nBanksPerChannel * nChannels | ||||
|   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) | ||||
|   } | ||||
|  | ||||
|   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 => io.masters(j)) | ||||
|  | ||||
|     val channelArb = Module(new NastiArbiter(nBanksPerChannel)) | ||||
|     channelArb.io.master <> banks | ||||
|     connectChannel(io.slaves(i), channelArb.io.slave) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Allows users to switch between various memory configurations.  Note that | ||||
|   * this is a dangerous operation: not only does switching the select input to | ||||
|   * this module violate Nasti, it also causes the memory of the machine to | ||||
|   * become garbled.  It's expected that select only changes at boot time, as | ||||
|   * part of the memory controller configuration. */ | ||||
| class NastiMemorySelectorIO(val nBanks: Int, val maxMemChannels: Int, nConfigs: Int) | ||||
|                            (implicit p: Parameters) | ||||
|                            extends NastiInterconnectIO(nBanks, maxMemChannels) { | ||||
|   val select  = UInt(INPUT, width = log2Up(nConfigs)) | ||||
|   override def cloneType = | ||||
|     new NastiMemorySelectorIO(nMasters, nSlaves, nConfigs).asInstanceOf[this.type] | ||||
| } | ||||
|  | ||||
| class NastiMemorySelector(nBanks: Int, maxMemChannels: Int, configs: Seq[Int]) | ||||
|                          (implicit p: Parameters) | ||||
|                          extends NastiInterconnect()(p) { | ||||
|   val nMasters = nBanks | ||||
|   val nSlaves  = maxMemChannels | ||||
|   val nConfigs = configs.size | ||||
|  | ||||
|   override lazy val io = new NastiMemorySelectorIO(nBanks, maxMemChannels, nConfigs) | ||||
|  | ||||
|   def muxOnSelect(up: DecoupledIO[Bundle], dn: DecoupledIO[Bundle], active: Bool): Unit = { | ||||
|     when (active) { dn.bits  := up.bits  } | ||||
|     when (active) { up.ready := dn.ready } | ||||
|     when (active) { dn.valid := up.valid } | ||||
|   } | ||||
|  | ||||
|   def muxOnSelect(up: NastiIO, dn: NastiIO, active: Bool): Unit = { | ||||
|     muxOnSelect(up.aw, dn.aw, active) | ||||
|     muxOnSelect(up.w,  dn.w,  active) | ||||
|     muxOnSelect(dn.b,  up.b,  active) | ||||
|     muxOnSelect(up.ar, dn.ar, active) | ||||
|     muxOnSelect(dn.r,  up.r,  active) | ||||
|   } | ||||
|  | ||||
|   def muxOnSelect(up: Vec[NastiIO], dn: Vec[NastiIO], active: Bool) : Unit = { | ||||
|     for (i <- 0 until up.size) | ||||
|       muxOnSelect(up(i), dn(i), active) | ||||
|   } | ||||
|  | ||||
|   /* Disconnects a vector of Nasti ports, which involves setting them to | ||||
|    * invalid.  Due to Chisel reasons, we need to also set the bits to 0 (since | ||||
|    * there can't be any unconnected inputs). */ | ||||
|   def disconnectSlave(slave: Vec[NastiIO]) = { | ||||
|     slave.foreach{ m => | ||||
|       m.aw.valid := Bool(false) | ||||
|       m.aw.bits  := m.aw.bits.fromBits( UInt(0) ) | ||||
|       m.w.valid  := Bool(false) | ||||
|       m.w.bits   := m.w.bits.fromBits( UInt(0) ) | ||||
|       m.b.ready  := Bool(false) | ||||
|       m.ar.valid := Bool(false) | ||||
|       m.ar.bits  := m.ar.bits.fromBits( UInt(0) ) | ||||
|       m.r.ready  := Bool(false) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def disconnectMaster(master: Vec[NastiIO]) = { | ||||
|     master.foreach{ m => | ||||
|       m.aw.ready := Bool(false) | ||||
|       m.w.ready  := Bool(false) | ||||
|       m.b.valid  := Bool(false) | ||||
|       m.b.bits   := m.b.bits.fromBits( UInt(0) ) | ||||
|       m.ar.ready := Bool(false) | ||||
|       m.r.valid  := Bool(false) | ||||
|       m.r.bits   := m.r.bits.fromBits( UInt(0) ) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Provides default wires on all our outputs. */ | ||||
|   disconnectMaster(io.masters) | ||||
|   disconnectSlave(io.slaves) | ||||
|  | ||||
|   /* Constructs interconnects for each of the layouts suggested by the | ||||
|    * configuration and switches between them based on the select input. */ | ||||
|   configs.zipWithIndex.foreach{ case (nChannels, select) => | ||||
|     val nBanksPerChannel = nBanks / nChannels | ||||
|     val ic = Module(new NastiMemoryInterconnect(nBanksPerChannel, nChannels)) | ||||
|     disconnectMaster(ic.io.slaves) | ||||
|     disconnectSlave(ic.io.masters) | ||||
|     muxOnSelect(   io.masters, ic.io.masters, io.select === UInt(select)) | ||||
|     muxOnSelect(ic.io.slaves,     io.slaves,  io.select === UInt(select)) | ||||
|   } | ||||
| } | ||||
|  | ||||
| class NastiMemoryDemux(nRoutes: Int)(implicit p: Parameters) extends NastiModule()(p) { | ||||
|   val io = new Bundle { | ||||
|     val master = (new NastiIO).flip | ||||
|     val slaves = Vec(nRoutes, new NastiIO) | ||||
|     val select = UInt(INPUT, log2Up(nRoutes)) | ||||
|   } | ||||
|  | ||||
|   def connectReqChannel[T <: Data](idx: Int, out: DecoupledIO[T], in: DecoupledIO[T]) { | ||||
|     out.valid := in.valid && io.select === UInt(idx) | ||||
|     out.bits := in.bits | ||||
|     when (io.select === UInt(idx)) { in.ready := out.ready } | ||||
|   } | ||||
|  | ||||
|   def connectRespChannel[T <: Data](idx: Int, out: DecoupledIO[T], in: DecoupledIO[T]) { | ||||
|     when (io.select === UInt(idx)) { out.valid := in.valid } | ||||
|     when (io.select === UInt(idx)) { out.bits := in.bits } | ||||
|     in.ready := out.ready && io.select === UInt(idx) | ||||
|   } | ||||
|  | ||||
|   io.master.ar.ready := Bool(false) | ||||
|   io.master.aw.ready := Bool(false) | ||||
|   io.master.w.ready := Bool(false) | ||||
|   io.master.r.valid := Bool(false) | ||||
|   io.master.r.bits := NastiReadDataChannel(id = UInt(0), data = UInt(0)) | ||||
|   io.master.b.valid := Bool(false) | ||||
|   io.master.b.bits := NastiWriteResponseChannel(id = UInt(0)) | ||||
|  | ||||
|   io.slaves.zipWithIndex.foreach { case (slave, i) => | ||||
|     connectReqChannel(i, slave.ar, io.master.ar) | ||||
|     connectReqChannel(i, slave.aw, io.master.aw) | ||||
|     connectReqChannel(i, slave.w, io.master.w) | ||||
|     connectRespChannel(i, io.master.r, slave.r) | ||||
|     connectRespChannel(i, io.master.b, slave.b) | ||||
|   } | ||||
| } | ||||
|  | ||||
| object AsyncNastiCrossing { | ||||
|   // takes from_source from the 'from' clock domain to the 'to' clock domain | ||||
|   def apply(from_clock: Clock, from_reset: Bool, from_source: NastiIO, to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3) = { | ||||
|   | ||||
| @@ -12,7 +12,6 @@ class WithJunctionsUnitTests extends Config( | ||||
|     case rocket.XLen => 64 | ||||
|     case UnitTests => (p: Parameters) => Seq( | ||||
|       Module(new junctions.MultiWidthFifoTest), | ||||
|       Module(new junctions.NastiMemoryDemuxTest()(p)), | ||||
|       Module(new junctions.HastiTest()(p))) | ||||
|     case _ => throw new CDEMatchError | ||||
|   }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user