1
0
rocket-chip/src/main/scala/rocket/PTW.scala

237 lines
6.6 KiB
Scala
Raw Normal View History

// See LICENSE.Berkeley for license details.
// See LICENSE.SiFive for license details.
2014-09-13 03:06:41 +02:00
package rocket
2011-11-09 23:52:17 +01:00
2012-10-08 05:15:54 +02:00
import Chisel._
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
import Chisel.ImplicitConversions._
import config._
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
import tile._
import uncore.constants._
import util._
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
import scala.collection.mutable.ListBuffer
2011-11-09 23:52:17 +01:00
2015-10-06 06:48:05 +02:00
class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
val prv = Bits(width = 2)
2016-07-06 04:19:49 +02:00
val pum = Bool()
val mxr = Bool()
val addr = UInt(width = vpnBits)
val store = Bool()
val fetch = Bool()
2015-03-14 10:49:07 +01:00
}
2015-10-06 06:48:05 +02:00
class PTWResp(implicit p: Parameters) extends CoreBundle()(p) {
val pte = new PTE
2013-08-12 19:39:11 +02:00
}
2015-10-06 06:48:05 +02:00
class TLBPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
2015-03-14 10:49:07 +01:00
val req = Decoupled(new PTWReq)
2013-08-12 19:39:11 +02:00
val resp = Valid(new PTWResp).flip
2016-06-18 03:29:05 +02:00
val ptbr = new PTBR().asInput
val invalidate = Bool(INPUT)
2016-06-18 03:29:05 +02:00
val status = new MStatus().asInput
}
2015-10-06 06:48:05 +02:00
class DatapathPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
2016-06-18 03:29:05 +02:00
val ptbr = new PTBR().asInput
val invalidate = Bool(INPUT)
2015-03-14 10:49:07 +01:00
val status = new MStatus().asInput
2011-11-09 23:52:17 +01:00
}
2015-10-06 06:48:05 +02:00
class PTE(implicit p: Parameters) extends CoreBundle()(p) {
2016-07-06 04:19:49 +02:00
val reserved_for_hardware = Bits(width = 16)
val ppn = UInt(width = 38)
val reserved_for_software = Bits(width = 2)
val d = Bool()
2016-07-06 04:19:49 +02:00
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
2015-05-19 03:23:58 +02:00
val v = Bool()
2016-07-06 04:19:49 +02:00
def table(dummy: Int = 0) = v && !r && !w && !x
def leaf(dummy: Int = 0) = v && (r || (x && !w))
def ur(dummy: Int = 0) = sr() && u
def uw(dummy: Int = 0) = sw() && u
def ux(dummy: Int = 0) = sx() && u
def sr(dummy: Int = 0) = leaf() && r
def sw(dummy: Int = 0) = leaf() && w
def sx(dummy: Int = 0) = leaf() && x
def access_ok(req: PTWReq) = {
val perm_ok = Mux(req.fetch, x, Mux(req.store, w, r || (x && req.mxr)))
val priv_ok = Mux(u, !req.pum, req.prv(0))
leaf() && priv_ok && perm_ok
}
}
2015-10-06 06:48:05 +02:00
class PTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) {
val io = new Bundle {
2016-01-14 22:57:45 +01:00
val requestor = Vec(n, new TLBPTWIO).flip
val mem = new HellaCacheIO
2013-01-07 22:38:59 +01:00
val dpath = new DatapathPTWIO
}
require(usingAtomics, "PTW requires atomic memory operations")
val s_ready :: s_req :: s_wait1 :: s_wait2 :: s_set_dirty :: s_wait1_dirty :: s_wait2_dirty :: s_done :: Nil = Enum(UInt(), 8)
2013-08-16 00:28:15 +02:00
val state = Reg(init=s_ready)
val count = Reg(UInt(width = log2Up(pgLevels)))
val s1_kill = Reg(next = Bool(false))
2015-03-14 10:49:07 +01:00
val r_req = Reg(new PTWReq)
2013-08-12 19:39:11 +02:00
val r_req_dest = Reg(Bits())
val r_pte = Reg(new PTE)
2011-11-09 23:52:17 +01:00
val vpn_idxs = (0 until pgLevels).map(i => (r_req.addr >> (pgLevels-i-1)*pgLevelBits)(pgLevelBits-1,0))
val vpn_idx = vpn_idxs(count)
2012-03-18 07:00:51 +01:00
2015-03-14 10:49:07 +01:00
val arb = Module(new RRArbiter(new PTWReq, n))
2012-10-10 06:35:03 +02:00
arb.io.in <> io.requestor.map(_.req)
arb.io.out.ready := state === s_ready
2016-07-30 02:52:56 +02:00
val pte = {
val tmp = new PTE().fromBits(io.mem.resp.bits.data)
val res = Wire(init = new PTE().fromBits(io.mem.resp.bits.data))
res.ppn := tmp.ppn(ppnBits-1, 0)
when ((tmp.ppn >> ppnBits) =/= 0) { res.v := false }
res
}
val pte_addr = Cat(r_pte.ppn, vpn_idx) << log2Ceil(xLen/8)
2012-10-10 06:35:03 +02:00
when (arb.io.out.fire()) {
2015-03-14 10:49:07 +01:00
r_req := arb.io.out.bits
2012-10-10 06:35:03 +02:00
r_req_dest := arb.io.chosen
2016-06-18 03:29:05 +02:00
r_pte.ppn := io.dpath.ptbr.ppn
2011-11-10 09:23:29 +01:00
}
val (pte_cache_hit, pte_cache_data) = {
val size = 1 << log2Up(pgLevels * 2)
val plru = new PseudoLRU(size)
2016-07-02 23:34:18 +02:00
val valid = Reg(init = UInt(0, size))
val tags = Reg(Vec(size, UInt(width = paddrBits)))
val data = Reg(Vec(size, UInt(width = ppnBits)))
val hits = tags.map(_ === pte_addr).asUInt & valid
val hit = hits.orR
when (io.mem.resp.valid && pte.table() && !hit) {
2016-07-02 23:34:18 +02:00
val r = Mux(valid.andR, plru.replace, PriorityEncoder(~valid))
valid := valid | UIntToOH(r)
tags(r) := pte_addr
data(r) := pte.ppn
}
when (hit && state === s_req) { plru.access(OHToUInt(hits)) }
2016-07-02 23:34:18 +02:00
when (io.dpath.invalidate) { valid := 0 }
(hit && count < pgLevels-1, Mux1H(hits, data))
2011-11-09 23:52:17 +01:00
}
2015-07-16 05:24:18 +02:00
val pte_wdata = Wire(init=new PTE().fromBits(0))
2016-07-06 04:19:49 +02:00
pte_wdata.a := true
pte_wdata.d := r_req.store
2011-11-09 23:52:17 +01:00
2016-08-19 18:46:43 +02:00
io.mem.req.valid := state.isOneOf(s_req, s_set_dirty)
io.mem.req.bits.phys := Bool(true)
2015-03-14 10:49:07 +01:00
io.mem.req.bits.cmd := Mux(state === s_set_dirty, M_XA_OR, M_XRD)
io.mem.req.bits.typ := log2Ceil(xLen/8)
io.mem.req.bits.addr := pte_addr
io.mem.s1_data := pte_wdata.asUInt
io.mem.s1_kill := s1_kill
io.mem.invalidate_lr := Bool(false)
2016-07-30 02:52:56 +02:00
val resp_ppns = (0 until pgLevels-1).map(i => Cat(pte_addr >> (pgIdxBits + pgLevelBits*(pgLevels-i-1)), r_req.addr(pgLevelBits*(pgLevels-i-1)-1,0))) :+ (pte_addr >> pgIdxBits)
for (i <- 0 until io.requestor.size) {
2016-07-30 02:52:56 +02:00
io.requestor(i).resp.valid := state === s_done && (r_req_dest === i)
io.requestor(i).resp.bits.pte := r_pte
2016-07-30 02:52:56 +02:00
io.requestor(i).resp.bits.pte.ppn := resp_ppns(count)
2016-06-18 03:29:05 +02:00
io.requestor(i).ptbr := io.dpath.ptbr
io.requestor(i).invalidate := io.dpath.invalidate
io.requestor(i).status := io.dpath.status
}
2011-11-09 23:52:17 +01:00
// control state machine
switch (state) {
is (s_ready) {
2012-10-10 06:35:03 +02:00
when (arb.io.out.valid) {
state := s_req
}
2013-08-12 19:39:11 +02:00
count := UInt(0)
2011-11-09 23:52:17 +01:00
}
is (s_req) {
when (pte_cache_hit) {
s1_kill := true
state := s_req
count := count + 1
r_pte.ppn := pte_cache_data
}.elsewhen (io.mem.req.ready) {
state := s_wait1
}
}
is (s_wait1) {
state := s_wait2
when (io.mem.xcpt.pf.ld) {
r_pte.v := false
state := s_done
2011-11-09 23:52:17 +01:00
}
}
is (s_wait2) {
when (io.mem.s2_nack) {
state := s_req
}
when (io.mem.resp.valid) {
2016-03-03 08:29:58 +01:00
state := s_done
when (pte.access_ok(r_req) && (!pte.a || (r_req.store && !pte.d))) {
2016-03-03 08:29:58 +01:00
state := s_set_dirty
}.otherwise {
r_pte := pte
2016-03-03 08:29:58 +01:00
}
when (pte.table() && count < pgLevels-1) {
state := s_req
count := count + 1
}
2011-11-09 23:52:17 +01:00
}
}
2015-03-14 10:49:07 +01:00
is (s_set_dirty) {
when (io.mem.req.ready) {
state := s_wait1_dirty
}
}
is (s_wait1_dirty) {
state := s_wait2_dirty
when (io.mem.xcpt.pf.st) {
r_pte.v := false
state := s_done
2015-03-14 10:49:07 +01:00
}
}
is (s_wait2_dirty) {
when (io.mem.s2_nack) {
2015-03-14 10:49:07 +01:00
state := s_set_dirty
}
when (io.mem.resp.valid) {
state := s_req
}
}
2011-11-09 23:52:17 +01:00
is (s_done) {
state := s_ready
2011-11-09 23:52:17 +01:00
}
}
}
/** Mix-ins for constructing tiles that might have a PTW */
trait CanHavePTW extends HasHellaCache {
implicit val p: Parameters
val module: CanHavePTWModule
var nPTWPorts = 1
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
nDCachePorts += usingPTW.toInt
}
trait CanHavePTWModule extends HasHellaCacheModule {
val outer: CanHavePTW
val ptwPorts = ListBuffer(outer.dcache.module.io.ptw)
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
val ptwOpt = if (outer.usingPTW) { Some(Module(new PTW(outer.nPTWPorts)(outer.p))) } else None
ptwOpt foreach { ptw => dcachePorts += ptw.io.mem }
}