First pages commit
This commit is contained in:
		
							
								
								
									
										2
									
								
								uncore/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								uncore/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
target/
 | 
			
		||||
project/target/
 | 
			
		||||
							
								
								
									
										24
									
								
								uncore/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								uncore/LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
Copyright (c) 2012-2014, The Regents of the University of California
 | 
			
		||||
(Regents).  All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
1. Redistributions of source code must retain the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
   documentation and/or other materials provided with the distribution.
 | 
			
		||||
3. Neither the name of the Regents nor the
 | 
			
		||||
   names of its contributors may be used to endorse or promote products
 | 
			
		||||
   derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 | 
			
		||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
 | 
			
		||||
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
 | 
			
		||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
 | 
			
		||||
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
 | 
			
		||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 | 
			
		||||
							
								
								
									
										11
									
								
								uncore/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								uncore/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
Uncore Library
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
This is the repository for uncore components assosciated with Rocket chip
 | 
			
		||||
project. To uses these modules, include this repo as a git submodule within
 | 
			
		||||
the your chip repository and add it as Project in your chip's build.scala. 
 | 
			
		||||
These components are only dependent on Chisel, i.e.
 | 
			
		||||
 | 
			
		||||
    lazy val uncore = Project("uncore", file("uncore"), settings = buildSettings) dependsOn(chisel)
 | 
			
		||||
 | 
			
		||||
Documentation about the uncore library will come in the near future.
 | 
			
		||||
							
								
								
									
										13
									
								
								uncore/build.sbt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								uncore/build.sbt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
organization := "edu.berkeley.cs"
 | 
			
		||||
 | 
			
		||||
version := "2.0"
 | 
			
		||||
 | 
			
		||||
name := "uncore"
 | 
			
		||||
 | 
			
		||||
scalaVersion := "2.10.2"
 | 
			
		||||
 | 
			
		||||
site.settings
 | 
			
		||||
 | 
			
		||||
ghpages.settings
 | 
			
		||||
 | 
			
		||||
git.remoteRepo := "git@github.com:ucb-bar/uncore.git"
 | 
			
		||||
							
								
								
									
										8
									
								
								uncore/chisel-dependent.sbt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								uncore/chisel-dependent.sbt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
// Provide a managed dependency on chisel if -DchiselVersion="" is
 | 
			
		||||
// supplied on the command line.
 | 
			
		||||
 | 
			
		||||
val chiselVersion_u = System.getProperty("chiselVersion", "None")
 | 
			
		||||
 | 
			
		||||
// _u a temporary fix until sbt 13.6 https://github.com/sbt/sbt/issues/1465
 | 
			
		||||
 | 
			
		||||
libraryDependencies ++= ( if (chiselVersion_u != "None" ) ("edu.berkeley.cs" %% "chisel" % chiselVersion_u) :: Nil; else Nil)
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								uncore/doc/TileLink0.3.1Specification.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								uncore/doc/TileLink0.3.1Specification.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1
									
								
								uncore/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								uncore/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
My GitHub Page
 | 
			
		||||
							
								
								
									
										80
									
								
								uncore/src/main/scala/bigmem.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								uncore/src/main/scala/bigmem.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
class BigMem[T <: Data](n: Int, preLatency: Int, postLatency: Int, leaf: Mem[UInt], noMask: Boolean = false)(gen: => T) extends Module
 | 
			
		||||
{
 | 
			
		||||
  class Inputs extends Bundle {
 | 
			
		||||
    val addr = UInt(INPUT, log2Up(n))
 | 
			
		||||
    val rw = Bool(INPUT)
 | 
			
		||||
    val wdata = gen.asInput
 | 
			
		||||
    val wmask = gen.asInput
 | 
			
		||||
    override def clone = new Inputs().asInstanceOf[this.type]
 | 
			
		||||
  }
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val in = Valid(new Inputs).flip
 | 
			
		||||
    val rdata = gen.asOutput
 | 
			
		||||
  }
 | 
			
		||||
  val data = gen
 | 
			
		||||
  val colMux = if (2*data.getWidth <= leaf.data.getWidth && n > leaf.n) 1 << math.floor(math.log(leaf.data.getWidth/data.getWidth)/math.log(2)).toInt else 1
 | 
			
		||||
  val nWide = if (data.getWidth > leaf.data.getWidth) 1+(data.getWidth-1)/leaf.data.getWidth else 1
 | 
			
		||||
  val nDeep = if (n > colMux*leaf.n) 1+(n-1)/(colMux*leaf.n) else 1
 | 
			
		||||
  if (nDeep > 1 || colMux > 1)
 | 
			
		||||
    require(isPow2(n) && isPow2(leaf.n))
 | 
			
		||||
 | 
			
		||||
  val rdataDeep = Vec.fill(nDeep){Bits()}
 | 
			
		||||
  val rdataSel = Vec.fill(nDeep){Bool()}
 | 
			
		||||
  for (i <- 0 until nDeep) {
 | 
			
		||||
    val in = Pipe(io.in.valid && (if (nDeep == 1) Bool(true) else UInt(i) === io.in.bits.addr(log2Up(n)-1, log2Up(n/nDeep))), io.in.bits, preLatency)
 | 
			
		||||
    val idx = in.bits.addr(log2Up(n/nDeep/colMux)-1, 0)
 | 
			
		||||
    val wdata = in.bits.wdata.toBits
 | 
			
		||||
    val wmask = in.bits.wmask.toBits
 | 
			
		||||
    val ren = in.valid && !in.bits.rw
 | 
			
		||||
    val reg_ren = Reg(next=ren)
 | 
			
		||||
    val rdata = Vec.fill(nWide){Bits()}
 | 
			
		||||
 | 
			
		||||
    val r = Pipe(ren, in.bits.addr, postLatency)
 | 
			
		||||
 | 
			
		||||
    for (j <- 0 until nWide) {
 | 
			
		||||
      val mem = leaf.clone
 | 
			
		||||
      var dout: Bits = null
 | 
			
		||||
      val ridx = if (postLatency > 0) Reg(Bits()) else null
 | 
			
		||||
 | 
			
		||||
      var wmask0 = Fill(colMux, wmask(math.min(wmask.getWidth, leaf.data.getWidth*(j+1))-1, leaf.data.getWidth*j))
 | 
			
		||||
      if (colMux > 1)
 | 
			
		||||
        wmask0 = wmask0 & FillInterleaved(gen.getWidth, UIntToOH(in.bits.addr(log2Up(n/nDeep)-1, log2Up(n/nDeep/colMux)), log2Up(colMux)))
 | 
			
		||||
      val wdata0 = Fill(colMux, wdata(math.min(wdata.getWidth, leaf.data.getWidth*(j+1))-1, leaf.data.getWidth*j))
 | 
			
		||||
      when (in.valid) {
 | 
			
		||||
        when (in.bits.rw) {
 | 
			
		||||
          if (noMask)
 | 
			
		||||
            mem.write(idx, wdata0)
 | 
			
		||||
          else
 | 
			
		||||
            mem.write(idx, wdata0, wmask0)
 | 
			
		||||
        }
 | 
			
		||||
        .otherwise { if (postLatency > 0) ridx := idx }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (postLatency == 0) {
 | 
			
		||||
        dout = mem(idx)
 | 
			
		||||
      } else if (postLatency == 1) {
 | 
			
		||||
        dout = mem(ridx)
 | 
			
		||||
      } else
 | 
			
		||||
        dout = Pipe(reg_ren, mem(ridx), postLatency-1).bits
 | 
			
		||||
 | 
			
		||||
      rdata(j) := dout
 | 
			
		||||
    }
 | 
			
		||||
    val rdataWide = rdata.reduceLeft((x, y) => Cat(y, x))
 | 
			
		||||
 | 
			
		||||
    var colMuxOut = rdataWide
 | 
			
		||||
    if (colMux > 1) {
 | 
			
		||||
      val colMuxIn = Vec((0 until colMux).map(k => rdataWide(gen.getWidth*(k+1)-1, gen.getWidth*k)))
 | 
			
		||||
      colMuxOut = colMuxIn(r.bits(log2Up(n/nDeep)-1, log2Up(n/nDeep/colMux)))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rdataDeep(i) := colMuxOut
 | 
			
		||||
    rdataSel(i) := r.valid
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.rdata := Mux1H(rdataSel, rdataDeep)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										387
									
								
								uncore/src/main/scala/broadcast.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								uncore/src/main/scala/broadcast.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,387 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
case object L2StoreDataQueueDepth extends Field[Int]
 | 
			
		||||
 | 
			
		||||
trait BroadcastHubParameters extends CoherenceAgentParameters {
 | 
			
		||||
  val sdqDepth = params(L2StoreDataQueueDepth)*innerDataBeats
 | 
			
		||||
  val dqIdxBits = math.max(log2Up(nReleaseTransactors) + 1, log2Up(sdqDepth))
 | 
			
		||||
  val nDataQueueLocations = 3 //Stores, VoluntaryWBs, Releases
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DataQueueLocation extends Bundle with BroadcastHubParameters {
 | 
			
		||||
  val idx = UInt(width = dqIdxBits)
 | 
			
		||||
  val loc = UInt(width = log2Ceil(nDataQueueLocations))
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
object DataQueueLocation {
 | 
			
		||||
  def apply(idx: UInt, loc: UInt) = {
 | 
			
		||||
    val d = new DataQueueLocation
 | 
			
		||||
    d.idx := idx
 | 
			
		||||
    d.loc := loc
 | 
			
		||||
    d
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class L2BroadcastHub extends ManagerCoherenceAgent
 | 
			
		||||
    with BroadcastHubParameters {
 | 
			
		||||
  val internalDataBits = new DataQueueLocation().getWidth
 | 
			
		||||
  val inStoreQueue :: inVolWBQueue :: inClientReleaseQueue :: Nil = Enum(UInt(), nDataQueueLocations)
 | 
			
		||||
 | 
			
		||||
  // Create SHRs for outstanding transactions
 | 
			
		||||
  val trackerList = (0 until nReleaseTransactors).map(id =>
 | 
			
		||||
    Module(new BroadcastVoluntaryReleaseTracker(id), {case TLDataBits => internalDataBits})) ++
 | 
			
		||||
      (nReleaseTransactors until nTransactors).map(id =>
 | 
			
		||||
        Module(new BroadcastAcquireTracker(id), {case TLDataBits => internalDataBits}))
 | 
			
		||||
  
 | 
			
		||||
  // Propagate incoherence flags
 | 
			
		||||
  trackerList.map(_.io.incoherent := io.incoherent.toBits)
 | 
			
		||||
 | 
			
		||||
  // Queue to store impending Put data
 | 
			
		||||
  val sdq = Vec.fill(sdqDepth){ Reg(io.iacq().data) }
 | 
			
		||||
  val sdq_val = Reg(init=Bits(0, sdqDepth))
 | 
			
		||||
  val sdq_alloc_id = PriorityEncoder(~sdq_val)
 | 
			
		||||
  val sdq_rdy = !sdq_val.andR
 | 
			
		||||
  val sdq_enq = io.inner.acquire.fire() && io.iacq().hasData()
 | 
			
		||||
  when (sdq_enq) { sdq(sdq_alloc_id) := io.iacq().data }
 | 
			
		||||
 | 
			
		||||
  // Handle acquire transaction initiation
 | 
			
		||||
  val trackerAcquireIOs = trackerList.map(_.io.inner.acquire)
 | 
			
		||||
  val acquireConflicts = Vec(trackerList.map(_.io.has_acquire_conflict)).toBits
 | 
			
		||||
  val acquireMatches = Vec(trackerList.map(_.io.has_acquire_match)).toBits
 | 
			
		||||
  val acquireReadys = Vec(trackerAcquireIOs.map(_.ready)).toBits
 | 
			
		||||
  val acquire_idx = Mux(acquireMatches.orR,
 | 
			
		||||
                      PriorityEncoder(acquireMatches),
 | 
			
		||||
                      PriorityEncoder(acquireReadys))
 | 
			
		||||
 | 
			
		||||
  val block_acquires = acquireConflicts.orR || !sdq_rdy
 | 
			
		||||
  io.inner.acquire.ready := acquireReadys.orR && !block_acquires
 | 
			
		||||
  trackerAcquireIOs.zipWithIndex.foreach {
 | 
			
		||||
    case(tracker, i) =>
 | 
			
		||||
      tracker.bits := io.inner.acquire.bits
 | 
			
		||||
      tracker.bits.data := DataQueueLocation(sdq_alloc_id, inStoreQueue).toBits
 | 
			
		||||
      tracker.valid := io.inner.acquire.valid && !block_acquires && (acquire_idx === UInt(i))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Queue to store impending Voluntary Release data
 | 
			
		||||
  val voluntary = io.irel().isVoluntary()
 | 
			
		||||
  val vwbdq_enq = io.inner.release.fire() && voluntary && io.irel().hasData()
 | 
			
		||||
  val (rel_data_cnt, rel_data_done) = Counter(vwbdq_enq, innerDataBeats) //TODO Zero width
 | 
			
		||||
  val vwbdq = Vec.fill(innerDataBeats){ Reg(io.irel().data) } //TODO Assumes nReleaseTransactors == 1 
 | 
			
		||||
  when(vwbdq_enq) { vwbdq(rel_data_cnt) := io.irel().data }
 | 
			
		||||
 | 
			
		||||
  // Handle releases, which might be voluntary and might have data
 | 
			
		||||
  val trackerReleaseIOs = trackerList.map(_.io.inner.release)
 | 
			
		||||
  val releaseReadys = Vec(trackerReleaseIOs.map(_.ready)).toBits
 | 
			
		||||
  val releaseMatches = Vec(trackerList.map(_.io.has_release_match)).toBits
 | 
			
		||||
  val release_idx = PriorityEncoder(releaseMatches)
 | 
			
		||||
  io.inner.release.ready := releaseReadys(release_idx)
 | 
			
		||||
  trackerReleaseIOs.zipWithIndex.foreach {
 | 
			
		||||
    case(tracker, i) =>
 | 
			
		||||
      tracker.valid := io.inner.release.valid && (release_idx === UInt(i))
 | 
			
		||||
      tracker.bits := io.inner.release.bits
 | 
			
		||||
      tracker.bits.data := DataQueueLocation(rel_data_cnt,
 | 
			
		||||
                                     (if(i < nReleaseTransactors) inVolWBQueue
 | 
			
		||||
                                      else inClientReleaseQueue)).toBits
 | 
			
		||||
  }
 | 
			
		||||
  assert(!(io.inner.release.valid && !releaseMatches.orR),
 | 
			
		||||
    "Non-voluntary release should always have a Tracker waiting for it.")
 | 
			
		||||
 | 
			
		||||
  // Wire probe requests and grant reply to clients, finish acks from clients
 | 
			
		||||
  // Note that we bypass the Grant data subbundles
 | 
			
		||||
  io.inner.grant.bits.data := io.outer.grant.bits.data
 | 
			
		||||
  io.inner.grant.bits.addr_beat := io.outer.grant.bits.addr_beat
 | 
			
		||||
  doOutputArbitration(io.inner.grant, trackerList.map(_.io.inner.grant))
 | 
			
		||||
  doOutputArbitration(io.inner.probe, trackerList.map(_.io.inner.probe))
 | 
			
		||||
  doInputRouting(io.inner.finish, trackerList.map(_.io.inner.finish))
 | 
			
		||||
 | 
			
		||||
  // Create an arbiter for the one memory port
 | 
			
		||||
  val outer_arb = Module(new ClientUncachedTileLinkIOArbiter(trackerList.size),
 | 
			
		||||
                         { case TLId => params(OuterTLId)
 | 
			
		||||
                           case TLDataBits => internalDataBits })
 | 
			
		||||
  outer_arb.io.in <> trackerList.map(_.io.outer)
 | 
			
		||||
  // Get the pending data out of the store data queue
 | 
			
		||||
  val outer_data_ptr = new DataQueueLocation().fromBits(outer_arb.io.out.acquire.bits.data)
 | 
			
		||||
  val is_in_sdq = outer_data_ptr.loc === inStoreQueue
 | 
			
		||||
  val free_sdq = io.outer.acquire.fire() &&
 | 
			
		||||
                  io.outer.acquire.bits.hasData() &&
 | 
			
		||||
                  outer_data_ptr.loc === inStoreQueue
 | 
			
		||||
  io.outer.acquire.bits.data := MuxLookup(outer_data_ptr.loc, io.irel().data, Array(
 | 
			
		||||
                                          inStoreQueue -> sdq(outer_data_ptr.idx),
 | 
			
		||||
                                          inVolWBQueue -> vwbdq(outer_data_ptr.idx)))
 | 
			
		||||
  io.outer <> outer_arb.io.out
 | 
			
		||||
 | 
			
		||||
  // Update SDQ valid bits
 | 
			
		||||
  when (io.outer.acquire.valid || sdq_enq) {
 | 
			
		||||
    sdq_val := sdq_val & ~(UIntToOH(outer_data_ptr.idx) & Fill(sdqDepth, free_sdq)) | 
 | 
			
		||||
               PriorityEncoderOH(~sdq_val(sdqDepth-1,0)) & Fill(sdqDepth, sdq_enq)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BroadcastXactTracker extends XactTracker {
 | 
			
		||||
  val io = new ManagerXactTrackerIO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BroadcastVoluntaryReleaseTracker(trackerId: Int) extends BroadcastXactTracker {
 | 
			
		||||
  val s_idle :: s_outer :: s_grant :: s_ack :: Nil = Enum(UInt(), 4)
 | 
			
		||||
  val state = Reg(init=s_idle)
 | 
			
		||||
 | 
			
		||||
  val xact = Reg(Bundle(new ReleaseFromSrc, { case TLId => params(InnerTLId); case TLDataBits => 0 }))
 | 
			
		||||
  val data_buffer = Vec.fill(innerDataBeats){ Reg(io.irel().data.clone) }
 | 
			
		||||
  val coh = ManagerMetadata.onReset
 | 
			
		||||
 | 
			
		||||
  val collect_irel_data = Reg(init=Bool(false))
 | 
			
		||||
  val irel_data_valid = Reg(init=Bits(0, width = innerDataBeats))
 | 
			
		||||
  val irel_data_done = connectIncomingDataBeatCounter(io.inner.release)
 | 
			
		||||
  val (oacq_data_cnt, oacq_data_done) = connectOutgoingDataBeatCounter(io.outer.acquire)
 | 
			
		||||
 | 
			
		||||
  io.has_acquire_conflict := Bool(false)
 | 
			
		||||
  io.has_release_match := io.irel().isVoluntary()
 | 
			
		||||
  io.has_acquire_match := Bool(false)
 | 
			
		||||
 | 
			
		||||
  io.outer.acquire.valid := Bool(false)
 | 
			
		||||
  io.outer.grant.ready := Bool(false)
 | 
			
		||||
  io.inner.acquire.ready := Bool(false)
 | 
			
		||||
  io.inner.probe.valid := Bool(false)
 | 
			
		||||
  io.inner.release.ready := Bool(false)
 | 
			
		||||
  io.inner.grant.valid := Bool(false)
 | 
			
		||||
  io.inner.finish.ready := Bool(false)
 | 
			
		||||
 | 
			
		||||
  io.inner.grant.bits := coh.makeGrant(xact, UInt(trackerId))
 | 
			
		||||
 | 
			
		||||
  //TODO: Use io.outer.release instead?
 | 
			
		||||
  io.outer.acquire.bits := Bundle(
 | 
			
		||||
    PutBlock( 
 | 
			
		||||
      client_xact_id = UInt(trackerId),
 | 
			
		||||
      addr_block = xact.addr_block,
 | 
			
		||||
      addr_beat = oacq_data_cnt,
 | 
			
		||||
      data = data_buffer(oacq_data_cnt)))(outerTLParams)
 | 
			
		||||
 | 
			
		||||
  when(collect_irel_data) {
 | 
			
		||||
    io.inner.release.ready := Bool(true)
 | 
			
		||||
    when(io.inner.release.valid) {
 | 
			
		||||
      data_buffer(io.irel().addr_beat) := io.irel().data
 | 
			
		||||
      irel_data_valid(io.irel().addr_beat) := Bool(true)
 | 
			
		||||
    }
 | 
			
		||||
    when(irel_data_done) { collect_irel_data := Bool(false) }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch (state) {
 | 
			
		||||
    is(s_idle) {
 | 
			
		||||
      io.inner.release.ready := Bool(true)
 | 
			
		||||
      when( io.inner.release.valid ) {
 | 
			
		||||
        xact := io.irel()
 | 
			
		||||
        data_buffer(UInt(0)) := io.irel().data
 | 
			
		||||
        collect_irel_data := io.irel().hasMultibeatData()
 | 
			
		||||
        irel_data_valid := io.irel().hasData() << io.irel().addr_beat
 | 
			
		||||
        state := Mux(io.irel().hasData(), s_outer,
 | 
			
		||||
                   Mux(io.irel().requiresAck(), s_ack, s_idle))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_outer) {
 | 
			
		||||
      io.outer.acquire.valid := !collect_irel_data || irel_data_valid(oacq_data_cnt)
 | 
			
		||||
      when(oacq_data_done) { 
 | 
			
		||||
        state := s_grant // converted irel to oacq, so expect grant TODO: Mux(xact.requiresAck(), s_grant, s_idle) ?
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_grant) { // Forward the Grant.voluntaryAck
 | 
			
		||||
      io.outer.grant.ready := io.inner.grant.ready
 | 
			
		||||
      io.inner.grant.valid := io.outer.grant.valid 
 | 
			
		||||
      when(io.inner.grant.fire()) {
 | 
			
		||||
        state := Mux(io.ignt().requiresAck(), s_ack, s_idle)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_ack) {
 | 
			
		||||
      // TODO: This state is unnecessary if no client will ever issue the
 | 
			
		||||
      // pending Acquire that caused this writeback until it receives the 
 | 
			
		||||
      // Grant.voluntaryAck for this writeback
 | 
			
		||||
      io.inner.finish.ready := Bool(true)
 | 
			
		||||
      when(io.inner.finish.valid) { state := s_idle }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BroadcastAcquireTracker(trackerId: Int) extends BroadcastXactTracker {
 | 
			
		||||
  val s_idle :: s_probe :: s_mem_read :: s_mem_write :: s_make_grant :: s_mem_resp :: s_ack :: Nil = Enum(UInt(), 7)
 | 
			
		||||
  val state = Reg(init=s_idle)
 | 
			
		||||
 | 
			
		||||
  val xact = Reg(Bundle(new AcquireFromSrc, { case TLId => params(InnerTLId); case TLDataBits => 0 }))
 | 
			
		||||
  val data_buffer = Vec.fill(innerDataBeats){ Reg(io.iacq().data.clone) }
 | 
			
		||||
  val coh = ManagerMetadata.onReset
 | 
			
		||||
 | 
			
		||||
  assert(!(state != s_idle && xact.isBuiltInType() && 
 | 
			
		||||
      Vec(Acquire.getType, Acquire.putType, Acquire.putAtomicType,
 | 
			
		||||
        Acquire.prefetchType).contains(xact.a_type)),
 | 
			
		||||
    "Broadcast Hub does not support PutAtomics, subblock Gets/Puts, or prefetches") // TODO
 | 
			
		||||
 | 
			
		||||
  val release_count = Reg(init=UInt(0, width = log2Up(io.inner.tlNCachingClients+1)))
 | 
			
		||||
  val pending_probes = Reg(init=Bits(0, width = io.inner.tlNCachingClients))
 | 
			
		||||
  val curr_p_id = PriorityEncoder(pending_probes)
 | 
			
		||||
  val full_sharers = coh.full()
 | 
			
		||||
  val probe_self = io.inner.acquire.bits.requiresSelfProbe()
 | 
			
		||||
  val mask_self_true = UInt(UInt(1) << io.inner.acquire.bits.client_id, width = io.inner.tlNCachingClients)
 | 
			
		||||
  val mask_self_false = ~UInt(UInt(1) << io.inner.acquire.bits.client_id, width = io.inner.tlNCachingClients)
 | 
			
		||||
  val mask_self = Mux(probe_self, full_sharers | mask_self_true, full_sharers & mask_self_false)
 | 
			
		||||
  val mask_incoherent = mask_self & ~io.incoherent.toBits
 | 
			
		||||
 | 
			
		||||
  val collect_iacq_data = Reg(init=Bool(false))
 | 
			
		||||
  val iacq_data_valid = Reg(init=Bits(0, width = innerDataBeats))
 | 
			
		||||
  val iacq_data_done = connectIncomingDataBeatCounter(io.inner.acquire)
 | 
			
		||||
  val irel_data_done = connectIncomingDataBeatCounter(io.inner.release)
 | 
			
		||||
  val (ignt_data_cnt, ignt_data_done) = connectOutgoingDataBeatCounter(io.inner.grant)
 | 
			
		||||
  val (oacq_data_cnt, oacq_data_done) = connectOutgoingDataBeatCounter(io.outer.acquire)
 | 
			
		||||
  val ognt_data_done = connectIncomingDataBeatCounter(io.outer.grant)
 | 
			
		||||
  val pending_ognt_ack = Reg(init=Bool(false))
 | 
			
		||||
  val pending_outer_write = xact.hasData()
 | 
			
		||||
  val pending_outer_write_ = io.iacq().hasData()
 | 
			
		||||
  val pending_outer_read = io.ignt().hasData()
 | 
			
		||||
  val pending_outer_read_ = coh.makeGrant(io.iacq(), UInt(trackerId)).hasData()
 | 
			
		||||
 | 
			
		||||
  io.has_acquire_conflict := xact.conflicts(io.iacq()) && 
 | 
			
		||||
                              (state != s_idle) &&
 | 
			
		||||
                              !collect_iacq_data
 | 
			
		||||
  io.has_acquire_match := xact.conflicts(io.iacq()) &&
 | 
			
		||||
                              collect_iacq_data
 | 
			
		||||
  io.has_release_match := xact.conflicts(io.irel()) &&
 | 
			
		||||
                            !io.irel().isVoluntary() &&
 | 
			
		||||
                            (state === s_probe)
 | 
			
		||||
 | 
			
		||||
  val outer_write_acq = Bundle(PutBlock(
 | 
			
		||||
                                client_xact_id = UInt(trackerId),
 | 
			
		||||
                                addr_block = xact.addr_block,
 | 
			
		||||
                                addr_beat = oacq_data_cnt,
 | 
			
		||||
                                data = data_buffer(oacq_data_cnt)))(outerTLParams)
 | 
			
		||||
  val outer_write_rel = Bundle(PutBlock(
 | 
			
		||||
                                client_xact_id = UInt(trackerId),
 | 
			
		||||
                                addr_block = xact.addr_block,
 | 
			
		||||
                                addr_beat = io.irel().addr_beat,
 | 
			
		||||
                                data = io.irel().data))(outerTLParams)
 | 
			
		||||
  val outer_read = Bundle(GetBlock(
 | 
			
		||||
                            client_xact_id = UInt(trackerId),
 | 
			
		||||
                            addr_block = xact.addr_block))(outerTLParams)
 | 
			
		||||
 | 
			
		||||
  io.outer.acquire.valid := Bool(false)
 | 
			
		||||
  io.outer.acquire.bits := outer_read //default
 | 
			
		||||
  io.outer.grant.ready := Bool(false)
 | 
			
		||||
 | 
			
		||||
  io.inner.probe.valid := Bool(false)
 | 
			
		||||
  io.inner.probe.bits := coh.makeProbe(curr_p_id, xact)
 | 
			
		||||
 | 
			
		||||
  io.inner.grant.valid := Bool(false)
 | 
			
		||||
  io.inner.grant.bits := coh.makeGrant(xact, UInt(trackerId)) // Data bypassed in parent
 | 
			
		||||
 | 
			
		||||
  io.inner.acquire.ready := Bool(false)
 | 
			
		||||
  io.inner.release.ready := Bool(false)
 | 
			
		||||
  io.inner.finish.ready := Bool(false)
 | 
			
		||||
 | 
			
		||||
  assert(!(state != s_idle && collect_iacq_data && io.inner.acquire.fire() &&
 | 
			
		||||
    io.iacq().client_id != xact.client_id),
 | 
			
		||||
    "AcquireTracker accepted data beat from different network source than initial request.")
 | 
			
		||||
 | 
			
		||||
  assert(!(state != s_idle && collect_iacq_data && io.inner.acquire.fire() &&
 | 
			
		||||
    io.iacq().client_xact_id != xact.client_xact_id),
 | 
			
		||||
    "AcquireTracker accepted data beat from different client transaction than initial request.")
 | 
			
		||||
 | 
			
		||||
  assert(!(state === s_idle && io.inner.acquire.fire() &&
 | 
			
		||||
    io.iacq().addr_beat != UInt(0)),
 | 
			
		||||
    "AcquireTracker initialized with a tail data beat.")
 | 
			
		||||
 | 
			
		||||
  when(collect_iacq_data) {
 | 
			
		||||
    io.inner.acquire.ready := Bool(true)
 | 
			
		||||
    when(io.inner.acquire.valid) {
 | 
			
		||||
      data_buffer(io.iacq().addr_beat) := io.iacq().data
 | 
			
		||||
      iacq_data_valid(io.iacq().addr_beat) := Bool(true)
 | 
			
		||||
    }
 | 
			
		||||
    when(iacq_data_done) { collect_iacq_data := Bool(false) }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  when(pending_ognt_ack) {
 | 
			
		||||
    io.outer.grant.ready := Bool(true)
 | 
			
		||||
    when(io.outer.grant.valid) { pending_ognt_ack := Bool(false) }
 | 
			
		||||
    //TODO add finish queue if this isnt the last level manager
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch (state) {
 | 
			
		||||
    is(s_idle) {
 | 
			
		||||
      io.inner.acquire.ready := Bool(true)
 | 
			
		||||
      when(io.inner.acquire.valid) {
 | 
			
		||||
        xact := io.iacq()
 | 
			
		||||
        data_buffer(UInt(0)) := io.iacq().data
 | 
			
		||||
        collect_iacq_data := io.iacq().hasMultibeatData()
 | 
			
		||||
        iacq_data_valid := io.iacq().hasData() << io.iacq().addr_beat
 | 
			
		||||
        val needs_probes = mask_incoherent.orR
 | 
			
		||||
        when(needs_probes) {
 | 
			
		||||
          pending_probes := mask_incoherent
 | 
			
		||||
          release_count := PopCount(mask_incoherent)
 | 
			
		||||
        }
 | 
			
		||||
        state := Mux(needs_probes, s_probe,
 | 
			
		||||
                  Mux(pending_outer_write_, s_mem_write,
 | 
			
		||||
                    Mux(pending_outer_read_, s_mem_read, s_make_grant)))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_probe) {
 | 
			
		||||
      // Generate probes
 | 
			
		||||
      io.inner.probe.valid := pending_probes.orR
 | 
			
		||||
      when(io.inner.probe.ready) {
 | 
			
		||||
        pending_probes := pending_probes & ~UIntToOH(curr_p_id)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Handle releases, which may have data to be written back
 | 
			
		||||
      io.inner.release.ready := !io.irel().hasData() || io.outer.acquire.ready
 | 
			
		||||
      when(io.inner.release.valid) {
 | 
			
		||||
        when(io.irel().hasData()) {
 | 
			
		||||
          io.outer.acquire.valid := Bool(true)
 | 
			
		||||
          io.outer.acquire.bits := outer_write_rel
 | 
			
		||||
          when(io.outer.acquire.ready) {
 | 
			
		||||
            when(oacq_data_done) {
 | 
			
		||||
              pending_ognt_ack := Bool(true)
 | 
			
		||||
              release_count := release_count - UInt(1)
 | 
			
		||||
              when(release_count === UInt(1)) {
 | 
			
		||||
                state := Mux(pending_outer_write, s_mem_write,
 | 
			
		||||
                          Mux(pending_outer_read, s_mem_read, s_make_grant))
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } .otherwise {
 | 
			
		||||
          release_count := release_count - UInt(1)
 | 
			
		||||
          when(release_count === UInt(1)) {
 | 
			
		||||
            state := Mux(pending_outer_write, s_mem_write, 
 | 
			
		||||
                      Mux(pending_outer_read, s_mem_read, s_make_grant))
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_mem_write) { // Write data to outer memory
 | 
			
		||||
      io.outer.acquire.valid := !pending_ognt_ack || !collect_iacq_data || iacq_data_valid(oacq_data_cnt)
 | 
			
		||||
      io.outer.acquire.bits := outer_write_acq
 | 
			
		||||
      when(oacq_data_done) {
 | 
			
		||||
        pending_ognt_ack := Bool(true)
 | 
			
		||||
        state := Mux(pending_outer_read, s_mem_read, s_mem_resp)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_mem_read) { // Read data from outer memory (possibly what was just written)
 | 
			
		||||
      io.outer.acquire.valid := !pending_ognt_ack
 | 
			
		||||
      io.outer.acquire.bits := outer_read
 | 
			
		||||
      when(io.outer.acquire.fire()) { state := s_mem_resp }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_mem_resp) { // Wait to forward grants from outer memory
 | 
			
		||||
      io.outer.grant.ready := io.inner.grant.ready
 | 
			
		||||
      io.inner.grant.valid := io.outer.grant.valid
 | 
			
		||||
      when(ignt_data_done) { 
 | 
			
		||||
        state := Mux(io.ignt().requiresAck(), s_ack, s_idle)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_make_grant) { // Manufacture a local grant (some kind of permission upgrade)
 | 
			
		||||
      io.inner.grant.valid := Bool(true)
 | 
			
		||||
      when(io.inner.grant.ready) { 
 | 
			
		||||
        state := Mux(io.ignt().requiresAck(), s_ack, s_idle)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    is(s_ack) { // Wait for transaction to complete
 | 
			
		||||
      io.inner.finish.ready := Bool(true)
 | 
			
		||||
      when(io.inner.finish.valid) { state := s_idle }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1078
									
								
								uncore/src/main/scala/cache.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1078
									
								
								uncore/src/main/scala/cache.scala
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										688
									
								
								uncore/src/main/scala/coherence.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										688
									
								
								uncore/src/main/scala/coherence.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,688 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
/** The entire CoherencePolicy API consists of the following three traits:
 | 
			
		||||
  * HasCustomTileLinkMessageTypes, used to define custom messages
 | 
			
		||||
  * HasClientSideCoherencePolicy, for client coherence agents
 | 
			
		||||
  * HasManagerSideCoherencePolicy, for manager coherence agents
 | 
			
		||||
  */
 | 
			
		||||
abstract class CoherencePolicy(val dir: DirectoryRepresentation) extends 
 | 
			
		||||
  HasCustomTileLinkMessageTypes with
 | 
			
		||||
  HasClientSideCoherencePolicy with
 | 
			
		||||
  HasManagerSideCoherencePolicy
 | 
			
		||||
 | 
			
		||||
/** This API defines the custom, coherence-policy-defined message types,
 | 
			
		||||
  * as opposed to the built-in ones found in tilelink.scala.
 | 
			
		||||
  * Policies must enumerate the custom messages to be sent over each
 | 
			
		||||
  * channel, as well as which of them have associated data.
 | 
			
		||||
  */
 | 
			
		||||
trait HasCustomTileLinkMessageTypes {
 | 
			
		||||
  val nAcquireTypes: Int
 | 
			
		||||
  def acquireTypeWidth = log2Up(nAcquireTypes)
 | 
			
		||||
  val nProbeTypes: Int
 | 
			
		||||
  def probeTypeWidth = log2Up(nProbeTypes)
 | 
			
		||||
  val nReleaseTypes: Int
 | 
			
		||||
  def releaseTypeWidth = log2Up(nReleaseTypes)
 | 
			
		||||
  val nGrantTypes: Int
 | 
			
		||||
  def grantTypeWidth = log2Up(nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val acquireTypesWithData = Nil // Only built-in Acquire types have data for now
 | 
			
		||||
  val releaseTypesWithData: Vec[UInt] 
 | 
			
		||||
  val grantTypesWithData: Vec[UInt]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** This API contains all functions required for client coherence agents.
 | 
			
		||||
  * Policies must enumerate the number of client states and define their 
 | 
			
		||||
  * permissions with respect to memory operations. Policies must fill in functions
 | 
			
		||||
  * to control which messages are sent and how metadata is updated in response
 | 
			
		||||
  * to coherence events. These funtions are generally called from within the 
 | 
			
		||||
  * ClientMetadata class in metadata.scala
 | 
			
		||||
  */
 | 
			
		||||
trait HasClientSideCoherencePolicy {
 | 
			
		||||
  // Client coherence states and their permissions
 | 
			
		||||
  val nClientStates: Int
 | 
			
		||||
  def clientStateWidth = log2Ceil(nClientStates)
 | 
			
		||||
  val clientStatesWithReadPermission: Vec[UInt]
 | 
			
		||||
  val clientStatesWithWritePermission: Vec[UInt]
 | 
			
		||||
  val clientStatesWithDirtyData: Vec[UInt]
 | 
			
		||||
 | 
			
		||||
  // Transaction initiation logic
 | 
			
		||||
  def isValid(meta: ClientMetadata): Bool
 | 
			
		||||
  def isHit(cmd: UInt, meta: ClientMetadata): Bool = {
 | 
			
		||||
    Mux(isWriteIntent(cmd), 
 | 
			
		||||
      clientStatesWithWritePermission.contains(meta.state),
 | 
			
		||||
      clientStatesWithReadPermission.contains(meta.state))
 | 
			
		||||
  }
 | 
			
		||||
  //TODO: Assumes all states with write permissions also have read permissions
 | 
			
		||||
  def requiresAcquireOnSecondaryMiss(
 | 
			
		||||
        first_cmd: UInt,
 | 
			
		||||
        second_cmd: UInt,
 | 
			
		||||
        meta: ClientMetadata): Bool = {
 | 
			
		||||
    isWriteIntent(second_cmd) && !isWriteIntent(first_cmd)
 | 
			
		||||
  }
 | 
			
		||||
  //TODO: Assumes all cache ctrl ops writeback dirty data, and
 | 
			
		||||
  //      doesn't issue transaction when e.g. downgrading Exclusive to Shared:
 | 
			
		||||
  def requiresReleaseOnCacheControl(cmd: UInt, meta: ClientMetadata): Bool =
 | 
			
		||||
    clientStatesWithDirtyData.contains(meta.state) 
 | 
			
		||||
 | 
			
		||||
  // Determine which custom message type to use
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt
 | 
			
		||||
  def getReleaseType(p: Probe, meta: ClientMetadata): UInt
 | 
			
		||||
 | 
			
		||||
  // Mutate ClientMetadata based on messages or cmds
 | 
			
		||||
  def clientMetadataOnReset: ClientMetadata
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata): ClientMetadata
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata): ClientMetadata 
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata): ClientMetadata 
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata): ClientMetadata 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** This API contains all functions required for manager coherence agents.
 | 
			
		||||
  * Policies must enumerate the number of manager states. Policies must fill
 | 
			
		||||
  * in functions to control which Probe and Grant messages are sent and how 
 | 
			
		||||
  * metadata should be updated in response to coherence events. These funtions
 | 
			
		||||
  * are generally called from within the ManagerMetadata class in metadata.scala
 | 
			
		||||
  */
 | 
			
		||||
trait HasManagerSideCoherencePolicy extends HasDirectoryRepresentation {
 | 
			
		||||
  val nManagerStates: Int
 | 
			
		||||
  def masterStateWidth = log2Ceil(nManagerStates)
 | 
			
		||||
 | 
			
		||||
  // Transaction probing logic
 | 
			
		||||
  def requiresProbes(acq: Acquire, meta: ManagerMetadata): Bool
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata): Bool
 | 
			
		||||
 | 
			
		||||
  // Determine which custom message type to use in response
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt
 | 
			
		||||
  def getProbeType(acq: Acquire, meta: ManagerMetadata): UInt
 | 
			
		||||
  def getGrantType(acq: Acquire, meta: ManagerMetadata): UInt
 | 
			
		||||
 | 
			
		||||
  // Mutate ManagerMetadata based on messages or cmds
 | 
			
		||||
  def managerMetadataOnReset: ManagerMetadata
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata): ManagerMetadata
 | 
			
		||||
  def managerMetadataOnGrant(outgoing: Grant, dst: UInt, meta: ManagerMetadata) =
 | 
			
		||||
    ManagerMetadata(sharers=Mux(outgoing.isBuiltInType(), // Assumes all built-ins are uncached
 | 
			
		||||
                                meta.sharers,
 | 
			
		||||
                                dir.push(meta.sharers, dst)))
 | 
			
		||||
                    //state = meta.state)  TODO: Fix 0-width wires in Chisel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** The following concrete implementations of CoherencePolicy each provide the 
 | 
			
		||||
  * functionality of one particular protocol.
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
/** A simple protocol with only two Client states.
 | 
			
		||||
  * Data is always assumed to be dirty.
 | 
			
		||||
  * Only a single client may ever have a copy of a block at a time.
 | 
			
		||||
  */
 | 
			
		||||
class MICoherence(dir: DirectoryRepresentation) extends CoherencePolicy(dir) {
 | 
			
		||||
  // Message types
 | 
			
		||||
  val nAcquireTypes = 1
 | 
			
		||||
  val nProbeTypes = 2
 | 
			
		||||
  val nReleaseTypes = 4
 | 
			
		||||
  val nGrantTypes = 1
 | 
			
		||||
 | 
			
		||||
  val acquireExclusive :: Nil = Enum(UInt(), nAcquireTypes)
 | 
			
		||||
  val probeInvalidate :: probeCopy :: Nil = Enum(UInt(), nProbeTypes)
 | 
			
		||||
  val releaseInvalidateData :: releaseCopyData :: releaseInvalidateAck :: releaseCopyAck :: Nil = Enum(UInt(), nReleaseTypes)
 | 
			
		||||
  val grantExclusive :: Nil = Enum(UInt(), nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val releaseTypesWithData = Vec(releaseInvalidateData, releaseCopyData)
 | 
			
		||||
  val grantTypesWithData = Vec(grantExclusive)
 | 
			
		||||
 | 
			
		||||
  // Client states and functions
 | 
			
		||||
  val nClientStates = 2
 | 
			
		||||
  val clientInvalid :: clientValid :: Nil = Enum(UInt(), nClientStates)
 | 
			
		||||
 | 
			
		||||
  val clientStatesWithReadPermission = Vec(clientValid)
 | 
			
		||||
  val clientStatesWithWritePermission = Vec(clientValid)
 | 
			
		||||
  val clientStatesWithDirtyData = Vec(clientValid)
 | 
			
		||||
 | 
			
		||||
  def isValid (meta: ClientMetadata): Bool = meta.state != clientInvalid
 | 
			
		||||
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt = acquireExclusive
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    MuxLookup(cmd, releaseCopyAck, Array(
 | 
			
		||||
      M_FLUSH   -> Mux(dirty, releaseInvalidateData, releaseInvalidateAck),
 | 
			
		||||
      M_PRODUCE -> Mux(dirty, releaseCopyData, releaseCopyAck),
 | 
			
		||||
      M_CLEAN   -> Mux(dirty, releaseCopyData, releaseCopyAck)))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(incoming: Probe, meta: ClientMetadata): UInt =
 | 
			
		||||
    MuxLookup(incoming.p_type, releaseInvalidateAck, Array(
 | 
			
		||||
      probeInvalidate -> getReleaseType(M_FLUSH, meta),
 | 
			
		||||
      probeCopy       -> getReleaseType(M_CLEAN, meta)))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnReset = ClientMetadata(clientInvalid)
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata) = meta
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(Mux(cmd === M_FLUSH, clientInvalid, meta.state))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(Mux(incoming.isBuiltInType(), clientInvalid, clientValid))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(Mux(incoming.p_type === probeInvalidate,
 | 
			
		||||
                       clientInvalid, meta.state))
 | 
			
		||||
 | 
			
		||||
  // Manager states and functions:
 | 
			
		||||
  val nManagerStates = 0 // We don't actually need any states for this protocol
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(a: Acquire, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt =
 | 
			
		||||
    MuxLookup(cmd, probeCopy, Array(
 | 
			
		||||
      M_FLUSH -> probeInvalidate))
 | 
			
		||||
 | 
			
		||||
  def getProbeType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.isBuiltInType(), 
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        Acquire.getBlockType -> probeCopy, 
 | 
			
		||||
        Acquire.putBlockType -> probeInvalidate,
 | 
			
		||||
        Acquire.getType -> probeCopy, 
 | 
			
		||||
        Acquire.putType -> probeInvalidate,
 | 
			
		||||
        Acquire.putAtomicType -> probeInvalidate)), 
 | 
			
		||||
      probeInvalidate)
 | 
			
		||||
 | 
			
		||||
  def getGrantType(a: Acquire, meta: ManagerMetadata): UInt = grantExclusive
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnReset = ManagerMetadata()
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata) = {
 | 
			
		||||
    val popped = ManagerMetadata(sharers=dir.pop(meta.sharers, src))
 | 
			
		||||
    MuxBundle(meta, Array(
 | 
			
		||||
      incoming.is(releaseInvalidateData) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAck)  -> popped))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** A simple protocol with only three Client states.
 | 
			
		||||
  * Data is marked as dirty when written.
 | 
			
		||||
  * Only a single client may ever have a copy of a block at a time.
 | 
			
		||||
  */
 | 
			
		||||
class MEICoherence(dir: DirectoryRepresentation) extends CoherencePolicy(dir) {
 | 
			
		||||
  // Message types
 | 
			
		||||
  val nAcquireTypes = 2
 | 
			
		||||
  val nProbeTypes = 3
 | 
			
		||||
  val nReleaseTypes = 6
 | 
			
		||||
  val nGrantTypes = 1
 | 
			
		||||
 | 
			
		||||
  val acquireExclusiveClean :: acquireExclusiveDirty :: Nil = Enum(UInt(), nAcquireTypes)
 | 
			
		||||
  val probeInvalidate :: probeDowngrade :: probeCopy :: Nil = Enum(UInt(), nProbeTypes)
 | 
			
		||||
  val releaseInvalidateData :: releaseDowngradeData :: releaseCopyData :: releaseInvalidateAck :: releaseDowngradeAck :: releaseCopyAck :: Nil = Enum(UInt(), nReleaseTypes)
 | 
			
		||||
  val grantExclusive :: Nil = Enum(UInt(), nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val releaseTypesWithData = Vec(releaseInvalidateData, releaseDowngradeData, releaseCopyData)
 | 
			
		||||
  val grantTypesWithData = Vec(grantExclusive)
 | 
			
		||||
 | 
			
		||||
  // Client states and functions
 | 
			
		||||
  val nClientStates = 3
 | 
			
		||||
  val clientInvalid :: clientExclusiveClean :: clientExclusiveDirty :: Nil = Enum(UInt(), nClientStates)
 | 
			
		||||
 | 
			
		||||
  val clientStatesWithReadPermission = Vec(clientExclusiveClean, clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithWritePermission = Vec(clientExclusiveClean, clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithDirtyData = Vec(clientExclusiveDirty)
 | 
			
		||||
 | 
			
		||||
  def isValid (meta: ClientMetadata) = meta.state != clientInvalid
 | 
			
		||||
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt =
 | 
			
		||||
    Mux(isWriteIntent(cmd), acquireExclusiveDirty, acquireExclusiveClean)
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    MuxLookup(cmd, releaseCopyAck, Array(
 | 
			
		||||
      M_FLUSH   -> Mux(dirty, releaseInvalidateData, releaseInvalidateAck),
 | 
			
		||||
      M_PRODUCE -> Mux(dirty, releaseDowngradeData, releaseDowngradeAck),
 | 
			
		||||
      M_CLEAN   -> Mux(dirty, releaseCopyData, releaseCopyAck)))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(incoming: Probe, meta: ClientMetadata): UInt =
 | 
			
		||||
    MuxLookup(incoming.p_type, releaseInvalidateAck, Array(
 | 
			
		||||
      probeInvalidate -> getReleaseType(M_FLUSH, meta),
 | 
			
		||||
      probeDowngrade  -> getReleaseType(M_PRODUCE, meta),
 | 
			
		||||
      probeCopy       -> getReleaseType(M_CLEAN, meta)))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnReset = ClientMetadata(clientInvalid)
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata) = 
 | 
			
		||||
    ClientMetadata(Mux(isWrite(cmd), clientExclusiveDirty, meta.state))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(cmd, meta.state, Array(
 | 
			
		||||
        M_FLUSH -> clientInvalid,
 | 
			
		||||
        M_CLEAN -> Mux(meta.state === clientExclusiveDirty, clientExclusiveClean, meta.state))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      Mux(incoming.isBuiltInType(), clientInvalid,
 | 
			
		||||
        Mux(isWrite(cmd), clientExclusiveDirty, clientExclusiveClean)))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(incoming.p_type, meta.state, Array(
 | 
			
		||||
        probeInvalidate -> clientInvalid,
 | 
			
		||||
        probeDowngrade  -> clientExclusiveClean,
 | 
			
		||||
        probeCopy       -> meta.state)))
 | 
			
		||||
 | 
			
		||||
  // Manager states and functions:
 | 
			
		||||
  val nManagerStates = 0 // We don't actually need any states for this protocol
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(a: Acquire, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt =
 | 
			
		||||
    MuxLookup(cmd, probeCopy, Array(
 | 
			
		||||
      M_FLUSH -> probeInvalidate,
 | 
			
		||||
      M_PRODUCE -> probeDowngrade))
 | 
			
		||||
 | 
			
		||||
  def getProbeType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.isBuiltInType(), 
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        Acquire.getBlockType -> probeCopy, 
 | 
			
		||||
        Acquire.putBlockType -> probeInvalidate,
 | 
			
		||||
        Acquire.getType -> probeCopy, 
 | 
			
		||||
        Acquire.putType -> probeInvalidate,
 | 
			
		||||
        Acquire.putAtomicType -> probeInvalidate)),
 | 
			
		||||
      probeInvalidate)
 | 
			
		||||
 | 
			
		||||
  def getGrantType(a: Acquire, meta: ManagerMetadata): UInt = grantExclusive
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnReset = ManagerMetadata()
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata) = {
 | 
			
		||||
    val popped = ManagerMetadata(sharers=dir.pop(meta.sharers, src))
 | 
			
		||||
    MuxBundle(meta, Array(
 | 
			
		||||
      incoming.is(releaseInvalidateData) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAck)  -> popped))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** A protocol with only three Client states.
 | 
			
		||||
  * Data is always assumed to be dirty.
 | 
			
		||||
  * Multiple clients may share read permissions on a block at the same time.
 | 
			
		||||
  */
 | 
			
		||||
class MSICoherence(dir: DirectoryRepresentation) extends CoherencePolicy(dir) {
 | 
			
		||||
  // Message types
 | 
			
		||||
  val nAcquireTypes = 2
 | 
			
		||||
  val nProbeTypes = 3
 | 
			
		||||
  val nReleaseTypes = 6
 | 
			
		||||
  val nGrantTypes = 3
 | 
			
		||||
 | 
			
		||||
  val acquireShared :: acquireExclusive :: Nil = Enum(UInt(), nAcquireTypes)
 | 
			
		||||
  val probeInvalidate :: probeDowngrade :: probeCopy :: Nil = Enum(UInt(), nProbeTypes)
 | 
			
		||||
  val releaseInvalidateData :: releaseDowngradeData :: releaseCopyData :: releaseInvalidateAck :: releaseDowngradeAck :: releaseCopyAck :: Nil = Enum(UInt(), nReleaseTypes)
 | 
			
		||||
  val grantShared :: grantExclusive :: grantExclusiveAck :: Nil = Enum(UInt(), nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val releaseTypesWithData = Vec(releaseInvalidateData, releaseDowngradeData, releaseCopyData)
 | 
			
		||||
  val grantTypesWithData = Vec(grantShared, grantExclusive)
 | 
			
		||||
 | 
			
		||||
  // Client states and functions
 | 
			
		||||
  val nClientStates = 3
 | 
			
		||||
  val clientInvalid :: clientShared :: clientExclusiveDirty :: Nil = Enum(UInt(), nClientStates)
 | 
			
		||||
 | 
			
		||||
  val clientStatesWithReadPermission = Vec(clientShared, clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithWritePermission = Vec(clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithDirtyData = Vec(clientExclusiveDirty)
 | 
			
		||||
 | 
			
		||||
  def isValid(meta: ClientMetadata): Bool = meta.state != clientInvalid
 | 
			
		||||
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt =
 | 
			
		||||
    Mux(isWriteIntent(cmd), acquireExclusive, acquireShared)
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    MuxLookup(cmd, releaseCopyAck, Array(
 | 
			
		||||
      M_FLUSH   -> Mux(dirty, releaseInvalidateData, releaseInvalidateAck),
 | 
			
		||||
      M_PRODUCE -> Mux(dirty, releaseDowngradeData, releaseDowngradeAck),
 | 
			
		||||
      M_CLEAN   -> Mux(dirty, releaseCopyData, releaseCopyAck)))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(incoming: Probe, meta: ClientMetadata): UInt =
 | 
			
		||||
    MuxLookup(incoming.p_type, releaseInvalidateAck, Array(
 | 
			
		||||
      probeInvalidate -> getReleaseType(M_FLUSH, meta),
 | 
			
		||||
      probeDowngrade  -> getReleaseType(M_PRODUCE, meta),
 | 
			
		||||
      probeCopy       -> getReleaseType(M_CLEAN, meta)))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnReset = ClientMetadata(clientInvalid)
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(Mux(isWrite(cmd), clientExclusiveDirty, meta.state))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(cmd, meta.state, Array(
 | 
			
		||||
        M_FLUSH   -> clientInvalid,
 | 
			
		||||
        M_PRODUCE -> Mux(clientStatesWithWritePermission.contains(meta.state), 
 | 
			
		||||
                      clientShared, meta.state))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      Mux(incoming.isBuiltInType(), clientInvalid,
 | 
			
		||||
        MuxLookup(incoming.g_type, clientInvalid, Array(
 | 
			
		||||
          grantShared -> clientShared,
 | 
			
		||||
          grantExclusive -> clientExclusiveDirty,
 | 
			
		||||
          grantExclusiveAck -> clientExclusiveDirty))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata) = 
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(incoming.p_type, meta.state, Array(
 | 
			
		||||
        probeInvalidate -> clientInvalid,
 | 
			
		||||
        probeDowngrade  -> clientShared,
 | 
			
		||||
        probeCopy       -> meta.state)))
 | 
			
		||||
 | 
			
		||||
  // Manager states and functions:
 | 
			
		||||
  val nManagerStates = 0 // TODO: We could add a Shared state to avoid probing
 | 
			
		||||
                         //        only a single sharer (also would need 
 | 
			
		||||
                         //        notification msg to track clean drops)
 | 
			
		||||
                         //        Also could avoid probes on outer WBs.
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(a: Acquire, meta: ManagerMetadata) =
 | 
			
		||||
    Mux(dir.none(meta.sharers), Bool(false), 
 | 
			
		||||
      Mux(dir.one(meta.sharers), Bool(true), //TODO: for now we assume it's Exclusive
 | 
			
		||||
        Mux(a.isBuiltInType(), a.hasData(), a.a_type != acquireShared)))
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt =
 | 
			
		||||
    MuxLookup(cmd, probeCopy, Array(
 | 
			
		||||
      M_FLUSH -> probeInvalidate,
 | 
			
		||||
      M_PRODUCE -> probeDowngrade))
 | 
			
		||||
 | 
			
		||||
  def getProbeType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.isBuiltInType(), 
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        Acquire.getBlockType -> probeCopy, 
 | 
			
		||||
        Acquire.putBlockType -> probeInvalidate,
 | 
			
		||||
        Acquire.getType -> probeCopy, 
 | 
			
		||||
        Acquire.putType -> probeInvalidate,
 | 
			
		||||
        Acquire.putAtomicType -> probeInvalidate)),
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        acquireShared -> probeDowngrade,
 | 
			
		||||
        acquireExclusive -> probeInvalidate)))
 | 
			
		||||
 | 
			
		||||
  def getGrantType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.a_type === acquireShared,
 | 
			
		||||
      Mux(!dir.none(meta.sharers), grantShared, grantExclusive),
 | 
			
		||||
      grantExclusive)
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnReset = ManagerMetadata()
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata) = {
 | 
			
		||||
    val popped = ManagerMetadata(sharers=dir.pop(meta.sharers, src))
 | 
			
		||||
    MuxBundle(meta, Array(
 | 
			
		||||
      incoming.is(releaseInvalidateData) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAck)  -> popped))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** A protocol with four Client states.
 | 
			
		||||
  * Data is marked as dirty when written.
 | 
			
		||||
  * Multiple clients may share read permissions on a block at the same time.
 | 
			
		||||
  */
 | 
			
		||||
class MESICoherence(dir: DirectoryRepresentation) extends CoherencePolicy(dir) {
 | 
			
		||||
  // Message types
 | 
			
		||||
  val nAcquireTypes = 2
 | 
			
		||||
  val nProbeTypes = 3
 | 
			
		||||
  val nReleaseTypes = 6
 | 
			
		||||
  val nGrantTypes = 3
 | 
			
		||||
 | 
			
		||||
  val acquireShared :: acquireExclusive :: Nil = Enum(UInt(), nAcquireTypes)
 | 
			
		||||
  val probeInvalidate :: probeDowngrade :: probeCopy :: Nil = Enum(UInt(), nProbeTypes)
 | 
			
		||||
  val releaseInvalidateData :: releaseDowngradeData :: releaseCopyData :: releaseInvalidateAck :: releaseDowngradeAck :: releaseCopyAck :: Nil = Enum(UInt(), nReleaseTypes)
 | 
			
		||||
  val grantShared :: grantExclusive :: grantExclusiveAck :: Nil = Enum(UInt(), nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val releaseTypesWithData = Vec(releaseInvalidateData, releaseDowngradeData, releaseCopyData)
 | 
			
		||||
  val grantTypesWithData = Vec(grantShared, grantExclusive)
 | 
			
		||||
 | 
			
		||||
  // Client states and functions
 | 
			
		||||
  val nClientStates = 4
 | 
			
		||||
  val clientInvalid :: clientShared :: clientExclusiveClean :: clientExclusiveDirty :: Nil = Enum(UInt(), nClientStates)
 | 
			
		||||
 | 
			
		||||
  val clientStatesWithReadPermission = Vec(clientShared, clientExclusiveClean, clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithWritePermission = Vec(clientExclusiveClean, clientExclusiveDirty)
 | 
			
		||||
  val clientStatesWithDirtyData = Vec(clientExclusiveDirty)
 | 
			
		||||
 | 
			
		||||
  def isValid (meta: ClientMetadata): Bool = meta.state != clientInvalid
 | 
			
		||||
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt =
 | 
			
		||||
    Mux(isWriteIntent(cmd), acquireExclusive, acquireShared)
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    MuxLookup(cmd, releaseCopyAck, Array(
 | 
			
		||||
      M_FLUSH   -> Mux(dirty, releaseInvalidateData, releaseInvalidateAck),
 | 
			
		||||
      M_PRODUCE -> Mux(dirty, releaseDowngradeData, releaseDowngradeAck),
 | 
			
		||||
      M_CLEAN   -> Mux(dirty, releaseCopyData, releaseCopyAck)))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(incoming: Probe, meta: ClientMetadata): UInt =
 | 
			
		||||
    MuxLookup(incoming.p_type, releaseInvalidateAck, Array(
 | 
			
		||||
      probeInvalidate -> getReleaseType(M_FLUSH, meta),
 | 
			
		||||
      probeDowngrade  -> getReleaseType(M_PRODUCE, meta),
 | 
			
		||||
      probeCopy       -> getReleaseType(M_CLEAN, meta)))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnReset = ClientMetadata(clientInvalid)
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(Mux(isWrite(cmd), clientExclusiveDirty, meta.state))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(cmd, meta.state, Array(
 | 
			
		||||
        M_FLUSH   -> clientInvalid,
 | 
			
		||||
        M_PRODUCE -> Mux(clientStatesWithWritePermission.contains(meta.state), 
 | 
			
		||||
                      clientShared, meta.state),
 | 
			
		||||
        M_CLEAN   -> Mux(meta.state === clientExclusiveDirty, clientExclusiveClean, meta.state))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      Mux(incoming.isBuiltInType(), clientInvalid,
 | 
			
		||||
        MuxLookup(incoming.g_type, clientInvalid, Array(
 | 
			
		||||
          grantShared -> clientShared,
 | 
			
		||||
          grantExclusive -> Mux(isWrite(cmd), clientExclusiveDirty, clientExclusiveClean),
 | 
			
		||||
          grantExclusiveAck -> clientExclusiveDirty))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(incoming.p_type, meta.state, Array(
 | 
			
		||||
        probeInvalidate -> clientInvalid,
 | 
			
		||||
        probeDowngrade  -> clientShared,
 | 
			
		||||
        probeCopy       -> meta.state)))
 | 
			
		||||
 | 
			
		||||
  // Manager states and functions:
 | 
			
		||||
  val nManagerStates = 0 // TODO: We could add a Shared state to avoid probing
 | 
			
		||||
                         //        only a single sharer (also would need 
 | 
			
		||||
                         //        notification msg to track clean drops)
 | 
			
		||||
                         //        Also could avoid probes on outer WBs.
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(a: Acquire, meta: ManagerMetadata) =
 | 
			
		||||
    Mux(dir.none(meta.sharers), Bool(false), 
 | 
			
		||||
      Mux(dir.one(meta.sharers), Bool(true), //TODO: for now we assume it's Exclusive
 | 
			
		||||
        Mux(a.isBuiltInType(), a.hasData(), a.a_type != acquireShared)))
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt =
 | 
			
		||||
    MuxLookup(cmd, probeCopy, Array(
 | 
			
		||||
      M_FLUSH -> probeInvalidate,
 | 
			
		||||
      M_PRODUCE -> probeDowngrade))
 | 
			
		||||
 | 
			
		||||
  def getProbeType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.isBuiltInType(), 
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        Acquire.getBlockType -> probeCopy, 
 | 
			
		||||
        Acquire.putBlockType -> probeInvalidate,
 | 
			
		||||
        Acquire.getType -> probeCopy, 
 | 
			
		||||
        Acquire.putType -> probeInvalidate,
 | 
			
		||||
        Acquire.putAtomicType -> probeInvalidate)),
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        acquireShared -> probeDowngrade,
 | 
			
		||||
        acquireExclusive -> probeInvalidate)))
 | 
			
		||||
 | 
			
		||||
  def getGrantType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.a_type === acquireShared,
 | 
			
		||||
      Mux(!dir.none(meta.sharers), grantShared, grantExclusive),
 | 
			
		||||
      grantExclusive)
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnReset = ManagerMetadata()
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata) = {
 | 
			
		||||
    val popped = ManagerMetadata(sharers=dir.pop(meta.sharers, src))
 | 
			
		||||
    MuxBundle(meta, Array(
 | 
			
		||||
      incoming.is(releaseInvalidateData) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAck)  -> popped))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MigratoryCoherence(dir: DirectoryRepresentation) extends CoherencePolicy(dir) {
 | 
			
		||||
  // Message types
 | 
			
		||||
  val nAcquireTypes = 3
 | 
			
		||||
  val nProbeTypes = 4
 | 
			
		||||
  val nReleaseTypes = 10
 | 
			
		||||
  val nGrantTypes = 4
 | 
			
		||||
 | 
			
		||||
  val acquireShared :: acquireExclusive :: acquireInvalidateOthers :: Nil = Enum(UInt(), nAcquireTypes)
 | 
			
		||||
  val probeInvalidate :: probeDowngrade :: probeCopy :: probeInvalidateOthers :: Nil = Enum(UInt(), nProbeTypes)
 | 
			
		||||
  val releaseInvalidateData :: releaseDowngradeData :: releaseCopyData :: releaseInvalidateAck :: releaseDowngradeAck :: releaseCopyAck :: releaseDowngradeDataMigratory :: releaseDowngradeAckHasCopy :: releaseInvalidateDataMigratory :: releaseInvalidateAckMigratory :: Nil = Enum(UInt(), nReleaseTypes)
 | 
			
		||||
  val grantShared :: grantExclusive :: grantExclusiveAck :: grantReadMigratory :: Nil = Enum(UInt(), nGrantTypes)
 | 
			
		||||
 | 
			
		||||
  val releaseTypesWithData = Vec(releaseInvalidateData, releaseDowngradeData, releaseCopyData, releaseInvalidateDataMigratory, releaseDowngradeDataMigratory)
 | 
			
		||||
  val grantTypesWithData = Vec(grantShared, grantExclusive, grantReadMigratory)
 | 
			
		||||
 | 
			
		||||
  // Client states and functions
 | 
			
		||||
  val nClientStates = 7
 | 
			
		||||
  val clientInvalid :: clientShared :: clientExclusiveClean :: clientExclusiveDirty :: clientSharedByTwo :: clientMigratoryClean :: clientMigratoryDirty :: Nil = Enum(UInt(), nClientStates)
 | 
			
		||||
 | 
			
		||||
  val clientStatesWithReadPermission = Vec(clientShared, clientExclusiveClean, clientExclusiveDirty, clientSharedByTwo, clientMigratoryClean, clientMigratoryDirty)
 | 
			
		||||
  val clientStatesWithWritePermission = Vec(clientExclusiveClean, clientExclusiveDirty, clientMigratoryClean, clientMigratoryDirty)
 | 
			
		||||
  val clientStatesWithDirtyData = Vec(clientExclusiveDirty, clientMigratoryDirty)
 | 
			
		||||
 | 
			
		||||
  def isValid (meta: ClientMetadata): Bool = meta.state != clientInvalid
 | 
			
		||||
 | 
			
		||||
  def getAcquireType(cmd: UInt, meta: ClientMetadata): UInt =
 | 
			
		||||
    Mux(isWriteIntent(cmd), 
 | 
			
		||||
      Mux(meta.state === clientInvalid, acquireExclusive, acquireInvalidateOthers), 
 | 
			
		||||
      acquireShared)
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(cmd: UInt, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    MuxLookup(cmd, releaseCopyAck, Array(
 | 
			
		||||
      M_FLUSH   -> Mux(dirty, releaseInvalidateData, releaseInvalidateAck),
 | 
			
		||||
      M_PRODUCE -> Mux(dirty, releaseDowngradeData, releaseDowngradeAck),
 | 
			
		||||
      M_CLEAN   -> Mux(dirty, releaseCopyData, releaseCopyAck)))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def getReleaseType(incoming: Probe, meta: ClientMetadata): UInt = {
 | 
			
		||||
    val dirty = clientStatesWithDirtyData.contains(meta.state)
 | 
			
		||||
    val with_data = MuxLookup(incoming.p_type, releaseInvalidateData, Array(
 | 
			
		||||
      probeInvalidate -> Mux(Vec(clientExclusiveDirty, clientMigratoryDirty).contains(meta.state),
 | 
			
		||||
                          releaseInvalidateDataMigratory, releaseInvalidateData),
 | 
			
		||||
      probeDowngrade -> Mux(meta.state === clientMigratoryDirty,
 | 
			
		||||
                          releaseDowngradeDataMigratory, releaseDowngradeData),
 | 
			
		||||
      probeCopy -> releaseCopyData))
 | 
			
		||||
    val without_data = MuxLookup(incoming.p_type, releaseInvalidateAck, Array(
 | 
			
		||||
      probeInvalidate -> Mux(clientExclusiveClean === meta.state,
 | 
			
		||||
                           releaseInvalidateAckMigratory, releaseInvalidateAck),
 | 
			
		||||
      probeInvalidateOthers -> Mux(clientSharedByTwo === meta.state,
 | 
			
		||||
                                 releaseInvalidateAckMigratory, releaseInvalidateAck),
 | 
			
		||||
      probeDowngrade  -> Mux(meta.state != clientInvalid,
 | 
			
		||||
                           releaseDowngradeAckHasCopy, releaseDowngradeAck),
 | 
			
		||||
      probeCopy       -> releaseCopyAck))
 | 
			
		||||
    Mux(dirty, with_data, without_data)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnReset = ClientMetadata(clientInvalid)
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnHit(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      Mux(isWrite(cmd), MuxLookup(meta.state, clientExclusiveDirty, Array(
 | 
			
		||||
                          clientExclusiveClean -> clientExclusiveDirty,
 | 
			
		||||
                          clientMigratoryClean -> clientMigratoryDirty)),
 | 
			
		||||
                        meta.state))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnCacheControl(cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(cmd, meta.state, Array(
 | 
			
		||||
        M_FLUSH   -> clientInvalid,
 | 
			
		||||
        M_PRODUCE -> Mux(clientStatesWithWritePermission.contains(meta.state), 
 | 
			
		||||
                       clientShared, meta.state),
 | 
			
		||||
        M_CLEAN   -> MuxLookup(meta.state, meta.state, Array(
 | 
			
		||||
                       clientExclusiveDirty -> clientExclusiveClean,
 | 
			
		||||
                       clientMigratoryDirty -> clientMigratoryClean)))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnGrant(incoming: Grant, cmd: UInt, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      Mux(incoming.isBuiltInType(), clientInvalid,
 | 
			
		||||
        MuxLookup(incoming.g_type, clientInvalid, Array(
 | 
			
		||||
          grantShared        -> clientShared,
 | 
			
		||||
          grantExclusive     -> Mux(isWrite(cmd), clientExclusiveDirty, clientExclusiveClean),
 | 
			
		||||
          grantExclusiveAck  -> clientExclusiveDirty, 
 | 
			
		||||
          grantReadMigratory -> Mux(isWrite(cmd), clientMigratoryDirty, clientMigratoryClean)))))
 | 
			
		||||
 | 
			
		||||
  def clientMetadataOnProbe(incoming: Probe, meta: ClientMetadata) =
 | 
			
		||||
    ClientMetadata(
 | 
			
		||||
      MuxLookup(incoming.p_type, meta.state, Array(
 | 
			
		||||
        probeInvalidate -> clientInvalid,
 | 
			
		||||
        probeInvalidateOthers -> clientInvalid,
 | 
			
		||||
        probeCopy -> meta.state,
 | 
			
		||||
        probeDowngrade -> MuxLookup(meta.state, clientShared, Array(
 | 
			
		||||
                                clientExclusiveClean -> clientSharedByTwo,
 | 
			
		||||
                                clientExclusiveDirty -> clientSharedByTwo,
 | 
			
		||||
                                clientSharedByTwo    -> clientShared,
 | 
			
		||||
                                clientMigratoryClean -> clientSharedByTwo,
 | 
			
		||||
                                clientMigratoryDirty -> clientInvalid)))))
 | 
			
		||||
 | 
			
		||||
  // Manager states and functions:
 | 
			
		||||
  val nManagerStates = 0 // TODO: we could add some states to reduce the number of message types
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(a: Acquire, meta: ManagerMetadata) =
 | 
			
		||||
    Mux(dir.none(meta.sharers), Bool(false),
 | 
			
		||||
      Mux(dir.one(meta.sharers), Bool(true), //TODO: for now we assume it's Exclusive
 | 
			
		||||
        Mux(a.isBuiltInType(), a.hasData(), a.a_type != acquireShared)))
 | 
			
		||||
 | 
			
		||||
  def requiresProbes(cmd: UInt, meta: ManagerMetadata) = !dir.none(meta.sharers)
 | 
			
		||||
 | 
			
		||||
  def getProbeType(cmd: UInt, meta: ManagerMetadata): UInt =
 | 
			
		||||
    MuxLookup(cmd, probeCopy, Array(
 | 
			
		||||
      M_FLUSH -> probeInvalidate,
 | 
			
		||||
      M_PRODUCE -> probeDowngrade))
 | 
			
		||||
 | 
			
		||||
  def getProbeType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
    Mux(a.isBuiltInType(), 
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        Acquire.getBlockType -> probeCopy, 
 | 
			
		||||
        Acquire.putBlockType -> probeInvalidate,
 | 
			
		||||
        Acquire.getType -> probeCopy, 
 | 
			
		||||
        Acquire.putType -> probeInvalidate,
 | 
			
		||||
        Acquire.putAtomicType -> probeInvalidate)),
 | 
			
		||||
      MuxLookup(a.a_type, probeCopy, Array(
 | 
			
		||||
        acquireShared -> probeDowngrade,
 | 
			
		||||
        acquireExclusive -> probeInvalidate, 
 | 
			
		||||
        acquireInvalidateOthers -> probeInvalidateOthers)))
 | 
			
		||||
 | 
			
		||||
  def getGrantType(a: Acquire, meta: ManagerMetadata): UInt =
 | 
			
		||||
      MuxLookup(a.a_type, grantShared, Array(
 | 
			
		||||
        acquireShared    -> Mux(!dir.none(meta.sharers), grantShared, grantExclusive),
 | 
			
		||||
        acquireExclusive -> grantExclusive,                                            
 | 
			
		||||
        acquireInvalidateOthers -> grantExclusiveAck))  //TODO: add this to MESI for broadcast?
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnReset = ManagerMetadata()
 | 
			
		||||
 | 
			
		||||
  def managerMetadataOnRelease(incoming: Release, src: UInt, meta: ManagerMetadata) = {
 | 
			
		||||
    val popped = ManagerMetadata(sharers=dir.pop(meta.sharers, src))
 | 
			
		||||
    MuxBundle(meta, Array(
 | 
			
		||||
      incoming.is(releaseInvalidateData) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAck)  -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateDataMigratory) -> popped,
 | 
			
		||||
      incoming.is(releaseInvalidateAckMigratory) -> popped))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								uncore/src/main/scala/consts.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								uncore/src/main/scala/consts.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
package constants
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
object MemoryOpConstants extends MemoryOpConstants
 | 
			
		||||
trait MemoryOpConstants {
 | 
			
		||||
  val MT_SZ = 3
 | 
			
		||||
  val MT_X  = Bits("b???")
 | 
			
		||||
  val MT_B  = Bits("b000")
 | 
			
		||||
  val MT_H  = Bits("b001")
 | 
			
		||||
  val MT_W  = Bits("b010")
 | 
			
		||||
  val MT_D  = Bits("b011")
 | 
			
		||||
  val MT_BU = Bits("b100")
 | 
			
		||||
  val MT_HU = Bits("b101")
 | 
			
		||||
  val MT_WU = Bits("b110")
 | 
			
		||||
 | 
			
		||||
  val NUM_XA_OPS = 9
 | 
			
		||||
  val M_SZ      = 5
 | 
			
		||||
  val M_X       = Bits("b?????");
 | 
			
		||||
  val M_XRD     = Bits("b00000"); // int load
 | 
			
		||||
  val M_XWR     = Bits("b00001"); // int store
 | 
			
		||||
  val M_PFR     = Bits("b00010"); // prefetch with intent to read
 | 
			
		||||
  val M_PFW     = Bits("b00011"); // prefetch with intent to write
 | 
			
		||||
  val M_XA_SWAP = Bits("b00100");
 | 
			
		||||
  val M_NOP     = Bits("b00101");
 | 
			
		||||
  val M_XLR     = Bits("b00110");
 | 
			
		||||
  val M_XSC     = Bits("b00111");
 | 
			
		||||
  val M_XA_ADD  = Bits("b01000");
 | 
			
		||||
  val M_XA_XOR  = Bits("b01001");
 | 
			
		||||
  val M_XA_OR   = Bits("b01010");
 | 
			
		||||
  val M_XA_AND  = Bits("b01011");
 | 
			
		||||
  val M_XA_MIN  = Bits("b01100");
 | 
			
		||||
  val M_XA_MAX  = Bits("b01101");
 | 
			
		||||
  val M_XA_MINU = Bits("b01110");
 | 
			
		||||
  val M_XA_MAXU = Bits("b01111");
 | 
			
		||||
  val M_FLUSH   = Bits("b10000") // write back dirty data and cede R/W permissions
 | 
			
		||||
  val M_PRODUCE = Bits("b10001") // write back dirty data and cede W permissions
 | 
			
		||||
  val M_CLEAN   = Bits("b10011") // write back dirty data and retain R/W permissions
 | 
			
		||||
 | 
			
		||||
  def isAMO(cmd: Bits) = cmd(3) || cmd === M_XA_SWAP
 | 
			
		||||
  def isPrefetch(cmd: Bits) = cmd === M_PFR || cmd === M_PFW
 | 
			
		||||
  def isRead(cmd: Bits) = cmd === M_XRD || cmd === M_XLR || isAMO(cmd)
 | 
			
		||||
  def isWrite(cmd: Bits) = cmd === M_XWR || cmd === M_XSC || isAMO(cmd)
 | 
			
		||||
  def isWriteIntent(cmd: Bits) = isWrite(cmd) || cmd === M_PFW || cmd === M_XLR
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								uncore/src/main/scala/directory.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								uncore/src/main/scala/directory.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
// This class encapsulates transformations on different directory information
 | 
			
		||||
// storage formats
 | 
			
		||||
abstract class DirectoryRepresentation(val width: Int) {
 | 
			
		||||
  def pop(prev: UInt, id: UInt): UInt
 | 
			
		||||
  def push(prev: UInt, id: UInt): UInt
 | 
			
		||||
  def flush: UInt
 | 
			
		||||
  def none(s: UInt): Bool
 | 
			
		||||
  def one(s: UInt): Bool
 | 
			
		||||
  def count(s: UInt): UInt
 | 
			
		||||
  def next(s: UInt): UInt
 | 
			
		||||
  def full(s: UInt): UInt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract trait HasDirectoryRepresentation {
 | 
			
		||||
  val dir: DirectoryRepresentation
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class NullRepresentation(nClients: Int) extends DirectoryRepresentation(1) {
 | 
			
		||||
  def pop(prev: UInt, id: UInt) = UInt(0)
 | 
			
		||||
  def push(prev: UInt, id: UInt) = UInt(0)
 | 
			
		||||
  def flush  = UInt(0)
 | 
			
		||||
  def none(s: UInt) = Bool(false)
 | 
			
		||||
  def one(s: UInt) = Bool(false)
 | 
			
		||||
  def count(s: UInt) = UInt(nClients)
 | 
			
		||||
  def next(s: UInt) = UInt(0)
 | 
			
		||||
  def full(s: UInt) = SInt(-1, width = nClients).toUInt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class FullRepresentation(nClients: Int) extends DirectoryRepresentation(nClients) {
 | 
			
		||||
  def pop(prev: UInt, id: UInt) =  prev &  ~UIntToOH(id)
 | 
			
		||||
  def push(prev: UInt, id: UInt) = prev | UIntToOH(id)
 | 
			
		||||
  def flush = UInt(0, width = width)
 | 
			
		||||
  def none(s: UInt) = s === UInt(0)
 | 
			
		||||
  def one(s: UInt) = PopCount(s) === UInt(1)
 | 
			
		||||
  def count(s: UInt) = PopCount(s)
 | 
			
		||||
  def next(s: UInt) = PriorityEncoder(s)
 | 
			
		||||
  def full(s: UInt) = s
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										146
									
								
								uncore/src/main/scala/ecc.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								uncore/src/main/scala/ecc.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
abstract class Decoding
 | 
			
		||||
{
 | 
			
		||||
  def uncorrected: Bits
 | 
			
		||||
  def corrected: Bits
 | 
			
		||||
  def correctable: Bool
 | 
			
		||||
  def uncorrectable: Bool
 | 
			
		||||
  def error = correctable || uncorrectable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class Code
 | 
			
		||||
{
 | 
			
		||||
  def width(w0: Int): Int
 | 
			
		||||
  def encode(x: Bits): Bits
 | 
			
		||||
  def decode(x: Bits): Decoding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class IdentityCode extends Code
 | 
			
		||||
{
 | 
			
		||||
  def width(w0: Int) = w0
 | 
			
		||||
  def encode(x: Bits) = x
 | 
			
		||||
  def decode(y: Bits) = new Decoding {
 | 
			
		||||
    def uncorrected = y
 | 
			
		||||
    def corrected = y
 | 
			
		||||
    def correctable = Bool(false)
 | 
			
		||||
    def uncorrectable = Bool(false)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ParityCode extends Code
 | 
			
		||||
{
 | 
			
		||||
  def width(w0: Int) = w0+1
 | 
			
		||||
  def encode(x: Bits) = Cat(x.xorR, x)
 | 
			
		||||
  def decode(y: Bits) = new Decoding {
 | 
			
		||||
    def uncorrected = y(y.getWidth-2,0)
 | 
			
		||||
    def corrected = uncorrected
 | 
			
		||||
    def correctable = Bool(false)
 | 
			
		||||
    def uncorrectable = y.xorR
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SECCode extends Code
 | 
			
		||||
{
 | 
			
		||||
  def width(k: Int) = {
 | 
			
		||||
    val m = new Unsigned(k).log2 + 1
 | 
			
		||||
    k + m + (if((1 << m) < m+k+1) 1 else 0)
 | 
			
		||||
  }
 | 
			
		||||
  def encode(x: Bits) = {
 | 
			
		||||
    val k = x.getWidth
 | 
			
		||||
    require(k > 0)
 | 
			
		||||
    val n = width(k)
 | 
			
		||||
 | 
			
		||||
    val y = for (i <- 1 to n) yield {
 | 
			
		||||
      if (isPow2(i)) {
 | 
			
		||||
        val r = for (j <- 1 to n; if j != i && (j & i) != 0)
 | 
			
		||||
          yield x(mapping(j))
 | 
			
		||||
        r reduce (_^_)
 | 
			
		||||
      } else
 | 
			
		||||
        x(mapping(i))
 | 
			
		||||
    }
 | 
			
		||||
    Vec(y).toBits
 | 
			
		||||
  }
 | 
			
		||||
  def decode(y: Bits) = new Decoding {
 | 
			
		||||
    val n = y.getWidth
 | 
			
		||||
    require(n > 0 && !isPow2(n))
 | 
			
		||||
 | 
			
		||||
    val p2 = for (i <- 0 until log2Up(n)) yield 1 << i
 | 
			
		||||
    val syndrome = p2 map { i =>
 | 
			
		||||
      val r = for (j <- 1 to n; if (j & i) != 0)
 | 
			
		||||
        yield y(j-1)
 | 
			
		||||
      r reduce (_^_)
 | 
			
		||||
    }
 | 
			
		||||
    val s = Vec(syndrome).toBits
 | 
			
		||||
 | 
			
		||||
    private def swizzle(z: Bits) = Vec((1 to n).filter(i => !isPow2(i)).map(i => z(i-1))).toBits
 | 
			
		||||
    def uncorrected = swizzle(y)
 | 
			
		||||
    def corrected = swizzle(((y.toUInt << UInt(1)) ^ UIntToOH(s)) >> UInt(1))
 | 
			
		||||
    def correctable = s.orR
 | 
			
		||||
    def uncorrectable = Bool(false)
 | 
			
		||||
  }
 | 
			
		||||
  private def mapping(i: Int) = i-1-log2Up(i)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SECDEDCode extends Code
 | 
			
		||||
{
 | 
			
		||||
  private val sec = new SECCode
 | 
			
		||||
  private val par = new ParityCode
 | 
			
		||||
 | 
			
		||||
  def width(k: Int) = sec.width(k)+1
 | 
			
		||||
  def encode(x: Bits) = par.encode(sec.encode(x))
 | 
			
		||||
  def decode(x: Bits) = new Decoding {
 | 
			
		||||
    val secdec = sec.decode(x(x.getWidth-2,0))
 | 
			
		||||
    val pardec = par.decode(x)
 | 
			
		||||
 | 
			
		||||
    def uncorrected = secdec.uncorrected
 | 
			
		||||
    def corrected = secdec.corrected
 | 
			
		||||
    def correctable = pardec.uncorrectable
 | 
			
		||||
    def uncorrectable = !pardec.uncorrectable && secdec.correctable
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object ErrGen
 | 
			
		||||
{
 | 
			
		||||
  // generate a 1-bit error with approximate probability 2^-f
 | 
			
		||||
  def apply(width: Int, f: Int): Bits = {
 | 
			
		||||
    require(width > 0 && f >= 0 && log2Up(width) + f <= 16)
 | 
			
		||||
    UIntToOH(LFSR16()(log2Up(width)+f-1,0))(width-1,0)
 | 
			
		||||
  }
 | 
			
		||||
  def apply(x: Bits, f: Int): Bits = x ^ apply(x.getWidth, f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SECDEDTest extends Module
 | 
			
		||||
{
 | 
			
		||||
  val code = new SECDEDCode
 | 
			
		||||
  val k = 4
 | 
			
		||||
  val n = code.width(k)
 | 
			
		||||
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val original = Bits(OUTPUT, k)
 | 
			
		||||
    val encoded = Bits(OUTPUT, n)
 | 
			
		||||
    val injected = Bits(OUTPUT, n)
 | 
			
		||||
    val uncorrected = Bits(OUTPUT, k)
 | 
			
		||||
    val corrected = Bits(OUTPUT, k)
 | 
			
		||||
    val correctable = Bool(OUTPUT)
 | 
			
		||||
    val uncorrectable = Bool(OUTPUT)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val c = Counter(Bool(true), 1 << k)
 | 
			
		||||
  val numErrors = Counter(c._2, 3)._1
 | 
			
		||||
  val e = code.encode(c._1)
 | 
			
		||||
  val i = e ^ Mux(numErrors < UInt(1), UInt(0), ErrGen(n, 1)) ^ Mux(numErrors < UInt(2), UInt(0), ErrGen(n, 1))
 | 
			
		||||
  val d = code.decode(i)
 | 
			
		||||
 | 
			
		||||
  io.original := c._1
 | 
			
		||||
  io.encoded := e
 | 
			
		||||
  io.injected := i
 | 
			
		||||
  io.uncorrected := d.uncorrected
 | 
			
		||||
  io.corrected := d.corrected
 | 
			
		||||
  io.correctable := d.correctable
 | 
			
		||||
  io.uncorrectable := d.uncorrectable
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										255
									
								
								uncore/src/main/scala/htif.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								uncore/src/main/scala/htif.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,255 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
import Node._
 | 
			
		||||
import uncore._
 | 
			
		||||
 | 
			
		||||
case object HTIFWidth extends Field[Int]
 | 
			
		||||
case object HTIFNSCR extends Field[Int]
 | 
			
		||||
case object HTIFOffsetBits extends Field[Int]
 | 
			
		||||
case object HTIFNCores extends Field[Int]
 | 
			
		||||
 | 
			
		||||
abstract trait HTIFParameters extends UsesParameters {
 | 
			
		||||
  val dataBits = params(TLDataBits)
 | 
			
		||||
  val dataBeats = params(TLDataBeats)
 | 
			
		||||
  val w = params(HTIFWidth)
 | 
			
		||||
  val nSCR = params(HTIFNSCR)
 | 
			
		||||
  val offsetBits = params(HTIFOffsetBits)
 | 
			
		||||
  val nCores = params(HTIFNCores)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class HTIFBundle extends Bundle with HTIFParameters
 | 
			
		||||
 | 
			
		||||
class HostIO extends HTIFBundle
 | 
			
		||||
{
 | 
			
		||||
  val clk = Bool(OUTPUT)
 | 
			
		||||
  val clk_edge = Bool(OUTPUT)
 | 
			
		||||
  val in = Decoupled(Bits(width = w)).flip
 | 
			
		||||
  val out = Decoupled(Bits(width = w))
 | 
			
		||||
  val debug_stats_pcr = Bool(OUTPUT)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PCRReq extends Bundle
 | 
			
		||||
{
 | 
			
		||||
  val rw = Bool()
 | 
			
		||||
  val addr = Bits(width = 12)
 | 
			
		||||
  val data = Bits(width = 64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HTIFIO extends HTIFBundle {
 | 
			
		||||
  val reset = Bool(INPUT)
 | 
			
		||||
  val id = UInt(INPUT, log2Up(nCores))
 | 
			
		||||
  val pcr_req = Decoupled(new PCRReq).flip
 | 
			
		||||
  val pcr_rep = Decoupled(Bits(width = 64))
 | 
			
		||||
  val ipi_req = Decoupled(Bits(width = log2Up(nCores)))
 | 
			
		||||
  val ipi_rep = Decoupled(Bool()).flip
 | 
			
		||||
  val debug_stats_pcr = Bool(OUTPUT)
 | 
			
		||||
    // wired directly to stats register
 | 
			
		||||
    // expected to be used to quickly indicate to testbench to do logging b/c in 'interesting' work
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SCRIO extends HTIFBundle {
 | 
			
		||||
  val rdata = Vec.fill(nSCR){Bits(INPUT, 64)}
 | 
			
		||||
  val wen = Bool(OUTPUT)
 | 
			
		||||
  val waddr = UInt(OUTPUT, log2Up(nSCR))
 | 
			
		||||
  val wdata = Bits(OUTPUT, 64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HTIFModuleIO extends HTIFBundle {
 | 
			
		||||
    val host = new HostIO
 | 
			
		||||
    val cpu = Vec.fill(nCores){new HTIFIO}.flip
 | 
			
		||||
    val mem = new ClientUncachedTileLinkIO
 | 
			
		||||
    val scr = new SCRIO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HTIF(pcr_RESET: Int) extends Module with HTIFParameters {
 | 
			
		||||
  val io = new HTIFModuleIO
 | 
			
		||||
 | 
			
		||||
  io.host.debug_stats_pcr := io.cpu.map(_.debug_stats_pcr).reduce(_||_)
 | 
			
		||||
    // system is 'interesting' if any tile is 'interesting'
 | 
			
		||||
 | 
			
		||||
  val short_request_bits = 64
 | 
			
		||||
  val long_request_bits = short_request_bits + dataBits*dataBeats
 | 
			
		||||
  require(short_request_bits % w == 0)
 | 
			
		||||
 | 
			
		||||
  val rx_count_w = 13 + log2Up(64) - log2Up(w) // data size field is 12 bits
 | 
			
		||||
  val rx_count = Reg(init=UInt(0,rx_count_w))
 | 
			
		||||
  val rx_shifter = Reg(Bits(width = short_request_bits))
 | 
			
		||||
  val rx_shifter_in = Cat(io.host.in.bits, rx_shifter(short_request_bits-1,w))
 | 
			
		||||
  val next_cmd = rx_shifter_in(3,0)
 | 
			
		||||
  val cmd = Reg(Bits())
 | 
			
		||||
  val size = Reg(Bits())
 | 
			
		||||
  val pos = Reg(Bits())
 | 
			
		||||
  val seqno = Reg(Bits())
 | 
			
		||||
  val addr = Reg(Bits())
 | 
			
		||||
  when (io.host.in.valid && io.host.in.ready) {
 | 
			
		||||
    rx_shifter := rx_shifter_in
 | 
			
		||||
    rx_count := rx_count + UInt(1)
 | 
			
		||||
    when (rx_count === UInt(short_request_bits/w-1)) {
 | 
			
		||||
      cmd := next_cmd
 | 
			
		||||
      size := rx_shifter_in(15,4)
 | 
			
		||||
      pos := rx_shifter_in(15,4+offsetBits-3)
 | 
			
		||||
      seqno := rx_shifter_in(23,16)
 | 
			
		||||
      addr := rx_shifter_in(63,24)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val rx_word_count = (rx_count >> UInt(log2Up(short_request_bits/w)))
 | 
			
		||||
  val rx_word_done = io.host.in.valid && rx_count(log2Up(short_request_bits/w)-1,0).andR
 | 
			
		||||
  val packet_ram_depth = long_request_bits/short_request_bits-1
 | 
			
		||||
  val packet_ram = Mem(Bits(width = short_request_bits), packet_ram_depth)
 | 
			
		||||
  when (rx_word_done && io.host.in.ready) {
 | 
			
		||||
    packet_ram(rx_word_count(log2Up(packet_ram_depth)-1,0) - UInt(1)) := rx_shifter_in
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val cmd_readmem :: cmd_writemem :: cmd_readcr :: cmd_writecr :: cmd_ack :: cmd_nack :: Nil = Enum(UInt(), 6)
 | 
			
		||||
 | 
			
		||||
  val pcr_addr = addr(io.cpu(0).pcr_req.bits.addr.getWidth-1, 0)
 | 
			
		||||
  val pcr_coreid = addr(log2Up(nCores)-1+20+1,20)
 | 
			
		||||
  val pcr_wdata = packet_ram(0)
 | 
			
		||||
 | 
			
		||||
  val bad_mem_packet = size(offsetBits-1-3,0).orR || addr(offsetBits-1-3,0).orR
 | 
			
		||||
  val nack = Mux(cmd === cmd_readmem || cmd === cmd_writemem, bad_mem_packet,
 | 
			
		||||
             Mux(cmd === cmd_readcr || cmd === cmd_writecr, size != UInt(1),
 | 
			
		||||
             Bool(true)))
 | 
			
		||||
 | 
			
		||||
  val tx_count = Reg(init=UInt(0, rx_count_w))
 | 
			
		||||
  val tx_subword_count = tx_count(log2Up(short_request_bits/w)-1,0)
 | 
			
		||||
  val tx_word_count = tx_count(rx_count_w-1, log2Up(short_request_bits/w))
 | 
			
		||||
  val packet_ram_raddr = tx_word_count(log2Up(packet_ram_depth)-1,0) - UInt(1)
 | 
			
		||||
  when (io.host.out.valid && io.host.out.ready) {
 | 
			
		||||
    tx_count := tx_count + UInt(1)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val rx_done = rx_word_done && Mux(rx_word_count === UInt(0), next_cmd != cmd_writemem && next_cmd != cmd_writecr, rx_word_count === size || rx_word_count(log2Up(packet_ram_depth)-1,0) === UInt(0))
 | 
			
		||||
  val tx_size = Mux(!nack && (cmd === cmd_readmem || cmd === cmd_readcr || cmd === cmd_writecr), size, UInt(0))
 | 
			
		||||
  val tx_done = io.host.out.ready && tx_subword_count.andR && (tx_word_count === tx_size || tx_word_count > UInt(0) && packet_ram_raddr.andR)
 | 
			
		||||
 | 
			
		||||
  val state_rx :: state_pcr_req :: state_pcr_resp :: state_mem_rreq :: state_mem_wreq :: state_mem_rresp :: state_mem_wresp :: state_tx :: Nil = Enum(UInt(), 8)
 | 
			
		||||
  val state = Reg(init=state_rx)
 | 
			
		||||
 | 
			
		||||
  val (cnt, cnt_done) = Counter((state === state_mem_wreq && io.mem.acquire.ready) ||
 | 
			
		||||
                                 (state === state_mem_rresp && io.mem.grant.valid), dataBeats)
 | 
			
		||||
  val rx_cmd = Mux(rx_word_count === UInt(0), next_cmd, cmd)
 | 
			
		||||
  when (state === state_rx && rx_done) {
 | 
			
		||||
    state := Mux(rx_cmd === cmd_readmem, state_mem_rreq,
 | 
			
		||||
             Mux(rx_cmd === cmd_writemem, state_mem_wreq,
 | 
			
		||||
             Mux(rx_cmd === cmd_readcr || rx_cmd === cmd_writecr, state_pcr_req,
 | 
			
		||||
             state_tx)))
 | 
			
		||||
  }
 | 
			
		||||
  when (state === state_mem_wreq) {
 | 
			
		||||
    when (cnt_done) { state := state_mem_wresp }
 | 
			
		||||
  }
 | 
			
		||||
  when (state === state_mem_rreq) {
 | 
			
		||||
    when(io.mem.acquire.ready) { state := state_mem_rresp }
 | 
			
		||||
  }
 | 
			
		||||
  when (state === state_mem_wresp && io.mem.grant.valid) {
 | 
			
		||||
    state := Mux(cmd === cmd_readmem || pos === UInt(1),  state_tx, state_rx)
 | 
			
		||||
    pos := pos - UInt(1)
 | 
			
		||||
    addr := addr + UInt(1 << offsetBits-3)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === state_mem_rresp && cnt_done) {
 | 
			
		||||
    state := Mux(cmd === cmd_readmem || pos === UInt(1),  state_tx, state_rx)
 | 
			
		||||
    pos := pos - UInt(1)
 | 
			
		||||
    addr := addr + UInt(1 << offsetBits-3)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === state_tx && tx_done) {
 | 
			
		||||
    when (tx_word_count === tx_size) {
 | 
			
		||||
      rx_count := UInt(0)
 | 
			
		||||
      tx_count := UInt(0)
 | 
			
		||||
    }
 | 
			
		||||
    state := Mux(cmd === cmd_readmem && pos != UInt(0), state_mem_rreq, state_rx)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val n = dataBits/short_request_bits
 | 
			
		||||
  val mem_req_data = (0 until n).map { i =>
 | 
			
		||||
    val ui = UInt(i, log2Up(n))
 | 
			
		||||
    when (state === state_mem_rresp && io.mem.grant.valid) {
 | 
			
		||||
      packet_ram(Cat(io.mem.grant.bits.addr_beat, ui)) := 
 | 
			
		||||
        io.mem.grant.bits.data((i+1)*short_request_bits-1, i*short_request_bits)
 | 
			
		||||
    }
 | 
			
		||||
    packet_ram(Cat(cnt, ui))
 | 
			
		||||
  }.reverse.reduce(_##_)
 | 
			
		||||
 | 
			
		||||
  val init_addr = addr.toUInt >> UInt(offsetBits-3)
 | 
			
		||||
  io.mem.acquire.valid := state === state_mem_rreq || state === state_mem_wreq
 | 
			
		||||
  io.mem.acquire.bits := Mux(cmd === cmd_writemem, 
 | 
			
		||||
    PutBlock(
 | 
			
		||||
      addr_block = init_addr,
 | 
			
		||||
      addr_beat = cnt,
 | 
			
		||||
      client_xact_id = UInt(0),
 | 
			
		||||
      data = mem_req_data), 
 | 
			
		||||
    GetBlock(addr_block = init_addr))
 | 
			
		||||
  io.mem.grant.ready := Bool(true)
 | 
			
		||||
 | 
			
		||||
  val pcrReadData = Reg(Bits(width = io.cpu(0).pcr_rep.bits.getWidth))
 | 
			
		||||
  for (i <- 0 until nCores) {
 | 
			
		||||
    val my_reset = Reg(init=Bool(true))
 | 
			
		||||
    val my_ipi = Reg(init=Bool(false))
 | 
			
		||||
 | 
			
		||||
    val cpu = io.cpu(i)
 | 
			
		||||
    val me = pcr_coreid === UInt(i)
 | 
			
		||||
    cpu.pcr_req.valid := state === state_pcr_req && me && pcr_addr != UInt(pcr_RESET)
 | 
			
		||||
    cpu.pcr_req.bits.rw := cmd === cmd_writecr
 | 
			
		||||
    cpu.pcr_req.bits.addr := pcr_addr
 | 
			
		||||
    cpu.pcr_req.bits.data := pcr_wdata
 | 
			
		||||
    cpu.reset := my_reset
 | 
			
		||||
 | 
			
		||||
    when (cpu.ipi_rep.ready) {
 | 
			
		||||
      my_ipi := Bool(false)
 | 
			
		||||
    }
 | 
			
		||||
    cpu.ipi_rep.valid := my_ipi
 | 
			
		||||
    cpu.ipi_req.ready := Bool(true)
 | 
			
		||||
    for (j <- 0 until nCores) {
 | 
			
		||||
      when (io.cpu(j).ipi_req.valid && io.cpu(j).ipi_req.bits === UInt(i)) {
 | 
			
		||||
        my_ipi := Bool(true)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    when (cpu.pcr_req.valid && cpu.pcr_req.ready) {
 | 
			
		||||
      state := state_pcr_resp
 | 
			
		||||
    }
 | 
			
		||||
    when (state === state_pcr_req && me && pcr_addr === UInt(pcr_RESET)) {
 | 
			
		||||
      when (cmd === cmd_writecr) {
 | 
			
		||||
        my_reset := pcr_wdata(0)
 | 
			
		||||
      }
 | 
			
		||||
      pcrReadData := my_reset.toBits
 | 
			
		||||
      state := state_tx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cpu.pcr_rep.ready := Bool(true)
 | 
			
		||||
    when (cpu.pcr_rep.valid) {
 | 
			
		||||
      pcrReadData := cpu.pcr_rep.bits
 | 
			
		||||
      state := state_tx
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val scr_addr = addr(log2Up(nSCR)-1, 0)
 | 
			
		||||
  val scr_rdata = Vec.fill(io.scr.rdata.size){Bits(width = 64)}
 | 
			
		||||
  for (i <- 0 until scr_rdata.size)
 | 
			
		||||
    scr_rdata(i) := io.scr.rdata(i)
 | 
			
		||||
  scr_rdata(0) := UInt(nCores)
 | 
			
		||||
  scr_rdata(1) := UInt((BigInt(dataBits*dataBeats/8) << params(TLBlockAddrBits)) >> 20)
 | 
			
		||||
 | 
			
		||||
  io.scr.wen := Bool(false)
 | 
			
		||||
  io.scr.wdata := pcr_wdata
 | 
			
		||||
  io.scr.waddr := scr_addr.toUInt
 | 
			
		||||
  when (state === state_pcr_req && pcr_coreid === SInt(-1)) {
 | 
			
		||||
    io.scr.wen := cmd === cmd_writecr
 | 
			
		||||
    pcrReadData := scr_rdata(scr_addr)
 | 
			
		||||
    state := state_tx
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val tx_cmd = Mux(nack, cmd_nack, cmd_ack)
 | 
			
		||||
  val tx_cmd_ext = Cat(Bits(0, 4-tx_cmd.getWidth), tx_cmd)
 | 
			
		||||
  val tx_header = Cat(addr, seqno, tx_size, tx_cmd_ext)
 | 
			
		||||
  val tx_data = Mux(tx_word_count === UInt(0), tx_header,
 | 
			
		||||
                Mux(cmd === cmd_readcr || cmd === cmd_writecr, pcrReadData,
 | 
			
		||||
                packet_ram(packet_ram_raddr)))
 | 
			
		||||
 | 
			
		||||
  io.host.in.ready := state === state_rx
 | 
			
		||||
  io.host.out.valid := state === state_tx
 | 
			
		||||
  io.host.out.bits := tx_data >> Cat(tx_count(log2Up(short_request_bits/w)-1,0), Bits(0, log2Up(w)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										584
									
								
								uncore/src/main/scala/memserdes.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										584
									
								
								uncore/src/main/scala/memserdes.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,584 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
import scala.math._
 | 
			
		||||
 | 
			
		||||
case object PAddrBits extends Field[Int]
 | 
			
		||||
case object VAddrBits extends Field[Int]
 | 
			
		||||
case object PgIdxBits extends Field[Int]
 | 
			
		||||
case object PgLevels extends Field[Int]
 | 
			
		||||
case object PgLevelBits extends Field[Int]
 | 
			
		||||
case object ASIdBits extends Field[Int]
 | 
			
		||||
case object PPNBits extends Field[Int]
 | 
			
		||||
case object VPNBits extends Field[Int]
 | 
			
		||||
 | 
			
		||||
case object MIFAddrBits extends Field[Int]
 | 
			
		||||
case object MIFDataBits extends Field[Int]
 | 
			
		||||
case object MIFTagBits extends Field[Int]
 | 
			
		||||
case object MIFDataBeats extends Field[Int]
 | 
			
		||||
 | 
			
		||||
trait MIFParameters extends UsesParameters {
 | 
			
		||||
  val mifTagBits = params(MIFTagBits)
 | 
			
		||||
  val mifAddrBits = params(MIFAddrBits)
 | 
			
		||||
  val mifDataBits = params(MIFDataBits)
 | 
			
		||||
  val mifDataBeats = params(MIFDataBeats)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
abstract class MIFBundle extends Bundle with MIFParameters
 | 
			
		||||
abstract class MIFModule extends Module with MIFParameters
 | 
			
		||||
 | 
			
		||||
trait HasMemData extends MIFBundle {
 | 
			
		||||
  val data = Bits(width = mifDataBits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasMemAddr extends MIFBundle {
 | 
			
		||||
  val addr = UInt(width = mifAddrBits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasMemTag extends MIFBundle {
 | 
			
		||||
  val tag = UInt(width = mifTagBits)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemReqCmd extends HasMemAddr with HasMemTag {
 | 
			
		||||
  val rw = Bool()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemTag extends HasMemTag
 | 
			
		||||
class MemData extends HasMemData
 | 
			
		||||
class MemResp extends HasMemData with HasMemTag
 | 
			
		||||
 | 
			
		||||
class MemIO extends Bundle {
 | 
			
		||||
  val req_cmd  = Decoupled(new MemReqCmd)
 | 
			
		||||
  val req_data = Decoupled(new MemData)
 | 
			
		||||
  val resp     = Decoupled(new MemResp).flip
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemPipeIO extends Bundle {
 | 
			
		||||
  val req_cmd  = Decoupled(new MemReqCmd)
 | 
			
		||||
  val req_data = Decoupled(new MemData)
 | 
			
		||||
  val resp     = Valid(new MemResp).flip
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemSerializedIO(w: Int) extends Bundle
 | 
			
		||||
{
 | 
			
		||||
  val req = Decoupled(Bits(width = w))
 | 
			
		||||
  val resp = Valid(Bits(width = w)).flip
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemSerdes(w: Int) extends MIFModule
 | 
			
		||||
{
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val wide = new MemIO().flip
 | 
			
		||||
    val narrow = new MemSerializedIO(w)
 | 
			
		||||
  }
 | 
			
		||||
  val abits = io.wide.req_cmd.bits.toBits.getWidth
 | 
			
		||||
  val dbits = io.wide.req_data.bits.toBits.getWidth
 | 
			
		||||
  val rbits = io.wide.resp.bits.getWidth
 | 
			
		||||
 | 
			
		||||
  val out_buf = Reg(Bits())
 | 
			
		||||
  val in_buf = Reg(Bits())
 | 
			
		||||
 | 
			
		||||
  val s_idle :: s_read_addr :: s_write_addr :: s_write_idle :: s_write_data :: Nil = Enum(UInt(), 5)
 | 
			
		||||
  val state = Reg(init=s_idle)
 | 
			
		||||
  val send_cnt = Reg(init=UInt(0, log2Up((max(abits, dbits)+w-1)/w)))
 | 
			
		||||
  val data_send_cnt = Reg(init=UInt(0, log2Up(mifDataBeats)))
 | 
			
		||||
  val adone = io.narrow.req.ready && send_cnt === UInt((abits-1)/w)
 | 
			
		||||
  val ddone = io.narrow.req.ready && send_cnt === UInt((dbits-1)/w)
 | 
			
		||||
 | 
			
		||||
  when (io.narrow.req.valid && io.narrow.req.ready) {
 | 
			
		||||
    send_cnt := send_cnt + UInt(1)
 | 
			
		||||
    out_buf := out_buf >> UInt(w)
 | 
			
		||||
  }
 | 
			
		||||
  when (io.wide.req_cmd.valid && io.wide.req_cmd.ready) {
 | 
			
		||||
    out_buf := io.wide.req_cmd.bits.toBits
 | 
			
		||||
  }
 | 
			
		||||
  when (io.wide.req_data.valid && io.wide.req_data.ready) {
 | 
			
		||||
    out_buf := io.wide.req_data.bits.toBits
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.wide.req_cmd.ready := state === s_idle
 | 
			
		||||
  io.wide.req_data.ready := state === s_write_idle
 | 
			
		||||
  io.narrow.req.valid := state === s_read_addr || state === s_write_addr || state === s_write_data
 | 
			
		||||
  io.narrow.req.bits := out_buf
 | 
			
		||||
 | 
			
		||||
  when (state === s_idle && io.wide.req_cmd.valid) {
 | 
			
		||||
    state := Mux(io.wide.req_cmd.bits.rw, s_write_addr, s_read_addr)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_read_addr && adone) {
 | 
			
		||||
    state := s_idle
 | 
			
		||||
    send_cnt := UInt(0)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_write_addr && adone) {
 | 
			
		||||
    state := s_write_idle
 | 
			
		||||
    send_cnt := UInt(0)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_write_idle && io.wide.req_data.valid) {
 | 
			
		||||
    state := s_write_data
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_write_data && ddone) {
 | 
			
		||||
    data_send_cnt := data_send_cnt + UInt(1)
 | 
			
		||||
    state := Mux(data_send_cnt === UInt(mifDataBeats-1), s_idle, s_write_idle)
 | 
			
		||||
    send_cnt := UInt(0)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val recv_cnt = Reg(init=UInt(0, log2Up((rbits+w-1)/w)))
 | 
			
		||||
  val data_recv_cnt = Reg(init=UInt(0, log2Up(mifDataBeats)))
 | 
			
		||||
  val resp_val = Reg(init=Bool(false))
 | 
			
		||||
 | 
			
		||||
  resp_val := Bool(false)
 | 
			
		||||
  when (io.narrow.resp.valid) {
 | 
			
		||||
    recv_cnt := recv_cnt + UInt(1)
 | 
			
		||||
    when (recv_cnt === UInt((rbits-1)/w)) {
 | 
			
		||||
      recv_cnt := UInt(0)
 | 
			
		||||
      data_recv_cnt := data_recv_cnt + UInt(1)
 | 
			
		||||
      resp_val := Bool(true)
 | 
			
		||||
    }
 | 
			
		||||
    in_buf := Cat(io.narrow.resp.bits, in_buf((rbits+w-1)/w*w-1,w))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.wide.resp.valid := resp_val
 | 
			
		||||
  io.wide.resp.bits := io.wide.resp.bits.fromBits(in_buf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemDesserIO(w: Int) extends Bundle {
 | 
			
		||||
  val narrow = new MemSerializedIO(w).flip
 | 
			
		||||
  val wide = new MemIO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemDesser(w: Int) extends Module // test rig side
 | 
			
		||||
{
 | 
			
		||||
  val io = new MemDesserIO(w)
 | 
			
		||||
  val abits = io.wide.req_cmd.bits.toBits.getWidth
 | 
			
		||||
  val dbits = io.wide.req_data.bits.toBits.getWidth
 | 
			
		||||
  val rbits = io.wide.resp.bits.getWidth
 | 
			
		||||
  val mifDataBeats = params(MIFDataBeats)
 | 
			
		||||
 | 
			
		||||
  require(dbits >= abits && rbits >= dbits)
 | 
			
		||||
  val recv_cnt = Reg(init=UInt(0, log2Up((rbits+w-1)/w)))
 | 
			
		||||
  val data_recv_cnt = Reg(init=UInt(0, log2Up(mifDataBeats)))
 | 
			
		||||
  val adone = io.narrow.req.valid && recv_cnt === UInt((abits-1)/w)
 | 
			
		||||
  val ddone = io.narrow.req.valid && recv_cnt === UInt((dbits-1)/w)
 | 
			
		||||
  val rdone = io.narrow.resp.valid && recv_cnt === UInt((rbits-1)/w)
 | 
			
		||||
 | 
			
		||||
  val s_cmd_recv :: s_cmd :: s_data_recv :: s_data :: s_reply :: Nil = Enum(UInt(), 5)
 | 
			
		||||
  val state = Reg(init=s_cmd_recv)
 | 
			
		||||
 | 
			
		||||
  val in_buf = Reg(Bits())
 | 
			
		||||
  when (io.narrow.req.valid && io.narrow.req.ready || io.narrow.resp.valid) {
 | 
			
		||||
    recv_cnt := recv_cnt + UInt(1)
 | 
			
		||||
    in_buf := Cat(io.narrow.req.bits, in_buf((rbits+w-1)/w*w-1,w))
 | 
			
		||||
  }
 | 
			
		||||
  io.narrow.req.ready := state === s_cmd_recv || state === s_data_recv
 | 
			
		||||
 | 
			
		||||
  when (state === s_cmd_recv && adone) {
 | 
			
		||||
    state := s_cmd
 | 
			
		||||
    recv_cnt := UInt(0)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_cmd && io.wide.req_cmd.ready) {
 | 
			
		||||
    state := Mux(io.wide.req_cmd.bits.rw, s_data_recv, s_reply)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_data_recv && ddone) {
 | 
			
		||||
    state := s_data
 | 
			
		||||
    recv_cnt := UInt(0)
 | 
			
		||||
  }
 | 
			
		||||
  when (state === s_data && io.wide.req_data.ready) {
 | 
			
		||||
    state := s_data_recv
 | 
			
		||||
    when (data_recv_cnt === UInt(mifDataBeats-1)) {
 | 
			
		||||
      state := s_cmd_recv
 | 
			
		||||
    }
 | 
			
		||||
    data_recv_cnt := data_recv_cnt + UInt(1)
 | 
			
		||||
  }
 | 
			
		||||
  when (rdone) { // state === s_reply
 | 
			
		||||
    when (data_recv_cnt === UInt(mifDataBeats-1)) {
 | 
			
		||||
      state := s_cmd_recv
 | 
			
		||||
    }
 | 
			
		||||
    recv_cnt := UInt(0)
 | 
			
		||||
    data_recv_cnt := data_recv_cnt + UInt(1)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val req_cmd = in_buf >> UInt(((rbits+w-1)/w - (abits+w-1)/w)*w)
 | 
			
		||||
  io.wide.req_cmd.valid := state === s_cmd
 | 
			
		||||
  io.wide.req_cmd.bits := io.wide.req_cmd.bits.fromBits(req_cmd)
 | 
			
		||||
 | 
			
		||||
  io.wide.req_data.valid := state === s_data
 | 
			
		||||
  io.wide.req_data.bits.data := in_buf >> UInt(((rbits+w-1)/w - (dbits+w-1)/w)*w)
 | 
			
		||||
 | 
			
		||||
  val dataq = Module(new Queue(new MemResp, mifDataBeats))
 | 
			
		||||
  dataq.io.enq <> io.wide.resp
 | 
			
		||||
  dataq.io.deq.ready := recv_cnt === UInt((rbits-1)/w)
 | 
			
		||||
 | 
			
		||||
  io.narrow.resp.valid := dataq.io.deq.valid
 | 
			
		||||
  io.narrow.resp.bits := dataq.io.deq.bits.toBits >> (recv_cnt * UInt(w))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Adapter betweewn an UncachedTileLinkIO and a mem controller MemIO
 | 
			
		||||
class MemIOTileLinkIOConverter(qDepth: Int) extends TLModule with MIFParameters {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val tl = new ManagerTileLinkIO
 | 
			
		||||
    val mem = new MemIO
 | 
			
		||||
  }
 | 
			
		||||
  val dataBits = tlDataBits*tlDataBeats 
 | 
			
		||||
  val dstIdBits = params(LNHeaderBits)
 | 
			
		||||
  require(tlDataBits*tlDataBeats == mifDataBits*mifDataBeats, "Data sizes between LLC and MC don't agree")
 | 
			
		||||
  require(dstIdBits + tlClientXactIdBits < mifTagBits, "MemIO converter is going truncate tags: " + dstIdBits + " + " + tlClientXactIdBits + " >= " + mifTagBits)
 | 
			
		||||
 | 
			
		||||
  io.tl.acquire.ready := Bool(false)
 | 
			
		||||
  io.tl.probe.valid := Bool(false)
 | 
			
		||||
  io.tl.release.ready := Bool(false)
 | 
			
		||||
  io.tl.finish.ready := Bool(true)
 | 
			
		||||
  io.mem.resp.ready := Bool(false)
 | 
			
		||||
 | 
			
		||||
  val gnt_arb = Module(new Arbiter(new GrantToDst, 2))
 | 
			
		||||
  io.tl.grant <> gnt_arb.io.out
 | 
			
		||||
 | 
			
		||||
  val dst_off = dstIdBits + tlClientXactIdBits
 | 
			
		||||
  val acq_has_data = io.tl.acquire.bits.hasData()
 | 
			
		||||
  val rel_has_data = io.tl.release.bits.hasData()
 | 
			
		||||
 | 
			
		||||
  // Decompose outgoing TL Acquires into MemIO cmd and data
 | 
			
		||||
  val active_out = Reg(init=Bool(false))
 | 
			
		||||
  val cmd_sent_out = Reg(init=Bool(false))
 | 
			
		||||
  val tag_out = Reg(UInt(width = mifTagBits))
 | 
			
		||||
  val addr_out = Reg(UInt(width = mifAddrBits))
 | 
			
		||||
  val has_data = Reg(init=Bool(false))
 | 
			
		||||
  val data_from_rel = Reg(init=Bool(false))
 | 
			
		||||
  val (tl_cnt_out, tl_wrap_out) =
 | 
			
		||||
    Counter((io.tl.acquire.fire() && acq_has_data) ||
 | 
			
		||||
              (io.tl.release.fire() && rel_has_data), tlDataBeats)
 | 
			
		||||
  val tl_done_out = Reg(init=Bool(false))
 | 
			
		||||
  val make_grant_ack = Reg(init=Bool(false))
 | 
			
		||||
 | 
			
		||||
  gnt_arb.io.in(1).valid := Bool(false)
 | 
			
		||||
  gnt_arb.io.in(1).bits := Grant(
 | 
			
		||||
    dst = (if(dstIdBits > 0) tag_out(dst_off, tlClientXactIdBits + 1) else UInt(0)),
 | 
			
		||||
    is_builtin_type = Bool(true),
 | 
			
		||||
    g_type = Mux(data_from_rel, Grant.voluntaryAckType, Grant.putAckType),
 | 
			
		||||
    client_xact_id = tag_out >> UInt(1),
 | 
			
		||||
    manager_xact_id = UInt(0))
 | 
			
		||||
 | 
			
		||||
  if(tlDataBits != mifDataBits || tlDataBeats != mifDataBeats) {
 | 
			
		||||
    val mem_cmd_q = Module(new Queue(new MemReqCmd, qDepth))
 | 
			
		||||
    val mem_data_q = Module(new Queue(new MemData, qDepth))
 | 
			
		||||
    mem_cmd_q.io.enq.valid := Bool(false)
 | 
			
		||||
    mem_data_q.io.enq.valid := Bool(false)
 | 
			
		||||
    val (mif_cnt_out, mif_wrap_out) = Counter(mem_data_q.io.enq.fire(), mifDataBeats)
 | 
			
		||||
    val mif_done_out = Reg(init=Bool(false))
 | 
			
		||||
    val tl_buf_out = Vec.fill(tlDataBeats){ Reg(io.tl.acquire.bits.data.clone) }
 | 
			
		||||
    val mif_buf_out = Vec.fill(mifDataBeats){ new MemData }
 | 
			
		||||
    mif_buf_out := mif_buf_out.fromBits(tl_buf_out.toBits)
 | 
			
		||||
    val mif_prog_out = (mif_cnt_out+UInt(1, width = log2Up(mifDataBeats+1)))*UInt(mifDataBits)
 | 
			
		||||
    val tl_prog_out = tl_cnt_out*UInt(tlDataBits)
 | 
			
		||||
 | 
			
		||||
    when(!active_out){
 | 
			
		||||
      io.tl.release.ready := Bool(true)
 | 
			
		||||
      io.tl.acquire.ready := !io.tl.release.valid
 | 
			
		||||
      when(io.tl.release.valid) {
 | 
			
		||||
        active_out := Bool(true)
 | 
			
		||||
        cmd_sent_out := Bool(false)
 | 
			
		||||
        tag_out := Cat(io.tl.release.bits.client_id,
 | 
			
		||||
                       io.tl.release.bits.client_xact_id,
 | 
			
		||||
                       io.tl.release.bits.isVoluntary())
 | 
			
		||||
        addr_out := io.tl.release.bits.addr_block
 | 
			
		||||
        has_data := rel_has_data
 | 
			
		||||
        data_from_rel := Bool(true)
 | 
			
		||||
        make_grant_ack := io.tl.release.bits.requiresAck()
 | 
			
		||||
        tl_done_out := tl_wrap_out
 | 
			
		||||
        tl_buf_out(tl_cnt_out) := io.tl.release.bits.data
 | 
			
		||||
      } .elsewhen(io.tl.acquire.valid) {
 | 
			
		||||
        active_out := Bool(true)
 | 
			
		||||
        cmd_sent_out := Bool(false)
 | 
			
		||||
        tag_out := Cat(io.tl.release.bits.client_id,
 | 
			
		||||
                       io.tl.acquire.bits.client_xact_id,
 | 
			
		||||
                       io.tl.acquire.bits.isBuiltInType())
 | 
			
		||||
        addr_out := io.tl.acquire.bits.addr_block
 | 
			
		||||
        has_data := acq_has_data
 | 
			
		||||
        data_from_rel := Bool(false)
 | 
			
		||||
        make_grant_ack := acq_has_data
 | 
			
		||||
        tl_done_out := tl_wrap_out
 | 
			
		||||
        tl_buf_out(tl_cnt_out) := io.tl.acquire.bits.data
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    when(active_out) {
 | 
			
		||||
      mem_cmd_q.io.enq.valid := !cmd_sent_out
 | 
			
		||||
      cmd_sent_out := cmd_sent_out || mem_cmd_q.io.enq.fire()
 | 
			
		||||
      when(has_data) {
 | 
			
		||||
        when(!tl_done_out) {
 | 
			
		||||
          io.tl.acquire.ready := Bool(true)
 | 
			
		||||
          when(io.tl.acquire.valid) {
 | 
			
		||||
            tl_buf_out(tl_cnt_out) := Mux(data_from_rel,
 | 
			
		||||
                                        io.tl.release.bits.data,
 | 
			
		||||
                                        io.tl.acquire.bits.data)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        when(!mif_done_out) { 
 | 
			
		||||
          mem_data_q.io.enq.valid := tl_done_out || mif_prog_out <= tl_prog_out
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      when(tl_wrap_out) { tl_done_out := Bool(true) }
 | 
			
		||||
      when(mif_wrap_out) { mif_done_out := Bool(true) }
 | 
			
		||||
      when(tl_done_out && make_grant_ack) {
 | 
			
		||||
        gnt_arb.io.in(1).valid := Bool(true)
 | 
			
		||||
        when(gnt_arb.io.in(1).ready) { make_grant_ack := Bool(false) }
 | 
			
		||||
      }
 | 
			
		||||
      when(cmd_sent_out && (!has_data || mif_done_out) && !make_grant_ack) {
 | 
			
		||||
        active_out := Bool(false)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mem_cmd_q.io.enq.bits.rw := has_data
 | 
			
		||||
    mem_cmd_q.io.enq.bits.tag := tag_out
 | 
			
		||||
    mem_cmd_q.io.enq.bits.addr := addr_out
 | 
			
		||||
    mem_data_q.io.enq.bits.data := mif_buf_out(mif_cnt_out).data
 | 
			
		||||
    io.mem.req_cmd <> mem_cmd_q.io.deq
 | 
			
		||||
    io.mem.req_data <> mem_data_q.io.deq
 | 
			
		||||
  } else { // Don't make the data buffers and try to flow cmd and data
 | 
			
		||||
    io.mem.req_cmd.valid := Bool(false)
 | 
			
		||||
    io.mem.req_data.valid := Bool(false)
 | 
			
		||||
    io.mem.req_cmd.bits.rw := has_data
 | 
			
		||||
    io.mem.req_cmd.bits.tag := tag_out
 | 
			
		||||
    io.mem.req_cmd.bits.addr := addr_out
 | 
			
		||||
    io.mem.req_data.bits.data := Mux(data_from_rel,
 | 
			
		||||
                                   io.tl.release.bits.data,
 | 
			
		||||
                                   io.tl.acquire.bits.data)
 | 
			
		||||
    when(!active_out){
 | 
			
		||||
      io.tl.release.ready := io.mem.req_data.ready
 | 
			
		||||
      io.tl.acquire.ready := io.mem.req_data.ready && !io.tl.release.valid
 | 
			
		||||
      io.mem.req_data.valid := (io.tl.release.valid && rel_has_data) ||
 | 
			
		||||
                                 (io.tl.acquire.valid && acq_has_data)
 | 
			
		||||
      when(io.mem.req_data.ready && (io.tl.release.valid || io.tl.acquire.valid)) {
 | 
			
		||||
        active_out := !io.mem.req_cmd.ready || io.mem.req_data.valid
 | 
			
		||||
        io.mem.req_cmd.valid := Bool(true)
 | 
			
		||||
        cmd_sent_out := io.mem.req_cmd.ready
 | 
			
		||||
        tl_done_out := tl_wrap_out
 | 
			
		||||
        when(io.tl.release.valid) {
 | 
			
		||||
          data_from_rel := Bool(true)
 | 
			
		||||
          make_grant_ack := io.tl.release.bits.requiresAck()
 | 
			
		||||
          io.mem.req_data.bits.data := io.tl.release.bits.data
 | 
			
		||||
          val tag =  Cat(io.tl.release.bits.client_id,
 | 
			
		||||
                         io.tl.release.bits.client_xact_id,
 | 
			
		||||
                         io.tl.release.bits.isVoluntary())
 | 
			
		||||
          val addr = io.tl.release.bits.addr_block
 | 
			
		||||
          io.mem.req_cmd.bits.tag := tag
 | 
			
		||||
          io.mem.req_cmd.bits.addr := addr
 | 
			
		||||
          io.mem.req_cmd.bits.rw := rel_has_data
 | 
			
		||||
          tag_out := tag
 | 
			
		||||
          addr_out := addr
 | 
			
		||||
          has_data := rel_has_data
 | 
			
		||||
        } .elsewhen(io.tl.acquire.valid) {
 | 
			
		||||
          data_from_rel := Bool(false)
 | 
			
		||||
          make_grant_ack := acq_has_data // i.e. is it a Put
 | 
			
		||||
          io.mem.req_data.bits.data := io.tl.acquire.bits.data
 | 
			
		||||
          io.mem.req_cmd.bits.rw := acq_has_data
 | 
			
		||||
          val tag = Cat(io.tl.acquire.bits.client_id,
 | 
			
		||||
                        io.tl.acquire.bits.client_xact_id,
 | 
			
		||||
                        io.tl.acquire.bits.isBuiltInType())
 | 
			
		||||
          val addr = io.tl.acquire.bits.addr_block
 | 
			
		||||
          io.mem.req_cmd.bits.tag := tag
 | 
			
		||||
          io.mem.req_cmd.bits.addr := addr
 | 
			
		||||
          io.mem.req_cmd.bits.rw := acq_has_data
 | 
			
		||||
          tag_out := tag
 | 
			
		||||
          addr_out := addr
 | 
			
		||||
          has_data := acq_has_data
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    when(active_out) {
 | 
			
		||||
      io.mem.req_cmd.valid := !cmd_sent_out
 | 
			
		||||
      cmd_sent_out := cmd_sent_out || io.mem.req_cmd.fire()
 | 
			
		||||
      when(has_data && !tl_done_out) {
 | 
			
		||||
        when(data_from_rel) {
 | 
			
		||||
          io.tl.release.ready := io.mem.req_data.ready
 | 
			
		||||
          io.mem.req_data.valid := io.tl.release.valid
 | 
			
		||||
        } .otherwise {
 | 
			
		||||
          io.tl.acquire.ready := io.mem.req_data.ready
 | 
			
		||||
          io.mem.req_data.valid := io.tl.acquire.valid
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      when(tl_wrap_out) { tl_done_out := Bool(true) }
 | 
			
		||||
      when(tl_done_out && make_grant_ack) {
 | 
			
		||||
        gnt_arb.io.in(1).valid := Bool(true) // TODO: grants for voluntary acks?
 | 
			
		||||
        when(gnt_arb.io.in(1).ready) { make_grant_ack := Bool(false) }
 | 
			
		||||
      }
 | 
			
		||||
      when(cmd_sent_out && (!has_data || tl_done_out) && !make_grant_ack) {
 | 
			
		||||
        active_out := Bool(false)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Aggregate incoming MemIO responses into TL Grants
 | 
			
		||||
  val active_in = Reg(init=Bool(false))
 | 
			
		||||
  val (tl_cnt_in, tl_wrap_in) = Counter(io.tl.grant.fire() && io.tl.grant.bits.hasMultibeatData(), tlDataBeats)
 | 
			
		||||
  val tag_in = Reg(UInt(width = mifTagBits))
 | 
			
		||||
 | 
			
		||||
  if(tlDataBits != mifDataBits || tlDataBeats != mifDataBeats) {
 | 
			
		||||
    val (mif_cnt_in, mif_wrap_in) = Counter(io.mem.resp.fire(), mifDataBeats) // TODO: Assumes all resps have data
 | 
			
		||||
    val mif_done_in = Reg(init=Bool(false))
 | 
			
		||||
    val mif_buf_in = Vec.fill(mifDataBeats){ Reg(new MemData) }
 | 
			
		||||
    val tl_buf_in = Vec.fill(tlDataBeats){ io.tl.acquire.bits.data.clone }
 | 
			
		||||
    tl_buf_in := tl_buf_in.fromBits(mif_buf_in.toBits)
 | 
			
		||||
    val tl_prog_in = (tl_cnt_in+UInt(1, width = log2Up(tlDataBeats+1)))*UInt(tlDataBits)
 | 
			
		||||
    val mif_prog_in = mif_cnt_in*UInt(mifDataBits)
 | 
			
		||||
    gnt_arb.io.in(0).bits := Grant(
 | 
			
		||||
      dst = (if(dstIdBits > 0) tag_in(dst_off, tlClientXactIdBits + 1) else UInt(0)),
 | 
			
		||||
      is_builtin_type = tag_in(0),
 | 
			
		||||
      g_type = Mux(tag_in(0), Grant.getDataBlockType, UInt(0)), // TODO: Assumes MI or MEI protocol
 | 
			
		||||
      client_xact_id = tag_in >> UInt(1),
 | 
			
		||||
      manager_xact_id = UInt(0),
 | 
			
		||||
      addr_beat = tl_cnt_in,
 | 
			
		||||
      data = tl_buf_in(tl_cnt_in))
 | 
			
		||||
 | 
			
		||||
    when(!active_in) {
 | 
			
		||||
      io.mem.resp.ready := Bool(true)
 | 
			
		||||
      when(io.mem.resp.valid) {
 | 
			
		||||
        active_in := Bool(true)
 | 
			
		||||
        mif_done_in := mif_wrap_in
 | 
			
		||||
        tag_in := io.mem.resp.bits.tag
 | 
			
		||||
        mif_buf_in(tl_cnt_in).data := io.mem.resp.bits.data
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    when(active_in) {
 | 
			
		||||
      gnt_arb.io.in(0).valid := mif_done_in || tl_prog_in <= mif_prog_in
 | 
			
		||||
      when(!mif_done_in) {
 | 
			
		||||
        io.mem.resp.ready := Bool(true)
 | 
			
		||||
        when(io.mem.resp.valid) {
 | 
			
		||||
          mif_buf_in(mif_cnt_in).data := io.mem.resp.bits.data
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      when(mif_wrap_in) { mif_done_in := Bool(true) }
 | 
			
		||||
      when(tl_wrap_in) { active_in := Bool(false) }
 | 
			
		||||
    }
 | 
			
		||||
  } else { // Don't generate all the uneeded data buffers and flow resp
 | 
			
		||||
    gnt_arb.io.in(0).valid := io.mem.resp.valid
 | 
			
		||||
    io.mem.resp.ready := gnt_arb.io.in(0).ready
 | 
			
		||||
    gnt_arb.io.in(0).bits := Grant(
 | 
			
		||||
      dst = (if(dstIdBits > 0) io.mem.resp.bits.tag(dst_off, tlClientXactIdBits + 1) else UInt(0)),
 | 
			
		||||
      is_builtin_type = io.mem.resp.bits.tag(0),
 | 
			
		||||
      g_type = Mux(io.mem.resp.bits.tag(0), Grant.getDataBlockType, UInt(0)), // TODO: Assumes MI or MEI protocol
 | 
			
		||||
      client_xact_id = io.mem.resp.bits.tag >> UInt(1),
 | 
			
		||||
      manager_xact_id = UInt(0),
 | 
			
		||||
      addr_beat = tl_cnt_in,
 | 
			
		||||
      data = io.mem.resp.bits.data)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HellaFlowQueue[T <: Data](val entries: Int)(data: => T) extends Module
 | 
			
		||||
{
 | 
			
		||||
  val io = new QueueIO(data, entries)
 | 
			
		||||
  require(entries > 1)
 | 
			
		||||
 | 
			
		||||
  val do_flow = Bool()
 | 
			
		||||
  val do_enq = io.enq.fire() && !do_flow
 | 
			
		||||
  val do_deq = io.deq.fire() && !do_flow
 | 
			
		||||
 | 
			
		||||
  val maybe_full = Reg(init=Bool(false))
 | 
			
		||||
  val enq_ptr = Counter(do_enq, entries)._1
 | 
			
		||||
  val (deq_ptr, deq_done) = Counter(do_deq, entries)
 | 
			
		||||
  when (do_enq != do_deq) { maybe_full := do_enq }
 | 
			
		||||
 | 
			
		||||
  val ptr_match = enq_ptr === deq_ptr
 | 
			
		||||
  val empty = ptr_match && !maybe_full
 | 
			
		||||
  val full = ptr_match && maybe_full
 | 
			
		||||
  val atLeastTwo = full || enq_ptr - deq_ptr >= UInt(2)
 | 
			
		||||
  do_flow := empty && io.deq.ready
 | 
			
		||||
 | 
			
		||||
  val ram = Mem(data, entries, seqRead = true)
 | 
			
		||||
  val ram_addr = Reg(Bits())
 | 
			
		||||
  val ram_out_valid = Reg(Bool())
 | 
			
		||||
  ram_out_valid := Bool(false)
 | 
			
		||||
  when (do_enq) { ram(enq_ptr) := io.enq.bits }
 | 
			
		||||
  when (io.deq.ready && (atLeastTwo || !io.deq.valid && !empty)) {
 | 
			
		||||
    ram_out_valid := Bool(true)
 | 
			
		||||
    ram_addr := Mux(io.deq.valid, Mux(deq_done, UInt(0), deq_ptr + UInt(1)), deq_ptr)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.deq.valid := Mux(empty, io.enq.valid, ram_out_valid)
 | 
			
		||||
  io.enq.ready := !full
 | 
			
		||||
  io.deq.bits := Mux(empty, io.enq.bits, ram(ram_addr))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HellaQueue[T <: Data](val entries: Int)(data: => T) extends Module
 | 
			
		||||
{
 | 
			
		||||
  val io = new QueueIO(data, entries)
 | 
			
		||||
 | 
			
		||||
  val fq = Module(new HellaFlowQueue(entries)(data))
 | 
			
		||||
  io.enq <> fq.io.enq
 | 
			
		||||
  io.deq <> Queue(fq.io.deq, 1, pipe = true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object HellaQueue
 | 
			
		||||
{
 | 
			
		||||
  def apply[T <: Data](enq: DecoupledIO[T], entries: Int) = {
 | 
			
		||||
    val q = Module((new HellaQueue(entries)) { enq.bits.clone })
 | 
			
		||||
    q.io.enq.valid := enq.valid // not using <> so that override is allowed
 | 
			
		||||
    q.io.enq.bits := enq.bits
 | 
			
		||||
    enq.ready := q.io.enq.ready
 | 
			
		||||
    q.io.deq
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemPipeIOMemIOConverter(numRequests: Int) extends MIFModule {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val cpu = new MemIO().flip
 | 
			
		||||
    val mem = new MemPipeIO
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val numEntries = numRequests * mifDataBeats
 | 
			
		||||
  val size = log2Down(numEntries) + 1
 | 
			
		||||
 | 
			
		||||
  val inc = Bool()
 | 
			
		||||
  val dec = Bool()
 | 
			
		||||
  val count = Reg(init=UInt(numEntries, size))
 | 
			
		||||
  val watermark = count >= UInt(mifDataBeats)
 | 
			
		||||
 | 
			
		||||
  when (inc && !dec) {
 | 
			
		||||
    count := count + UInt(1)
 | 
			
		||||
  }
 | 
			
		||||
  when (!inc && dec) {
 | 
			
		||||
    count := count - UInt(mifDataBeats)
 | 
			
		||||
  }
 | 
			
		||||
  when (inc && dec) {
 | 
			
		||||
    count := count - UInt(mifDataBeats-1)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val cmdq_mask = io.cpu.req_cmd.bits.rw || watermark
 | 
			
		||||
 | 
			
		||||
  io.mem.req_cmd.valid := io.cpu.req_cmd.valid && cmdq_mask
 | 
			
		||||
  io.cpu.req_cmd.ready := io.mem.req_cmd.ready && cmdq_mask
 | 
			
		||||
  io.mem.req_cmd.bits := io.cpu.req_cmd.bits
 | 
			
		||||
 | 
			
		||||
  io.mem.req_data <> io.cpu.req_data
 | 
			
		||||
 | 
			
		||||
  // Have separate queues to allow for different mem implementations
 | 
			
		||||
  val resp_data_q = Module((new HellaQueue(numEntries)) { new MemData })
 | 
			
		||||
  resp_data_q.io.enq.valid := io.mem.resp.valid
 | 
			
		||||
  resp_data_q.io.enq.bits.data := io.mem.resp.bits.data
 | 
			
		||||
 | 
			
		||||
  val resp_tag_q = Module((new HellaQueue(numEntries)) { new MemTag })
 | 
			
		||||
  resp_tag_q.io.enq.valid := io.mem.resp.valid
 | 
			
		||||
  resp_tag_q.io.enq.bits.tag := io.mem.resp.bits.tag
 | 
			
		||||
 | 
			
		||||
  io.cpu.resp.valid := resp_data_q.io.deq.valid && resp_tag_q.io.deq.valid
 | 
			
		||||
  io.cpu.resp.bits.data := resp_data_q.io.deq.bits.data
 | 
			
		||||
  io.cpu.resp.bits.tag := resp_tag_q.io.deq.bits.tag
 | 
			
		||||
  resp_data_q.io.deq.ready := io.cpu.resp.ready
 | 
			
		||||
  resp_tag_q.io.deq.ready := io.cpu.resp.ready
 | 
			
		||||
 | 
			
		||||
  inc := resp_data_q.io.deq.fire() && resp_tag_q.io.deq.fire()
 | 
			
		||||
  dec := io.mem.req_cmd.fire() && !io.mem.req_cmd.bits.rw
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MemPipeIOTileLinkIOConverter(outstanding: Int) extends MIFModule {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val tl = new ManagerTileLinkIO
 | 
			
		||||
    val mem = new MemPipeIO
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  val a = Module(new MemIOTileLinkIOConverter(1))
 | 
			
		||||
  val b = Module(new MemPipeIOMemIOConverter(outstanding))
 | 
			
		||||
  a.io.tl <> io.tl
 | 
			
		||||
  b.io.cpu.req_cmd <> Queue(a.io.mem.req_cmd, 2, pipe=true)
 | 
			
		||||
  b.io.cpu.req_data <> Queue(a.io.mem.req_data, mifDataBeats, pipe=true)
 | 
			
		||||
  a.io.mem.resp <> b.io.cpu.resp
 | 
			
		||||
  b.io.mem <> io.mem
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										315
									
								
								uncore/src/main/scala/metadata.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								uncore/src/main/scala/metadata.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,315 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
/** Base class to represent coherence information in clients and managers */
 | 
			
		||||
abstract class CoherenceMetadata extends Bundle {
 | 
			
		||||
  val co = params(TLCoherencePolicy)
 | 
			
		||||
  val id = params(TLId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Stores the client-side coherence information,
 | 
			
		||||
  * such as permissions on the data and whether the data is dirty.
 | 
			
		||||
  * Its API can be used to make TileLink messages in response to
 | 
			
		||||
  * memory operations or [[uncore.Probe]] messages.
 | 
			
		||||
  */
 | 
			
		||||
class ClientMetadata extends CoherenceMetadata {
 | 
			
		||||
  /** Actual state information stored in this bundle */
 | 
			
		||||
  val state = UInt(width = co.clientStateWidth)
 | 
			
		||||
 | 
			
		||||
  /** Metadata equality */
 | 
			
		||||
  def ===(rhs: ClientMetadata): Bool = this.state === rhs.state
 | 
			
		||||
  def !=(rhs: ClientMetadata): Bool = !this.===(rhs)
 | 
			
		||||
 | 
			
		||||
  /** Is the block's data present in this cache */
 | 
			
		||||
  def isValid(dummy: Int = 0): Bool = co.isValid(this)
 | 
			
		||||
  /** Does this cache have permissions on this block sufficient to perform op */
 | 
			
		||||
  def isHit(op_code: UInt): Bool = co.isHit(op_code, this)
 | 
			
		||||
  /** Does this cache lack permissions on this block sufficient to perform op */ 
 | 
			
		||||
  def isMiss(op_code: UInt): Bool = !co.isHit(op_code, this)
 | 
			
		||||
  /** Does a secondary miss on the block require another Acquire message */
 | 
			
		||||
  def requiresAcquireOnSecondaryMiss(first_op: UInt, second_op: UInt): Bool =
 | 
			
		||||
    co.requiresAcquireOnSecondaryMiss(first_op, second_op, this)
 | 
			
		||||
  /** Does op require a Release to be made to outer memory */
 | 
			
		||||
  def requiresReleaseOnCacheControl(op_code: UInt): Bool =
 | 
			
		||||
    co.requiresReleaseOnCacheControl(op_code: UInt, this)
 | 
			
		||||
  /** Does an eviction require a Release to be made to outer memory */
 | 
			
		||||
  def requiresVoluntaryWriteback(dummy: Int = 0): Bool =
 | 
			
		||||
    co.requiresReleaseOnCacheControl(M_FLUSH, this)
 | 
			
		||||
 | 
			
		||||
  /** Constructs an Acquire message based on this metdata and a memory operation
 | 
			
		||||
    *
 | 
			
		||||
    * @param client_xact_id client's transaction id
 | 
			
		||||
    * @param addr_block address of the cache block
 | 
			
		||||
    * @param op_code a memory operation from [[uncore.constants.MemoryOpConstants]]
 | 
			
		||||
    */
 | 
			
		||||
  def makeAcquire(
 | 
			
		||||
      client_xact_id: UInt,
 | 
			
		||||
      addr_block: UInt,
 | 
			
		||||
      op_code: UInt): Acquire = {
 | 
			
		||||
    Bundle(Acquire(
 | 
			
		||||
        is_builtin_type = Bool(false),
 | 
			
		||||
        a_type = co.getAcquireType(op_code, this),
 | 
			
		||||
        client_xact_id = client_xact_id,
 | 
			
		||||
        addr_block = addr_block,
 | 
			
		||||
        union = Cat(op_code, Bool(true))),
 | 
			
		||||
      { case TLId => id })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Constructs a Release message based on this metadata on an eviction
 | 
			
		||||
    *
 | 
			
		||||
    * @param client_xact_id client's transaction id
 | 
			
		||||
    * @param addr_block address of the cache block
 | 
			
		||||
    * @param addr_beat sub-block address (which beat)
 | 
			
		||||
    * @param data data being written back
 | 
			
		||||
    */
 | 
			
		||||
  def makeVoluntaryWriteback(
 | 
			
		||||
      client_xact_id: UInt,
 | 
			
		||||
      addr_block: UInt,
 | 
			
		||||
      addr_beat: UInt = UInt(0),
 | 
			
		||||
      data: UInt = UInt(0)): Release = {
 | 
			
		||||
    Bundle(Release(
 | 
			
		||||
      voluntary = Bool(true),
 | 
			
		||||
      r_type = co.getReleaseType(M_FLUSH, this),
 | 
			
		||||
      client_xact_id = client_xact_id,
 | 
			
		||||
      addr_block = addr_block,
 | 
			
		||||
      addr_beat = addr_beat,
 | 
			
		||||
      data = data), { case TLId => id })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Constructs a Release message based on this metadata and a [[uncore.Probe]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param the incoming [[uncore.Probe]]
 | 
			
		||||
    * @param addr_beat sub-block address (which beat)
 | 
			
		||||
    * @param data data being released
 | 
			
		||||
    */
 | 
			
		||||
  def makeRelease(
 | 
			
		||||
      prb: Probe,
 | 
			
		||||
      addr_beat: UInt = UInt(0),
 | 
			
		||||
      data: UInt = UInt(0)): Release = {
 | 
			
		||||
    Bundle(Release(
 | 
			
		||||
      voluntary = Bool(false),
 | 
			
		||||
      r_type = co.getReleaseType(prb, this),
 | 
			
		||||
      client_xact_id = UInt(0),
 | 
			
		||||
      addr_block = prb.addr_block,
 | 
			
		||||
      addr_beat = addr_beat,
 | 
			
		||||
      data = data), { case TLId => id })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** New metadata after receiving a [[uncore.Grant]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param incoming the incoming [[uncore.Grant]]
 | 
			
		||||
    * @param pending the mem op that triggered this transaction
 | 
			
		||||
    */
 | 
			
		||||
  def onGrant(incoming: Grant, pending: UInt): ClientMetadata =
 | 
			
		||||
    Bundle(co.clientMetadataOnGrant(incoming, pending, this), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** New metadata after receiving a [[uncore.Probe]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param incoming the incoming [[uncore.Probe]]
 | 
			
		||||
    */
 | 
			
		||||
  def onProbe(incoming: Probe): ClientMetadata =
 | 
			
		||||
    Bundle(co.clientMetadataOnProbe(incoming, this), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** New metadata after a op_code hits this block
 | 
			
		||||
    *
 | 
			
		||||
    * @param op_code a memory operation from [[uncore.constants.MemoryOpConstants]]
 | 
			
		||||
    */
 | 
			
		||||
  def onHit(op_code: UInt): ClientMetadata =
 | 
			
		||||
    Bundle(co.clientMetadataOnHit(op_code, this), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** New metadata after receiving a [[uncore.Probe]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param op_code a memory operation from [[uncore.constants.MemoryOpConstants]]
 | 
			
		||||
    */
 | 
			
		||||
  def onCacheControl(op_code: UInt): ClientMetadata =
 | 
			
		||||
    Bundle(co.clientMetadataOnCacheControl(op_code, this), { case TLId => id })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Factories for ClientMetadata, including on reset */
 | 
			
		||||
object ClientMetadata {
 | 
			
		||||
  def apply(state: UInt) = {
 | 
			
		||||
    val meta = new ClientMetadata
 | 
			
		||||
    meta.state := state
 | 
			
		||||
    meta
 | 
			
		||||
  }
 | 
			
		||||
  def onReset = new ClientMetadata().co.clientMetadataOnReset
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Stores manager-side information about the status 
 | 
			
		||||
  * of a cache block, including whether it has any known sharers.
 | 
			
		||||
  *
 | 
			
		||||
  * Its API can be used to create [[uncore.Probe]] and [[uncore.Grant]] messages.
 | 
			
		||||
  */
 | 
			
		||||
class ManagerMetadata extends CoherenceMetadata {
 | 
			
		||||
  // Currently no coherence policies assume manager-side state information
 | 
			
		||||
  // val state = UInt(width = co.masterStateWidth) TODO: Fix 0-width wires in Chisel
 | 
			
		||||
 | 
			
		||||
  /** The directory information for this block */
 | 
			
		||||
  val sharers = UInt(width = co.dir.width)
 | 
			
		||||
 | 
			
		||||
  /** Metadata equality */
 | 
			
		||||
  def ===(rhs: ManagerMetadata): Bool = //this.state === rhs.state && TODO: Fix 0-width wires in Chisel
 | 
			
		||||
                                         this.sharers === rhs.sharers
 | 
			
		||||
  def !=(rhs: ManagerMetadata): Bool = !this.===(rhs)
 | 
			
		||||
 | 
			
		||||
  /** Converts the directory info into an N-hot sharer bitvector (i.e. full representation) */
 | 
			
		||||
  def full(dummy: Int = 0): UInt = co.dir.full(this.sharers)
 | 
			
		||||
 | 
			
		||||
  /** Does this [[uncore.Acquire]] require [[uncore.Probe Probes]] to be sent */
 | 
			
		||||
  def requiresProbes(acq: Acquire): Bool = co.requiresProbes(acq, this)
 | 
			
		||||
  /** Does this memory op require [[uncore.Probe Probes]] to be sent */
 | 
			
		||||
  def requiresProbes(op_code: UInt): Bool = co.requiresProbes(op_code, this)
 | 
			
		||||
  /** Does an eviction require [[uncore.Probe Probes]] to be sent */
 | 
			
		||||
  def requiresProbesOnVoluntaryWriteback(dummy: Int = 0): Bool =
 | 
			
		||||
    co.requiresProbes(M_FLUSH, this)
 | 
			
		||||
 | 
			
		||||
  /** Construct an appropriate [[uncore.ProbeToDst]] for a given [[uncore.Acquire]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param dst Destination client id for this Probe
 | 
			
		||||
    * @param acq Acquire message triggering this Probe
 | 
			
		||||
    */
 | 
			
		||||
  def makeProbe(dst: UInt, acq: Acquire): ProbeToDst = 
 | 
			
		||||
    Bundle(Probe(dst, co.getProbeType(acq, this), acq.addr_block), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** Construct an appropriate [[uncore.ProbeToDst]] for a given mem op
 | 
			
		||||
    *
 | 
			
		||||
    * @param dst Destination client id for this Probe
 | 
			
		||||
    * @param op_code memory operation triggering this Probe
 | 
			
		||||
    * @param addr_block address of the cache block being probed
 | 
			
		||||
    */
 | 
			
		||||
  def makeProbe(dst: UInt, op_code: UInt, addr_block: UInt): ProbeToDst =
 | 
			
		||||
    Bundle(Probe(dst, co.getProbeType(op_code, this), addr_block), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** Construct an appropriate [[uncore.ProbeToDst]] for an eviction
 | 
			
		||||
    *
 | 
			
		||||
    * @param dst Destination client id for this Probe
 | 
			
		||||
    * @param addr_block address of the cache block being probed prior to eviction
 | 
			
		||||
    */
 | 
			
		||||
  def makeProbeForVoluntaryWriteback(dst: UInt, addr_block: UInt): ProbeToDst =
 | 
			
		||||
    makeProbe(dst, M_FLUSH, addr_block)
 | 
			
		||||
 | 
			
		||||
  /** Construct an appropriate [[uncore.GrantToDst]] to acknowledge an [[uncore.Release]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param rel Release message being acknowledged by this Grant
 | 
			
		||||
    * @param manager_xact_id manager's transaction id
 | 
			
		||||
    */
 | 
			
		||||
  def makeGrant(rel: ReleaseFromSrc, manager_xact_id: UInt): GrantToDst = {
 | 
			
		||||
    Bundle(Grant(
 | 
			
		||||
      dst = rel.client_id,
 | 
			
		||||
      is_builtin_type = Bool(true),
 | 
			
		||||
      g_type = Grant.voluntaryAckType,
 | 
			
		||||
      client_xact_id = rel.client_xact_id,
 | 
			
		||||
      manager_xact_id = manager_xact_id), { case TLId => id })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Construct an appropriate [[uncore.GrantToDst]] to respond to an [[uncore.Acquire]]
 | 
			
		||||
    *
 | 
			
		||||
    * May contain single or multiple beats of data, or just be a permissions upgrade.
 | 
			
		||||
    *
 | 
			
		||||
    * @param acq Acquire message being responded to by this Grant
 | 
			
		||||
    * @param manager_xact_id manager's transaction id
 | 
			
		||||
    * @param addr_beat beat id of the data
 | 
			
		||||
    * @param data data being refilled to the original requestor
 | 
			
		||||
    */
 | 
			
		||||
  def makeGrant(
 | 
			
		||||
      acq: AcquireFromSrc,
 | 
			
		||||
      manager_xact_id: UInt, 
 | 
			
		||||
      addr_beat: UInt = UInt(0),
 | 
			
		||||
      data: UInt = UInt(0)): GrantToDst = {
 | 
			
		||||
    Bundle(Grant(
 | 
			
		||||
      dst = acq.client_id,
 | 
			
		||||
      is_builtin_type = acq.isBuiltInType(),
 | 
			
		||||
      g_type = Mux(acq.isBuiltInType(), 
 | 
			
		||||
                     acq.getBuiltInGrantType(),
 | 
			
		||||
                     co.getGrantType(acq, this)),
 | 
			
		||||
      client_xact_id = acq.client_xact_id,
 | 
			
		||||
      manager_xact_id = manager_xact_id,
 | 
			
		||||
      addr_beat = addr_beat,
 | 
			
		||||
      data = data), { case TLId => id })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Construct an [[uncore.GrantToDst]] to respond to an [[uncore.Acquire]] with some overrides
 | 
			
		||||
    *
 | 
			
		||||
    * Used to respond to secondary misses merged into this transaction.
 | 
			
		||||
    * May contain single or multiple beats of data.
 | 
			
		||||
    *
 | 
			
		||||
    * @param pri Primary miss's Acquire message, used to get g_type and dst
 | 
			
		||||
    * @param sec Secondary miss info, used to get beat and client_xact_id
 | 
			
		||||
    * @param manager_xact_id manager's transaction id
 | 
			
		||||
    * @param data data being refilled to the original requestor
 | 
			
		||||
    */
 | 
			
		||||
  def makeGrant(
 | 
			
		||||
      pri: AcquireFromSrc,
 | 
			
		||||
      sec: SecondaryMissInfo,
 | 
			
		||||
      manager_xact_id: UInt, 
 | 
			
		||||
      data: UInt): GrantToDst = {
 | 
			
		||||
    val g = makeGrant(pri, manager_xact_id, sec.addr_beat, data)
 | 
			
		||||
    g.client_xact_id := sec.client_xact_id
 | 
			
		||||
    g
 | 
			
		||||
  }
 | 
			
		||||
    
 | 
			
		||||
  /** New metadata after receiving a [[uncore.ReleaseFromSrc]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param incoming the incoming [[uncore.ReleaseFromSrc]]
 | 
			
		||||
    */
 | 
			
		||||
  def onRelease(incoming: ReleaseFromSrc): ManagerMetadata =
 | 
			
		||||
    Bundle(co.managerMetadataOnRelease(incoming, incoming.client_id, this), { case TLId => id })
 | 
			
		||||
 | 
			
		||||
  /** New metadata after sending a [[uncore.GrantToDst]]
 | 
			
		||||
    *
 | 
			
		||||
    * @param outgoing the outgoing [[uncore.GrantToDst]]
 | 
			
		||||
    */
 | 
			
		||||
  def onGrant(outgoing: GrantToDst): ManagerMetadata =
 | 
			
		||||
    Bundle(co.managerMetadataOnGrant(outgoing, outgoing.client_id, this), { case TLId => id })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Factories for ManagerMetadata, including on reset */
 | 
			
		||||
object ManagerMetadata {
 | 
			
		||||
  def apply(sharers: UInt, state: UInt = UInt(width = 0)) = {
 | 
			
		||||
    val meta = new ManagerMetadata
 | 
			
		||||
    //meta.state := state TODO: Fix 0-width wires in Chisel 
 | 
			
		||||
    meta.sharers := sharers
 | 
			
		||||
    meta
 | 
			
		||||
  }
 | 
			
		||||
  def apply() = {
 | 
			
		||||
    val meta = new ManagerMetadata
 | 
			
		||||
    //meta.state := UInt(width = 0) TODO: Fix 0-width wires in Chisel 
 | 
			
		||||
    meta.sharers := meta.co.dir.flush
 | 
			
		||||
    meta
 | 
			
		||||
  }
 | 
			
		||||
  def onReset = new ManagerMetadata().co.managerMetadataOnReset
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** HierarchicalMetadata is used in a cache in a multi-level memory hierarchy
 | 
			
		||||
  * that is a manager with respect to some inner caches and a client with
 | 
			
		||||
  * respect to some outer cache.
 | 
			
		||||
  *
 | 
			
		||||
  * This class makes use of two different sets of TileLink parameters, which are
 | 
			
		||||
  * applied by contextually mapping [[uncore.TLId]] to one of 
 | 
			
		||||
  * [[uncore.InnerTLId]] or [[uncore.OuterTLId]].
 | 
			
		||||
  */ 
 | 
			
		||||
class HierarchicalMetadata extends CoherenceMetadata {
 | 
			
		||||
  val inner: ManagerMetadata = Bundle(new ManagerMetadata, {case TLId => params(InnerTLId)})
 | 
			
		||||
  val outer: ClientMetadata = Bundle(new ClientMetadata, {case TLId => params(OuterTLId)})
 | 
			
		||||
  def ===(rhs: HierarchicalMetadata): Bool = 
 | 
			
		||||
    this.inner === rhs.inner && this.outer === rhs.outer
 | 
			
		||||
  def !=(rhs: HierarchicalMetadata): Bool = !this.===(rhs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Factories for HierarchicalMetadata, including on reset */
 | 
			
		||||
object HierarchicalMetadata {
 | 
			
		||||
  def apply(inner: ManagerMetadata, outer: ClientMetadata): HierarchicalMetadata = {
 | 
			
		||||
    val m = new HierarchicalMetadata
 | 
			
		||||
    m.inner := inner
 | 
			
		||||
    m.outer := outer
 | 
			
		||||
    m
 | 
			
		||||
  }
 | 
			
		||||
  def onReset: HierarchicalMetadata = apply(ManagerMetadata.onReset, ClientMetadata.onReset)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Identifies the TLId of the inner network in a hierarchical cache controller */ 
 | 
			
		||||
case object InnerTLId extends Field[String]
 | 
			
		||||
/** Identifies the TLId of the outer network in a hierarchical cache controller */ 
 | 
			
		||||
case object OuterTLId extends Field[String]
 | 
			
		||||
							
								
								
									
										104
									
								
								uncore/src/main/scala/network.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								uncore/src/main/scala/network.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
case object LNEndpoints extends Field[Int]
 | 
			
		||||
case object LNHeaderBits extends Field[Int]
 | 
			
		||||
 | 
			
		||||
class PhysicalHeader(n: Int) extends Bundle {
 | 
			
		||||
  val src = UInt(width = log2Up(n))
 | 
			
		||||
  val dst = UInt(width = log2Up(n))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PhysicalNetworkIO[T <: Data](n: Int, dType: T) extends Bundle {
 | 
			
		||||
  val header = new PhysicalHeader(n)
 | 
			
		||||
  val payload = dType.clone
 | 
			
		||||
  override def clone = new PhysicalNetworkIO(n,dType).asInstanceOf[this.type]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BasicCrossbarIO[T <: Data](n: Int, dType: T) extends Bundle {
 | 
			
		||||
    val in  = Vec.fill(n){Decoupled(new PhysicalNetworkIO(n,dType))}.flip 
 | 
			
		||||
    val out = Vec.fill(n){Decoupled(new PhysicalNetworkIO(n,dType))}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class PhysicalNetwork extends Module
 | 
			
		||||
 | 
			
		||||
class BasicCrossbar[T <: Data](n: Int, dType: T, count: Int = 1, needsLock: Option[PhysicalNetworkIO[T] => Bool] = None) extends PhysicalNetwork {
 | 
			
		||||
  val io = new BasicCrossbarIO(n, dType)
 | 
			
		||||
 | 
			
		||||
  val rdyVecs = List.fill(n){Vec.fill(n)(Bool())}
 | 
			
		||||
 | 
			
		||||
  io.out.zip(rdyVecs).zipWithIndex.map{ case ((out, rdys), i) => {
 | 
			
		||||
    val rrarb = Module(new LockingRRArbiter(io.in(0).bits, n, count, needsLock))
 | 
			
		||||
    (rrarb.io.in, io.in, rdys).zipped.map{ case (arb, in, rdy) => {
 | 
			
		||||
      arb.valid := in.valid && (in.bits.header.dst === UInt(i)) 
 | 
			
		||||
      arb.bits := in.bits
 | 
			
		||||
      rdy := arb.ready && (in.bits.header.dst === UInt(i))
 | 
			
		||||
    }}
 | 
			
		||||
    out <> rrarb.io.out
 | 
			
		||||
  }}
 | 
			
		||||
  for(i <- 0 until n) {
 | 
			
		||||
    io.in(i).ready := rdyVecs.map(r => r(i)).reduceLeft(_||_)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class LogicalNetwork extends Module
 | 
			
		||||
 | 
			
		||||
class LogicalHeader extends Bundle {
 | 
			
		||||
  val src = UInt(width = params(LNHeaderBits))
 | 
			
		||||
  val dst = UInt(width = params(LNHeaderBits))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class LogicalNetworkIO[T <: Data](dType: T) extends Bundle {
 | 
			
		||||
  val header = new LogicalHeader
 | 
			
		||||
  val payload = dType.clone
 | 
			
		||||
  override def clone = { new LogicalNetworkIO(dType).asInstanceOf[this.type] }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object DecoupledLogicalNetworkIOWrapper {
 | 
			
		||||
  def apply[T <: Data](
 | 
			
		||||
      in: DecoupledIO[T],
 | 
			
		||||
      src: UInt = UInt(0),
 | 
			
		||||
      dst: UInt = UInt(0)): DecoupledIO[LogicalNetworkIO[T]] = {
 | 
			
		||||
    val out = Decoupled(new LogicalNetworkIO(in.bits.clone)).asDirectionless
 | 
			
		||||
    out.valid := in.valid
 | 
			
		||||
    out.bits.payload := in.bits
 | 
			
		||||
    out.bits.header.dst := dst
 | 
			
		||||
    out.bits.header.src := src
 | 
			
		||||
    in.ready := out.ready
 | 
			
		||||
    out
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object DecoupledLogicalNetworkIOUnwrapper {
 | 
			
		||||
  def apply[T <: Data](in: DecoupledIO[LogicalNetworkIO[T]]): DecoupledIO[T] = {
 | 
			
		||||
    val out = Decoupled(in.bits.payload.clone).asDirectionless
 | 
			
		||||
    out.valid := in.valid
 | 
			
		||||
    out.bits := in.bits.payload
 | 
			
		||||
    in.ready := out.ready
 | 
			
		||||
    out
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object DefaultFromPhysicalShim {
 | 
			
		||||
  def apply[T <: Data](in: DecoupledIO[PhysicalNetworkIO[T]]): DecoupledIO[LogicalNetworkIO[T]] = {
 | 
			
		||||
    val out = Decoupled(new LogicalNetworkIO(in.bits.payload)).asDirectionless
 | 
			
		||||
    out.bits.header := in.bits.header
 | 
			
		||||
    out.bits.payload := in.bits.payload
 | 
			
		||||
    out.valid := in.valid
 | 
			
		||||
    in.ready := out.ready
 | 
			
		||||
    out
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object DefaultToPhysicalShim {
 | 
			
		||||
  def apply[T <: Data](n: Int, in: DecoupledIO[LogicalNetworkIO[T]]): DecoupledIO[PhysicalNetworkIO[T]] = {
 | 
			
		||||
    val out = Decoupled(new PhysicalNetworkIO(n, in.bits.payload)).asDirectionless
 | 
			
		||||
    out.bits.header := in.bits.header
 | 
			
		||||
    out.bits.payload := in.bits.payload
 | 
			
		||||
    out.valid := in.valid
 | 
			
		||||
    in.ready := out.ready
 | 
			
		||||
    out
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								uncore/src/main/scala/package.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								uncore/src/main/scala/package.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package object uncore extends uncore.constants.MemoryOpConstants
 | 
			
		||||
{
 | 
			
		||||
  implicit def toOption[A](a: A) = Option(a)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								uncore/src/main/scala/slowio.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								uncore/src/main/scala/slowio.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
class SlowIO[T <: Data](val divisor_max: Int)(data: => T) extends Module
 | 
			
		||||
{
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val out_fast = Decoupled(data).flip
 | 
			
		||||
    val out_slow = Decoupled(data)
 | 
			
		||||
    val in_fast = Decoupled(data)
 | 
			
		||||
    val in_slow = Decoupled(data).flip
 | 
			
		||||
    val clk_slow = Bool(OUTPUT)
 | 
			
		||||
    val set_divisor = Valid(Bits(width = 32)).flip
 | 
			
		||||
    val divisor = Bits(OUTPUT, 32)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  require(divisor_max >= 8 && divisor_max <= 65536 && isPow2(divisor_max))
 | 
			
		||||
  val divisor = Reg(init=UInt(divisor_max-1))
 | 
			
		||||
  val d_shadow = Reg(init=UInt(divisor_max-1))
 | 
			
		||||
  val hold = Reg(init=UInt(divisor_max/4-1))
 | 
			
		||||
  val h_shadow = Reg(init=UInt(divisor_max/4-1))
 | 
			
		||||
  when (io.set_divisor.valid) {
 | 
			
		||||
    d_shadow := io.set_divisor.bits(log2Up(divisor_max)-1, 0).toUInt
 | 
			
		||||
    h_shadow := io.set_divisor.bits(log2Up(divisor_max)-1+16, 16).toUInt
 | 
			
		||||
  }
 | 
			
		||||
  io.divisor := hold << UInt(16) | divisor
 | 
			
		||||
 | 
			
		||||
  val count = Reg{UInt(width = log2Up(divisor_max))}
 | 
			
		||||
  val myclock = Reg{Bool()}
 | 
			
		||||
  count := count + UInt(1)
 | 
			
		||||
 | 
			
		||||
  val rising = count === (divisor >> UInt(1))
 | 
			
		||||
  val falling = count === divisor
 | 
			
		||||
  val held = count === (divisor >> UInt(1)) + hold
 | 
			
		||||
 | 
			
		||||
  when (falling) {
 | 
			
		||||
    divisor := d_shadow
 | 
			
		||||
    hold := h_shadow
 | 
			
		||||
    count := UInt(0)
 | 
			
		||||
    myclock := Bool(false)
 | 
			
		||||
  }
 | 
			
		||||
  when (rising) {
 | 
			
		||||
    myclock := Bool(true)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val in_slow_rdy = Reg(init=Bool(false))
 | 
			
		||||
  val out_slow_val = Reg(init=Bool(false))
 | 
			
		||||
  val out_slow_bits = Reg(data)
 | 
			
		||||
 | 
			
		||||
  val fromhost_q = Module(new Queue(data,1))
 | 
			
		||||
  fromhost_q.io.enq.valid := rising && (io.in_slow.valid && in_slow_rdy || this.reset)
 | 
			
		||||
  fromhost_q.io.enq.bits := io.in_slow.bits
 | 
			
		||||
  fromhost_q.io.deq <> io.in_fast
 | 
			
		||||
 | 
			
		||||
  val tohost_q = Module(new Queue(data,1))
 | 
			
		||||
  tohost_q.io.enq <> io.out_fast
 | 
			
		||||
  tohost_q.io.deq.ready := rising && io.out_slow.ready && out_slow_val
 | 
			
		||||
 | 
			
		||||
  when (held) {
 | 
			
		||||
    in_slow_rdy := fromhost_q.io.enq.ready
 | 
			
		||||
    out_slow_val := tohost_q.io.deq.valid
 | 
			
		||||
    out_slow_bits := Mux(this.reset, fromhost_q.io.deq.bits, tohost_q.io.deq.bits)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.in_slow.ready := in_slow_rdy
 | 
			
		||||
  io.out_slow.valid := out_slow_val
 | 
			
		||||
  io.out_slow.bits := out_slow_bits
 | 
			
		||||
  io.clk_slow := myclock
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1221
									
								
								uncore/src/main/scala/tilelink.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1221
									
								
								uncore/src/main/scala/tilelink.scala
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										129
									
								
								uncore/src/main/scala/uncore.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								uncore/src/main/scala/uncore.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
import Chisel._
 | 
			
		||||
 | 
			
		||||
case object NReleaseTransactors extends Field[Int]
 | 
			
		||||
case object NProbeTransactors extends Field[Int]
 | 
			
		||||
case object NAcquireTransactors extends Field[Int]
 | 
			
		||||
 | 
			
		||||
trait CoherenceAgentParameters extends UsesParameters {
 | 
			
		||||
  val nReleaseTransactors = 1
 | 
			
		||||
  val nAcquireTransactors = params(NAcquireTransactors)
 | 
			
		||||
  val nTransactors = nReleaseTransactors + nAcquireTransactors
 | 
			
		||||
  def outerTLParams = params.alterPartial({ case TLId => params(OuterTLId)})
 | 
			
		||||
  val outerDataBeats = outerTLParams(TLDataBeats)
 | 
			
		||||
  val outerDataBits = outerTLParams(TLDataBits)
 | 
			
		||||
  val outerBeatAddrBits = log2Up(outerDataBeats)
 | 
			
		||||
  val outerByteAddrBits = log2Up(outerDataBits/8)
 | 
			
		||||
  def innerTLParams = params.alterPartial({case TLId => params(InnerTLId)})
 | 
			
		||||
  val innerDataBeats = innerTLParams(TLDataBeats)
 | 
			
		||||
  val innerDataBits = innerTLParams(TLDataBits)
 | 
			
		||||
  val innerBeatAddrBits = log2Up(innerDataBeats)
 | 
			
		||||
  val innerByteAddrBits = log2Up(innerDataBits/8)
 | 
			
		||||
  require(outerDataBeats == innerDataBeats) //TODO: must fix all xact_data Vecs to remove this requirement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class CoherenceAgentBundle extends Bundle with CoherenceAgentParameters
 | 
			
		||||
abstract class CoherenceAgentModule extends Module with CoherenceAgentParameters
 | 
			
		||||
 | 
			
		||||
trait HasCoherenceAgentWiringHelpers {
 | 
			
		||||
  def doOutputArbitration[T <: TileLinkChannel](
 | 
			
		||||
      out: DecoupledIO[T],
 | 
			
		||||
      ins: Seq[DecoupledIO[T]]) {
 | 
			
		||||
    def lock(o: T) = o.hasMultibeatData()
 | 
			
		||||
    val arb = Module(new LockingRRArbiter(out.bits.clone, ins.size, out.bits.tlDataBeats, lock _))
 | 
			
		||||
    out <> arb.io.out
 | 
			
		||||
    arb.io.in <> ins
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def doInputRouting[T <: HasManagerTransactionId](
 | 
			
		||||
        in: DecoupledIO[T],
 | 
			
		||||
        outs: Seq[DecoupledIO[T]]) {
 | 
			
		||||
    val idx = in.bits.manager_xact_id
 | 
			
		||||
    outs.map(_.bits := in.bits)
 | 
			
		||||
    outs.zipWithIndex.map { case (o,i) => o.valid := in.valid && idx === UInt(i) }
 | 
			
		||||
    in.ready := Vec(outs.map(_.ready)).read(idx)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasInnerTLIO extends CoherenceAgentBundle {
 | 
			
		||||
  val inner = Bundle(new ManagerTileLinkIO)(innerTLParams)
 | 
			
		||||
  val incoherent = Vec.fill(inner.tlNCachingClients){Bool()}.asInput
 | 
			
		||||
  def iacq(dummy: Int = 0) = inner.acquire.bits
 | 
			
		||||
  def iprb(dummy: Int = 0) = inner.probe.bits
 | 
			
		||||
  def irel(dummy: Int = 0) = inner.release.bits
 | 
			
		||||
  def ignt(dummy: Int = 0) = inner.grant.bits
 | 
			
		||||
  def ifin(dummy: Int = 0) = inner.finish.bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasUncachedOuterTLIO extends CoherenceAgentBundle {
 | 
			
		||||
  val outer = Bundle(new ClientUncachedTileLinkIO)(outerTLParams)
 | 
			
		||||
  def oacq(dummy: Int = 0) = outer.acquire.bits
 | 
			
		||||
  def ognt(dummy: Int = 0) = outer.grant.bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasCachedOuterTLIO extends CoherenceAgentBundle {
 | 
			
		||||
  val outer = Bundle(new ClientTileLinkIO)(outerTLParams)
 | 
			
		||||
  def oacq(dummy: Int = 0) = outer.acquire.bits
 | 
			
		||||
  def oprb(dummy: Int = 0) = outer.probe.bits
 | 
			
		||||
  def orel(dummy: Int = 0) = outer.release.bits
 | 
			
		||||
  def ognt(dummy: Int = 0) = outer.grant.bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ManagerTLIO extends HasInnerTLIO with HasUncachedOuterTLIO
 | 
			
		||||
 | 
			
		||||
abstract class CoherenceAgent extends CoherenceAgentModule {
 | 
			
		||||
  def innerTL: ManagerTileLinkIO
 | 
			
		||||
  def outerTL: ClientTileLinkIO
 | 
			
		||||
  def incoherent: Vec[Bool]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class ManagerCoherenceAgent extends CoherenceAgent
 | 
			
		||||
    with HasCoherenceAgentWiringHelpers {
 | 
			
		||||
  val io = new ManagerTLIO
 | 
			
		||||
  def innerTL = io.inner
 | 
			
		||||
  def outerTL = TileLinkIOWrapper(io.outer, outerTLParams)
 | 
			
		||||
  def incoherent = io.incoherent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class HierarchicalTLIO extends HasInnerTLIO with HasCachedOuterTLIO
 | 
			
		||||
 | 
			
		||||
abstract class HierarchicalCoherenceAgent extends CoherenceAgent {
 | 
			
		||||
  val io = new HierarchicalTLIO
 | 
			
		||||
  def innerTL = io.inner
 | 
			
		||||
  def outerTL = io.outer
 | 
			
		||||
  def incoherent = io.incoherent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
trait HasTrackerConflictIO extends Bundle {
 | 
			
		||||
  val has_acquire_conflict = Bool(OUTPUT)
 | 
			
		||||
  val has_acquire_match = Bool(OUTPUT)
 | 
			
		||||
  val has_release_match = Bool(OUTPUT)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ManagerXactTrackerIO extends ManagerTLIO with HasTrackerConflictIO
 | 
			
		||||
class HierarchicalXactTrackerIO extends HierarchicalTLIO with HasTrackerConflictIO
 | 
			
		||||
 | 
			
		||||
abstract class XactTracker extends CoherenceAgentModule with HasDataBeatCounters {
 | 
			
		||||
  def addPendingBitWhenBeat[T <: HasBeat](inc: Bool, in: T): UInt =
 | 
			
		||||
    Fill(in.tlDataBeats, inc) &  UIntToOH(in.addr_beat)
 | 
			
		||||
  def dropPendingBitWhenBeat[T <: HasBeat](dec: Bool, in: T): UInt =
 | 
			
		||||
    ~Fill(in.tlDataBeats, dec) | ~UIntToOH(in.addr_beat)
 | 
			
		||||
 | 
			
		||||
  def addPendingBitWhenBeatHasData[T <: HasBeat](in: DecoupledIO[T]): UInt =
 | 
			
		||||
    addPendingBitWhenBeat(in.fire() && in.bits.hasData(), in.bits)
 | 
			
		||||
 | 
			
		||||
  def addPendingBitWhenBeatIsGetOrAtomic(in: DecoupledIO[AcquireFromSrc]): UInt = {
 | 
			
		||||
    val a = in.bits
 | 
			
		||||
    val isGetOrAtomic = a.isBuiltInType() &&
 | 
			
		||||
      (Vec(Acquire.getType, Acquire.getBlockType, Acquire.putAtomicType).contains(a.a_type))
 | 
			
		||||
    addPendingBitWhenBeat(in.fire() && isGetOrAtomic, a)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def dropPendingBitWhenBeatHasData[T <: HasBeat](in: DecoupledIO[T]): UInt =
 | 
			
		||||
    dropPendingBitWhenBeat(in.fire() && in.bits.hasData(), in.bits)
 | 
			
		||||
 | 
			
		||||
  def dropPendingBitAtDest(in: DecoupledIO[ProbeToDst]): UInt =
 | 
			
		||||
    ~Fill(in.bits.tlNCachingClients, in.fire()) | ~UIntToOH(in.bits.client_id)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								uncore/src/main/scala/util.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								uncore/src/main/scala/util.scala
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
package uncore
 | 
			
		||||
 | 
			
		||||
import Chisel._
 | 
			
		||||
import scala.math._
 | 
			
		||||
 | 
			
		||||
class Unsigned(x: Int) {
 | 
			
		||||
  require(x >= 0)
 | 
			
		||||
  def clog2: Int = { require(x > 0); ceil(log(x)/log(2)).toInt }
 | 
			
		||||
  def log2: Int = { require(x > 0); floor(log(x)/log(2)).toInt }
 | 
			
		||||
  def isPow2: Boolean = x > 0 && (x & (x-1)) == 0
 | 
			
		||||
  def nextPow2: Int = if (x == 0) 1 else 1 << clog2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object MuxBundle {
 | 
			
		||||
  def apply[T <: Data] (default: T, mapping: Seq[(Bool, T)]): T = {
 | 
			
		||||
    mapping.reverse.foldLeft(default)((b, a) => Mux(a._1, a._2, b))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Produces 0-width value when counting to 1
 | 
			
		||||
class ZCounter(val n: Int) {
 | 
			
		||||
  val value = Reg(init=UInt(0, log2Ceil(n)))
 | 
			
		||||
  def inc(): Bool = {
 | 
			
		||||
    if (n == 1) Bool(true)
 | 
			
		||||
    else {
 | 
			
		||||
      val wrap = value === UInt(n-1)
 | 
			
		||||
      value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1))
 | 
			
		||||
      wrap
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object ZCounter {
 | 
			
		||||
  def apply(n: Int) = new ZCounter(n)
 | 
			
		||||
  def apply(cond: Bool, n: Int): (UInt, Bool) = {
 | 
			
		||||
    val c = new ZCounter(n)
 | 
			
		||||
    var wrap: Bool = null
 | 
			
		||||
    when (cond) { wrap = c.inc() }
 | 
			
		||||
    (c.value, cond && wrap)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class FlowThroughSerializer[T <: HasTileLinkData](gen: T, n: Int) extends Module {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val in = Decoupled(gen.clone).flip
 | 
			
		||||
    val out = Decoupled(gen.clone)
 | 
			
		||||
    val cnt = UInt(OUTPUT, log2Up(n))
 | 
			
		||||
    val done = Bool(OUTPUT)
 | 
			
		||||
  }
 | 
			
		||||
  val narrowWidth = io.in.bits.data.getWidth / n
 | 
			
		||||
  require(io.in.bits.data.getWidth % narrowWidth == 0)
 | 
			
		||||
 | 
			
		||||
  if(n == 1) {
 | 
			
		||||
    io.in <> io.out
 | 
			
		||||
    io.cnt := UInt(width = 0)
 | 
			
		||||
    io.done := Bool(true)
 | 
			
		||||
  } else {
 | 
			
		||||
    val cnt = Reg(init=UInt(0, width = log2Up(n)))
 | 
			
		||||
    val wrap = cnt === UInt(n-1)
 | 
			
		||||
    val rbits = Reg(io.in.bits.clone)
 | 
			
		||||
    val active = Reg(init=Bool(false))
 | 
			
		||||
 | 
			
		||||
    val shifter = Vec.fill(n){Bits(width = narrowWidth)}
 | 
			
		||||
    (0 until n).foreach { 
 | 
			
		||||
      i => shifter(i) := rbits.data((i+1)*narrowWidth-1,i*narrowWidth)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    io.done := Bool(false)
 | 
			
		||||
    io.cnt := cnt
 | 
			
		||||
    io.in.ready := !active
 | 
			
		||||
    io.out.valid := active || io.in.valid
 | 
			
		||||
    io.out.bits := io.in.bits
 | 
			
		||||
    when(!active && io.in.valid) {
 | 
			
		||||
      when(io.in.bits.hasData()) {
 | 
			
		||||
        cnt := Mux(io.out.ready, UInt(1), UInt(0))
 | 
			
		||||
        rbits := io.in.bits
 | 
			
		||||
        active := Bool(true)
 | 
			
		||||
      }
 | 
			
		||||
      io.done := !io.in.bits.hasData()
 | 
			
		||||
    }
 | 
			
		||||
    when(active) {
 | 
			
		||||
      io.out.bits := rbits
 | 
			
		||||
      io.out.bits.data := shifter(cnt)
 | 
			
		||||
      when(io.out.ready) { 
 | 
			
		||||
        cnt := cnt + UInt(1)
 | 
			
		||||
        when(wrap) {
 | 
			
		||||
          cnt := UInt(0)
 | 
			
		||||
          io.done := Bool(true)
 | 
			
		||||
          active := Bool(false)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object FlowThroughSerializer {
 | 
			
		||||
  def apply[T <: HasTileLinkData](in: DecoupledIO[T], n: Int): DecoupledIO[T] = {
 | 
			
		||||
    val fs = Module(new FlowThroughSerializer(in.bits, n))
 | 
			
		||||
    fs.io.in.valid := in.valid
 | 
			
		||||
    fs.io.in.bits := in.bits
 | 
			
		||||
    in.ready := fs.io.in.ready
 | 
			
		||||
    fs.io.out
 | 
			
		||||
  }
 | 
			
		||||
} 
 | 
			
		||||
		Reference in New Issue
	
	Block a user