style(Frontend): use scalafmt formatting frontend (#3370)

Format frontend according to the scalafmt file drafted in #3061.
This commit is contained in:
Muzi 2024-10-25 23:08:56 +08:00 committed by GitHub
parent b9dc808db3
commit cf7d6b7a1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 5214 additions and 4507 deletions

23
.github/workflows/format.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Format Checking
on: [push]
jobs:
scalafmt:
runs-on: ubuntu-latest
continue-on-error: true
timeout-minutes: 900
name: Check Format
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
- run: |
mkdir ~/.local/bin
sh -c "curl -L https://github.com/com-lihaoyi/mill/releases/download/0.11.7/0.11.7 > ~/.local/bin/mill && chmod +x ~/.local/bin/mill"
export PATH=~/.local/bin:$PATH
- run: make check-format

26
.scalafmt.conf Normal file
View File

@ -0,0 +1,26 @@
version = 3.8.1
runner.dialect = scala213
maxColumn = 120
preset = defaultWithAlign
align.tokens."+" = [{
code = ":"
}]
newlines.source = keep
newlines.afterCurlyLambdaParams = squash
rewrite.rules = [
RedundantBraces,
RedundantParens,
SortModifiers,
Imports
]
rewrite.redundantBraces.generalExpressions = false
rewrite.imports.expand = true
rewrite.imports.sort = scalastyle
rewrite.trailingCommas.style = never
docstrings.style = keep
project.includePaths = ["glob:**/src/main/scala/xiangshan/frontend/**.scala"]

View File

@ -209,6 +209,12 @@ bsp:
idea:
mill -i mill.idea.GenIdea/idea
check-format:
mill xiangshan.checkFormat
reformat:
mill xiangshan.reformat
# verilator simulation
emu: sim-verilog
$(MAKE) -C ./difftest emu SIM_TOP=SimTop DESIGN_DIR=$(NOOP_HOME) NUM_CORES=$(NUM_CORES) RTL_SUFFIX=$(RTL_SUFFIX)

View File

@ -17,6 +17,7 @@
import mill._
import scalalib._
import scalafmt._
import $file.`rocket-chip`.common
import $file.`rocket-chip`.cde.common
import $file.`rocket-chip`.hardfloat.build
@ -229,7 +230,7 @@ trait XiangShanModule extends ScalaModule {
override def forkEnv = Map("PATH" -> envPATH)
}
object xiangshan extends XiangShanModule with HasChisel {
object xiangshan extends XiangShanModule with HasChisel with ScalafmtModule {
override def millSourcePath = os.pwd

File diff suppressed because it is too large Load Diff

View File

@ -121,4 +121,4 @@ class BIM(implicit p: Parameters) extends BasePredictor with BimParams with BPUU
}
}
*/
*/

View File

@ -16,12 +16,12 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
class Composer(implicit p: Parameters) extends BasePredictor with HasBPUConst with HasPerfEvents {
val (components, resp) = getBPDComponents(io.in.bits.resp_in(0), p)
@ -35,15 +35,15 @@ class Composer(implicit p: Parameters) extends BasePredictor with HasBPUConst wi
io.out.s1 := fast_pred.io.out.s1
}
var metas = 0.U(1.W)
var metas = 0.U(1.W)
var meta_sz = 0
for (c <- components) {
c.io.reset_vector := io.reset_vector
c.io.in.valid := io.in.valid
c.io.in.bits.s0_pc := io.in.bits.s0_pc
c.io.in.bits.folded_hist := io.in.bits.folded_hist
c.io.reset_vector := io.reset_vector
c.io.in.valid := io.in.valid
c.io.in.bits.s0_pc := io.in.bits.s0_pc
c.io.in.bits.folded_hist := io.in.bits.folded_hist
c.io.in.bits.s1_folded_hist := io.in.bits.s1_folded_hist
c.io.in.bits.ghist := io.in.bits.ghist
c.io.in.bits.ghist := io.in.bits.ghist
c.io.s0_fire := io.s0_fire
c.io.s1_fire := io.s1_fire
@ -53,18 +53,17 @@ class Composer(implicit p: Parameters) extends BasePredictor with HasBPUConst wi
c.io.s2_redirect := io.s2_redirect
c.io.s3_redirect := io.s3_redirect
c.io.redirect := io.redirect
c.io.ctrl := DelayN(io.ctrl, 1)
c.io.redirect := io.redirect
c.io.ctrl := DelayN(io.ctrl, 1)
c.io.redirectFromIFU := io.redirectFromIFU
if (c.meta_size > 0) {
metas = (metas << c.meta_size) | c.io.out.last_stage_meta(c.meta_size-1,0)
metas = (metas << c.meta_size) | c.io.out.last_stage_meta(c.meta_size - 1, 0)
}
meta_sz = meta_sz + c.meta_size
}
println(s"total meta size: $meta_sz\n\n")
io.in.ready := components.map(_.io.s1_ready).reduce(_ && _)
io.s1_ready := components.map(_.io.s1_ready).reduce(_ && _)
@ -75,7 +74,7 @@ class Composer(implicit p: Parameters) extends BasePredictor with HasBPUConst wi
var update_meta = io.update.bits.meta
for (c <- components.reverse) {
c.io.update := io.update
c.io.update := io.update
c.io.update.bits.meta := update_meta
update_meta = update_meta >> c.meta_size
}
@ -90,8 +89,8 @@ class Composer(implicit p: Parameters) extends BasePredictor with HasBPUConst wi
metas(idx)
}
override def getFoldedHistoryInfo = Some(components.map(_.getFoldedHistoryInfo.getOrElse(Set())).reduce(_++_))
override def getFoldedHistoryInfo = Some(components.map(_.getFoldedHistoryInfo.getOrElse(Set())).reduce(_ ++ _))
override val perfEvents = components.map(_.getPerfEvents).reduce(_++_)
override val perfEvents = components.map(_.getPerfEvents).reduce(_ ++ _)
generatePerfEvent()
}

File diff suppressed because it is too large Load Diff

View File

@ -16,123 +16,121 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import utils._
import utility._
import xiangshan._
import org.chipsalliance.cde.config.Parameters
import scala.{Tuple2 => &}
import utility._
import utils._
import xiangshan._
trait FauFTBParams extends HasXSParameter with HasBPUConst {
val numWays = 32
val tagSize = 16
val TAR_STAT_SZ = 2
def TAR_FIT = 0.U(TAR_STAT_SZ.W)
def TAR_OVF = 1.U(TAR_STAT_SZ.W)
def TAR_UDF = 2.U(TAR_STAT_SZ.W)
def TAR_FIT = 0.U(TAR_STAT_SZ.W)
def TAR_OVF = 1.U(TAR_STAT_SZ.W)
def TAR_UDF = 2.U(TAR_STAT_SZ.W)
def BR_OFFSET_LEN = 12
def BR_OFFSET_LEN = 12
def JMP_OFFSET_LEN = 20
def getTag(pc: UInt) = pc(tagSize+instOffsetBits-1, instOffsetBits)
def getTag(pc: UInt) = pc(tagSize + instOffsetBits - 1, instOffsetBits)
}
class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {}
class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams {
val io = IO(new Bundle{
val req_tag = Input(UInt(tagSize.W))
val resp = Output(new FauFTBEntry)
val resp_hit = Output(Bool())
val io = IO(new Bundle {
val req_tag = Input(UInt(tagSize.W))
val resp = Output(new FauFTBEntry)
val resp_hit = Output(Bool())
val update_req_tag = Input(UInt(tagSize.W))
val update_hit = Output(Bool())
val write_valid = Input(Bool())
val write_entry = Input(new FauFTBEntry)
val write_tag = Input(UInt(tagSize.W))
val tag_read = Output(UInt(tagSize.W))
val update_hit = Output(Bool())
val write_valid = Input(Bool())
val write_entry = Input(new FauFTBEntry)
val write_tag = Input(UInt(tagSize.W))
val tag_read = Output(UInt(tagSize.W))
})
val data = Reg(new FauFTBEntry)
val tag = Reg(UInt(tagSize.W))
val data = Reg(new FauFTBEntry)
val tag = Reg(UInt(tagSize.W))
val valid = RegInit(false.B)
io.resp := data
io.resp := data
io.resp_hit := tag === io.req_tag && valid
// write bypass to avoid multiple hit
io.update_hit := ((tag === io.update_req_tag) && valid) ||
((io.write_tag === io.update_req_tag) && io.write_valid)
((io.write_tag === io.update_req_tag) && io.write_valid)
io.tag_read := tag
when (io.write_valid) {
when (!valid) {
when(io.write_valid) {
when(!valid) {
valid := true.B
}
tag := io.write_tag
data := io.write_entry
tag := io.write_tag
data := io.write_entry
}
}
class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams {
val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None
val hit = Bool()
val hit = Bool()
}
val resp_meta = Wire(new FauFTBMeta)
override val meta_size = resp_meta.getWidth
val resp_meta = Wire(new FauFTBMeta)
override val meta_size = resp_meta.getWidth
override val is_fast_pred = true
val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay))
// numWays * numBr
val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
val replacer = ReplacementPolicy.fromString("plru", numWays)
val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
val replacer = ReplacementPolicy.fromString("plru", numWays)
val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W))))
// pred req
ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0)))
// pred resp
val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
val s1_hit = s1_hit_oh.orR
val s1_hit_way = OHToUInt(s1_hit_oh)
val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
val s1_hit = s1_hit_oh.orR
val s1_hit_way = OHToUInt(s1_hit_oh)
val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction(isNotS3 = true)))
val s1_all_entries = VecInit(ways.map(_.io.resp))
for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) {
fp.hit := DontCare
fp.hit := DontCare
fp.multiHit := false.B
fp.fromFtbEntry(e, s1_pc_dup(0))
for (i <- 0 until numBr) {
fp.br_taken_mask(i) := c(i)(1) || e.always_taken(i)
}
}
val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries)
val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries)
XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n")
val fauftb_enable = RegNext(io.ctrl.ubtb_enable)
io.out.s1.full_pred.map(_ := s1_hit_full_pred)
io.out.s1.full_pred.map(_ .hit := s1_hit && fauftb_enable)
io.fauftb_entry_out := s1_hit_fauftbentry
io.out.s1.full_pred.map(_.hit := s1_hit && fauftb_enable)
io.fauftb_entry_out := s1_hit_fauftbentry
io.fauftb_entry_hit_out := s1_hit && fauftb_enable
// Illegal check for FTB entry reading
val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits))
val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits))
val uftb_entry_endLowerwithCarry = Cat(s1_hit_fauftbentry.carry, s1_hit_fauftbentry.pftAddr)
val fallThroughErr = s1_pc_startLower + (PredictWidth).U >= uftb_entry_endLowerwithCarry
when(io.s1_fire(0) && s1_hit){
val fallThroughErr = s1_pc_startLower + PredictWidth.U >= uftb_entry_endLowerwithCarry
when(io.s1_fire(0) && s1_hit) {
assert(fallThroughErr, s"FauFTB read entry fallThrough address error!")
}
// assign metas
io.out.last_stage_meta := resp_meta.asUInt
resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0))
if(resp_meta.pred_way.isDefined) {resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0))}
resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0))
if (resp_meta.pred_way.isDefined) {
resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0))
}
// pred update replacer state
val s1_fire = io.s1_fire(0)
@ -144,25 +142,26 @@ class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
// s1: alloc_way and write
// s0
val u = io.update
val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
val u = io.update
val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
val u_s0_tag = getTag(u.bits.pc)
ways.foreach(_.io.update_req_tag := u_s0_tag)
val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt
val u_s0_hit = u_s0_hit_oh.orR
val u_s0_hit = u_s0_hit_oh.orR
val u_s0_br_update_valids =
VecInit((0 until numBr).map(w =>
u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) &&
!(PriorityEncoder(u.bits.br_taken_mask) < w.U)))
!(PriorityEncoder(u.bits.br_taken_mask) < w.U)
))
// s1
val u_s1_valid = RegNext(u.valid)
val u_s1_tag = RegEnable(u_s0_tag, u.valid)
val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u.valid)
val u_s1_hit = RegEnable(u_s0_hit, u.valid)
val u_s1_alloc_way = replacer.way
val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
val u_s1_valid = RegNext(u.valid)
val u_s1_tag = RegEnable(u_s0_tag, u.valid)
val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u.valid)
val u_s1_hit = RegEnable(u_s0_hit, u.valid)
val u_s1_alloc_way = replacer.way
val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid))
for (w <- 0 until numWays) {
ways(w).io.write_valid := u_s1_ways_write_valid(w)
@ -171,19 +170,22 @@ class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
}
// Illegal check for FTB entry writing
val uftb_write_pc = RegEnable(u.bits.pc, u.valid)
val uftb_write_pc = RegEnable(u.bits.pc, u.valid)
val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc)
when(u_s1_valid && u_s1_hit){
assert(uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough, s"FauFTB write entry fallThrough address error!")
when(u_s1_valid && u_s1_hit) {
assert(
uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough,
s"FauFTB write entry fallThrough address error!"
)
}
// update saturating counters
val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid)
val u_s1_br_takens = RegEnable(u.bits.br_taken_mask, u.valid)
val u_s1_br_takens = RegEnable(u.bits.br_taken_mask, u.valid)
for (w <- 0 until numWays) {
when (u_s1_ways_write_valid(w)) {
when(u_s1_ways_write_valid(w)) {
for (br <- 0 until numBr) {
when (u_s1_br_update_valids(br)) {
when(u_s1_br_update_valids(br)) {
ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br))
}
}
@ -197,21 +199,20 @@ class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
/******** update replacer *********/
replacer.access(replacer_touch_ways)
/********************** perf counters **********************/
val s0_fire_next_cycle = RegNext(io.s0_fire(0))
val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit)
val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit)
XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit)
XSPerfAccumulate("uftb_commit_hits", u.valid && u_meta.hit)
XSPerfAccumulate("uftb_commit_hits", u.valid && u_meta.hit)
XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit)
XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR)
for (w <- 0 until numWays) {
XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w))
XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w))
XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U)
}
if(u_meta.pred_way.isDefined) {
if (u_meta.pred_way.isDefined) {
val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way.get === w.U)
for (w <- 0 until numWays) {
XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w))
@ -219,9 +220,9 @@ class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
}
override val perfEvents = Seq(
("fauftb_commit_hit ", u.valid && u_meta.hit),
("fauftb_commit_miss ", u.valid && !u_meta.hit),
("fauftb_commit_hit ", u.valid && u_meta.hit),
("fauftb_commit_miss ", u.valid && !u_meta.hit)
)
generatePerfEvent()
}
}

View File

@ -15,25 +15,29 @@
***************************************************************************************/
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
import utils._
import freechips.rocketchip.diplomacy.LazyModule
import freechips.rocketchip.diplomacy.LazyModuleImp
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.backend.fu.{PFEvent, PMP, PMPChecker, PMPReqBundle}
import xiangshan.backend.fu.PFEvent
import xiangshan.backend.fu.PMP
import xiangshan.backend.fu.PMPChecker
import xiangshan.backend.fu.PMPReqBundle
import xiangshan.cache.mmu._
import xiangshan.frontend.icache._
class Frontend()(implicit p: Parameters) extends LazyModule with HasXSParameter {
override def shouldBeInlined: Boolean = false
val inner = LazyModule(new FrontendInlined)
val inner = LazyModule(new FrontendInlined)
lazy val module = new FrontendImp(this)
}
class FrontendImp(wrapper: Frontend)(implicit p: Parameters) extends LazyModuleImp(wrapper) {
val io = IO(wrapper.inner.module.io.cloneType)
val io = IO(wrapper.inner.module.io.cloneType)
val io_perf = IO(wrapper.inner.module.io_perf.cloneType)
io <> wrapper.inner.module.io
io_perf <> wrapper.inner.module.io_perf
@ -45,29 +49,28 @@ class FrontendImp(wrapper: Frontend)(implicit p: Parameters) extends LazyModuleI
class FrontendInlined()(implicit p: Parameters) extends LazyModule with HasXSParameter {
override def shouldBeInlined: Boolean = true
val instrUncache = LazyModule(new InstrUncache())
val icache = LazyModule(new ICache())
val instrUncache = LazyModule(new InstrUncache())
val icache = LazyModule(new ICache())
lazy val module = new FrontendInlinedImp(this)
}
class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
with HasXSParameter
with HasPerfEvents
{
class FrontendInlinedImp(outer: FrontendInlined) extends LazyModuleImp(outer)
with HasXSParameter
with HasPerfEvents {
val io = IO(new Bundle() {
val hartId = Input(UInt(hartIdLen.W))
val hartId = Input(UInt(hartIdLen.W))
val reset_vector = Input(UInt(PAddrBits.W))
val fencei = Input(Bool())
val ptw = new TlbPtwIO()
val backend = new FrontendToCtrlIO
val fencei = Input(Bool())
val ptw = new TlbPtwIO()
val backend = new FrontendToCtrlIO
val softPrefetch = Vec(backendParams.LduCnt, Flipped(Valid(new SoftIfetchPrefetchBundle)))
val sfence = Input(new SfenceBundle)
val tlbCsr = Input(new TlbCsrBundle)
val csrCtrl = Input(new CustomCSRCtrlIO)
val error = ValidIO(new L1CacheErrorInfo)
val sfence = Input(new SfenceBundle)
val tlbCsr = Input(new TlbCsrBundle)
val csrCtrl = Input(new CustomCSRCtrlIO)
val error = ValidIO(new L1CacheErrorInfo)
val frontendInfo = new Bundle {
val ibufFull = Output(Bool())
val ibufFull = Output(Bool())
val bpuInfo = new Bundle {
val bpRight = Output(UInt(XLEN.W))
val bpWrong = Output(UInt(XLEN.W))
@ -79,40 +82,40 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
}
})
//decouped-frontend modules
// decouped-frontend modules
val instrUncache = outer.instrUncache.module
val icache = outer.icache.module
val bpu = Module(new Predictor)
val ifu = Module(new NewIFU)
val ibuffer = Module(new IBuffer)
val ftq = Module(new Ftq)
val bpu = Module(new Predictor)
val ifu = Module(new NewIFU)
val ibuffer = Module(new IBuffer)
val ftq = Module(new Ftq)
val needFlush = RegNext(io.backend.toFtq.redirect.valid)
val needFlush = RegNext(io.backend.toFtq.redirect.valid)
val FlushControlRedirect = RegNext(io.backend.toFtq.redirect.bits.debugIsCtrl)
val FlushMemVioRedirect = RegNext(io.backend.toFtq.redirect.bits.debugIsMemVio)
val FlushControlBTBMiss = Wire(Bool())
val FlushTAGEMiss = Wire(Bool())
val FlushSCMiss = Wire(Bool())
val FlushITTAGEMiss = Wire(Bool())
val FlushRASMiss = Wire(Bool())
val FlushMemVioRedirect = RegNext(io.backend.toFtq.redirect.bits.debugIsMemVio)
val FlushControlBTBMiss = Wire(Bool())
val FlushTAGEMiss = Wire(Bool())
val FlushSCMiss = Wire(Bool())
val FlushITTAGEMiss = Wire(Bool())
val FlushRASMiss = Wire(Bool())
val tlbCsr = DelayN(io.tlbCsr, 2)
val tlbCsr = DelayN(io.tlbCsr, 2)
val csrCtrl = DelayN(io.csrCtrl, 2)
val sfence = RegNext(RegNext(io.sfence))
val sfence = RegNext(RegNext(io.sfence))
// trigger
ifu.io.frontendTrigger := csrCtrl.frontend_trigger
// bpu ctrl
bpu.io.ctrl := csrCtrl.bp_ctrl
bpu.io.ctrl := csrCtrl.bp_ctrl
bpu.io.reset_vector := io.reset_vector
// pmp
val PortNumber = ICacheParameters().PortNumber
val pmp = Module(new PMP())
val pmp_check = VecInit(Seq.fill(coreParams.ipmpPortNum)(Module(new PMPChecker(3, sameCycle = true)).io))
val pmp = Module(new PMP())
val pmp_check = VecInit(Seq.fill(coreParams.ipmpPortNum)(Module(new PMPChecker(3, sameCycle = true)).io))
pmp.io.distribute_csr := csrCtrl.distribute_csr
val pmp_req_vec = Wire(Vec(coreParams.ipmpPortNum, Valid(new PMPReqBundle())))
val pmp_req_vec = Wire(Vec(coreParams.ipmpPortNum, Valid(new PMPReqBundle())))
(0 until 2 * PortNumber).foreach(i => pmp_req_vec(i) <> icache.io.pmp(i).req)
pmp_req_vec.last <> ifu.io.pmp.req
@ -122,9 +125,9 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
(0 until 2 * PortNumber).foreach(i => icache.io.pmp(i).resp <> pmp_check(i).resp)
ifu.io.pmp.resp <> pmp_check.last.resp
val itlb = Module(new TLB(coreParams.itlbPortNum, nRespDups = 1,
Seq.fill(PortNumber)(false) ++ Seq(true), itlbParams))
itlb.io.requestor.take(PortNumber) zip icache.io.itlb foreach {case (a,b) => a <> b}
val itlb =
Module(new TLB(coreParams.itlbPortNum, nRespDups = 1, Seq.fill(PortNumber)(false) ++ Seq(true), itlbParams))
itlb.io.requestor.take(PortNumber) zip icache.io.itlb foreach { case (a, b) => a <> b }
itlb.io.requestor.last <> ifu.io.iTLBInter // mmio may need re-tlb, blocked
itlb.io.hartId := io.hartId
itlb.io.base_connect(sfence, tlbCsr)
@ -134,31 +137,32 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
val itlb_ptw = Wire(new VectorTlbPtwIO(coreParams.itlbPortNum))
itlb_ptw.connect(itlb.io.ptw)
val itlbRepeater1 = PTWFilter(itlbParams.fenceDelay, itlb_ptw, sfence, tlbCsr, l2tlbParams.ifilterSize)
val itlbRepeater2 = PTWRepeaterNB(passReady = false, itlbParams.fenceDelay, itlbRepeater1.io.ptw, io.ptw, sfence, tlbCsr)
val itlbRepeater2 =
PTWRepeaterNB(passReady = false, itlbParams.fenceDelay, itlbRepeater1.io.ptw, io.ptw, sfence, tlbCsr)
icache.io.ftqPrefetch <> ftq.io.toPrefetch
icache.io.softPrefetch <> io.softPrefetch
//IFU-Ftq
// IFU-Ftq
ifu.io.ftqInter.fromFtq <> ftq.io.toIfu
ftq.io.toIfu.req.ready := ifu.io.ftqInter.fromFtq.req.ready && icache.io.fetch.req.ready
ftq.io.toIfu.req.ready := ifu.io.ftqInter.fromFtq.req.ready && icache.io.fetch.req.ready
ftq.io.fromIfu <> ifu.io.ftqInter.toFtq
bpu.io.ftq_to_bpu <> ftq.io.toBpu
ftq.io.fromBpu <> bpu.io.bpu_to_ftq
ftq.io.fromIfu <> ifu.io.ftqInter.toFtq
bpu.io.ftq_to_bpu <> ftq.io.toBpu
ftq.io.fromBpu <> bpu.io.bpu_to_ftq
ftq.io.mmioCommitRead <> ifu.io.mmioCommitRead
//IFU-ICache
ftq.io.mmioCommitRead <> ifu.io.mmioCommitRead
// IFU-ICache
icache.io.fetch.req <> ftq.io.toICache.req
ftq.io.toICache.req.ready := ifu.io.ftqInter.fromFtq.req.ready && icache.io.fetch.req.ready
ftq.io.toICache.req.ready := ifu.io.ftqInter.fromFtq.req.ready && icache.io.fetch.req.ready
ifu.io.icacheInter.resp <> icache.io.fetch.resp
ifu.io.icacheInter.icacheReady := icache.io.toIFU
ifu.io.icacheInter.resp <> icache.io.fetch.resp
ifu.io.icacheInter.icacheReady := icache.io.toIFU
ifu.io.icacheInter.topdownIcacheMiss := icache.io.fetch.topdownIcacheMiss
ifu.io.icacheInter.topdownItlbMiss := icache.io.fetch.topdownItlbMiss
icache.io.stop := ifu.io.icacheStop
icache.io.flush := ftq.io.icacheFlush
ifu.io.icacheInter.topdownItlbMiss := icache.io.fetch.topdownItlbMiss
icache.io.stop := ifu.io.icacheStop
icache.io.flush := ftq.io.icacheFlush
ifu.io.icachePerfInfo := icache.io.perfInfo
@ -167,8 +171,8 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
icache.io.fencei := RegNext(io.fencei)
//IFU-Ibuffer
ifu.io.toIbuffer <> ibuffer.io.in
// IFU-Ibuffer
ifu.io.toIbuffer <> ibuffer.io.in
ftq.io.fromBackend <> io.backend.toFtq
io.backend.fromFtq := ftq.io.toBackend
@ -176,169 +180,185 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
io.frontendInfo.bpuInfo <> ftq.io.bpuInfo
val checkPcMem = Reg(Vec(FtqSize, new Ftq_RF_Components))
when (ftq.io.toBackend.pc_mem_wen) {
when(ftq.io.toBackend.pc_mem_wen) {
checkPcMem(ftq.io.toBackend.pc_mem_waddr) := ftq.io.toBackend.pc_mem_wdata
}
val checkTargetIdx = Wire(Vec(DecodeWidth, UInt(log2Up(FtqSize).W)))
val checkTarget = Wire(Vec(DecodeWidth, UInt(VAddrBits.W)))
val checkTarget = Wire(Vec(DecodeWidth, UInt(VAddrBits.W)))
for (i <- 0 until DecodeWidth) {
checkTargetIdx(i) := ibuffer.io.out(i).bits.ftqPtr.value
checkTarget(i) := Mux(ftq.io.toBackend.newest_entry_ptr.value === checkTargetIdx(i),
ftq.io.toBackend.newest_entry_target,
checkPcMem(checkTargetIdx(i) + 1.U).startAddr)
checkTarget(i) := Mux(
ftq.io.toBackend.newest_entry_ptr.value === checkTargetIdx(i),
ftq.io.toBackend.newest_entry_target,
checkPcMem(checkTargetIdx(i) + 1.U).startAddr
)
}
// commented out for this br could be the last instruction in the fetch block
def checkNotTakenConsecutive = {
val prevNotTakenValid = RegInit(0.B)
val prevNotTakenValid = RegInit(0.B)
val prevNotTakenFtqIdx = Reg(UInt(log2Up(FtqSize).W))
for (i <- 0 until DecodeWidth - 1) {
// for instrs that is not the last, if a not-taken br, the next instr should have the same ftqPtr
// for instrs that is the last, record and check next request
when (ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr) {
when (ibuffer.io.out(i+1).fire) {
when(ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr) {
when(ibuffer.io.out(i + 1).fire) {
// not last br, check now
XSError(checkTargetIdx(i) =/= checkTargetIdx(i+1), "not-taken br should have same ftqPtr\n")
} .otherwise {
XSError(checkTargetIdx(i) =/= checkTargetIdx(i + 1), "not-taken br should have same ftqPtr\n")
}.otherwise {
// last br, record its info
prevNotTakenValid := true.B
prevNotTakenValid := true.B
prevNotTakenFtqIdx := checkTargetIdx(i)
}
}
}
when (ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr) {
when(ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr) {
// last instr is a br, record its info
prevNotTakenValid := true.B
prevNotTakenValid := true.B
prevNotTakenFtqIdx := checkTargetIdx(DecodeWidth - 1)
}
when (prevNotTakenValid && ibuffer.io.out(0).fire) {
when(prevNotTakenValid && ibuffer.io.out(0).fire) {
XSError(prevNotTakenFtqIdx =/= checkTargetIdx(0), "not-taken br should have same ftqPtr\n")
prevNotTakenValid := false.B
}
when (needFlush) {
when(needFlush) {
prevNotTakenValid := false.B
}
}
def checkTakenNotConsecutive = {
val prevTakenValid = RegInit(0.B)
val prevTakenValid = RegInit(0.B)
val prevTakenFtqIdx = Reg(UInt(log2Up(FtqSize).W))
for (i <- 0 until DecodeWidth - 1) {
// for instrs that is not the last, if a taken br, the next instr should not have the same ftqPtr
// for instrs that is the last, record and check next request
when (ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr && ibuffer.io.out(i).bits.pred_taken) {
when (ibuffer.io.out(i+1).fire) {
when(ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr && ibuffer.io.out(i).bits.pred_taken) {
when(ibuffer.io.out(i + 1).fire) {
// not last br, check now
XSError(checkTargetIdx(i) + 1.U =/= checkTargetIdx(i+1), "taken br should have consecutive ftqPtr\n")
} .otherwise {
XSError(checkTargetIdx(i) + 1.U =/= checkTargetIdx(i + 1), "taken br should have consecutive ftqPtr\n")
}.otherwise {
// last br, record its info
prevTakenValid := true.B
prevTakenValid := true.B
prevTakenFtqIdx := checkTargetIdx(i)
}
}
}
when (ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr && ibuffer.io.out(DecodeWidth - 1).bits.pred_taken) {
when(ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr && ibuffer.io.out(
DecodeWidth - 1
).bits.pred_taken) {
// last instr is a br, record its info
prevTakenValid := true.B
prevTakenValid := true.B
prevTakenFtqIdx := checkTargetIdx(DecodeWidth - 1)
}
when (prevTakenValid && ibuffer.io.out(0).fire) {
when(prevTakenValid && ibuffer.io.out(0).fire) {
XSError(prevTakenFtqIdx + 1.U =/= checkTargetIdx(0), "taken br should have consecutive ftqPtr\n")
prevTakenValid := false.B
}
when (needFlush) {
when(needFlush) {
prevTakenValid := false.B
}
}
def checkNotTakenPC = {
val prevNotTakenPC = Reg(UInt(VAddrBits.W))
val prevIsRVC = Reg(Bool())
val prevNotTakenPC = Reg(UInt(VAddrBits.W))
val prevIsRVC = Reg(Bool())
val prevNotTakenValid = RegInit(0.B)
for (i <- 0 until DecodeWidth - 1) {
when (ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr && !ibuffer.io.out(i).bits.pred_taken) {
when (ibuffer.io.out(i+1).fire) {
XSError(ibuffer.io.out(i).bits.pc + Mux(ibuffer.io.out(i).bits.pd.isRVC, 2.U, 4.U) =/= ibuffer.io.out(i+1).bits.pc, "not-taken br should have consecutive pc\n")
} .otherwise {
when(ibuffer.io.out(i).fire && ibuffer.io.out(i).bits.pd.isBr && !ibuffer.io.out(i).bits.pred_taken) {
when(ibuffer.io.out(i + 1).fire) {
XSError(
ibuffer.io.out(i).bits.pc + Mux(ibuffer.io.out(i).bits.pd.isRVC, 2.U, 4.U) =/= ibuffer.io.out(
i + 1
).bits.pc,
"not-taken br should have consecutive pc\n"
)
}.otherwise {
prevNotTakenValid := true.B
prevIsRVC := ibuffer.io.out(i).bits.pd.isRVC
prevNotTakenPC := ibuffer.io.out(i).bits.pc
prevIsRVC := ibuffer.io.out(i).bits.pd.isRVC
prevNotTakenPC := ibuffer.io.out(i).bits.pc
}
}
}
when (ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr && !ibuffer.io.out(DecodeWidth - 1).bits.pred_taken) {
when(ibuffer.io.out(DecodeWidth - 1).fire && ibuffer.io.out(DecodeWidth - 1).bits.pd.isBr && !ibuffer.io.out(
DecodeWidth - 1
).bits.pred_taken) {
prevNotTakenValid := true.B
prevIsRVC := ibuffer.io.out(DecodeWidth - 1).bits.pd.isRVC
prevNotTakenPC := ibuffer.io.out(DecodeWidth - 1).bits.pc
prevIsRVC := ibuffer.io.out(DecodeWidth - 1).bits.pd.isRVC
prevNotTakenPC := ibuffer.io.out(DecodeWidth - 1).bits.pc
}
when (prevNotTakenValid && ibuffer.io.out(0).fire) {
XSError(prevNotTakenPC + Mux(prevIsRVC, 2.U, 4.U) =/= ibuffer.io.out(0).bits.pc, "not-taken br should have same pc\n")
when(prevNotTakenValid && ibuffer.io.out(0).fire) {
XSError(
prevNotTakenPC + Mux(prevIsRVC, 2.U, 4.U) =/= ibuffer.io.out(0).bits.pc,
"not-taken br should have same pc\n"
)
prevNotTakenValid := false.B
}
when (needFlush) {
when(needFlush) {
prevNotTakenValid := false.B
}
}
def checkTakenPC = {
val prevTakenFtqIdx = Reg(UInt(log2Up(FtqSize).W))
val prevTakenValid = RegInit(0.B)
val prevTakenValid = RegInit(0.B)
val prevTakenTarget = Wire(UInt(VAddrBits.W))
prevTakenTarget := checkPcMem(prevTakenFtqIdx + 1.U).startAddr
for (i <- 0 until DecodeWidth - 1) {
when (ibuffer.io.out(i).fire && !ibuffer.io.out(i).bits.pd.notCFI && ibuffer.io.out(i).bits.pred_taken) {
when (ibuffer.io.out(i+1).fire) {
XSError(checkTarget(i) =/= ibuffer.io.out(i+1).bits.pc, "taken instr should follow target pc\n")
} .otherwise {
prevTakenValid := true.B
when(ibuffer.io.out(i).fire && !ibuffer.io.out(i).bits.pd.notCFI && ibuffer.io.out(i).bits.pred_taken) {
when(ibuffer.io.out(i + 1).fire) {
XSError(checkTarget(i) =/= ibuffer.io.out(i + 1).bits.pc, "taken instr should follow target pc\n")
}.otherwise {
prevTakenValid := true.B
prevTakenFtqIdx := checkTargetIdx(i)
}
}
}
when (ibuffer.io.out(DecodeWidth - 1).fire && !ibuffer.io.out(DecodeWidth - 1).bits.pd.notCFI && ibuffer.io.out(DecodeWidth - 1).bits.pred_taken) {
prevTakenValid := true.B
when(ibuffer.io.out(DecodeWidth - 1).fire && !ibuffer.io.out(DecodeWidth - 1).bits.pd.notCFI && ibuffer.io.out(
DecodeWidth - 1
).bits.pred_taken) {
prevTakenValid := true.B
prevTakenFtqIdx := checkTargetIdx(DecodeWidth - 1)
}
when (prevTakenValid && ibuffer.io.out(0).fire) {
when(prevTakenValid && ibuffer.io.out(0).fire) {
XSError(prevTakenTarget =/= ibuffer.io.out(0).bits.pc, "taken instr should follow target pc\n")
prevTakenValid := false.B
}
when (needFlush) {
when(needFlush) {
prevTakenValid := false.B
}
}
//checkNotTakenConsecutive
// checkNotTakenConsecutive
checkTakenNotConsecutive
checkTakenPC
checkNotTakenPC
ifu.io.rob_commits <> io.backend.toFtq.rob_commits
ibuffer.io.flush := needFlush
ibuffer.io.ControlRedirect := FlushControlRedirect
ibuffer.io.MemVioRedirect := FlushMemVioRedirect
ibuffer.io.flush := needFlush
ibuffer.io.ControlRedirect := FlushControlRedirect
ibuffer.io.MemVioRedirect := FlushMemVioRedirect
ibuffer.io.ControlBTBMissBubble := FlushControlBTBMiss
ibuffer.io.TAGEMissBubble := FlushTAGEMiss
ibuffer.io.SCMissBubble := FlushSCMiss
ibuffer.io.ITTAGEMissBubble := FlushITTAGEMiss
ibuffer.io.RASMissBubble := FlushRASMiss
ibuffer.io.decodeCanAccept := io.backend.canAccept
ibuffer.io.TAGEMissBubble := FlushTAGEMiss
ibuffer.io.SCMissBubble := FlushSCMiss
ibuffer.io.ITTAGEMissBubble := FlushITTAGEMiss
ibuffer.io.RASMissBubble := FlushRASMiss
ibuffer.io.decodeCanAccept := io.backend.canAccept
FlushControlBTBMiss := ftq.io.ControlBTBMissBubble
FlushTAGEMiss := ftq.io.TAGEMissBubble
FlushSCMiss := ftq.io.SCMissBubble
FlushITTAGEMiss := ftq.io.ITTAGEMissBubble
FlushRASMiss := ftq.io.RASMissBubble
FlushTAGEMiss := ftq.io.TAGEMissBubble
FlushSCMiss := ftq.io.SCMissBubble
FlushITTAGEMiss := ftq.io.ITTAGEMissBubble
FlushRASMiss := ftq.io.RASMissBubble
io.backend.cfVec <> ibuffer.io.out
io.backend.stallReason <> ibuffer.io.stallReason
instrUncache.io.req <> ifu.io.uncacheInter.toUncache
instrUncache.io.req <> ifu.io.uncacheInter.toUncache
ifu.io.uncacheInter.fromUncache <> instrUncache.io.resp
instrUncache.io.flush := false.B
io.error <> RegNext(RegNext(icache.io.error))
@ -350,7 +370,7 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
val frontendBubble = Mux(io.backend.canAccept, DecodeWidth.U - PopCount(ibuffer.io.out.map(_.valid)), 0.U)
XSPerfAccumulate("FrontendBubble", frontendBubble)
io.frontendInfo.ibufFull := RegNext(ibuffer.io.full)
io.resetInFrontend := reset.asBool
io.resetInFrontend := reset.asBool
// PFEvent
val pfevent = Module(new PFEvent)
@ -369,7 +389,7 @@ class FrontendInlinedImp (outer: FrontendInlined) extends LazyModuleImp(outer)
}
}
val allPerfInc = allPerfEvents.map(_._2.asTypeOf(new PerfEvent))
val allPerfInc = allPerfEvents.map(_._2.asTypeOf(new PerfEvent))
override val perfEvents = HPerfMonitor(csrevents, allPerfInc).getPerfEvents
generatePerfEvent()
}

View File

@ -16,40 +16,39 @@
***************************************************************************************/
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.frontend.icache._
import utils._
import utility._
import xiangshan.cache.mmu.TlbResp
import xiangshan.backend.fu.PMPRespBundle
import scala.math._
import java.util.ResourceBundle.Control
import org.chipsalliance.cde.config.Parameters
import scala.math._
import utility._
import utils._
import xiangshan._
import xiangshan.backend.fu.PMPRespBundle
import xiangshan.cache.mmu.TlbResp
import xiangshan.frontend.icache._
class FrontendTopDownBundle(implicit p: Parameters) extends XSBundle {
val reasons = Vec(TopDownCounters.NumStallReasons.id, Bool())
val reasons = Vec(TopDownCounters.NumStallReasons.id, Bool())
val stallWidth = UInt(log2Ceil(PredictWidth).W)
}
class FetchRequestBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters {
//fast path: Timing critical
val startAddr = UInt(VAddrBits.W)
val nextlineStart = UInt(VAddrBits.W)
val nextStartAddr = UInt(VAddrBits.W)
//slow path
val ftqIdx = new FtqPtr
val ftqOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
// fast path: Timing critical
val startAddr = UInt(VAddrBits.W)
val nextlineStart = UInt(VAddrBits.W)
val nextStartAddr = UInt(VAddrBits.W)
// slow path
val ftqIdx = new FtqPtr
val ftqOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val topdown_info = new FrontendTopDownBundle
val topdown_info = new FrontendTopDownBundle
def crossCacheline = startAddr(blockOffBits - 1) === 1.U
def crossCacheline = startAddr(blockOffBits - 1) === 1.U
def fromFtqPcBundle(b: Ftq_RF_Components) = {
this.startAddr := b.startAddr
this.startAddr := b.startAddr
this.nextlineStart := b.nextLineAddr
// when (b.fallThruError) {
// val nextBlockHigherTemp = Mux(startAddr(log2Ceil(PredictWidth)+instOffsetBits), b.nextLineAddr, b.startAddr)
@ -63,87 +62,89 @@ class FetchRequestBundle(implicit p: Parameters) extends XSBundle with HasICache
// }
this
}
override def toPrintable: Printable = {
override def toPrintable: Printable =
p"[start] ${Hexadecimal(startAddr)} [next] ${Hexadecimal(nextlineStart)}" +
p"[tgt] ${Hexadecimal(nextStartAddr)} [ftqIdx] $ftqIdx [jmp] v:${ftqOffset.valid}" +
p" offset: ${ftqOffset.bits}\n"
}
}
class FtqICacheInfo(implicit p: Parameters)extends XSBundle with HasICacheParameters{
val startAddr = UInt(VAddrBits.W)
val nextlineStart = UInt(VAddrBits.W)
val ftqIdx = new FtqPtr
def crossCacheline = startAddr(blockOffBits - 1) === 1.U
class FtqICacheInfo(implicit p: Parameters) extends XSBundle with HasICacheParameters {
val startAddr = UInt(VAddrBits.W)
val nextlineStart = UInt(VAddrBits.W)
val ftqIdx = new FtqPtr
def crossCacheline = startAddr(blockOffBits - 1) === 1.U
def fromFtqPcBundle(b: Ftq_RF_Components) = {
this.startAddr := b.startAddr
this.startAddr := b.startAddr
this.nextlineStart := b.nextLineAddr
this
}
}
class IFUICacheIO(implicit p: Parameters)extends XSBundle with HasICacheParameters{
class IFUICacheIO(implicit p: Parameters) extends XSBundle with HasICacheParameters {
val icacheReady = Output(Bool())
val resp = Vec(PortNumber, ValidIO(new ICacheMainPipeResp))
val topdownIcacheMiss = Output(Bool())
val topdownItlbMiss = Output(Bool())
val topdownItlbMiss = Output(Bool())
}
class FtqToICacheRequestBundle(implicit p: Parameters)extends XSBundle with HasICacheParameters{
val pcMemRead = Vec(5, new FtqICacheInfo)
val readValid = Vec(5, Bool())
val backendIpf = Bool()
val backendIgpf = Bool()
val backendIaf = Bool()
class FtqToICacheRequestBundle(implicit p: Parameters) extends XSBundle with HasICacheParameters {
val pcMemRead = Vec(5, new FtqICacheInfo)
val readValid = Vec(5, Bool())
val backendIpf = Bool()
val backendIgpf = Bool()
val backendIaf = Bool()
}
class PredecodeWritebackBundle(implicit p:Parameters) extends XSBundle {
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pd = Vec(PredictWidth, new PreDecodeInfo) // TODO: redefine Predecode
val ftqIdx = new FtqPtr
val ftqOffset = UInt(log2Ceil(PredictWidth).W)
val misOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val cfiOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val target = UInt(VAddrBits.W)
val jalTarget = UInt(VAddrBits.W)
val instrRange = Vec(PredictWidth, Bool())
class PredecodeWritebackBundle(implicit p: Parameters) extends XSBundle {
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pd = Vec(PredictWidth, new PreDecodeInfo) // TODO: redefine Predecode
val ftqIdx = new FtqPtr
val ftqOffset = UInt(log2Ceil(PredictWidth).W)
val misOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val cfiOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val target = UInt(VAddrBits.W)
val jalTarget = UInt(VAddrBits.W)
val instrRange = Vec(PredictWidth, Bool())
}
class mmioCommitRead(implicit p: Parameters) extends XSBundle {
val mmioFtqPtr = Output(new FtqPtr)
val mmioFtqPtr = Output(new FtqPtr)
val mmioLastCommit = Input(Bool())
}
object ExceptionType {
def none : UInt = "b00".U
def pf : UInt = "b01".U // instruction page fault
def gpf : UInt = "b10".U // instruction guest page fault
def af : UInt = "b11".U // instruction access fault
def width : Int = 2
def none: UInt = "b00".U
def pf: UInt = "b01".U // instruction page fault
def gpf: UInt = "b10".U // instruction guest page fault
def af: UInt = "b11".U // instruction access fault
def width: Int = 2
def fromOH(has_pf: Bool, has_gpf: Bool, has_af: Bool): UInt = {
assert(
PopCount(VecInit(has_pf, has_gpf, has_af)) <= 1.U,
"ExceptionType.fromOH receives input that is not one-hot: pf=%d, gpf=%d, af=%d",
has_pf, has_gpf, has_af
has_pf,
has_gpf,
has_af
)
// input is at-most-one-hot encoded, so we don't worry about priority here.
MuxCase(none, Seq(
has_pf -> pf,
has_gpf -> gpf,
has_af -> af
))
MuxCase(
none,
Seq(
has_pf -> pf,
has_gpf -> gpf,
has_af -> af
)
)
}
// raise pf/gpf/af according to ftq(backend) request
def fromFtq(req: FtqToICacheRequestBundle): UInt = {
def fromFtq(req: FtqToICacheRequestBundle): UInt =
fromOH(
req.backendIpf,
req.backendIgpf,
req.backendIaf
)
}
// raise pf/gpf/af according to itlb response
def fromTlbResp(resp: TlbResp, useDup: Int = 0): UInt = {
@ -157,9 +158,8 @@ object ExceptionType {
}
// raise af if pmp check failed
def fromPMPResp(resp: PMPRespBundle): UInt = {
def fromPMPResp(resp: PMPRespBundle): UInt =
Mux(resp.instr, af, none)
}
// raise af if meta/data array ecc check failed or l2 cache respond with tilelink corrupt
/* FIXME: RISC-V Machine ISA v1.13 (draft) introduced a "hardware error" exception, described as:
@ -175,9 +175,8 @@ object ExceptionType {
* Maybe it's better to raise hardware error instead of access fault when ECC check failed.
* But it's draft and XiangShan backend does not implement this exception code yet, so we still raise af here.
*/
def fromECC(enable: Bool, corrupt: Bool): UInt = {
def fromECC(enable: Bool, corrupt: Bool): UInt =
Mux(enable && corrupt, af, none)
}
/**Generates exception mux tree
*
@ -238,27 +237,25 @@ object ExceptionType {
// merge port-by-port
val length = exceptionVecs.head.length
exceptionVecs.tail.foreach(vec => require(vec.length == length))
VecInit((0 until length).map{ i =>
merge(exceptionVecs.map(_(i)): _*)
})
VecInit((0 until length).map(i => merge(exceptionVecs.map(_(i)): _*)))
}
}
class FetchToIBuffer(implicit p: Parameters) extends XSBundle {
val instrs = Vec(PredictWidth, UInt(32.W))
val valid = UInt(PredictWidth.W)
val enqEnable = UInt(PredictWidth.W)
val pd = Vec(PredictWidth, new PreDecodeInfo)
val foldpc = Vec(PredictWidth, UInt(MemPredPCWidth.W))
val ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
val instrs = Vec(PredictWidth, UInt(32.W))
val valid = UInt(PredictWidth.W)
val enqEnable = UInt(PredictWidth.W)
val pd = Vec(PredictWidth, new PreDecodeInfo)
val foldpc = Vec(PredictWidth, UInt(MemPredPCWidth.W))
val ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)))
val exceptionFromBackend = Vec(PredictWidth, Bool())
val exceptionType = Vec(PredictWidth, UInt(ExceptionType.width.W))
val crossPageIPFFix = Vec(PredictWidth, Bool())
val illegalInstr = Vec(PredictWidth, Bool())
val triggered = Vec(PredictWidth, TriggerAction())
val isLastInFtqEntry = Vec(PredictWidth, Bool())
val exceptionType = Vec(PredictWidth, UInt(ExceptionType.width.W))
val crossPageIPFFix = Vec(PredictWidth, Bool())
val illegalInstr = Vec(PredictWidth, Bool())
val triggered = Vec(PredictWidth, TriggerAction())
val isLastInFtqEntry = Vec(PredictWidth, Bool())
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val ftqPtr = new FtqPtr
val topdown_info = new FrontendTopDownBundle
}
@ -287,78 +284,68 @@ class ShiftingGlobalHistory(implicit p: Parameters) extends GlobalHistory {
require(real_taken_mask.length == numBr)
val last_valid_idx = PriorityMux(
br_valids.reverse :+ true.B,
(numBr to 0 by -1).map(_.U(log2Ceil(numBr+1).W))
(numBr to 0 by -1).map(_.U(log2Ceil(numBr + 1).W))
)
val first_taken_idx = PriorityEncoder(false.B +: real_taken_mask)
val smaller = Mux(last_valid_idx < first_taken_idx,
last_valid_idx,
first_taken_idx
)
val shift = smaller
val taken = real_taken_mask.reduce(_||_)
val smaller = Mux(last_valid_idx < first_taken_idx, last_valid_idx, first_taken_idx)
val shift = smaller
val taken = real_taken_mask.reduce(_ || _)
update(shift, taken, this.predHist)
}
// static read
def read(n: Int): Bool = predHist.asBools(n)
final def === (that: ShiftingGlobalHistory): Bool = {
final def ===(that: ShiftingGlobalHistory): Bool =
predHist === that.predHist
}
final def =/= (that: ShiftingGlobalHistory): Bool = !(this === that)
final def =/=(that: ShiftingGlobalHistory): Bool = !(this === that)
}
// circular global history pointer
class CGHPtr(implicit p: Parameters) extends CircularQueuePtr[CGHPtr](
p => p(XSCoreParamsKey).HistoryLength
){
}
class CGHPtr(implicit p: Parameters) extends CircularQueuePtr[CGHPtr](p => p(XSCoreParamsKey).HistoryLength) {}
object CGHPtr {
def apply(f: Bool, v: UInt)(implicit p: Parameters): CGHPtr = {
val ptr = Wire(new CGHPtr)
ptr.flag := f
ptr.flag := f
ptr.value := v
ptr
}
def inverse(ptr: CGHPtr)(implicit p: Parameters): CGHPtr = {
def inverse(ptr: CGHPtr)(implicit p: Parameters): CGHPtr =
apply(!ptr.flag, ptr.value)
}
}
class CircularGlobalHistory(implicit p: Parameters) extends GlobalHistory {
val buffer = Vec(HistoryLength, Bool())
type HistPtr = UInt
def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): CircularGlobalHistory = {
def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): CircularGlobalHistory =
this
}
}
class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(implicit p: Parameters)
extends XSBundle with HasBPUConst {
extends XSBundle with HasBPUConst {
require(compLen >= 1)
require(len > 0)
// require(folded_len <= len)
require(compLen >= max_update_num)
val folded_hist = UInt(compLen.W)
def need_oldest_bits = len > compLen
def info = (len, compLen)
def need_oldest_bits = len > compLen
def info = (len, compLen)
def oldest_bit_to_get_from_ghr = (0 until max_update_num).map(len - _ - 1)
def oldest_bit_pos_in_folded = oldest_bit_to_get_from_ghr map (_ % compLen)
def oldest_bit_wrap_around = oldest_bit_to_get_from_ghr map (_ / compLen > 0)
def oldest_bit_start = oldest_bit_pos_in_folded.head
def oldest_bit_pos_in_folded = oldest_bit_to_get_from_ghr map (_ % compLen)
def oldest_bit_wrap_around = oldest_bit_to_get_from_ghr map (_ / compLen > 0)
def oldest_bit_start = oldest_bit_pos_in_folded.head
def get_oldest_bits_from_ghr(ghr: Vec[Bool], histPtr: CGHPtr) = {
def get_oldest_bits_from_ghr(ghr: Vec[Bool], histPtr: CGHPtr) =
// TODO: wrap inc for histPtr value
oldest_bit_to_get_from_ghr.map(i => ghr((histPtr + (i+1).U).value))
}
oldest_bit_to_get_from_ghr.map(i => ghr((histPtr + (i + 1).U).value))
def circular_shift_left(src: UInt, shamt: Int) = {
val srcLen = src.getWidth
val srcLen = src.getWidth
val src_doubled = Cat(src, src)
val shifted = src_doubled(srcLen*2-1-shamt, srcLen-shamt)
val shifted = src_doubled(srcLen * 2 - 1 - shamt, srcLen - shamt)
shifted
}
@ -368,7 +355,6 @@ class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(imp
update(oldest_bits, num, taken)
}
// fast path, use pre-read oldest bits
def update(ob: Vec[Bool], num: Int, taken: Bool): FoldedHistory = {
// do xors for several bitsets at specified bits
@ -389,7 +375,7 @@ class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(imp
if (resArr(i).length == 0) {
println(f"[error] bits $i is not assigned in folded hist update logic! histlen:${this.len}, compLen:$compLen")
}
res(i) := resArr(i).foldLeft(false.B)(_^_)
res(i) := resArr(i).foldLeft(false.B)(_ ^ _)
}
res.asUInt
}
@ -398,23 +384,25 @@ class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(imp
val oldest_bits = ob
require(oldest_bits.length == max_update_num)
// mask off bits that do not update
val oldest_bits_masked = oldest_bits.zipWithIndex.map{
val oldest_bits_masked = oldest_bits.zipWithIndex.map {
case (ob, i) => ob && (i < num).B
}
// if a bit does not wrap around, it should not be xored when it exits
val oldest_bits_set = (0 until max_update_num).filter(oldest_bit_wrap_around).map(i => (oldest_bit_pos_in_folded(i), oldest_bits_masked(i)))
val oldest_bits_set = (0 until max_update_num).filter(oldest_bit_wrap_around).map(i =>
(oldest_bit_pos_in_folded(i), oldest_bits_masked(i))
)
// println(f"old bits pos ${oldest_bits_set.map(_._1)}")
// only the last bit could be 1, as we have at most one taken branch at a time
val newest_bits_masked = VecInit((0 until max_update_num).map(i => taken && ((i+1) == num).B)).asUInt
val newest_bits_masked = VecInit((0 until max_update_num).map(i => taken && ((i + 1) == num).B)).asUInt
// if a bit does not wrap around, newest bits should not be xored onto it either
val newest_bits_set = (0 until max_update_num).map(i => (compLen-1-i, newest_bits_masked(i)))
val newest_bits_set = (0 until max_update_num).map(i => (compLen - 1 - i, newest_bits_masked(i)))
// println(f"new bits set ${newest_bits_set.map(_._1)}")
//
val original_bits_masked = VecInit(folded_hist.asBools.zipWithIndex.map{
case (fb, i) => fb && !(num >= (len-i)).B
val original_bits_masked = VecInit(folded_hist.asBools.zipWithIndex.map {
case (fb, i) => fb && !(num >= (len - i)).B
})
val original_bits_set = (0 until compLen).map(i => (i, original_bits_masked(i)))
@ -423,7 +411,7 @@ class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(imp
circular_shift_left(xored, num)
} else {
// histLen too short to wrap around
((folded_hist << num) | taken)(compLen-1,0)
((folded_hist << num) | taken)(compLen - 1, 0)
}
val fh = WireInit(this)
@ -433,19 +421,20 @@ class FoldedHistory(val len: Int, val compLen: Int, val max_update_num: Int)(imp
}
class AheadFoldedHistoryOldestBits(val len: Int, val max_update_num: Int)(implicit p: Parameters) extends XSBundle {
val bits = Vec(max_update_num*2, Bool())
val bits = Vec(max_update_num * 2, Bool())
// def info = (len, compLen)
def getRealOb(brNumOH: UInt): Vec[Bool] = {
val ob = Wire(Vec(max_update_num, Bool()))
for (i <- 0 until max_update_num) {
ob(i) := Mux1H(brNumOH, bits.drop(i).take(numBr+1))
ob(i) := Mux1H(brNumOH, bits.drop(i).take(numBr + 1))
}
ob
}
}
class AllAheadFoldedHistoryOldestBits(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters) extends XSBundle with HasBPUConst {
val afhob = MixedVec(gen.filter(t => t._1 > t._2).map{_._1}
class AllAheadFoldedHistoryOldestBits(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters) extends XSBundle
with HasBPUConst {
val afhob = MixedVec(gen.filter(t => t._1 > t._2).map(_._1)
.toSet.toList.map(l => new AheadFoldedHistoryOldestBits(l, numBr))) // remove duplicates
require(gen.toSet.toList.equals(gen))
def getObWithInfo(info: Tuple2[Int, Int]) = {
@ -454,12 +443,12 @@ class AllAheadFoldedHistoryOldestBits(val gen: Seq[Tuple2[Int, Int]])(implicit p
selected(0)
}
def read(ghv: Vec[Bool], ptr: CGHPtr) = {
val hisLens = afhob.map(_.len)
val bitsToRead = hisLens.flatMap(l => (0 until numBr*2).map(i => l-i-1)).toSet // remove duplicates
val bitsWithInfo = bitsToRead.map(pos => (pos, ghv((ptr+(pos+1).U).value)))
val hisLens = afhob.map(_.len)
val bitsToRead = hisLens.flatMap(l => (0 until numBr * 2).map(i => l - i - 1)).toSet // remove duplicates
val bitsWithInfo = bitsToRead.map(pos => (pos, ghv((ptr + (pos + 1).U).value)))
for (ob <- afhob) {
for (i <- 0 until numBr*2) {
val pos = ob.len - i - 1
for (i <- 0 until numBr * 2) {
val pos = ob.len - i - 1
val bit_found = bitsWithInfo.filter(_._1 == pos).toList
require(bit_found.length == 1)
ob.bits(i) := bit_found(0)._2
@ -469,7 +458,7 @@ class AllAheadFoldedHistoryOldestBits(val gen: Seq[Tuple2[Int, Int]])(implicit p
}
class AllFoldedHistories(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters) extends XSBundle with HasBPUConst {
val hist = MixedVec(gen.map{case (l, cl) => new FoldedHistory(l, cl, numBr)})
val hist = MixedVec(gen.map { case (l, cl) => new FoldedHistory(l, cl, numBr) })
// println(gen.mkString)
require(gen.toSet.toList.equals(gen))
def getHistWithInfo(info: Tuple2[Int, Int]) = {
@ -495,47 +484,46 @@ class AllFoldedHistories(val gen: Seq[Tuple2[Int, Int]])(implicit p: Parameters)
for (i <- 0 until this.hist.length) {
val fh = this.hist(i)
if (fh.need_oldest_bits) {
val info = fh.info
val info = fh.info
val selectedAfhob = afhob.getObWithInfo(info)
val ob = selectedAfhob.getRealOb(lastBrNumOH)
val ob = selectedAfhob.getRealOb(lastBrNumOH)
res.hist(i) := this.hist(i).update(ob, shift, taken)
} else {
val dumb = Wire(Vec(numBr, Bool())) // not needed
dumb := DontCare
dumb := DontCare
res.hist(i) := this.hist(i).update(dumb, shift, taken)
}
}
res
}
def display(cond: Bool) = {
def display(cond: Bool) =
for (h <- hist) {
XSDebug(cond, p"hist len ${h.len}, folded len ${h.compLen}, value ${Binary(h.folded_hist)}\n")
}
}
}
class TableAddr(val idxBits: Int, val banks: Int)(implicit p: Parameters) extends XSBundle{
class TableAddr(val idxBits: Int, val banks: Int)(implicit p: Parameters) extends XSBundle {
def tagBits = VAddrBits - idxBits - instOffsetBits
val tag = UInt(tagBits.W)
val idx = UInt(idxBits.W)
val tag = UInt(tagBits.W)
val idx = UInt(idxBits.W)
val offset = UInt(instOffsetBits.W)
def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
def getTag(x: UInt) = fromUInt(x).tag
def getIdx(x: UInt) = fromUInt(x).idx
def getBank(x: UInt) = if (banks > 1) getIdx(x)(log2Up(banks) - 1, 0) else 0.U
def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
def getTag(x: UInt) = fromUInt(x).tag
def getIdx(x: UInt) = fromUInt(x).idx
def getBank(x: UInt) = if (banks > 1) getIdx(x)(log2Up(banks) - 1, 0) else 0.U
def getBankIdx(x: UInt) = if (banks > 1) getIdx(x)(idxBits - 1, log2Up(banks)) else getIdx(x)
}
trait BasicPrediction extends HasXSParameter {
def cfiIndex: ValidUndirectioned[UInt]
def target(pc: UInt): UInt
def lastBrPosOH: Vec[Bool]
def brTaken: Bool
def lastBrPosOH: Vec[Bool]
def brTaken: Bool
def shouldShiftVec: Vec[Bool]
def fallThruError: Bool
def fallThruError: Bool
}
// selectByTaken selects some data according to takenMask
@ -543,105 +531,104 @@ trait BasicPrediction extends HasXSParameter {
object selectByTaken {
def apply[T <: Data](takenMask: Vec[Bool], hit: Bool, allTargets: Vec[T]): T = {
val selVecOH =
takenMask.zipWithIndex.map { case (t, i) => !takenMask.take(i).fold(false.B)(_ || _) && t && hit } :+
takenMask.zipWithIndex.map { case (t, i) =>
!takenMask.take(i).fold(false.B)(_ || _) && t && hit
} :+
(!takenMask.asUInt.orR && hit) :+ !hit
Mux1H(selVecOH, allTargets)
}
}
class FullBranchPrediction(val isNotS3: Boolean)(implicit p: Parameters) extends XSBundle with HasBPUConst with BasicPrediction {
class FullBranchPrediction(val isNotS3: Boolean)(implicit p: Parameters) extends XSBundle with HasBPUConst
with BasicPrediction {
val br_taken_mask = Vec(numBr, Bool())
val slot_valids = Vec(totalSlot, Bool())
val targets = Vec(totalSlot, UInt(VAddrBits.W))
val jalr_target = UInt(VAddrBits.W) // special path for indirect predictors
val offsets = Vec(totalSlot, UInt(log2Ceil(PredictWidth).W))
val targets = Vec(totalSlot, UInt(VAddrBits.W))
val jalr_target = UInt(VAddrBits.W) // special path for indirect predictors
val offsets = Vec(totalSlot, UInt(log2Ceil(PredictWidth).W))
val fallThroughAddr = UInt(VAddrBits.W)
val fallThroughErr = Bool()
val multiHit = Bool()
val fallThroughErr = Bool()
val multiHit = Bool()
val is_jal = Bool()
val is_jalr = Bool()
val is_call = Bool()
val is_ret = Bool()
val is_jal = Bool()
val is_jalr = Bool()
val is_call = Bool()
val is_ret = Bool()
val last_may_be_rvi_call = Bool()
val is_br_sharing = Bool()
val is_br_sharing = Bool()
// val call_is_rvc = Bool()
val hit = Bool()
val predCycle = if (!env.FPGAPlatform) Some(UInt(64.W)) else None
def br_slot_valids = slot_valids.init
def br_slot_valids = slot_valids.init
def tail_slot_valid = slot_valids.last
def br_valids = {
def br_valids =
VecInit(br_slot_valids :+ (tail_slot_valid && is_br_sharing))
}
def taken_mask_on_slot = {
def taken_mask_on_slot =
VecInit(
(br_slot_valids zip br_taken_mask.init).map{ case (t, v) => t && v } :+ (
(br_slot_valids zip br_taken_mask.init).map { case (t, v) => t && v } :+ (
tail_slot_valid && (
is_br_sharing && br_taken_mask.last || !is_br_sharing
)
)
)
}
def real_slot_taken_mask(): Vec[Bool] = {
def real_slot_taken_mask(): Vec[Bool] =
VecInit(taken_mask_on_slot.map(_ && hit))
}
// len numBr
def real_br_taken_mask(): Vec[Bool] = {
def real_br_taken_mask(): Vec[Bool] =
VecInit(
taken_mask_on_slot.map(_ && hit).init :+
(br_taken_mask.last && tail_slot_valid && is_br_sharing && hit)
(br_taken_mask.last && tail_slot_valid && is_br_sharing && hit)
)
}
// the vec indicating if ghr should shift on each branch
def shouldShiftVec =
VecInit(br_valids.zipWithIndex.map{ case (v, i) =>
v && hit && !real_br_taken_mask().take(i).reduceOption(_||_).getOrElse(false.B)})
VecInit(br_valids.zipWithIndex.map { case (v, i) =>
v && hit && !real_br_taken_mask().take(i).reduceOption(_ || _).getOrElse(false.B)
})
def lastBrPosOH =
VecInit((!hit || !br_valids.reduce(_||_)) +: // not hit or no brs in entry
VecInit((!hit || !br_valids.reduce(_ || _)) +: // not hit or no brs in entry
(0 until numBr).map(i =>
br_valids(i) &&
!real_br_taken_mask().take(i).reduceOption(_||_).getOrElse(false.B) && // no brs taken in front it
(real_br_taken_mask()(i) || !br_valids.drop(i+1).reduceOption(_||_).getOrElse(false.B)) && // no brs behind it
hit
)
)
!real_br_taken_mask().take(i).reduceOption(_ || _).getOrElse(false.B) && // no brs taken in front it
(real_br_taken_mask()(i) || !br_valids.drop(i + 1).reduceOption(_ || _).getOrElse(
false.B
)) && // no brs behind it
hit
))
def brTaken = (br_valids zip br_taken_mask).map{ case (a, b) => a && b && hit}.reduce(_||_)
def brTaken = (br_valids zip br_taken_mask).map { case (a, b) => a && b && hit }.reduce(_ || _)
def target(pc: UInt): UInt = {
if (isNotS3){
def target(pc: UInt): UInt =
if (isNotS3) {
selectByTaken(taken_mask_on_slot, hit, allTarget(pc))
}else {
} else {
selectByTaken(taken_mask_on_slot, hit && !fallThroughErr, allTarget(pc))
}
}
// allTarget return a Vec of all possible target of a BP stage
// in the following order: [taken_target0, taken_target1, ..., fallThroughAddr, not hit (plus fetch width)]
//
// This exposes internal targets for timing optimization,
// since usually targets are generated quicker than taken
def allTarget(pc: UInt): Vec[UInt] = {
def allTarget(pc: UInt): Vec[UInt] =
VecInit(targets :+ fallThroughAddr :+ (pc + (FetchWidth * 4).U))
}
def fallThruError: Bool = hit && fallThroughErr
def ftbMultiHit: Bool = hit && multiHit
def ftbMultiHit: Bool = hit && multiHit
def hit_taken_on_jmp =
!real_slot_taken_mask().init.reduce(_||_) &&
real_slot_taken_mask().last && !is_br_sharing
!real_slot_taken_mask().init.reduce(_ || _) &&
real_slot_taken_mask().last && !is_br_sharing
def hit_taken_on_call = hit_taken_on_jmp && is_call
def hit_taken_on_ret = hit_taken_on_jmp && is_ret
def hit_taken_on_jalr = hit_taken_on_jmp && is_jalr
@ -652,75 +639,73 @@ class FullBranchPrediction(val isNotS3: Boolean)(implicit p: Parameters) extends
// when no takens, set cfiIndex to PredictWidth-1
cfiIndex.bits :=
ParallelPriorityMux(real_slot_taken_mask(), offsets) |
Fill(log2Ceil(PredictWidth), (!real_slot_taken_mask().asUInt.orR).asUInt)
Fill(log2Ceil(PredictWidth), (!real_slot_taken_mask().asUInt.orR).asUInt)
cfiIndex
}
def taken = br_taken_mask.reduce(_||_) || slot_valids.last // || (is_jal || is_jalr)
def taken = br_taken_mask.reduce(_ || _) || slot_valids.last // || (is_jal || is_jalr)
def fromFtbEntry(
entry: FTBEntry,
pc: UInt,
last_stage_pc: Option[Tuple2[UInt, Bool]] = None,
last_stage_entry: Option[Tuple2[FTBEntry, Bool]] = None
) = {
slot_valids := entry.brSlots.map(_.valid) :+ entry.tailSlot.valid
targets := entry.getTargetVec(pc, last_stage_pc) // Use previous stage pc for better timing
jalr_target := targets.last
offsets := entry.getOffsetVec
is_jal := entry.tailSlot.valid && entry.isJal
is_jalr := entry.tailSlot.valid && entry.isJalr
is_call := entry.tailSlot.valid && entry.isCall
is_ret := entry.tailSlot.valid && entry.isRet
entry: FTBEntry,
pc: UInt,
last_stage_pc: Option[Tuple2[UInt, Bool]] = None,
last_stage_entry: Option[Tuple2[FTBEntry, Bool]] = None
) = {
slot_valids := entry.brSlots.map(_.valid) :+ entry.tailSlot.valid
targets := entry.getTargetVec(pc, last_stage_pc) // Use previous stage pc for better timing
jalr_target := targets.last
offsets := entry.getOffsetVec
is_jal := entry.tailSlot.valid && entry.isJal
is_jalr := entry.tailSlot.valid && entry.isJalr
is_call := entry.tailSlot.valid && entry.isCall
is_ret := entry.tailSlot.valid && entry.isRet
last_may_be_rvi_call := entry.last_may_be_rvi_call
is_br_sharing := entry.tailSlot.valid && entry.tailSlot.sharing
is_br_sharing := entry.tailSlot.valid && entry.tailSlot.sharing
predCycle.map(_ := GTimer())
val startLower = Cat(0.U(1.W), pc(instOffsetBits+log2Ceil(PredictWidth)-1, instOffsetBits))
val startLower = Cat(0.U(1.W), pc(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits))
val endLowerwithCarry = Cat(entry.carry, entry.pftAddr)
fallThroughErr := startLower >= endLowerwithCarry || endLowerwithCarry > (startLower + (PredictWidth).U)
fallThroughErr := startLower >= endLowerwithCarry || endLowerwithCarry > (startLower + PredictWidth.U)
fallThroughAddr := Mux(fallThroughErr, pc + (FetchWidth * 4).U, entry.getFallThrough(pc, last_stage_entry))
}
def display(cond: Bool): Unit = {
def display(cond: Bool): Unit =
XSDebug(cond, p"[taken_mask] ${Binary(br_taken_mask.asUInt)} [hit] $hit\n")
}
}
class SpeculativeInfo(implicit p: Parameters) extends XSBundle
with HasBPUConst with BPUUtils {
with HasBPUConst with BPUUtils {
val histPtr = new CGHPtr
val ssp = UInt(log2Up(RasSize).W)
val sctr = UInt(RasCtrSize.W)
val TOSW = new RASPtr
val TOSR = new RASPtr
val NOS = new RASPtr
val ssp = UInt(log2Up(RasSize).W)
val sctr = UInt(RasCtrSize.W)
val TOSW = new RASPtr
val TOSR = new RASPtr
val NOS = new RASPtr
val topAddr = UInt(VAddrBits.W)
}
//
//
class BranchPredictionBundle(val isNotS3: Boolean)(implicit p: Parameters) extends XSBundle
with HasBPUConst with BPUUtils {
val pc = Vec(numDup, UInt(VAddrBits.W))
val valid = Vec(numDup, Bool())
val hasRedirect = Vec(numDup, Bool())
val ftq_idx = new FtqPtr
val full_pred = Vec(numDup, new FullBranchPrediction(isNotS3))
with HasBPUConst with BPUUtils {
val pc = Vec(numDup, UInt(VAddrBits.W))
val valid = Vec(numDup, Bool())
val hasRedirect = Vec(numDup, Bool())
val ftq_idx = new FtqPtr
val full_pred = Vec(numDup, new FullBranchPrediction(isNotS3))
def target(pc: UInt) = VecInit(full_pred.map(_.target(pc)))
def targets(pc: Vec[UInt]) = VecInit(pc.zipWithIndex.map{case (pc, idx) => full_pred(idx).target(pc)})
def allTargets(pc: Vec[UInt]) = VecInit(pc.zipWithIndex.map{case (pc, idx) => full_pred(idx).allTarget(pc)})
def cfiIndex = VecInit(full_pred.map(_.cfiIndex))
def lastBrPosOH = VecInit(full_pred.map(_.lastBrPosOH))
def brTaken = VecInit(full_pred.map(_.brTaken))
def shouldShiftVec = VecInit(full_pred.map(_.shouldShiftVec))
def fallThruError = VecInit(full_pred.map(_.fallThruError))
def ftbMultiHit = VecInit(full_pred.map(_.ftbMultiHit))
def target(pc: UInt) = VecInit(full_pred.map(_.target(pc)))
def targets(pc: Vec[UInt]) = VecInit(pc.zipWithIndex.map { case (pc, idx) => full_pred(idx).target(pc) })
def allTargets(pc: Vec[UInt]) = VecInit(pc.zipWithIndex.map { case (pc, idx) => full_pred(idx).allTarget(pc) })
def cfiIndex = VecInit(full_pred.map(_.cfiIndex))
def lastBrPosOH = VecInit(full_pred.map(_.lastBrPosOH))
def brTaken = VecInit(full_pred.map(_.brTaken))
def shouldShiftVec = VecInit(full_pred.map(_.shouldShiftVec))
def fallThruError = VecInit(full_pred.map(_.fallThruError))
def ftbMultiHit = VecInit(full_pred.map(_.ftbMultiHit))
def taken = VecInit(cfiIndex.map(_.valid))
def getTarget = targets(pc)
def getTarget = targets(pc)
def getAllTargets = allTargets(pc)
def display(cond: Bool): Unit = {
@ -734,30 +719,30 @@ class BranchPredictionResp(implicit p: Parameters) extends XSBundle with HasBPUC
val s2 = new BranchPredictionBundle(isNotS3 = true)
val s3 = new BranchPredictionBundle(isNotS3 = false)
val s1_uftbHit = Bool()
val s1_uftbHit = Bool()
val s1_uftbHasIndirect = Bool()
val s1_ftbCloseReq = Bool()
val s1_ftbCloseReq = Bool()
val last_stage_meta = UInt(MaxMetaLength.W)
val last_stage_meta = UInt(MaxMetaLength.W)
val last_stage_spec_info = new Ftq_Redirect_SRAMEntry
val last_stage_ftb_entry = new FTBEntry
val topdown_info = new FrontendTopDownBundle
def selectedResp ={
def selectedResp = {
val res =
PriorityMux(Seq(
((s3.valid(3) && s3.hasRedirect(3)) -> s3),
((s2.valid(3) && s2.hasRedirect(3)) -> s2),
(s1.valid(3) -> s1)
(s3.valid(3) && s3.hasRedirect(3)) -> s3,
(s2.valid(3) && s2.hasRedirect(3)) -> s2,
s1.valid(3) -> s1
))
res
}
def selectedRespIdxForFtq =
PriorityMux(Seq(
((s3.valid(3) && s3.hasRedirect(3)) -> BP_S3),
((s2.valid(3) && s2.hasRedirect(3)) -> BP_S2),
(s1.valid(3) -> BP_S1)
(s3.valid(3) && s3.hasRedirect(3)) -> BP_S3,
(s2.valid(3) && s2.hasRedirect(3)) -> BP_S2,
s1.valid(3) -> BP_S1
))
def lastStage = s3
}
@ -765,31 +750,31 @@ class BranchPredictionResp(implicit p: Parameters) extends XSBundle with HasBPUC
class BpuToFtqBundle(implicit p: Parameters) extends BranchPredictionResp {}
class BranchPredictionUpdate(implicit p: Parameters) extends XSBundle with HasBPUConst {
val pc = UInt(VAddrBits.W)
val pc = UInt(VAddrBits.W)
val spec_info = new SpeculativeInfo
val ftb_entry = new FTBEntry()
val cfi_idx = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val br_taken_mask = Vec(numBr, Bool())
val br_committed = Vec(numBr, Bool()) // High only when br valid && br committed
val jmp_taken = Bool()
val mispred_mask = Vec(numBr+1, Bool())
val pred_hit = Bool()
val false_hit = Bool()
val cfi_idx = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
val br_taken_mask = Vec(numBr, Bool())
val br_committed = Vec(numBr, Bool()) // High only when br valid && br committed
val jmp_taken = Bool()
val mispred_mask = Vec(numBr + 1, Bool())
val pred_hit = Bool()
val false_hit = Bool()
val new_br_insert_pos = Vec(numBr, Bool())
val old_entry = Bool()
val meta = UInt(MaxMetaLength.W)
val full_target = UInt(VAddrBits.W)
val from_stage = UInt(2.W)
val ghist = UInt(HistoryLength.W)
val old_entry = Bool()
val meta = UInt(MaxMetaLength.W)
val full_target = UInt(VAddrBits.W)
val from_stage = UInt(2.W)
val ghist = UInt(HistoryLength.W)
def is_jal = ftb_entry.tailSlot.valid && ftb_entry.isJal
def is_jal = ftb_entry.tailSlot.valid && ftb_entry.isJal
def is_jalr = ftb_entry.tailSlot.valid && ftb_entry.isJalr
def is_call = ftb_entry.tailSlot.valid && ftb_entry.isCall
def is_ret = ftb_entry.tailSlot.valid && ftb_entry.isRet
def is_ret = ftb_entry.tailSlot.valid && ftb_entry.isRet
def is_call_taken = is_call && jmp_taken && cfi_idx.valid && cfi_idx.bits === ftb_entry.tailSlot.offset
def is_ret_taken = is_ret && jmp_taken && cfi_idx.valid && cfi_idx.bits === ftb_entry.tailSlot.offset
def is_ret_taken = is_ret && jmp_taken && cfi_idx.valid && cfi_idx.bits === ftb_entry.tailSlot.offset
def display(cond: Bool) = {
XSDebug(cond, p"-----------BranchPredictionUpdate-----------\n")
@ -820,24 +805,23 @@ class BranchPredictionRedirect(implicit p: Parameters) extends Redirect with Has
// TODO: backend should pass topdown signals here
// must not change its parent since BPU has used asTypeOf(this type) from its parent class
require(isInstanceOf[Redirect])
val BTBMissBubble = Bool()
val BTBMissBubble = Bool()
def ControlRedirectBubble = debugIsCtrl
// if mispred br not in ftb, count as BTB miss
def ControlBTBMissBubble = ControlRedirectBubble && !cfiUpdate.br_hit && !cfiUpdate.jr_hit
def TAGEMissBubble = ControlRedirectBubble && cfiUpdate.br_hit && !cfiUpdate.sc_hit
def SCMissBubble = ControlRedirectBubble && cfiUpdate.br_hit && cfiUpdate.sc_hit
def ITTAGEMissBubble = ControlRedirectBubble && cfiUpdate.jr_hit && !cfiUpdate.pd.isRet
def RASMissBubble = ControlRedirectBubble && cfiUpdate.jr_hit && cfiUpdate.pd.isRet
def TAGEMissBubble = ControlRedirectBubble && cfiUpdate.br_hit && !cfiUpdate.sc_hit
def SCMissBubble = ControlRedirectBubble && cfiUpdate.br_hit && cfiUpdate.sc_hit
def ITTAGEMissBubble = ControlRedirectBubble && cfiUpdate.jr_hit && !cfiUpdate.pd.isRet
def RASMissBubble = ControlRedirectBubble && cfiUpdate.jr_hit && cfiUpdate.pd.isRet
def MemVioRedirectBubble = debugIsMemVio
def OtherRedirectBubble = !debugIsCtrl && !debugIsMemVio
def OtherRedirectBubble = !debugIsCtrl && !debugIsMemVio
def connectRedirect(source: Redirect): Unit = {
def connectRedirect(source: Redirect): Unit =
for ((name, data) <- this.elements) {
if (source.elements.contains(name)) {
data := source.elements(name)
}
}
}
def display(cond: Bool): Unit = {
XSDebug(cond, p"-----------BranchPredictionRedirect----------- \n")
@ -845,7 +829,10 @@ class BranchPredictionRedirect(implicit p: Parameters) extends Redirect with Has
XSDebug(cond, p"[pc] ${Hexadecimal(cfiUpdate.pc)}\n")
// XSDebug(cond, p"[hist] ${Binary(cfiUpdate.hist.predHist)}\n")
XSDebug(cond, p"[br_hit] ${cfiUpdate.br_hit} [isMisPred] ${cfiUpdate.isMisPred}\n")
XSDebug(cond, p"[pred_taken] ${cfiUpdate.predTaken} [taken] ${cfiUpdate.taken} [isMisPred] ${cfiUpdate.isMisPred}\n")
XSDebug(
cond,
p"[pred_taken] ${cfiUpdate.predTaken} [taken] ${cfiUpdate.taken} [isMisPred] ${cfiUpdate.isMisPred}\n"
)
XSDebug(cond, p"[target] ${Hexadecimal(cfiUpdate.target)} \n")
XSDebug(cond, p"[shift] ${cfiUpdate.shift}\n")
XSDebug(cond, p"------------------------------- \n")

View File

@ -16,125 +16,121 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.ExceptionNO._
class IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](
p => p(XSCoreParamsKey).IBufSize
) {
}
class IBufPtr(implicit p: Parameters) extends CircularQueuePtr[IBufPtr](p => p(XSCoreParamsKey).IBufSize) {}
class IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](
p => p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank
) {
}
class IBufInBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufInBankPtr](p =>
p(XSCoreParamsKey).IBufSize / p(XSCoreParamsKey).IBufNBank
) {}
class IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](
p => p(XSCoreParamsKey).IBufNBank
) {
}
class IBufBankPtr(implicit p: Parameters) extends CircularQueuePtr[IBufBankPtr](p => p(XSCoreParamsKey).IBufNBank) {}
class IBufferIO(implicit p: Parameters) extends XSBundle {
val flush = Input(Bool())
val ControlRedirect = Input(Bool())
val flush = Input(Bool())
val ControlRedirect = Input(Bool())
val ControlBTBMissBubble = Input(Bool())
val TAGEMissBubble = Input(Bool())
val SCMissBubble = Input(Bool())
val ITTAGEMissBubble = Input(Bool())
val RASMissBubble = Input(Bool())
val MemVioRedirect = Input(Bool())
val in = Flipped(DecoupledIO(new FetchToIBuffer))
val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
val full = Output(Bool())
val decodeCanAccept = Input(Bool())
val stallReason = new StallReasonIO(DecodeWidth)
val TAGEMissBubble = Input(Bool())
val SCMissBubble = Input(Bool())
val ITTAGEMissBubble = Input(Bool())
val RASMissBubble = Input(Bool())
val MemVioRedirect = Input(Bool())
val in = Flipped(DecoupledIO(new FetchToIBuffer))
val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
val full = Output(Bool())
val decodeCanAccept = Input(Bool())
val stallReason = new StallReasonIO(DecodeWidth)
}
class IBufEntry(implicit p: Parameters) extends XSBundle {
val inst = UInt(32.W)
val pc = UInt(VAddrBits.W)
val foldpc = UInt(MemPredPCWidth.W)
val pd = new PreDecodeInfo
val pred_taken = Bool()
val ftqPtr = new FtqPtr
val ftqOffset = UInt(log2Ceil(PredictWidth).W)
val exceptionType = IBufferExceptionType()
val inst = UInt(32.W)
val pc = UInt(VAddrBits.W)
val foldpc = UInt(MemPredPCWidth.W)
val pd = new PreDecodeInfo
val pred_taken = Bool()
val ftqPtr = new FtqPtr
val ftqOffset = UInt(log2Ceil(PredictWidth).W)
val exceptionType = IBufferExceptionType()
val exceptionFromBackend = Bool()
val triggered = TriggerAction()
val isLastInFtqEntry = Bool()
val triggered = TriggerAction()
val isLastInFtqEntry = Bool()
def fromFetch(fetch: FetchToIBuffer, i: Int): IBufEntry = {
inst := fetch.instrs(i)
pc := fetch.pc(i)
foldpc := fetch.foldpc(i)
pd := fetch.pd(i)
inst := fetch.instrs(i)
pc := fetch.pc(i)
foldpc := fetch.foldpc(i)
pd := fetch.pd(i)
pred_taken := fetch.ftqOffset(i).valid
ftqPtr := fetch.ftqPtr
ftqOffset := fetch.ftqOffset(i).bits
ftqPtr := fetch.ftqPtr
ftqOffset := fetch.ftqOffset(i).bits
exceptionType := IBufferExceptionType.cvtFromFetchExcpAndCrossPageAndRVCII(
fetch.exceptionType(i),
fetch.crossPageIPFFix(i),
fetch.illegalInstr(i),
fetch.illegalInstr(i)
)
exceptionFromBackend := fetch.exceptionFromBackend(i)
triggered := fetch.triggered(i)
isLastInFtqEntry := fetch.isLastInFtqEntry(i)
triggered := fetch.triggered(i)
isLastInFtqEntry := fetch.isLastInFtqEntry(i)
this
}
def toCtrlFlow: CtrlFlow = {
val cf = Wire(new CtrlFlow)
cf.instr := inst
cf.pc := pc
cf.foldpc := foldpc
cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
cf.exceptionVec(instrPageFault) := IBufferExceptionType.isPF (this.exceptionType)
cf.instr := inst
cf.pc := pc
cf.foldpc := foldpc
cf.exceptionVec := 0.U.asTypeOf(ExceptionVec())
cf.exceptionVec(instrPageFault) := IBufferExceptionType.isPF(this.exceptionType)
cf.exceptionVec(instrGuestPageFault) := IBufferExceptionType.isGPF(this.exceptionType)
cf.exceptionVec(instrAccessFault) := IBufferExceptionType.isAF (this.exceptionType)
cf.exceptionVec(instrAccessFault) := IBufferExceptionType.isAF(this.exceptionType)
cf.exceptionVec(EX_II) := IBufferExceptionType.isRVCII(this.exceptionType)
cf.exceptionFromBackend := exceptionFromBackend
cf.trigger := triggered
cf.pd := pd
cf.pred_taken := pred_taken
cf.crossPageIPFFix := IBufferExceptionType.isCrossPage(this.exceptionType)
cf.storeSetHit := DontCare
cf.waitForRobIdx := DontCare
cf.loadWaitBit := DontCare
cf.loadWaitStrict := DontCare
cf.ssid := DontCare
cf.ftqPtr := ftqPtr
cf.ftqOffset := ftqOffset
cf.isLastInFtqEntry := isLastInFtqEntry
cf.exceptionFromBackend := exceptionFromBackend
cf.trigger := triggered
cf.pd := pd
cf.pred_taken := pred_taken
cf.crossPageIPFFix := IBufferExceptionType.isCrossPage(this.exceptionType)
cf.storeSetHit := DontCare
cf.waitForRobIdx := DontCare
cf.loadWaitBit := DontCare
cf.loadWaitStrict := DontCare
cf.ssid := DontCare
cf.ftqPtr := ftqPtr
cf.ftqOffset := ftqOffset
cf.isLastInFtqEntry := isLastInFtqEntry
cf
}
object IBufferExceptionType extends NamedUInt(3) {
def None = "b000".U
def NonCrossPF = "b001".U
def NonCrossGPF = "b010".U
def NonCrossAF = "b011".U
def None = "b000".U
def NonCrossPF = "b001".U
def NonCrossGPF = "b010".U
def NonCrossAF = "b011".U
// illegal instruction
def rvcII = "b100".U
def CrossPF = "b101".U
def CrossGPF = "b110".U
def CrossAF = "b111".U
def rvcII = "b100".U
def CrossPF = "b101".U
def CrossGPF = "b110".U
def CrossAF = "b111".U
def cvtFromFetchExcpAndCrossPageAndRVCII(fetchExcp: UInt, crossPage: Bool, rvcIll: Bool): UInt = {
require(
fetchExcp.getWidth == ExceptionType.width,
s"The width(${fetchExcp.getWidth}) of fetchExcp should be equal to " +
s"the width(${ExceptionType.width}) of frontend.ExceptionType."
s"the width(${ExceptionType.width}) of frontend.ExceptionType."
)
MuxCase(
0.U,
Seq(
crossPage -> Cat(1.U(1.W), fetchExcp),
fetchExcp.orR -> fetchExcp,
rvcIll -> this.rvcII
)
)
MuxCase(0.U, Seq(
crossPage -> Cat(1.U(1.W), fetchExcp),
fetchExcp.orR -> fetchExcp,
rvcIll -> this.rvcII,
))
}
def isRVCII(uint: UInt): Bool = {
@ -147,9 +143,9 @@ class IBufEntry(implicit p: Parameters) extends XSBundle {
uint(2) && uint(1, 0) =/= 0.U
}
def isPF (uint: UInt): Bool = uint(1, 0) === this.NonCrossPF (1, 0)
def isPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossPF(1, 0)
def isGPF(uint: UInt): Bool = uint(1, 0) === this.NonCrossGPF(1, 0)
def isAF (uint: UInt): Bool = uint(1, 0) === this.NonCrossAF (1, 0)
def isAF(uint: UInt): Bool = uint(1, 0) === this.NonCrossAF(1, 0)
}
}
@ -162,8 +158,10 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
// Parameter Check
private val bankSize = IBufSize / IBufNBank
require(IBufSize % IBufNBank == 0, s"IBufNBank should divide IBufSize, IBufNBank: $IBufNBank, IBufSize: $IBufSize")
require(IBufNBank >= DecodeWidth,
s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth")
require(
IBufNBank >= DecodeWidth,
s"IBufNBank should be equal or larger than DecodeWidth, IBufNBank: $IBufNBank, DecodeWidth: $DecodeWidth"
)
// IBuffer is organized as raw registers
// This is due to IBuffer is a huge queue, read & write port logic should be precisely controlled
@ -177,37 +175,35 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
// Enqueue writes cannot benefit from this characteristic unless use a SRAM
// For detail see Enqueue and Dequeue below
private val ibuf: Vec[IBufEntry] = RegInit(VecInit.fill(IBufSize)(0.U.asTypeOf(new IBufEntry)))
private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(
bankID => VecInit.tabulate(bankSize)(
inBankOffset => ibuf(bankID + inBankOffset * IBufNBank)
)
private val bankedIBufView: Vec[Vec[IBufEntry]] = VecInit.tabulate(IBufNBank)(bankID =>
VecInit.tabulate(bankSize)(inBankOffset => ibuf(bankID + inBankOffset * IBufNBank))
)
// Bypass wire
private val bypassEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
// Normal read wire
private val deqEntries = WireDefault(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
// Output register
private val outputEntries = RegInit(VecInit.fill(DecodeWidth)(0.U.asTypeOf(Valid(new IBufEntry))))
private val outputEntriesValidNum = PriorityMuxDefault(outputEntries.map(_.valid).zip(Seq.range(1, DecodeWidth).map(_.U)).reverse.toSeq, 0.U)
private val outputEntriesValidNum =
PriorityMuxDefault(outputEntries.map(_.valid).zip(Seq.range(1, DecodeWidth).map(_.U)).reverse.toSeq, 0.U)
// Between Bank
private val deqBankPtrVec: Vec[IBufBankPtr] = RegInit(VecInit.tabulate(DecodeWidth)(_.U.asTypeOf(new IBufBankPtr)))
private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0)
private val deqBankPtr: IBufBankPtr = deqBankPtrVec(0)
private val deqBankPtrVecNext = Wire(deqBankPtrVec.cloneType)
// Inside Bank
private val deqInBankPtr: Vec[IBufInBankPtr] = RegInit(VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr)))
private val deqInBankPtrNext = Wire(deqInBankPtr.cloneType)
val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr))
val deqPtr = RegInit(0.U.asTypeOf(new IBufPtr))
val deqPtrNext = Wire(deqPtr.cloneType)
val enqPtrVec = RegInit(VecInit.tabulate(PredictWidth)(_.U.asTypeOf(new IBufPtr)))
val enqPtr = enqPtrVec(0)
val enqPtr = enqPtrVec(0)
val numTryEnq = WireDefault(0.U)
val numEnq = Mux(io.in.fire, numTryEnq, 0.U)
val numEnq = Mux(io.in.fire, numTryEnq, 0.U)
// empty and decode can accept insts
val useBypass = enqPtr === deqPtr && decodeCanAccept
@ -218,19 +214,19 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
private val numDeq = numOut
// counter current number of valid
val numValid = distanceBetween(enqPtr, deqPtr)
val numValid = distanceBetween(enqPtr, deqPtr)
val numValidAfterDeq = numValid - numDeq
// counter next number of valid
val numValidNext = numValid + numEnq - numDeq
val allowEnq = RegInit(true.B)
val allowEnq = RegInit(true.B)
val numFromFetch = Mux(io.in.valid, PopCount(io.in.bits.enqEnable), 0.U)
allowEnq := (IBufSize - PredictWidth).U >= numValidNext // Disable when almost full
val enqOffset = VecInit.tabulate(PredictWidth)(i => PopCount(io.in.bits.valid.asBools.take(i)))
val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i))
val enqData = VecInit.tabulate(PredictWidth)(i => Wire(new IBufEntry).fromFetch(io.in.bits, i))
val outputEntriesIsNotFull = !outputEntries(DecodeWidth-1).valid
val outputEntriesIsNotFull = !outputEntries(DecodeWidth - 1).valid
when(decodeCanAccept) {
numOut := Mux(numValid >= DecodeWidth.U, DecodeWidth.U, numValid)
}.elsewhen(outputEntriesIsNotFull) {
@ -244,11 +240,11 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
when(numFromFetch >= DecodeWidth.U) {
numTryEnq := numFromFetch - DecodeWidth.U
numBypass := DecodeWidth.U
} .otherwise {
}.otherwise {
numTryEnq := 0.U
numBypass := numFromFetch
}
} .otherwise {
}.otherwise {
numTryEnq := numFromFetch
numBypass := 0.U
}
@ -262,11 +258,11 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
val validOH = Range(0, PredictWidth).map {
i =>
io.in.bits.valid(i) &&
io.in.bits.enqEnable(i) &&
enqOffset(i) === idx.asUInt
io.in.bits.enqEnable(i) &&
enqOffset(i) === idx.asUInt
} // Should be OneHot
entry.valid := validOH.reduce(_ || _) && io.in.fire && !io.flush
entry.bits := Mux1H(validOH, enqData)
entry.bits := Mux1H(validOH, enqData)
// Debug Assertion
XSError(io.in.valid && PopCount(validOH) > 1.asUInt, "validOH is not OneHot")
@ -277,7 +273,7 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
io.out zip outputEntries foreach {
case (io, reg) =>
io.valid := reg.valid
io.bits := reg.bits.toCtrlFlow
io.bits := reg.bits.toCtrlFlow
}
(outputEntries zip bypassEntries).zipWithIndex.foreach {
case ((out, bypass), i) =>
@ -287,9 +283,13 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
}.otherwise {
out := deqEntries(i)
}
}.elsewhen(outputEntriesIsNotFull){
}.elsewhen(outputEntriesIsNotFull) {
out.valid := deqEntries(i).valid
out.bits := Mux(i.U < outputEntriesValidNum, out.bits, VecInit(deqEntries.take(i + 1).map(_.bits))(i.U - outputEntriesValidNum))
out.bits := Mux(
i.U < outputEntriesValidNum,
out.bits,
VecInit(deqEntries.take(i + 1).map(_.bits))(i.U - outputEntriesValidNum)
)
}
}
@ -322,7 +322,7 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
}
}
// Pointer maintenance
when (io.in.fire && !io.flush) {
when(io.in.fire && !io.flush) {
enqPtrVec := VecInit(enqPtrVec.map(_ + numTryEnq))
}
@ -343,40 +343,40 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
// Read port
// 2-stage, IBufNBank * (bankSize -> 1) + IBufNBank -> 1
// Should be better than IBufSize -> 1 in area, with no significant latency increase
private val readStage1: Vec[IBufEntry] = VecInit.tabulate(IBufNBank)(
bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID))
)
private val readStage1: Vec[IBufEntry] =
VecInit.tabulate(IBufNBank)(bankID => Mux1H(UIntToOH(deqInBankPtr(bankID).value), bankedIBufView(bankID)))
for (i <- 0 until DecodeWidth) {
deqEntries(i).valid := validVec(i)
deqEntries(i).bits := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1)
deqEntries(i).bits := Mux1H(UIntToOH(deqBankPtrVec(i).value), readStage1)
}
// Pointer maintenance
deqBankPtrVecNext := VecInit(deqBankPtrVec.map(_ + numDeq))
deqPtrNext := deqPtr + numDeq
deqPtrNext := deqPtr + numDeq
deqInBankPtrNext.zip(deqInBankPtr).zipWithIndex.foreach {
case ((ptrNext, ptr), idx) => {
// validVec[k] == bankValid[deqBankPtr + k]
// So bankValid[n] == validVec[n - deqBankPtr]
val validIdx = Mux(idx.asUInt >= deqBankPtr.value,
val validIdx = Mux(
idx.asUInt >= deqBankPtr.value,
idx.asUInt - deqBankPtr.value,
((idx + IBufNBank).asUInt - deqBankPtr.value)(log2Ceil(IBufNBank) - 1, 0)
)(log2Ceil(DecodeWidth) - 1, 0)
val bankAdvance = numOut > validIdx
ptrNext := Mux(bankAdvance , ptr + 1.U, ptr)
ptrNext := Mux(bankAdvance, ptr + 1.U, ptr)
}
}
// Flush
when (io.flush) {
allowEnq := true.B
enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr))
when(io.flush) {
allowEnq := true.B
enqPtrVec := enqPtrVec.indices.map(_.U.asTypeOf(new IBufPtr))
deqBankPtrVec := deqBankPtrVec.indices.map(_.U.asTypeOf(new IBufBankPtr))
deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))
deqPtr := 0.U.asTypeOf(new IBufPtr())
deqInBankPtr := VecInit.fill(IBufNBank)(0.U.asTypeOf(new IBufInBankPtr))
deqPtr := 0.U.asTypeOf(new IBufPtr())
outputEntries.foreach(_.valid := false.B)
}.otherwise {
deqPtr := deqPtrNext
deqInBankPtr := deqInBankPtrNext
deqPtr := deqPtrNext
deqInBankPtr := deqInBankPtrNext
deqBankPtrVec := deqBankPtrVecNext
}
io.full := !allowEnq
@ -406,8 +406,7 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
}
}
val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W))
val matchBubble = Wire(UInt(log2Up(TopDownCounters.NumStallReasons.id).W))
val deqValidCount = PopCount(validVec.asBools)
val deqWasteCount = DecodeWidth.U - deqValidCount
matchBubble := (TopDownCounters.NumStallReasons.id - 1).U - PriorityEncoder(topdown_stage.reasons.reverse)
@ -445,28 +444,30 @@ class IBuffer(implicit p: Parameters) extends XSModule with HasCircularQueuePtrH
when(io.in.fire) {
XSDebug("Enque:\n")
XSDebug(p"MASK=${Binary(io.in.bits.valid)}\n")
for(i <- 0 until PredictWidth){
for (i <- 0 until PredictWidth) {
XSDebug(p"PC=${Hexadecimal(io.in.bits.pc(i))} ${Hexadecimal(io.in.bits.instrs(i))}\n")
}
}
for (i <- 0 until DecodeWidth) {
XSDebug(io.out(i).fire,
XSDebug(
io.out(i).fire,
p"deq: ${Hexadecimal(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)}" +
p"v=${io.out(i).valid} r=${io.out(i).ready} " +
p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n")
p"v=${io.out(i).valid} r=${io.out(i).ready} " +
p"excpVec=${Binary(io.out(i).bits.exceptionVec.asUInt)} crossPageIPF=${io.out(i).bits.crossPageIPFFix}\n"
)
}
XSDebug(p"numValid: ${numValid}\n")
XSDebug(p"EnqNum: ${numEnq}\n")
XSDebug(p"DeqNum: ${numDeq}\n")
val afterInit = RegInit(false.B)
val afterInit = RegInit(false.B)
val headBubble = RegInit(false.B)
when (io.in.fire) { afterInit := true.B }
when (io.flush) {
when(io.in.fire)(afterInit := true.B)
when(io.flush) {
headBubble := true.B
} .elsewhen(numValid =/= 0.U) {
}.elsewhen(numValid =/= 0.U) {
headBubble := false.B
}
val instrHungry = afterInit && (numValid === 0.U) && !headBubble

File diff suppressed because it is too large Load Diff

View File

@ -16,138 +16,128 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import utility._
import org.chipsalliance.cde.config.Parameters
import scala.{Tuple2 => &}
import scala.math.min
import scala.util.matching.Regex
import scala.{Tuple2 => &}
import utility._
import utils._
import xiangshan._
trait ITTageParams extends HasXSParameter with HasBPUParameter {
val ITTageNTables = ITTageTableInfos.size // Number of tage tables
val UBitPeriod = 2048
val UBitPeriod = 2048
val ITTageCtrBits = 2
val uFoldedWidth = 16
val TickWidth = 8
val ITTageUsBits = 1
def ctr_null(ctr: UInt, ctrBits: Int = ITTageCtrBits) = {
val uFoldedWidth = 16
val TickWidth = 8
val ITTageUsBits = 1
def ctr_null(ctr: UInt, ctrBits: Int = ITTageCtrBits) =
ctr === 0.U
}
def ctr_unconf(ctr: UInt, ctrBits: Int = ITTageCtrBits) = {
ctr < (1 << (ctrBits-1)).U
}
def ctr_unconf(ctr: UInt, ctrBits: Int = ITTageCtrBits) =
ctr < (1 << (ctrBits - 1)).U
val UAONA_bits = 4
val TotalBits = ITTageTableInfos.map {
case (s, h, t) => {
s * (1+t+ITTageCtrBits+ITTageUsBits+VAddrBits)
s * (1 + t + ITTageCtrBits + ITTageUsBits + VAddrBits)
}
}.reduce(_+_)
}.reduce(_ + _)
}
// reuse TAGE implementation
trait ITTageHasFoldedHistory {
val histLen: Int
def compute_folded_hist(hist: UInt, l: Int) = {
def compute_folded_hist(hist: UInt, l: Int) =
if (histLen > 0) {
val nChunks = (histLen + l - 1) / l
val hist_chunks = (0 until nChunks) map {i =>
hist(min((i+1)*l, histLen)-1, i*l)
}
val nChunks = (histLen + l - 1) / l
val hist_chunks = (0 until nChunks) map { i => hist(min((i + 1) * l, histLen) - 1, i * l) }
ParallelXOR(hist_chunks)
}
else 0.U
}
} else 0.U
}
abstract class ITTageBundle(implicit p: Parameters)
extends XSBundle with ITTageParams with BPUUtils
extends XSBundle with ITTageParams with BPUUtils
abstract class ITTageModule(implicit p: Parameters)
extends XSModule with ITTageParams with BPUUtils
{}
extends XSModule with ITTageParams with BPUUtils {}
class ITTageReq(implicit p: Parameters) extends ITTageBundle {
val pc = UInt(VAddrBits.W)
val pc = UInt(VAddrBits.W)
val folded_hist = new AllFoldedHistories(foldedGHistInfos)
}
class ITTageResp(implicit p: Parameters) extends ITTageBundle {
val ctr = UInt(ITTageCtrBits.W)
val u = UInt(2.W)
val ctr = UInt(ITTageCtrBits.W)
val u = UInt(2.W)
val target = UInt(VAddrBits.W)
}
class ITTageUpdate(implicit p: Parameters) extends ITTageBundle {
val pc = UInt(VAddrBits.W)
val pc = UInt(VAddrBits.W)
val ghist = UInt(HistoryLength.W)
// update tag and ctr
val valid = Bool()
val valid = Bool()
val correct = Bool()
val alloc = Bool()
val oldCtr = UInt(ITTageCtrBits.W)
val alloc = Bool()
val oldCtr = UInt(ITTageCtrBits.W)
// update u
val uValid = Bool()
val u = Bool()
val uValid = Bool()
val u = Bool()
val reset_u = Bool()
// target
val target = UInt(VAddrBits.W)
val target = UInt(VAddrBits.W)
val old_target = UInt(VAddrBits.W)
}
// reuse TAGE Implementation
class ITTageMeta(implicit p: Parameters) extends XSBundle with ITTageParams{
val provider = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val altProvider = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val altDiffers = Bool()
val providerU = Bool()
val providerCtr = UInt(ITTageCtrBits.W)
val altProviderCtr = UInt(ITTageCtrBits.W)
val allocate = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val providerTarget = UInt(VAddrBits.W)
class ITTageMeta(implicit p: Parameters) extends XSBundle with ITTageParams {
val provider = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val altProvider = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val altDiffers = Bool()
val providerU = Bool()
val providerCtr = UInt(ITTageCtrBits.W)
val altProviderCtr = UInt(ITTageCtrBits.W)
val allocate = ValidUndirectioned(UInt(log2Ceil(ITTageNTables).W))
val providerTarget = UInt(VAddrBits.W)
val altProviderTarget = UInt(VAddrBits.W)
// val scMeta = new SCMeta(EnableSC)
// TODO: check if we need target info here
val pred_cycle = if (!env.FPGAPlatform) Some(UInt(64.W)) else None
override def toPrintable = {
override def toPrintable =
p"pvdr(v:${provider.valid} num:${provider.bits} ctr:$providerCtr u:$providerU tar:${Hexadecimal(providerTarget)}), " +
p"altpvdr(v:${altProvider.valid} num:${altProvider.bits}, ctr:$altProviderCtr, tar:${Hexadecimal(altProviderTarget)})"
}
p"altpvdr(v:${altProvider.valid} num:${altProvider.bits}, ctr:$altProviderCtr, tar:${Hexadecimal(altProviderTarget)})"
}
class FakeITTageTable()(implicit p: Parameters) extends ITTageModule {
val io = IO(new Bundle() {
val req = Input(Valid(new ITTageReq))
val resp = Output(Valid(new ITTageResp))
val req = Input(Valid(new ITTageReq))
val resp = Output(Valid(new ITTageResp))
val update = Input(new ITTageUpdate)
})
io.resp := DontCare
}
class ITTageTable
(
val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPeriod: Int, val tableIdx: Int
class ITTageTable(
val nRows: Int,
val histLen: Int,
val tagLen: Int,
val uBitPeriod: Int,
val tableIdx: Int
)(implicit p: Parameters)
extends ITTageModule with HasFoldedHistory {
extends ITTageModule with HasFoldedHistory {
val io = IO(new Bundle() {
val req = Flipped(DecoupledIO(new ITTageReq))
val resp = Output(Valid(new ITTageResp))
val req = Flipped(DecoupledIO(new ITTageReq))
val resp = Output(Valid(new ITTageResp))
val update = Input(new ITTageUpdate)
})
val SRAM_SIZE=128
val SRAM_SIZE = 128
val foldedWidth = if (nRows >= SRAM_SIZE) nRows / SRAM_SIZE else 1
@ -160,35 +150,33 @@ class ITTageTable
val wrBypassEntries = 4
require(histLen == 0 && tagLen == 0 || histLen != 0 && tagLen != 0)
val idxFhInfo = (histLen, min(log2Ceil(nRows), histLen))
val tagFhInfo = (histLen, min(histLen, tagLen))
val altTagFhInfo = (histLen, min(histLen, tagLen-1))
val allFhInfos = Seq(idxFhInfo, tagFhInfo, altTagFhInfo)
val idxFhInfo = (histLen, min(log2Ceil(nRows), histLen))
val tagFhInfo = (histLen, min(histLen, tagLen))
val altTagFhInfo = (histLen, min(histLen, tagLen - 1))
val allFhInfos = Seq(idxFhInfo, tagFhInfo, altTagFhInfo)
def getFoldedHistoryInfo = allFhInfos.filter(_._1 >0).toSet
def getFoldedHistoryInfo = allFhInfos.filter(_._1 > 0).toSet
def compute_tag_and_hash(unhashed_idx: UInt, allFh: AllFoldedHistories) = {
def compute_tag_and_hash(unhashed_idx: UInt, allFh: AllFoldedHistories) =
if (histLen > 0) {
val idx_fh = allFh.getHistWithInfo(idxFhInfo).folded_hist
val tag_fh = allFh.getHistWithInfo(tagFhInfo).folded_hist
val idx_fh = allFh.getHistWithInfo(idxFhInfo).folded_hist
val tag_fh = allFh.getHistWithInfo(tagFhInfo).folded_hist
val alt_tag_fh = allFh.getHistWithInfo(altTagFhInfo).folded_hist
// require(idx_fh.getWidth == log2Ceil(nRows))
val idx = (unhashed_idx ^ idx_fh)(log2Ceil(nRows)-1, 0)
val tag = ((unhashed_idx >> log2Ceil(nRows)) ^ tag_fh ^ (alt_tag_fh << 1)) (tagLen - 1, 0)
val idx = (unhashed_idx ^ idx_fh)(log2Ceil(nRows) - 1, 0)
val tag = ((unhashed_idx >> log2Ceil(nRows)) ^ tag_fh ^ (alt_tag_fh << 1))(tagLen - 1, 0)
(idx, tag)
}
else {
} else {
require(tagLen == 0)
(unhashed_idx(log2Ceil(nRows)-1, 0), 0.U)
(unhashed_idx(log2Ceil(nRows) - 1, 0), 0.U)
}
}
def inc_ctr(ctr: UInt, taken: Bool): UInt = satUpdate(ctr, ITTageCtrBits, taken)
class ITTageEntry() extends ITTageBundle {
val valid = Bool()
val tag = UInt(tagLen.W)
val ctr = UInt(ITTageCtrBits.W)
val valid = Bool()
val tag = UInt(tagLen.W)
val ctr = UInt(ITTageCtrBits.W)
val target = UInt(VAddrBits.W)
val useful = Bool()
}
@ -200,67 +188,74 @@ class ITTageTable
// def getUnhashedIdx(pc: UInt) = pc >> (instOffsetBits+log2Ceil(TageBanks))
def getUnhashedIdx(pc: UInt): UInt = pc >> instOffsetBits
val s0_valid = io.req.valid
val s0_pc = io.req.bits.pc
val s0_valid = io.req.valid
val s0_pc = io.req.bits.pc
val s0_unhashed_idx = getUnhashedIdx(io.req.bits.pc)
val (s0_idx, s0_tag) = compute_tag_and_hash(s0_unhashed_idx, io.req.bits.folded_hist)
val (s1_idx, s1_tag) = (RegEnable(s0_idx, io.req.fire), RegEnable(s0_tag, io.req.fire))
val s1_valid = RegNext(s0_valid)
val s1_valid = RegNext(s0_valid)
val table = Module(new FoldedSRAMTemplate(
new ITTageEntry, set=nRows, width=foldedWidth, shouldReset=true, holdRead=true, singlePort=true, useBitmask=true))
new ITTageEntry,
set = nRows,
width = foldedWidth,
shouldReset = true,
holdRead = true,
singlePort = true,
useBitmask = true
))
table.io.r.req.valid := io.req.fire
table.io.r.req.valid := io.req.fire
table.io.r.req.bits.setIdx := s0_idx
val table_read_data = table.io.r.resp.data(0)
val s1_req_rhit = table_read_data.valid && table_read_data.tag === s1_tag
val read_write_conflict = io.update.valid && io.req.valid
val read_write_conflict = io.update.valid && io.req.valid
val s1_read_write_conflict = RegEnable(read_write_conflict, io.req.valid)
io.resp.valid := (if (tagLen != 0) s1_req_rhit && !s1_read_write_conflict else true.B) && s1_valid // && s1_mask(b)
io.resp.valid := (if (tagLen != 0) s1_req_rhit && !s1_read_write_conflict else true.B) && s1_valid // && s1_mask(b)
io.resp.bits.ctr := table_read_data.ctr
io.resp.bits.u := table_read_data.useful
io.resp.bits.u := table_read_data.useful
io.resp.bits.target := table_read_data.target
// Use fetchpc to compute hash
val update_folded_hist = WireInit(0.U.asTypeOf(new AllFoldedHistories(foldedGHistInfos)))
update_folded_hist.getHistWithInfo(idxFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, log2Ceil(nRows))
update_folded_hist.getHistWithInfo(tagFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, tagLen)
update_folded_hist.getHistWithInfo(altTagFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, tagLen-1)
update_folded_hist.getHistWithInfo(idxFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, log2Ceil(nRows))
update_folded_hist.getHistWithInfo(tagFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, tagLen)
update_folded_hist.getHistWithInfo(altTagFhInfo).folded_hist := compute_folded_ghist(io.update.ghist, tagLen - 1)
dontTouch(update_folded_hist)
val (update_idx, update_tag) = compute_tag_and_hash(getUnhashedIdx(io.update.pc), update_folded_hist)
val update_target = io.update.target
val update_wdata = Wire(new ITTageEntry)
val update_target = io.update.target
val update_wdata = Wire(new ITTageEntry)
val updateAllBitmask = VecInit.fill(ittageEntrySz)(1.U).asUInt // update all entry
val updateNoBitmask = VecInit.fill(ittageEntrySz)(0.U).asUInt // update no
val updateNoUsBitmask =
VecInit.tabulate(ittageEntrySz)(_.U >= ITTageUsBits.U).asUInt // update others besides useful bit
val updateUsBitmask = VecInit.tabulate(ittageEntrySz)(_.U < ITTageUsBits.U).asUInt // update useful bit
val updateAllBitmask = VecInit.fill(ittageEntrySz)(1.U).asUInt //update all entry
val updateNoBitmask = VecInit.fill(ittageEntrySz)(0.U).asUInt //update no
val updateNoUsBitmask = VecInit.tabulate(ittageEntrySz)(_.U >= ITTageUsBits.U).asUInt //update others besides useful bit
val updateUsBitmask = VecInit.tabulate(ittageEntrySz)(_.U < ITTageUsBits.U).asUInt //update useful bit
val needReset = RegInit(false.B)
val useful_can_reset = !(io.req.fire || io.update.valid) && needReset
val needReset = RegInit(false.B)
val useful_can_reset = !(io.req.fire || io.update.valid) && needReset
val (resetSet, resetFinish) = Counter(useful_can_reset, nRows)
when (io.update.reset_u) {
when(io.update.reset_u) {
needReset := true.B
}.elsewhen (resetFinish) {
}.elsewhen(resetFinish) {
needReset := false.B
}
val update_bitmask = Mux(io.update.uValid && io.update.valid,
updateAllBitmask,
Mux(io.update.valid, updateNoUsBitmask,
Mux(useful_can_reset, updateUsBitmask, updateNoBitmask)
))
val update_bitmask = Mux(
io.update.uValid && io.update.valid,
updateAllBitmask,
Mux(io.update.valid, updateNoUsBitmask, Mux(useful_can_reset, updateUsBitmask, updateNoBitmask))
)
table.io.w.apply(
valid = io.update.valid || useful_can_reset,
data = update_wdata,
setIdx = Mux(useful_can_reset, resetSet, update_idx),
valid = io.update.valid || useful_can_reset,
data = update_wdata,
setIdx = Mux(useful_can_reset, resetSet, update_idx),
waymask = true.B,
bitmask = update_bitmask
)
@ -279,48 +274,54 @@ class ITTageTable
val wrbypass = Module(new WrBypass(UInt(ITTageCtrBits.W), wrBypassEntries, log2Ceil(nRows)))
wrbypass.io.wen := io.update.valid
wrbypass.io.wen := io.update.valid
wrbypass.io.write_idx := update_idx
wrbypass.io.write_data.map(_ := update_wdata.ctr)
val old_ctr = Mux(wrbypass.io.hit, wrbypass.io.hit_data(0).bits, io.update.oldCtr)
update_wdata.valid := true.B
update_wdata.ctr := Mux(io.update.alloc, 2.U, inc_ctr(old_ctr, io.update.correct))
update_wdata.tag := update_tag
update_wdata.useful:= Mux(useful_can_reset, false.B, io.update.u)
update_wdata.valid := true.B
update_wdata.ctr := Mux(io.update.alloc, 2.U, inc_ctr(old_ctr, io.update.correct))
update_wdata.tag := update_tag
update_wdata.useful := Mux(useful_can_reset, false.B, io.update.u)
// only when ctr is null
update_wdata.target := Mux(io.update.alloc || ctr_null(old_ctr), update_target, io.update.old_target)
XSPerfAccumulate("ittage_table_updates", io.update.valid)
XSPerfAccumulate("ittage_table_hits", io.resp.valid)
XSPerfAccumulate("ittage_us_tick_reset", io.update.reset_u)
XSPerfAccumulate("ittage_table_read_write_conflict", read_write_conflict)
if (BPUDebug && debug) {
val u = io.update
val u = io.update
val idx = s0_idx
val tag = s0_tag
XSDebug(io.req.fire,
XSDebug(
io.req.fire,
p"ITTageTableReq: pc=0x${Hexadecimal(io.req.bits.pc)}, " +
p"idx=$idx, tag=$tag\n")
XSDebug(RegNext(io.req.fire) && s1_req_rhit,
p"idx=$idx, tag=$tag\n"
)
XSDebug(
RegNext(io.req.fire) && s1_req_rhit,
p"ITTageTableResp: idx=$s1_idx, hit:${s1_req_rhit}, " +
p"ctr:${io.resp.bits.ctr}, u:${io.resp.bits.u}, tar:${Hexadecimal(io.resp.bits.target)}\n")
XSDebug(io.update.valid,
p"ctr:${io.resp.bits.ctr}, u:${io.resp.bits.u}, tar:${Hexadecimal(io.resp.bits.target)}\n"
)
XSDebug(
io.update.valid,
p"update ITTAGE Table: pc:${Hexadecimal(u.pc)}}, " +
p"correct:${u.correct}, alloc:${u.alloc}, oldCtr:${u.oldCtr}, " +
p"target:${Hexadecimal(u.target)}, old_target:${Hexadecimal(u.old_target)}\n")
XSDebug(io.update.valid,
p"correct:${u.correct}, alloc:${u.alloc}, oldCtr:${u.oldCtr}, " +
p"target:${Hexadecimal(u.target)}, old_target:${Hexadecimal(u.old_target)}\n"
)
XSDebug(
io.update.valid,
p"update ITTAGE Table: writing tag:${update_tag}, " +
p"ctr: ${update_wdata.ctr}, target:${Hexadecimal(update_wdata.target)}" +
p" in idx $update_idx\n")
p"ctr: ${update_wdata.ctr}, target:${Hexadecimal(update_wdata.target)}" +
p" in idx $update_idx\n"
)
XSDebug(RegNext(io.req.fire) && !s1_req_rhit, "TageTableResp: no hits!\n")
// ------------------------------Debug-------------------------------------
val valids = RegInit(0.U.asTypeOf(Vec(nRows, Bool())))
when (io.update.valid) { valids(update_idx) := true.B }
when(io.update.valid)(valids(update_idx) := true.B)
XSDebug("ITTAGE Table usage:------------------------\n")
XSDebug("%d out of %d rows are valid\n", PopCount(valids), nRows.U)
}
@ -365,16 +366,15 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
val t = Module(new ITTageTable(nRows, histLen, tagLen, UBitPeriod, i))
t
}
override def getFoldedHistoryInfo = Some(tables.map(_.getFoldedHistoryInfo).reduce(_++_))
override def getFoldedHistoryInfo = Some(tables.map(_.getFoldedHistoryInfo).reduce(_ ++ _))
val useAltOnNa = RegInit((1 << (UAONA_bits-1)).U(UAONA_bits.W))
val tickCtr = RegInit(0.U(TickWidth.W))
val useAltOnNa = RegInit((1 << (UAONA_bits - 1)).U(UAONA_bits.W))
val tickCtr = RegInit(0.U(TickWidth.W))
// uftb miss or hasIndirect
val s1_uftbHit = io.in.bits.resp_in(0).s1_uftbHit
val s1_uftbHit = io.in.bits.resp_in(0).s1_uftbHit
val s1_uftbHasIndirect = io.in.bits.resp_in(0).s1_uftbHasIndirect
val s1_isIndirect = (!s1_uftbHit && !io.in.bits.resp_in(0).s1_ftbCloseReq) || s1_uftbHasIndirect
val s1_isIndirect = (!s1_uftbHit && !io.in.bits.resp_in(0).s1_ftbCloseReq) || s1_uftbHasIndirect
// Keep the table responses to process in s2
@ -413,10 +413,10 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
// Update logic
val u_valid = io.update.valid
val update = io.update.bits
val update = io.update.bits
val updateValid =
update.is_jalr && !update.is_ret && u_valid && update.ftb_entry.jmpValid &&
update.jmp_taken && update.cfi_idx.valid && update.cfi_idx.bits === update.ftb_entry.tailSlot.offset
update.jmp_taken && update.cfi_idx.valid && update.cfi_idx.bits === update.ftb_entry.tailSlot.offset
// meta is splited by composer
val updateMeta = update.meta.asTypeOf(new ITTageMeta)
@ -431,44 +431,44 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
val updateOldCtr = Wire(Vec(ITTageNTables, UInt(ITTageCtrBits.W)))
val updateU = Wire(Vec(ITTageNTables, Bool()))
updateCorrect := DontCare
updateTarget := DontCare
updateOldTarget := DontCare
updateAlloc := DontCare
updateOldCtr := DontCare
updateU := DontCare
updateTarget := DontCare
updateOldTarget := DontCare
updateAlloc := DontCare
updateOldCtr := DontCare
updateU := DontCare
// val updateTageMisPreds = VecInit((0 until numBr).map(i => updateMetas(i).taken =/= u.takens(i)))
val updateMisPred = update.mispred_mask(numBr) // the last one indicates jmp results
// Predict
tables.map { t => {
t.io.req.valid := io.s1_fire(3) && s1_isIndirect
t.io.req.bits.pc := s1_pc_dup(3)
t.io.req.bits.folded_hist := io.in.bits.s1_folded_hist(3)
}
tables.map { t =>
t.io.req.valid := io.s1_fire(3) && s1_isIndirect
t.io.req.bits.pc := s1_pc_dup(3)
t.io.req.bits.folded_hist := io.in.bits.s1_folded_hist(3)
}
// access tag tables and output meta info
class ITTageTableInfo(implicit p: Parameters) extends ITTageResp {
val tableIdx = UInt(log2Ceil(ITTageNTables).W)
}
val inputRes = VecInit(s2_resps.zipWithIndex.map{case (r, i) => {
val tableInfo = Wire(new ITTageTableInfo)
tableInfo.u := r.bits.u
tableInfo.ctr := r.bits.ctr
tableInfo.target := r.bits.target
tableInfo.tableIdx := i.U(log2Ceil(ITTageNTables).W)
SelectTwoInterRes(r.valid, tableInfo)
}})
val inputRes = VecInit(s2_resps.zipWithIndex.map {
case (r, i) => {
val tableInfo = Wire(new ITTageTableInfo)
tableInfo.u := r.bits.u
tableInfo.ctr := r.bits.ctr
tableInfo.target := r.bits.target
tableInfo.tableIdx := i.U(log2Ceil(ITTageNTables).W)
SelectTwoInterRes(r.valid, tableInfo)
}
})
val selectedInfo = ParallelSelectTwo(inputRes.reverse)
val provided = selectedInfo.hasOne
val altProvided = selectedInfo.hasTwo
val provided = selectedInfo.hasOne
val altProvided = selectedInfo.hasTwo
val providerInfo = selectedInfo.first
val providerInfo = selectedInfo.first
val altProviderInfo = selectedInfo.second
val providerNull = providerInfo.ctr === 0.U
val providerNull = providerInfo.ctr === 0.U
val baseTarget = io.in.bits.resp_in(0).s2.full_pred(3).jalr_target // use ftb pred as base target
@ -477,22 +477,23 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
(altProvided && providerNull, altProviderInfo.target),
(!provided, baseTarget)
))
s2_provided := provided
s2_provider := providerInfo.tableIdx
s2_altProvided := altProvided
s2_altProvider := altProviderInfo.tableIdx
s2_providerU := providerInfo.u
s2_providerCtr := providerInfo.ctr
s2_altProviderCtr := altProviderInfo.ctr
s2_providerTarget := providerInfo.target
s2_provided := provided
s2_provider := providerInfo.tableIdx
s2_altProvided := altProvided
s2_altProvider := altProviderInfo.tableIdx
s2_providerU := providerInfo.u
s2_providerCtr := providerInfo.ctr
s2_altProviderCtr := altProviderInfo.ctr
s2_providerTarget := providerInfo.target
s2_altProviderTarget := altProviderInfo.target
XSDebug(io.s2_fire(3), p"hit_taken_jalr:")
for (fp & s3_tageTarget <-
io.out.s3.full_pred zip s3_tageTarget_dup)
yield
fp.jalr_target := s3_tageTarget
for (
fp & s3_tageTarget <-
io.out.s3.full_pred zip s3_tageTarget_dup
)
yield fp.jalr_target := s3_tageTarget
resp_meta.provider.valid := s3_provided
resp_meta.provider.bits := s3_provider
@ -504,7 +505,7 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
resp_meta.altProviderCtr := s3_altProviderCtr
resp_meta.providerTarget := s3_providerTarget
resp_meta.altProviderTarget := s3_altProviderTarget
resp_meta.pred_cycle.map(_:= GTimer())
resp_meta.pred_cycle.map(_ := GTimer())
// TODO: adjust for ITTAGE
// Create a mask fo tables which did not hit our query, and also contain useless entries
// and also uses a longer history than the provider
@ -519,121 +520,127 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
// Update in loop
val updateRealTarget = update.full_target
when (updateValid) {
when (updateMeta.provider.valid) {
when(updateValid) {
when(updateMeta.provider.valid) {
val provider = updateMeta.provider.bits
XSDebug(true.B, p"update provider $provider, pred cycle ${updateMeta.pred_cycle.getOrElse(0.U)}\n")
val altProvider = updateMeta.altProvider.bits
val usedAltpred = updateMeta.altProvider.valid && updateMeta.providerCtr === 0.U
when (usedAltpred && updateMisPred) { // update altpred if used as pred
when(usedAltpred && updateMisPred) { // update altpred if used as pred
XSDebug(true.B, p"update altprovider $altProvider, pred cycle ${updateMeta.pred_cycle.getOrElse(0.U)}\n")
updateMask(altProvider) := true.B
updateUMask(altProvider) := false.B
updateCorrect(altProvider) := false.B
updateOldCtr(altProvider) := updateMeta.altProviderCtr
updateAlloc(altProvider) := false.B
updateTarget(altProvider) := updateRealTarget
updateMask(altProvider) := true.B
updateUMask(altProvider) := false.B
updateCorrect(altProvider) := false.B
updateOldCtr(altProvider) := updateMeta.altProviderCtr
updateAlloc(altProvider) := false.B
updateTarget(altProvider) := updateRealTarget
updateOldTarget(altProvider) := updateMeta.altProviderTarget
}
updateMask(provider) := true.B
updateUMask(provider) := true.B
updateMask(provider) := true.B
updateUMask(provider) := true.B
updateU(provider) := Mux(!updateMeta.altDiffers, updateMeta.providerU,
updateMeta.providerTarget === updateRealTarget)
updateCorrect(provider) := updateMeta.providerTarget === updateRealTarget
updateTarget(provider) := updateRealTarget
updateU(provider) := Mux(
!updateMeta.altDiffers,
updateMeta.providerU,
updateMeta.providerTarget === updateRealTarget
)
updateCorrect(provider) := updateMeta.providerTarget === updateRealTarget
updateTarget(provider) := updateRealTarget
updateOldTarget(provider) := updateMeta.providerTarget
updateOldCtr(provider) := updateMeta.providerCtr
updateAlloc(provider) := false.B
updateOldCtr(provider) := updateMeta.providerCtr
updateAlloc(provider) := false.B
}
}
// if mispredicted and not the case that
// provider offered correct target but used altpred due to unconfident
val providerCorrect = updateMeta.provider.valid && updateMeta.providerTarget === updateRealTarget
val providerUnconf = updateMeta.providerCtr === 0.U
when (updateValid && updateMisPred && !(providerCorrect && providerUnconf)) {
val providerUnconf = updateMeta.providerCtr === 0.U
when(updateValid && updateMisPred && !(providerCorrect && providerUnconf)) {
val allocate = updateMeta.allocate
tickCtr := satUpdate(tickCtr, TickWidth, !allocate.valid)
when (allocate.valid) {
when(allocate.valid) {
XSDebug(true.B, p"allocate new table entry, pred cycle ${updateMeta.pred_cycle.getOrElse(0.U)}\n")
updateMask(allocate.bits) := true.B
updateMask(allocate.bits) := true.B
updateCorrect(allocate.bits) := true.B // useless for alloc
updateTarget(allocate.bits) := updateRealTarget
updateAlloc(allocate.bits) := true.B
updateUMask(allocate.bits) := true.B
updateU(allocate.bits) := false.B
updateTarget(allocate.bits) := updateRealTarget
updateAlloc(allocate.bits) := true.B
updateUMask(allocate.bits) := true.B
updateU(allocate.bits) := false.B
}
}
when (tickCtr === ((1 << TickWidth) - 1).U) {
tickCtr := 0.U
when(tickCtr === ((1 << TickWidth) - 1).U) {
tickCtr := 0.U
updateResetU := true.B
}
for (i <- 0 until ITTageNTables) {
tables(i).io.update.valid := RegNext(updateMask(i), init = false.B)
tables(i).io.update.reset_u := RegNext(updateResetU, init = false.B)
tables(i).io.update.correct := RegEnable(updateCorrect(i), updateMask(i))
tables(i).io.update.target := RegEnable(updateTarget(i), updateMask(i))
tables(i).io.update.valid := RegNext(updateMask(i), init = false.B)
tables(i).io.update.reset_u := RegNext(updateResetU, init = false.B)
tables(i).io.update.correct := RegEnable(updateCorrect(i), updateMask(i))
tables(i).io.update.target := RegEnable(updateTarget(i), updateMask(i))
tables(i).io.update.old_target := RegEnable(updateOldTarget(i), updateMask(i))
tables(i).io.update.alloc := RegEnable(updateAlloc(i), updateMask(i))
tables(i).io.update.oldCtr := RegEnable(updateOldCtr(i), updateMask(i))
tables(i).io.update.alloc := RegEnable(updateAlloc(i), updateMask(i))
tables(i).io.update.oldCtr := RegEnable(updateOldCtr(i), updateMask(i))
tables(i).io.update.uValid := RegEnable(updateUMask(i), false.B, updateMask(i))
tables(i).io.update.u := RegEnable(updateU(i), updateMask(i))
tables(i).io.update.pc := RegEnable(update.pc, updateMask(i))
tables(i).io.update.u := RegEnable(updateU(i), updateMask(i))
tables(i).io.update.pc := RegEnable(update.pc, updateMask(i))
// use fetch pc instead of instruction pc
tables(i).io.update.ghist := RegEnable(update.ghist, updateMask(i))
}
// all should be ready for req
io.s1_ready := tables.map(_.io.req.ready).reduce(_&&_)
io.s1_ready := tables.map(_.io.req.ready).reduce(_ && _)
// Debug and perf info
XSPerfAccumulate("ittage_reset_u", updateResetU)
XSPerfAccumulate("ittage_used", io.s1_fire(0) && s1_isIndirect)
XSPerfAccumulate("ittage_closed_due_to_uftb_info", io.s1_fire(0) && !s1_isIndirect)
def pred_perf(name: String, cond: Bool) = XSPerfAccumulate(s"${name}_at_pred", cond && io.s2_fire(3))
def pred_perf(name: String, cond: Bool) = XSPerfAccumulate(s"${name}_at_pred", cond && io.s2_fire(3))
def commit_perf(name: String, cond: Bool) = XSPerfAccumulate(s"${name}_at_commit", cond && updateValid)
def ittage_perf(name: String, pred_cond: Bool, commit_cond: Bool) = {
pred_perf(s"ittage_${name}", pred_cond)
commit_perf(s"ittage_${name}", commit_cond)
}
val pred_use_provider = s2_provided && !ctr_null(s2_providerCtr)
val pred_use_altpred = s2_provided && ctr_null(s2_providerCtr)
val pred_use_ht_as_altpred = pred_use_altpred && s2_altProvided
val pred_use_provider = s2_provided && !ctr_null(s2_providerCtr)
val pred_use_altpred = s2_provided && ctr_null(s2_providerCtr)
val pred_use_ht_as_altpred = pred_use_altpred && s2_altProvided
val pred_use_bim_as_altpred = pred_use_altpred && !s2_altProvided
val pred_use_bim_as_pred = !s2_provided
val pred_use_bim_as_pred = !s2_provided
val commit_use_provider = updateMeta.provider.valid && !ctr_null(updateMeta.providerCtr)
val commit_use_altpred = updateMeta.provider.valid && ctr_null(updateMeta.providerCtr)
val commit_use_ht_as_altpred = commit_use_altpred && updateMeta.altProvider.valid
val commit_use_provider = updateMeta.provider.valid && !ctr_null(updateMeta.providerCtr)
val commit_use_altpred = updateMeta.provider.valid && ctr_null(updateMeta.providerCtr)
val commit_use_ht_as_altpred = commit_use_altpred && updateMeta.altProvider.valid
val commit_use_bim_as_altpred = commit_use_altpred && !updateMeta.altProvider.valid
val commit_use_bim_as_pred = !updateMeta.provider.valid
val commit_use_bim_as_pred = !updateMeta.provider.valid
for (i <- 0 until ITTageNTables) {
val pred_this_is_provider = s2_provider === i.U
val pred_this_is_altpred = s2_altProvider === i.U
val pred_this_is_provider = s2_provider === i.U
val pred_this_is_altpred = s2_altProvider === i.U
val commit_this_is_provider = updateMeta.provider.bits === i.U
val commit_this_is_altpred = updateMeta.altProvider.bits === i.U
ittage_perf(s"table_${i}_final_provided",
ittage_perf(
s"table_${i}_final_provided",
pred_use_provider && pred_this_is_provider,
commit_use_provider && commit_this_is_provider
)
ittage_perf(s"table_${i}_provided_not_used",
ittage_perf(
s"table_${i}_provided_not_used",
pred_use_altpred && pred_this_is_provider,
commit_use_altpred && commit_this_is_provider
)
ittage_perf(s"table_${i}_alt_provider_as_final_pred",
ittage_perf(
s"table_${i}_alt_provider_as_final_pred",
pred_use_ht_as_altpred && pred_this_is_altpred,
commit_use_ht_as_altpred && commit_this_is_altpred
)
ittage_perf(s"table_${i}_alt_provider_not_used",
ittage_perf(
s"table_${i}_alt_provider_not_used",
pred_use_provider && pred_this_is_altpred,
commit_use_provider && commit_this_is_altpred
)
@ -652,16 +659,20 @@ class ITTage(implicit p: Parameters) extends BaseITTage {
val s2_resps_regs = RegEnable(s2_resps, io.s2_fire(3))
XSDebug("req: v=%d, pc=0x%x\n", io.s0_fire(3), s0_pc_dup(3))
XSDebug("s1_fire:%d, resp: pc=%x\n", io.s1_fire(3), debug_pc_s1)
XSDebug("s2_fireOnLastCycle: resp: pc=%x, target=%x, hit=%b\n",
debug_pc_s2, io.out.s2.getTarget(3), s2_provided)
XSDebug("s2_fireOnLastCycle: resp: pc=%x, target=%x, hit=%b\n", debug_pc_s2, io.out.s2.getTarget(3), s2_provided)
for (i <- 0 until ITTageNTables) {
XSDebug("TageTable(%d): valids:%b, resp_ctrs:%b, resp_us:%b, target:%x\n",
i.U, VecInit(s2_resps_regs(i).valid).asUInt, s2_resps_regs(i).bits.ctr,
s2_resps_regs(i).bits.u, s2_resps_regs(i).bits.target)
XSDebug(
"TageTable(%d): valids:%b, resp_ctrs:%b, resp_us:%b, target:%x\n",
i.U,
VecInit(s2_resps_regs(i).valid).asUInt,
s2_resps_regs(i).bits.ctr,
s2_resps_regs(i).bits.u,
s2_resps_regs(i).bits.target
)
}
}
XSDebug(updateValid, p"pc: ${Hexadecimal(update.pc)}, target: ${Hexadecimal(update.full_target)}\n")
XSDebug(updateValid, updateMeta.toPrintable+p"\n")
XSDebug(updateValid, updateMeta.toPrintable + p"\n")
XSDebug(updateValid, p"correct(${!updateMisPred})\n")
generatePerfEvent()

File diff suppressed because it is too large Load Diff

View File

@ -16,40 +16,42 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.rocket.{RVCDecoder, ExpandedInstruction}
import chisel3.{util, _}
import chisel3._
import chisel3.util
import chisel3.util._
import utils._
import freechips.rocketchip.rocket.ExpandedInstruction
import freechips.rocketchip.rocket.RVCDecoder
import java.lang.reflect.Parameter
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.frontend.icache._
import xiangshan.backend.decode.isa.predecode.PreDecodeInst
import xiangshan.backend.fu.NewCSR.TriggerUtil
import java.lang.reflect.Parameter
import xiangshan.backend.fu.util.SdtrigExt
import xiangshan.frontend.icache._
trait HasPdConst extends HasXSParameter with HasICacheParameters with HasIFUConst{
def isRVC(inst: UInt) = (inst(1,0) =/= 3.U)
def isLink(reg:UInt) = reg === 1.U || reg === 5.U
trait HasPdConst extends HasXSParameter with HasICacheParameters with HasIFUConst {
def isRVC(inst: UInt) = inst(1, 0) =/= 3.U
def isLink(reg: UInt) = reg === 1.U || reg === 5.U
def brInfo(instr: UInt) = {
val brType::Nil = ListLookup(instr, List(BrType.notCFI), PreDecodeInst.brTable)
val rd = Mux(isRVC(instr), instr(12), instr(11,7))
val rs = Mux(isRVC(instr), Mux(brType === BrType.jal, 0.U, instr(11, 7)), instr(19, 15))
val brType :: Nil = ListLookup(instr, List(BrType.notCFI), PreDecodeInst.brTable)
val rd = Mux(isRVC(instr), instr(12), instr(11, 7))
val rs = Mux(isRVC(instr), Mux(brType === BrType.jal, 0.U, instr(11, 7)), instr(19, 15))
val isCall = (brType === BrType.jal && !isRVC(instr) || brType === BrType.jalr) && isLink(rd) // Only for RV64
val isRet = brType === BrType.jalr && isLink(rs) && !isCall
val isRet = brType === BrType.jalr && isLink(rs) && !isCall
List(brType, isCall, isRet)
}
def jal_offset(inst: UInt, rvc: Bool): UInt = {
val rvc_offset = Cat(inst(12), inst(8), inst(10, 9), inst(6), inst(7), inst(2), inst(11), inst(5, 3), 0.U(1.W))
val rvi_offset = Cat(inst(31), inst(19, 12), inst(20), inst(30, 21), 0.U(1.W))
val max_width = rvi_offset.getWidth
val max_width = rvi_offset.getWidth
SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
}
def br_offset(inst: UInt, rvc: Bool): UInt = {
val rvc_offset = Cat(inst(12), inst(6, 5), inst(2), inst(11, 10), inst(4, 3), 0.U(1.W))
val rvi_offset = Cat(inst(31), inst(7), inst(30, 25), inst(11, 8), 0.U(1.W))
val max_width = rvi_offset.getWidth
val max_width = rvi_offset.getWidth
SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
}
@ -57,59 +59,59 @@ trait HasPdConst extends HasXSParameter with HasICacheParameters with HasIFUCons
}
object BrType {
def notCFI = "b00".U
def notCFI = "b00".U
def branch = "b01".U
def jal = "b10".U
def jalr = "b11".U
def apply() = UInt(2.W)
}
object ExcType { //TODO:add exctype
def notExc = "b000".U
object ExcType { // TODO:add exctype
def notExc = "b000".U
def apply() = UInt(3.W)
}
class PreDecodeInfo extends Bundle { // 8 bit
val valid = Bool()
val isRVC = Bool()
val brType = UInt(2.W)
val isCall = Bool()
val isRet = Bool()
//val excType = UInt(3.W)
def isBr = brType === BrType.branch
def isJal = brType === BrType.jal
def isJalr = brType === BrType.jalr
def notCFI = brType === BrType.notCFI
class PreDecodeInfo extends Bundle { // 8 bit
val valid = Bool()
val isRVC = Bool()
val brType = UInt(2.W)
val isCall = Bool()
val isRet = Bool()
// val excType = UInt(3.W)
def isBr = brType === BrType.branch
def isJal = brType === BrType.jal
def isJalr = brType === BrType.jalr
def notCFI = brType === BrType.notCFI
}
class PreDecodeResp(implicit p: Parameters) extends XSBundle with HasPdConst {
val pd = Vec(PredictWidth, new PreDecodeInfo)
val pd = Vec(PredictWidth, new PreDecodeInfo)
val hasHalfValid = Vec(PredictWidth, Bool())
//val expInstr = Vec(PredictWidth, UInt(32.W))
// val expInstr = Vec(PredictWidth, UInt(32.W))
val instr = Vec(PredictWidth, UInt(32.W))
val jumpOffset = Vec(PredictWidth, UInt(XLEN.W))
// val hasLastHalf = Bool()
val triggered = Vec(PredictWidth, TriggerAction())
val triggered = Vec(PredictWidth, TriggerAction())
}
class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst {
val io = IO(new Bundle() {
val in = Input(ValidIO(new IfuToPreDecode))
val in = Input(ValidIO(new IfuToPreDecode))
val out = Output(new PreDecodeResp)
})
val data = io.in.bits.data
val data = io.in.bits.data
// val lastHalfMatch = io.in.lastHalfMatch
val validStart, validEnd = Wire(Vec(PredictWidth, Bool()))
val validStart, validEnd = Wire(Vec(PredictWidth, Bool()))
val h_validStart, h_validEnd = Wire(Vec(PredictWidth, Bool()))
val validStart_half, validEnd_half = Wire(Vec(PredictWidth, Bool()))
val validStart_half, validEnd_half = Wire(Vec(PredictWidth, Bool()))
val h_validStart_half, h_validEnd_half = Wire(Vec(PredictWidth, Bool()))
val validStart_halfPlus1, validEnd_halfPlus1 = Wire(Vec(PredictWidth, Bool()))
val validStart_halfPlus1, validEnd_halfPlus1 = Wire(Vec(PredictWidth, Bool()))
val h_validStart_halfPlus1, h_validEnd_halfPlus1 = Wire(Vec(PredictWidth, Bool()))
val validStart_diff, validEnd_diff = Wire(Vec(PredictWidth, Bool()))
val validStart_diff, validEnd_diff = Wire(Vec(PredictWidth, Bool()))
val h_validStart_diff, h_validEnd_diff = Wire(Vec(PredictWidth, Bool()))
val currentIsRVC = Wire(Vec(PredictWidth, Bool()))
@ -124,108 +126,117 @@ class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
h_validStart_halfPlus1.map(_ := false.B)
h_validEnd_halfPlus1.map(_ := false.B)
val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i+1), data(i))))
else VecInit((0 until PredictWidth).map(i => data(i)))
val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i + 1), data(i))))
else VecInit((0 until PredictWidth).map(i => data(i)))
for (i <- 0 until PredictWidth) {
val inst = WireInit(rawInsts(i))
//val expander = Module(new RVCExpander)
currentIsRVC(i) := isRVC(inst)
val currentPC = io.in.bits.pc(i)
//expander.io.in := inst
val inst = WireInit(rawInsts(i))
// val expander = Module(new RVCExpander)
currentIsRVC(i) := isRVC(inst)
val currentPC = io.in.bits.pc(i)
// expander.io.in := inst
val brType::isCall::isRet::Nil = brInfo(inst)
val jalOffset = jal_offset(inst, currentIsRVC(i))
val brOffset = br_offset(inst, currentIsRVC(i))
val brType :: isCall :: isRet :: Nil = brInfo(inst)
val jalOffset = jal_offset(inst, currentIsRVC(i))
val brOffset = br_offset(inst, currentIsRVC(i))
io.out.hasHalfValid(i) := h_validStart(i)
io.out.hasHalfValid(i) := h_validStart(i)
io.out.triggered(i) := DontCare//VecInit(Seq.fill(10)(false.B))
io.out.triggered(i) := DontCare // VecInit(Seq.fill(10)(false.B))
io.out.pd(i).valid := validStart(i)
io.out.pd(i).isRVC := currentIsRVC(i)
io.out.pd(i).valid := validStart(i)
io.out.pd(i).isRVC := currentIsRVC(i)
// for diff purpose only
io.out.pd(i).brType := brType
io.out.pd(i).isCall := isCall
io.out.pd(i).isRet := isRet
io.out.pd(i).brType := brType
io.out.pd(i).isCall := isCall
io.out.pd(i).isRet := isRet
//io.out.expInstr(i) := expander.io.out.bits
io.out.instr(i) :=inst
io.out.jumpOffset(i) := Mux(io.out.pd(i).isBr, brOffset, jalOffset)
// io.out.expInstr(i) := expander.io.out.bits
io.out.instr(i) := inst
io.out.jumpOffset(i) := Mux(io.out.pd(i).isBr, brOffset, jalOffset)
}
// the first half is always reliable
for (i <- 0 until PredictWidth / 2) {
val lastIsValidEnd = if (i == 0) { true.B } else { validEnd(i-1) || !HasCExtension.B }
validStart(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd(i) := validStart(i) && currentIsRVC(i) || !validStart(i) || !HasCExtension.B
val lastIsValidEnd = if (i == 0) { true.B }
else { validEnd(i - 1) || !HasCExtension.B }
validStart(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd(i) := validStart(i) && currentIsRVC(i) || !validStart(i) || !HasCExtension.B
//prepared for last half match
val h_lastIsValidEnd = if (i == 0) { false.B } else { h_validEnd(i-1) || !HasCExtension.B }
h_validStart(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd(i) := h_validStart(i) && currentIsRVC(i) || !h_validStart(i) || !HasCExtension.B
// prepared for last half match
val h_lastIsValidEnd = if (i == 0) { false.B }
else { h_validEnd(i - 1) || !HasCExtension.B }
h_validStart(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd(i) := h_validStart(i) && currentIsRVC(i) || !h_validStart(i) || !HasCExtension.B
}
for (i <- 0 until PredictWidth) {
val lastIsValidEnd = if (i == 0) { true.B } else { validEnd_diff(i-1) || !HasCExtension.B }
validStart_diff(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_diff(i) := validStart_diff(i) && currentIsRVC(i) || !validStart_diff(i) || !HasCExtension.B
val lastIsValidEnd = if (i == 0) { true.B }
else { validEnd_diff(i - 1) || !HasCExtension.B }
validStart_diff(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_diff(i) := validStart_diff(i) && currentIsRVC(i) || !validStart_diff(i) || !HasCExtension.B
//prepared for last half match
val h_lastIsValidEnd = if (i == 0) { false.B } else { h_validEnd_diff(i-1) || !HasCExtension.B }
h_validStart_diff(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_diff(i) := h_validStart_diff(i) && currentIsRVC(i) || !h_validStart_diff(i) || !HasCExtension.B
// prepared for last half match
val h_lastIsValidEnd = if (i == 0) { false.B }
else { h_validEnd_diff(i - 1) || !HasCExtension.B }
h_validStart_diff(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_diff(i) := h_validStart_diff(i) && currentIsRVC(i) || !h_validStart_diff(i) || !HasCExtension.B
}
// assume PredictWidth / 2 is a valid start
for (i <- PredictWidth / 2 until PredictWidth) {
val lastIsValidEnd = if (i == PredictWidth / 2) { true.B } else { validEnd_half(i-1) || !HasCExtension.B }
validStart_half(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_half(i) := validStart_half(i) && currentIsRVC(i) || !validStart_half(i) || !HasCExtension.B
val lastIsValidEnd = if (i == PredictWidth / 2) { true.B }
else { validEnd_half(i - 1) || !HasCExtension.B }
validStart_half(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_half(i) := validStart_half(i) && currentIsRVC(i) || !validStart_half(i) || !HasCExtension.B
//prepared for last half match
val h_lastIsValidEnd = if (i == PredictWidth / 2) { true.B } else { h_validEnd_half(i-1) || !HasCExtension.B }
h_validStart_half(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_half(i) := h_validStart_half(i) && currentIsRVC(i) || !h_validStart_half(i) || !HasCExtension.B
// prepared for last half match
val h_lastIsValidEnd = if (i == PredictWidth / 2) { true.B }
else { h_validEnd_half(i - 1) || !HasCExtension.B }
h_validStart_half(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_half(i) := h_validStart_half(i) && currentIsRVC(i) || !h_validStart_half(i) || !HasCExtension.B
}
// assume PredictWidth / 2 + 1 is a valid start (and PredictWidth / 2 is last half of RVI)
for (i <- PredictWidth / 2 + 1 until PredictWidth) {
val lastIsValidEnd = if (i == PredictWidth / 2 + 1) { true.B } else { validEnd_halfPlus1(i-1) || !HasCExtension.B }
validStart_halfPlus1(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_halfPlus1(i) := validStart_halfPlus1(i) && currentIsRVC(i) || !validStart_halfPlus1(i) || !HasCExtension.B
val lastIsValidEnd = if (i == PredictWidth / 2 + 1) { true.B }
else { validEnd_halfPlus1(i - 1) || !HasCExtension.B }
validStart_halfPlus1(i) := (lastIsValidEnd || !HasCExtension.B)
validEnd_halfPlus1(i) := validStart_halfPlus1(i) && currentIsRVC(i) || !validStart_halfPlus1(i) || !HasCExtension.B
//prepared for last half match
val h_lastIsValidEnd = if (i == PredictWidth / 2 + 1) { true.B } else { h_validEnd_halfPlus1(i-1) || !HasCExtension.B }
h_validStart_halfPlus1(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_halfPlus1(i) := h_validStart_halfPlus1(i) && currentIsRVC(i) || !h_validStart_halfPlus1(i) || !HasCExtension.B
// prepared for last half match
val h_lastIsValidEnd = if (i == PredictWidth / 2 + 1) { true.B }
else { h_validEnd_halfPlus1(i - 1) || !HasCExtension.B }
h_validStart_halfPlus1(i) := (h_lastIsValidEnd || !HasCExtension.B)
h_validEnd_halfPlus1(i) := h_validStart_halfPlus1(i) && currentIsRVC(i) || !h_validStart_halfPlus1(
i
) || !HasCExtension.B
}
validStart_halfPlus1(PredictWidth / 2) := false.B // could be true but when true we select half, not halfPlus1
validEnd_halfPlus1(PredictWidth / 2) := true.B
validEnd_halfPlus1(PredictWidth / 2) := true.B
// assume h_PredictWidth / 2 is an end
h_validStart_halfPlus1(PredictWidth / 2) := false.B // could be true but when true we select half, not halfPlus1
h_validEnd_halfPlus1(PredictWidth / 2) := true.B
h_validEnd_halfPlus1(PredictWidth / 2) := true.B
// if PredictWidth / 2 - 1 is a valid end, PredictWidth / 2 is a valid start
for (i <- PredictWidth / 2 until PredictWidth) {
validStart(i) := Mux(validEnd(PredictWidth / 2 - 1), validStart_half(i), validStart_halfPlus1(i))
validEnd(i) := Mux(validEnd(PredictWidth / 2 - 1), validEnd_half(i), validEnd_halfPlus1(i))
validStart(i) := Mux(validEnd(PredictWidth / 2 - 1), validStart_half(i), validStart_halfPlus1(i))
validEnd(i) := Mux(validEnd(PredictWidth / 2 - 1), validEnd_half(i), validEnd_halfPlus1(i))
h_validStart(i) := Mux(h_validEnd(PredictWidth / 2 - 1), h_validStart_half(i), h_validStart_halfPlus1(i))
h_validEnd(i) := Mux(h_validEnd(PredictWidth / 2 - 1), h_validEnd_half(i), h_validEnd_halfPlus1(i))
h_validEnd(i) := Mux(h_validEnd(PredictWidth / 2 - 1), h_validEnd_half(i), h_validEnd_halfPlus1(i))
}
val validStartMismatch = Wire(Bool())
val validEndMismatch = Wire(Bool())
val validStartMismatch = Wire(Bool())
val validEndMismatch = Wire(Bool())
val validH_ValidStartMismatch = Wire(Bool())
val validH_ValidEndMismatch = Wire(Bool())
val validH_ValidEndMismatch = Wire(Bool())
validStartMismatch := validStart.zip(validStart_diff).map{case(a,b) => a =/= b}.reduce(_||_)
validEndMismatch := validEnd.zip(validEnd_diff).map{case(a,b) => a =/= b}.reduce(_||_)
validH_ValidStartMismatch := h_validStart.zip(h_validStart_diff).map{case(a,b) => a =/= b}.reduce(_||_)
validH_ValidEndMismatch := h_validEnd.zip(h_validEnd_diff).map{case(a,b) => a =/= b}.reduce(_||_)
validStartMismatch := validStart.zip(validStart_diff).map { case (a, b) => a =/= b }.reduce(_ || _)
validEndMismatch := validEnd.zip(validEnd_diff).map { case (a, b) => a =/= b }.reduce(_ || _)
validH_ValidStartMismatch := h_validStart.zip(h_validStart_diff).map { case (a, b) => a =/= b }.reduce(_ || _)
validH_ValidEndMismatch := h_validEnd.zip(h_validEnd_diff).map { case (a, b) => a =/= b }.reduce(_ || _)
XSError(io.in.valid && validStartMismatch, p"validStart mismatch\n")
XSError(io.in.valid && validEndMismatch, p"validEnd mismatch\n")
@ -235,7 +246,8 @@ class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
// io.out.hasLastHalf := !io.out.pd(PredictWidth - 1).isRVC && io.out.pd(PredictWidth - 1).valid
for (i <- 0 until PredictWidth) {
XSDebug(true.B,
XSDebug(
true.B,
p"instr ${Hexadecimal(io.out.instr(i))}, " +
p"validStart ${Binary(validStart(i))}, " +
p"validEnd ${Binary(validEnd(i))}, " +
@ -248,7 +260,7 @@ class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
}
class IfuToF3PreDecode(implicit p: Parameters) extends XSBundle with HasPdConst {
val instr = Vec(PredictWidth, UInt(32.W))
val instr = Vec(PredictWidth, UInt(32.W))
}
class F3PreDecodeResp(implicit p: Parameters) extends XSBundle with HasPdConst {
@ -256,22 +268,22 @@ class F3PreDecodeResp(implicit p: Parameters) extends XSBundle with HasPdConst {
}
class F3Predecoder(implicit p: Parameters) extends XSModule with HasPdConst {
val io = IO(new Bundle() {
val in = Input(new IfuToF3PreDecode)
val in = Input(new IfuToF3PreDecode)
val out = Output(new F3PreDecodeResp)
})
io.out.pd.zipWithIndex.map{ case (pd,i) =>
pd.valid := DontCare
pd.isRVC := DontCare
io.out.pd.zipWithIndex.map { case (pd, i) =>
pd.valid := DontCare
pd.isRVC := DontCare
pd.brType := brInfo(io.in.instr(i))(0)
pd.isCall := brInfo(io.in.instr(i))(1)
pd.isRet := brInfo(io.in.instr(i))(2)
pd.isRet := brInfo(io.in.instr(i))(2)
}
}
class RVCExpander(implicit p: Parameters) extends XSModule {
val io = IO(new Bundle {
val in = Input(UInt(32.W))
val in = Input(UInt(32.W))
val out = Output(new ExpandedInstruction)
val ill = Output(Bool())
})
@ -294,50 +306,49 @@ class RVCExpander(implicit p: Parameters) extends XSModule {
*/
object FaultType {
def noFault = "b000".U
def jalFault = "b001".U //not CFI taken or invalid instruction taken
def retFault = "b010".U //not CFI taken or invalid instruction taken
def targetFault = "b011".U
def notCFIFault = "b100".U //not CFI taken or invalid instruction taken
def invalidTaken = "b101".U
def apply() = UInt(3.W)
def noFault = "b000".U
def jalFault = "b001".U // not CFI taken or invalid instruction taken
def retFault = "b010".U // not CFI taken or invalid instruction taken
def targetFault = "b011".U
def notCFIFault = "b100".U // not CFI taken or invalid instruction taken
def invalidTaken = "b101".U
def apply() = UInt(3.W)
}
class CheckInfo extends Bundle { // 8 bit
val value = UInt(3.W)
def isjalFault = value === FaultType.jalFault
def isRetFault = value === FaultType.retFault
def istargetFault = value === FaultType.targetFault
def invalidTakenFault = value === FaultType.invalidTaken
def notCFIFault = value === FaultType.notCFIFault
class CheckInfo extends Bundle { // 8 bit
val value = UInt(3.W)
def isjalFault = value === FaultType.jalFault
def isRetFault = value === FaultType.retFault
def istargetFault = value === FaultType.targetFault
def invalidTakenFault = value === FaultType.invalidTaken
def notCFIFault = value === FaultType.notCFIFault
}
class PredCheckerResp(implicit p: Parameters) extends XSBundle with HasPdConst {
//to Ibuffer write port (stage 1)
val stage1Out = new Bundle{
val fixedRange = Vec(PredictWidth, Bool())
val fixedTaken = Vec(PredictWidth, Bool())
// to Ibuffer write port (stage 1)
val stage1Out = new Bundle {
val fixedRange = Vec(PredictWidth, Bool())
val fixedTaken = Vec(PredictWidth, Bool())
}
//to Ftq write back port (stage 2)
val stage2Out = new Bundle{
val fixedTarget = Vec(PredictWidth, UInt(VAddrBits.W))
val jalTarget = Vec(PredictWidth, UInt(VAddrBits.W))
val fixedMissPred = Vec(PredictWidth, Bool())
val faultType = Vec(PredictWidth, new CheckInfo)
// to Ftq write back port (stage 2)
val stage2Out = new Bundle {
val fixedTarget = Vec(PredictWidth, UInt(VAddrBits.W))
val jalTarget = Vec(PredictWidth, UInt(VAddrBits.W))
val fixedMissPred = Vec(PredictWidth, Bool())
val faultType = Vec(PredictWidth, new CheckInfo)
}
}
class PredChecker(implicit p: Parameters) extends XSModule with HasPdConst {
val io = IO( new Bundle{
val in = Input(new IfuToPredChecker)
val io = IO(new Bundle {
val in = Input(new IfuToPredChecker)
val out = Output(new PredCheckerResp)
})
val (takenIdx, predTaken) = (io.in.ftqOffset.bits, io.in.ftqOffset.valid)
val predTarget = (io.in.target)
val (instrRange, instrValid) = (io.in.instrRange, io.in.instrValid)
val (pds, pc, jumpOffset) = (io.in.pds, io.in.pc, io.in.jumpOffset)
val (takenIdx, predTaken) = (io.in.ftqOffset.bits, io.in.ftqOffset.valid)
val predTarget = io.in.target
val (instrRange, instrValid) = (io.in.instrRange, io.in.instrValid)
val (pds, pc, jumpOffset) = (io.in.pds, io.in.pc, io.in.jumpOffset)
val jalFaultVec, retFaultVec, targetFault, notCFITaken, invalidTaken = Wire(Vec(PredictWidth, Bool()))
@ -346,71 +357,104 @@ class PredChecker(implicit p: Parameters) extends XSModule with HasPdConst {
* we first detecct remask fault and then use fixedRange to do second check
**/
//Stage 1: detect remask fault
// Stage 1: detect remask fault
/** first check: remask Fault */
jalFaultVec := VecInit(pds.zipWithIndex.map{case(pd, i) => pd.isJal && instrRange(i) && instrValid(i) && (takenIdx > i.U && predTaken || !predTaken) })
retFaultVec := VecInit(pds.zipWithIndex.map{case(pd, i) => pd.isRet && instrRange(i) && instrValid(i) && (takenIdx > i.U && predTaken || !predTaken) })
val remaskFault = VecInit((0 until PredictWidth).map(i => jalFaultVec(i) || retFaultVec(i)))
val remaskIdx = ParallelPriorityEncoder(remaskFault.asUInt)
val needRemask = ParallelOR(remaskFault)
val fixedRange = instrRange.asUInt & (Fill(PredictWidth, !needRemask) | Fill(PredictWidth, 1.U(1.W)) >> ~remaskIdx)
jalFaultVec := VecInit(pds.zipWithIndex.map { case (pd, i) =>
pd.isJal && instrRange(i) && instrValid(i) && (takenIdx > i.U && predTaken || !predTaken)
})
retFaultVec := VecInit(pds.zipWithIndex.map { case (pd, i) =>
pd.isRet && instrRange(i) && instrValid(i) && (takenIdx > i.U && predTaken || !predTaken)
})
val remaskFault = VecInit((0 until PredictWidth).map(i => jalFaultVec(i) || retFaultVec(i)))
val remaskIdx = ParallelPriorityEncoder(remaskFault.asUInt)
val needRemask = ParallelOR(remaskFault)
val fixedRange = instrRange.asUInt & (Fill(PredictWidth, !needRemask) | Fill(PredictWidth, 1.U(1.W)) >> ~remaskIdx)
io.out.stage1Out.fixedRange := fixedRange.asTypeOf((Vec(PredictWidth, Bool())))
io.out.stage1Out.fixedRange := fixedRange.asTypeOf(Vec(PredictWidth, Bool()))
io.out.stage1Out.fixedTaken := VecInit(pds.zipWithIndex.map{case(pd, i) => instrValid (i) && fixedRange(i) && (pd.isRet || pd.isJal || takenIdx === i.U && predTaken && !pd.notCFI) })
io.out.stage1Out.fixedTaken := VecInit(pds.zipWithIndex.map { case (pd, i) =>
instrValid(i) && fixedRange(i) && (pd.isRet || pd.isJal || takenIdx === i.U && predTaken && !pd.notCFI)
})
/** second check: faulse prediction fault and target fault */
notCFITaken := VecInit(pds.zipWithIndex.map{case(pd, i) => fixedRange(i) && instrValid(i) && i.U === takenIdx && pd.notCFI && predTaken })
invalidTaken := VecInit(pds.zipWithIndex.map{case(pd, i) => fixedRange(i) && !instrValid(i) && i.U === takenIdx && predTaken })
notCFITaken := VecInit(pds.zipWithIndex.map { case (pd, i) =>
fixedRange(i) && instrValid(i) && i.U === takenIdx && pd.notCFI && predTaken
})
invalidTaken := VecInit(pds.zipWithIndex.map { case (pd, i) =>
fixedRange(i) && !instrValid(i) && i.U === takenIdx && predTaken
})
val jumpTargets = VecInit(pds.zipWithIndex.map{case(pd,i) => (pc(i) + jumpOffset(i)).asTypeOf(UInt(VAddrBits.W))})
val seqTargets = VecInit((0 until PredictWidth).map(i => pc(i) + Mux(pds(i).isRVC || !instrValid(i), 2.U, 4.U ) ))
val jumpTargets = VecInit(pds.zipWithIndex.map { case (pd, i) =>
(pc(i) + jumpOffset(i)).asTypeOf(UInt(VAddrBits.W))
})
val seqTargets = VecInit((0 until PredictWidth).map(i => pc(i) + Mux(pds(i).isRVC || !instrValid(i), 2.U, 4.U)))
//Stage 2: detect target fault
// Stage 2: detect target fault
/** target calculation: in the next stage */
val fixedRangeNext = RegEnable(fixedRange, io.in.fire_in)
val instrValidNext = RegEnable(instrValid, io.in.fire_in)
val takenIdxNext = RegEnable(takenIdx, io.in.fire_in)
val predTakenNext = RegEnable(predTaken, io.in.fire_in)
val predTargetNext = RegEnable(predTarget, io.in.fire_in)
val jumpTargetsNext = RegEnable(jumpTargets, io.in.fire_in)
val seqTargetsNext = RegEnable(seqTargets, io.in.fire_in)
val pdsNext = RegEnable(pds, io.in.fire_in)
val jalFaultVecNext = RegEnable(jalFaultVec, io.in.fire_in)
val retFaultVecNext = RegEnable(retFaultVec, io.in.fire_in)
val notCFITakenNext = RegEnable(notCFITaken, io.in.fire_in)
val fixedRangeNext = RegEnable(fixedRange, io.in.fire_in)
val instrValidNext = RegEnable(instrValid, io.in.fire_in)
val takenIdxNext = RegEnable(takenIdx, io.in.fire_in)
val predTakenNext = RegEnable(predTaken, io.in.fire_in)
val predTargetNext = RegEnable(predTarget, io.in.fire_in)
val jumpTargetsNext = RegEnable(jumpTargets, io.in.fire_in)
val seqTargetsNext = RegEnable(seqTargets, io.in.fire_in)
val pdsNext = RegEnable(pds, io.in.fire_in)
val jalFaultVecNext = RegEnable(jalFaultVec, io.in.fire_in)
val retFaultVecNext = RegEnable(retFaultVec, io.in.fire_in)
val notCFITakenNext = RegEnable(notCFITaken, io.in.fire_in)
val invalidTakenNext = RegEnable(invalidTaken, io.in.fire_in)
targetFault := VecInit(pdsNext.zipWithIndex.map{case(pd,i) => fixedRangeNext(i) && instrValidNext(i) && (pd.isJal || pd.isBr) && takenIdxNext === i.U && predTakenNext && (predTargetNext =/= jumpTargetsNext(i))})
targetFault := VecInit(pdsNext.zipWithIndex.map { case (pd, i) =>
fixedRangeNext(i) && instrValidNext(
i
) && (pd.isJal || pd.isBr) && takenIdxNext === i.U && predTakenNext && (predTargetNext =/= jumpTargetsNext(i))
})
io.out.stage2Out.faultType.zipWithIndex.foreach { case (faultType, i) =>
faultType.value := Mux(
jalFaultVecNext(i),
FaultType.jalFault,
Mux(
retFaultVecNext(i),
FaultType.retFault,
Mux(
targetFault(i),
FaultType.targetFault,
Mux(
notCFITakenNext(i),
FaultType.notCFIFault,
Mux(invalidTakenNext(i), FaultType.invalidTaken, FaultType.noFault)
)
)
)
)
}
io.out.stage2Out.faultType.zipWithIndex.foreach{case(faultType, i) => faultType.value := Mux(jalFaultVecNext(i) , FaultType.jalFault ,
Mux(retFaultVecNext(i), FaultType.retFault ,
Mux(targetFault(i), FaultType.targetFault ,
Mux(notCFITakenNext(i) , FaultType.notCFIFault,
Mux(invalidTakenNext(i), FaultType.invalidTaken, FaultType.noFault)))))}
io.out.stage2Out.fixedMissPred.zipWithIndex.foreach{case(missPred, i ) => missPred := jalFaultVecNext(i) || retFaultVecNext(i) || notCFITakenNext(i) || invalidTakenNext(i) || targetFault(i)}
io.out.stage2Out.fixedTarget.zipWithIndex.foreach{case(target, i) => target := Mux(jalFaultVecNext(i) || targetFault(i), jumpTargetsNext(i), seqTargetsNext(i) )}
io.out.stage2Out.jalTarget.zipWithIndex.foreach{case(target, i) => target := jumpTargetsNext(i) }
io.out.stage2Out.fixedMissPred.zipWithIndex.foreach { case (missPred, i) =>
missPred := jalFaultVecNext(i) || retFaultVecNext(i) || notCFITakenNext(i) || invalidTakenNext(i) || targetFault(i)
}
io.out.stage2Out.fixedTarget.zipWithIndex.foreach { case (target, i) =>
target := Mux(jalFaultVecNext(i) || targetFault(i), jumpTargetsNext(i), seqTargetsNext(i))
}
io.out.stage2Out.jalTarget.zipWithIndex.foreach { case (target, i) => target := jumpTargetsNext(i) }
}
class FrontendTrigger(implicit p: Parameters) extends XSModule with SdtrigExt {
val io = IO(new Bundle(){
val io = IO(new Bundle() {
val frontendTrigger = Input(new FrontendTdataDistributeIO)
val triggered = Output(Vec(PredictWidth, TriggerAction()))
val triggered = Output(Vec(PredictWidth, TriggerAction()))
val pds = Input(Vec(PredictWidth, new PreDecodeInfo))
val pc = Input(Vec(PredictWidth, UInt(VAddrBits.W)))
val data = if(HasCExtension) Input(Vec(PredictWidth + 1, UInt(16.W)))
else Input(Vec(PredictWidth, UInt(32.W)))
val pds = Input(Vec(PredictWidth, new PreDecodeInfo))
val pc = Input(Vec(PredictWidth, UInt(VAddrBits.W)))
val data = if (HasCExtension) Input(Vec(PredictWidth + 1, UInt(16.W)))
else Input(Vec(PredictWidth, UInt(32.W)))
})
val data = io.data
val data = io.data
val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i+1), data(i))))
else VecInit((0 until PredictWidth).map(i => data(i)))
val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i + 1), data(i))))
else VecInit((0 until PredictWidth).map(i => data(i)))
val tdataVec = RegInit(VecInit(Seq.fill(TriggerNum)(0.U.asTypeOf(new MatchTriggerIO))))
when(io.frontendTrigger.tUpdate.valid) {
@ -421,28 +465,32 @@ class FrontendTrigger(implicit p: Parameters) extends XSModule with SdtrigExt {
XSDebug(triggerEnableVec.asUInt.orR, "Debug Mode: At least one frontend trigger is enabled\n")
val triggerTimingVec = VecInit(tdataVec.map(_.timing))
val triggerChainVec = VecInit(tdataVec.map(_.chain))
val triggerChainVec = VecInit(tdataVec.map(_.chain))
for (i <- 0 until TriggerNum) { PrintTriggerInfo(triggerEnableVec(i), tdataVec(i)) }
val debugMode = io.frontendTrigger.debugMode
val debugMode = io.frontendTrigger.debugMode
val triggerCanRaiseBpExp = io.frontendTrigger.triggerCanRaiseBpExp
//val triggerHitVec = Wire(Vec(PredictWidth, Vec(TriggerNum, Bool())))
// val triggerHitVec = Wire(Vec(PredictWidth, Vec(TriggerNum, Bool())))
val triggerHitVec = (0 until TriggerNum).map(j =>
TriggerCmpConsecutive(io.pc, tdataVec(j).tdata2, tdataVec(j).matchType, triggerEnableVec(j)).map(
hit => hit && !tdataVec(j).select && !debugMode)
TriggerCmpConsecutive(io.pc, tdataVec(j).tdata2, tdataVec(j).matchType, triggerEnableVec(j)).map(hit =>
hit && !tdataVec(j).select && !debugMode
)
).transpose
for (i <- 0 until PredictWidth) {
val triggerCanFireVec = Wire(Vec(TriggerNum, Bool()))
TriggerCheckCanFire(TriggerNum, triggerCanFireVec, VecInit(triggerHitVec(i)), triggerTimingVec, triggerChainVec)
val actionVec = VecInit(tdataVec.map(_.action))
val actionVec = VecInit(tdataVec.map(_.action))
val triggerAction = Wire(TriggerAction())
TriggerUtil.triggerActionGen(triggerAction, triggerCanFireVec, actionVec, triggerCanRaiseBpExp)
// Priority may select last when no trigger fire.
io.triggered(i) := triggerAction
XSDebug(triggerCanFireVec.asUInt.orR, p"Debug Mode: Predecode Inst No. ${i} has trigger action vec ${triggerCanFireVec.asUInt.orR}\n")
XSDebug(
triggerCanFireVec.asUInt.orR,
p"Debug Mode: Predecode Inst No. ${i} has trigger action vec ${triggerCanFireVec.asUInt.orR}\n"
)
}
}

View File

@ -306,4 +306,4 @@ class RAS(implicit p: Parameters) extends BasePredictor {
generatePerfEvent()
}
*/
*/

View File

@ -16,102 +16,102 @@
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import utility._
import scala.math.min
import org.chipsalliance.cde.config.Parameters
import scala.{Tuple2 => &}
import scala.math.min
import utility._
import utils._
import xiangshan._
trait HasSCParameter extends TageParams {
}
trait HasSCParameter extends TageParams {}
class SCReq(implicit p: Parameters) extends TageReq
abstract class SCBundle(implicit p: Parameters) extends TageBundle with HasSCParameter {}
abstract class SCModule(implicit p: Parameters) extends TageModule with HasSCParameter {}
class SCMeta(val ntables: Int)(implicit p: Parameters) extends XSBundle with HasSCParameter {
val scPreds = Vec(numBr, Bool())
// Suppose ctrbits of all tables are identical
val ctrs = Vec(numBr, Vec(ntables, SInt(SCCtrBits.W)))
}
class SCResp(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle {
val ctrs = Vec(numBr, Vec(2, SInt(ctrBits.W)))
}
class SCUpdate(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle {
val pc = UInt(VAddrBits.W)
val ghist = UInt(HistoryLength.W)
val mask = Vec(numBr, Bool())
val oldCtrs = Vec(numBr, SInt(ctrBits.W))
val pc = UInt(VAddrBits.W)
val ghist = UInt(HistoryLength.W)
val mask = Vec(numBr, Bool())
val oldCtrs = Vec(numBr, SInt(ctrBits.W))
val tagePreds = Vec(numBr, Bool())
val takens = Vec(numBr, Bool())
val takens = Vec(numBr, Bool())
}
class SCTableIO(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle {
val req = Input(Valid(new SCReq))
val resp = Output(new SCResp(ctrBits))
val req = Input(Valid(new SCReq))
val resp = Output(new SCResp(ctrBits))
val update = Input(new SCUpdate(ctrBits))
}
class SCTable(val nRows: Int, val ctrBits: Int, val histLen: Int)(implicit p: Parameters)
extends SCModule with HasFoldedHistory {
extends SCModule with HasFoldedHistory {
val io = IO(new SCTableIO(ctrBits))
// val table = Module(new SRAMTemplate(SInt(ctrBits.W), set=nRows, way=2*TageBanks, shouldReset=true, holdRead=true, singlePort=false))
val table = Module(new SRAMTemplate(SInt(ctrBits.W), set=nRows, way=2*TageBanks, shouldReset=true, holdRead=true, singlePort=false, bypassWrite=true))
val table = Module(new SRAMTemplate(
SInt(ctrBits.W),
set = nRows,
way = 2 * TageBanks,
shouldReset = true,
holdRead = true,
singlePort = false,
bypassWrite = true
))
// def getIdx(hist: UInt, pc: UInt) = {
// (compute_folded_ghist(hist, log2Ceil(nRows)) ^ (pc >> instOffsetBits))(log2Ceil(nRows)-1,0)
// }
val idxFhInfo = (histLen, min(log2Ceil(nRows), histLen))
def getFoldedHistoryInfo = Set(idxFhInfo).filter(_._1 > 0)
def getIdx(pc: UInt, allFh: AllFoldedHistories) = {
def getIdx(pc: UInt, allFh: AllFoldedHistories) =
if (histLen > 0) {
val idx_fh = allFh.getHistWithInfo(idxFhInfo).folded_hist
// require(idx_fh.getWidth == log2Ceil(nRows))
((pc >> instOffsetBits) ^ idx_fh)(log2Ceil(nRows)-1,0)
((pc >> instOffsetBits) ^ idx_fh)(log2Ceil(nRows) - 1, 0)
} else {
(pc >> instOffsetBits)(log2Ceil(nRows) - 1, 0)
}
else {
(pc >> instOffsetBits)(log2Ceil(nRows)-1,0)
}
}
def ctrUpdate(ctr: SInt, cond: Bool): SInt = signedSatUpdate(ctr, ctrBits, cond)
val s0_idx = getIdx(io.req.bits.pc, io.req.bits.folded_hist)
val s1_idx = RegEnable(s0_idx, io.req.valid)
val s1_pc = RegEnable(io.req.bits.pc, io.req.fire)
val s1_pc = RegEnable(io.req.bits.pc, io.req.fire)
val s1_unhashed_idx = s1_pc >> instOffsetBits
table.io.r.req.valid := io.req.valid
table.io.r.req.valid := io.req.valid
table.io.r.req.bits.setIdx := s0_idx
val update_wdata = Wire(Vec(numBr, SInt(ctrBits.W))) // correspond to physical bridx
val update_wdata_packed = VecInit(update_wdata.map(Seq.fill(2)(_)).reduce(_++_))
val updateWayMask = Wire(Vec(2*numBr, Bool())) // correspond to physical bridx
val update_wdata = Wire(Vec(numBr, SInt(ctrBits.W))) // correspond to physical bridx
val update_wdata_packed = VecInit(update_wdata.map(Seq.fill(2)(_)).reduce(_ ++ _))
val updateWayMask = Wire(Vec(2 * numBr, Bool())) // correspond to physical bridx
val update_unhashed_idx = io.update.pc >> instOffsetBits
for (pi <- 0 until numBr) {
updateWayMask(2*pi) := Seq.tabulate(numBr)(li =>
updateWayMask(2 * pi) := Seq.tabulate(numBr)(li =>
io.update.mask(li) && get_phy_br_idx(update_unhashed_idx, li) === pi.U && !io.update.tagePreds(li)
).reduce(_||_)
updateWayMask(2*pi+1) := Seq.tabulate(numBr)(li =>
io.update.mask(li) && get_phy_br_idx(update_unhashed_idx, li) === pi.U && io.update.tagePreds(li)
).reduce(_||_)
).reduce(_ || _)
updateWayMask(2 * pi + 1) := Seq.tabulate(numBr)(li =>
io.update.mask(li) && get_phy_br_idx(update_unhashed_idx, li) === pi.U && io.update.tagePreds(li)
).reduce(_ || _)
}
val update_folded_hist = WireInit(0.U.asTypeOf(new AllFoldedHistories(foldedGHistInfos)))
@ -120,43 +120,49 @@ class SCTable(val nRows: Int, val ctrBits: Int, val histLen: Int)(implicit p: Pa
}
val update_idx = getIdx(io.update.pc, update_folded_hist)
//SCTable dual port SRAM reads and writes to the same address processing
// SCTable dual port SRAM reads and writes to the same address processing
val conflict_buffer_valid = RegInit(false.B)
val conflict_buffer_data = RegInit(0.U.asTypeOf(update_wdata_packed))
val conflict_buffer_idx = RegInit(0.U.asTypeOf(update_idx))
val conflict_buffer_waymask = RegInit(0.U.asTypeOf(updateWayMask))
val write_conflict = update_idx === s0_idx && io.update.mask.reduce(_||_) && io.req.valid
val can_write = (conflict_buffer_idx =/= s0_idx || !io.req.valid) && conflict_buffer_valid
val write_conflict = update_idx === s0_idx && io.update.mask.reduce(_ || _) && io.req.valid
val can_write = (conflict_buffer_idx =/= s0_idx || !io.req.valid) && conflict_buffer_valid
when(write_conflict){
when(write_conflict) {
conflict_buffer_valid := true.B
conflict_buffer_data := update_wdata_packed
conflict_buffer_idx := update_idx
conflict_buffer_waymask := updateWayMask
}
when(can_write){
conflict_buffer_valid := false.B
when(can_write) {
conflict_buffer_valid := false.B
}
//Using buffer data for prediction
// Using buffer data for prediction
val use_conflict_data = conflict_buffer_valid && conflict_buffer_idx === s1_idx
val conflict_data_bypass = conflict_buffer_data.zip(conflict_buffer_waymask).map {case (data, mask) => Mux(mask, data, 0.U.asTypeOf(data))}
val conflict_prediction_data = conflict_data_bypass.sliding(2,2).toSeq.map(VecInit(_))
val per_br_ctrs_unshuffled = table.io.r.resp.data.sliding(2,2).toSeq.map(VecInit(_))
val per_br_ctrs = VecInit((0 until numBr).map(i => Mux1H(
UIntToOH(get_phy_br_idx(s1_unhashed_idx, i), numBr),
per_br_ctrs_unshuffled
)))
val conflict_br_ctrs = VecInit((0 until numBr).map(i => Mux1H(
UIntToOH(get_phy_br_idx(s1_unhashed_idx, i), numBr),
conflict_prediction_data
)))
val conflict_data_bypass = conflict_buffer_data.zip(conflict_buffer_waymask).map { case (data, mask) =>
Mux(mask, data, 0.U.asTypeOf(data))
}
val conflict_prediction_data = conflict_data_bypass.sliding(2, 2).toSeq.map(VecInit(_))
val per_br_ctrs_unshuffled = table.io.r.resp.data.sliding(2, 2).toSeq.map(VecInit(_))
val per_br_ctrs = VecInit((0 until numBr).map(i =>
Mux1H(
UIntToOH(get_phy_br_idx(s1_unhashed_idx, i), numBr),
per_br_ctrs_unshuffled
)
))
val conflict_br_ctrs = VecInit((0 until numBr).map(i =>
Mux1H(
UIntToOH(get_phy_br_idx(s1_unhashed_idx, i), numBr),
conflict_prediction_data
)
))
io.resp.ctrs := Mux(use_conflict_data, conflict_br_ctrs, per_br_ctrs)
table.io.w.apply(
valid = (io.update.mask.reduce(_||_) && !write_conflict) || can_write,
valid = (io.update.mask.reduce(_ || _) && !write_conflict) || can_write,
data = Mux(can_write, conflict_buffer_data, update_wdata_packed),
setIdx = Mux(can_write, conflict_buffer_idx, update_idx),
waymask = Mux(can_write, conflict_buffer_waymask.asUInt, updateWayMask.asUInt)
@ -165,44 +171,49 @@ class SCTable(val nRows: Int, val ctrBits: Int, val histLen: Int)(implicit p: Pa
val wrBypassEntries = 16
// let it corresponds to logical brIdx
val wrbypasses = Seq.fill(numBr)(Module(new WrBypass(SInt(ctrBits.W), wrBypassEntries, log2Ceil(nRows), numWays=2)))
val wrbypasses = Seq.fill(numBr)(Module(new WrBypass(SInt(ctrBits.W), wrBypassEntries, log2Ceil(nRows), numWays = 2)))
for (pi <- 0 until numBr) {
val br_lidx = get_lgc_br_idx(update_unhashed_idx, pi.U(log2Ceil(numBr).W))
val wrbypass_io = Mux1H(UIntToOH(br_lidx, numBr), wrbypasses.map(_.io))
val ctrPos = Mux1H(UIntToOH(br_lidx, numBr), io.update.tagePreds)
val bypass_ctr = wrbypass_io.hit_data(ctrPos)
val previous_ctr = Mux1H(UIntToOH(br_lidx, numBr), io.update.oldCtrs)
val ctrPos = Mux1H(UIntToOH(br_lidx, numBr), io.update.tagePreds)
val bypass_ctr = wrbypass_io.hit_data(ctrPos)
val previous_ctr = Mux1H(UIntToOH(br_lidx, numBr), io.update.oldCtrs)
val hit_and_valid = wrbypass_io.hit && bypass_ctr.valid
val oldCtr = Mux(hit_and_valid, bypass_ctr.bits, previous_ctr)
val taken = Mux1H(UIntToOH(br_lidx, numBr), io.update.takens)
val oldCtr = Mux(hit_and_valid, bypass_ctr.bits, previous_ctr)
val taken = Mux1H(UIntToOH(br_lidx, numBr), io.update.takens)
update_wdata(pi) := ctrUpdate(oldCtr, taken)
}
val per_br_update_wdata_packed = update_wdata_packed.sliding(2,2).map(VecInit(_)).toSeq
val per_br_update_way_mask = updateWayMask.sliding(2,2).map(VecInit(_)).toSeq
val per_br_update_wdata_packed = update_wdata_packed.sliding(2, 2).map(VecInit(_)).toSeq
val per_br_update_way_mask = updateWayMask.sliding(2, 2).map(VecInit(_)).toSeq
for (li <- 0 until numBr) {
val wrbypass = wrbypasses(li)
val br_pidx = get_phy_br_idx(update_unhashed_idx, li)
wrbypass.io.wen := io.update.mask(li)
wrbypass.io.write_idx := update_idx
val br_pidx = get_phy_br_idx(update_unhashed_idx, li)
wrbypass.io.wen := io.update.mask(li)
wrbypass.io.write_idx := update_idx
wrbypass.io.write_data := Mux1H(UIntToOH(br_pidx, numBr), per_br_update_wdata_packed)
wrbypass.io.write_way_mask.map(_ := Mux1H(UIntToOH(br_pidx, numBr), per_br_update_way_mask))
}
val u = io.update
XSDebug(io.req.valid,
XSDebug(
io.req.valid,
p"scTableReq: pc=0x${Hexadecimal(io.req.bits.pc)}, " +
p"s0_idx=${s0_idx}\n")
XSDebug(RegNext(io.req.valid),
p"s0_idx=${s0_idx}\n"
)
XSDebug(
RegNext(io.req.valid),
p"scTableResp: s1_idx=${s1_idx}," +
p"ctr:${io.resp.ctrs}\n")
XSDebug(io.update.mask.reduce(_||_),
p"ctr:${io.resp.ctrs}\n"
)
XSDebug(
io.update.mask.reduce(_ || _),
p"update Table: pc:${Hexadecimal(u.pc)}, " +
p"tageTakens:${u.tagePreds}, taken:${u.takens}, oldCtr:${u.oldCtrs}\n")
p"tageTakens:${u.tagePreds}, taken:${u.takens}, oldCtr:${u.oldCtrs}\n"
)
}
class SCThreshold(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle {
@ -210,18 +221,20 @@ class SCThreshold(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle
def satPos(ctr: UInt = this.ctr) = ctr === ((1.U << ctrBits) - 1.U)
def satNeg(ctr: UInt = this.ctr) = ctr === 0.U
def neutralVal = (1 << (ctrBits - 1)).U
val thres = UInt(8.W)
def initVal = 6.U
def minThres = 6.U
def maxThres = 31.U
val thres = UInt(8.W)
def initVal = 6.U
def minThres = 6.U
def maxThres = 31.U
def update(cause: Bool): SCThreshold = {
val res = Wire(new SCThreshold(this.ctrBits))
val res = Wire(new SCThreshold(this.ctrBits))
val newCtr = satUpdate(this.ctr, this.ctrBits, cause)
val newThres = Mux(res.satPos(newCtr) && this.thres <= maxThres, this.thres + 2.U,
Mux(res.satNeg(newCtr) && this.thres >= minThres, this.thres - 2.U,
this.thres))
val newThres = Mux(
res.satPos(newCtr) && this.thres <= maxThres,
this.thres + 2.U,
Mux(res.satNeg(newCtr) && this.thres >= minThres, this.thres - 2.U, this.thres)
)
res.thres := newThres
res.ctr := Mux(res.satPos(newCtr) || res.satNeg(newCtr), res.neutralVal, newCtr)
res.ctr := Mux(res.satPos(newCtr) || res.satNeg(newCtr), res.neutralVal, newCtr)
// XSDebug(true.B, p"scThres Update: cause${cause} newCtr ${newCtr} newThres ${newThres}\n")
res
}
@ -229,56 +242,55 @@ class SCThreshold(val ctrBits: Int = 6)(implicit p: Parameters) extends SCBundle
object SCThreshold {
def apply(bits: Int)(implicit p: Parameters) = {
val t = Wire(new SCThreshold(ctrBits=bits))
t.ctr := t.neutralVal
val t = Wire(new SCThreshold(ctrBits = bits))
t.ctr := t.neutralVal
t.thres := t.initVal
t
}
}
trait HasSC extends HasSCParameter with HasPerfEvents { this: Tage =>
val update_on_mispred, update_on_unconf = WireInit(0.U.asTypeOf(Vec(TageBanks, Bool())))
var sc_fh_info = Set[FoldedHistoryInfo]()
var sc_fh_info = Set[FoldedHistoryInfo]()
if (EnableSC) {
val scTables = SCTableInfos.map {
case (nRows, ctrBits, histLen) => {
val t = Module(new SCTable(nRows/TageBanks, ctrBits, histLen))
val t = Module(new SCTable(nRows / TageBanks, ctrBits, histLen))
val req = t.io.req
req.valid := io.s0_fire(3)
req.bits.pc := s0_pc_dup(3)
req.valid := io.s0_fire(3)
req.bits.pc := s0_pc_dup(3)
req.bits.folded_hist := io.in.bits.folded_hist(3)
req.bits.ghist := DontCare
if (!EnableSC) {t.io.update := DontCare}
req.bits.ghist := DontCare
if (!EnableSC) { t.io.update := DontCare }
t
}
}
sc_fh_info = scTables.map(_.getFoldedHistoryInfo).reduce(_++_).toSet
sc_fh_info = scTables.map(_.getFoldedHistoryInfo).reduce(_ ++ _).toSet
val scThresholds = List.fill(TageBanks)(RegInit(SCThreshold(5)))
val scThresholds = List.fill(TageBanks)(RegInit(SCThreshold(5)))
val useThresholds = VecInit(scThresholds map (_.thres))
def sign(x: SInt) = x(x.getWidth-1)
def pos(x: SInt) = !sign(x)
def neg(x: SInt) = sign(x)
def sign(x: SInt) = x(x.getWidth - 1)
def pos(x: SInt) = !sign(x)
def neg(x: SInt) = sign(x)
def aboveThreshold(scSum: SInt, tagePvdr: SInt, threshold: UInt): Bool = {
val signedThres = threshold.zext
val totalSum = scSum +& tagePvdr
(scSum > signedThres - tagePvdr) && pos(totalSum) ||
val totalSum = scSum +& tagePvdr
(scSum > signedThres - tagePvdr) && pos(totalSum) ||
(scSum < -signedThres - tagePvdr) && neg(totalSum)
}
val updateThresholds = VecInit(useThresholds map (t => (t << 3) +& 21.U))
val s1_scResps = VecInit(scTables.map(t => t.io.resp))
val scUpdateMask = WireInit(0.U.asTypeOf(Vec(numBr, Vec(SCNTables, Bool()))))
val scUpdateMask = WireInit(0.U.asTypeOf(Vec(numBr, Vec(SCNTables, Bool()))))
val scUpdateTagePreds = Wire(Vec(TageBanks, Bool()))
val scUpdateTakens = Wire(Vec(TageBanks, Bool()))
val scUpdateOldCtrs = Wire(Vec(numBr, Vec(SCNTables, SInt(SCCtrBits.W))))
val scUpdateTakens = Wire(Vec(TageBanks, Bool()))
val scUpdateOldCtrs = Wire(Vec(numBr, Vec(SCNTables, SInt(SCCtrBits.W))))
scUpdateTagePreds := DontCare
scUpdateTakens := DontCare
scUpdateOldCtrs := DontCare
scUpdateTakens := DontCare
scUpdateOldCtrs := DontCare
val updateSCMeta = updateMeta.scMeta.get
@ -292,7 +304,7 @@ trait HasSC extends HasSCParameter with HasPerfEvents { this: Tage =>
// for sc ctrs
def getCentered(ctr: SInt): SInt = Cat(ctr, 1.U(1.W)).asSInt
// for tage ctrs, (2*(ctr-4)+1)*8
def getPvdrCentered(ctr: UInt): SInt = Cat(ctr ^ (1 << (TageCtrBits-1)).U, 1.U(1.W), 0.U(3.W)).asSInt
def getPvdrCentered(ctr: UInt): SInt = Cat(ctr ^ (1 << (TageCtrBits - 1)).U, 1.U(1.W), 0.U(3.W)).asSInt
val scMeta = resp_meta.scMeta.get
scMeta := DontCare
@ -303,38 +315,36 @@ trait HasSC extends HasSCParameter with HasPerfEvents { this: Tage =>
ParallelSingedExpandingAdd(s1_scResps map (r => getCentered(r.ctrs(w)(i)))) // TODO: rewrite with wallace tree
}
)
val s2_scTableSums = RegEnable(s1_scTableSums, io.s1_fire(3))
val s2_scTableSums = RegEnable(s1_scTableSums, io.s1_fire(3))
val s2_tagePrvdCtrCentered = getPvdrCentered(RegEnable(s1_providerResps(w).ctr, io.s1_fire(3)))
val s2_totalSums = s2_scTableSums.map(_ +& s2_tagePrvdCtrCentered)
val s2_sumAboveThresholds = VecInit((0 to 1).map(i => aboveThreshold(s2_scTableSums(i), s2_tagePrvdCtrCentered, useThresholds(w))))
val s2_totalSums = s2_scTableSums.map(_ +& s2_tagePrvdCtrCentered)
val s2_sumAboveThresholds =
VecInit((0 to 1).map(i => aboveThreshold(s2_scTableSums(i), s2_tagePrvdCtrCentered, useThresholds(w))))
val s2_scPreds = VecInit(s2_totalSums.map(_ >= 0.S))
val s2_scResps = VecInit(RegEnable(s1_scResps, io.s1_fire(3)).map(_.ctrs(w)))
val s2_scCtrs = VecInit(s2_scResps.map(_(s2_tageTakens_dup(3)(w).asUInt)))
val s2_scResps = VecInit(RegEnable(s1_scResps, io.s1_fire(3)).map(_.ctrs(w)))
val s2_scCtrs = VecInit(s2_scResps.map(_(s2_tageTakens_dup(3)(w).asUInt)))
val s2_chooseBit = s2_tageTakens_dup(3)(w)
val s2_pred =
Mux(s2_provideds(w) && s2_sumAboveThresholds(s2_chooseBit),
s2_scPreds(s2_chooseBit),
s2_tageTakens_dup(3)(w)
)
Mux(s2_provideds(w) && s2_sumAboveThresholds(s2_chooseBit), s2_scPreds(s2_chooseBit), s2_tageTakens_dup(3)(w))
val s3_disagree = RegEnable(s2_disagree, io.s2_fire(3))
io.out.last_stage_spec_info.sc_disagree.map(_ := s3_disagree)
scMeta.scPreds(w) := RegEnable(s2_scPreds(s2_chooseBit), io.s2_fire(3))
scMeta.ctrs(w) := RegEnable(s2_scCtrs, io.s2_fire(3))
scMeta.scPreds(w) := RegEnable(s2_scPreds(s2_chooseBit), io.s2_fire(3))
scMeta.ctrs(w) := RegEnable(s2_scCtrs, io.s2_fire(3))
when (s2_provideds(w)) {
when(s2_provideds(w)) {
s2_sc_used(w) := true.B
s2_unconf(w) := !s2_sumAboveThresholds(s2_chooseBit)
s2_conf(w) := s2_sumAboveThresholds(s2_chooseBit)
s2_unconf(w) := !s2_sumAboveThresholds(s2_chooseBit)
s2_conf(w) := s2_sumAboveThresholds(s2_chooseBit)
// Use prediction from Statistical Corrector
XSDebug(p"---------tage_bank_${w} provided so that sc used---------\n")
when (s2_sumAboveThresholds(s2_chooseBit)) {
val pred = s2_scPreds(s2_chooseBit)
when(s2_sumAboveThresholds(s2_chooseBit)) {
val pred = s2_scPreds(s2_chooseBit)
val debug_pc = Cat(debug_pc_s2, w.U, 0.U(instOffsetBits.W))
s2_agree(w) := s2_tageTakens_dup(3)(w) === pred
s2_agree(w) := s2_tageTakens_dup(3)(w) === pred
s2_disagree(w) := s2_tageTakens_dup(3)(w) =/= pred
// fit to always-taken condition
// io.out.s2.full_pred.br_taken_mask(w) := pred
@ -342,73 +352,76 @@ trait HasSC extends HasSCParameter with HasPerfEvents { this: Tage =>
}
}
val s3_pred_dup = io.s2_fire.map(f => RegEnable(s2_pred, f))
val s3_pred_dup = io.s2_fire.map(f => RegEnable(s2_pred, f))
val sc_enable_dup = dup(RegNext(io.ctrl.sc_enable))
for (sc_enable & fp & s3_pred <-
sc_enable_dup zip io.out.s3.full_pred zip s3_pred_dup) {
when (sc_enable) {
fp.br_taken_mask(w) := s3_pred
}
for (
sc_enable & fp & s3_pred <-
sc_enable_dup zip io.out.s3.full_pred zip s3_pred_dup
) {
when(sc_enable) {
fp.br_taken_mask(w) := s3_pred
}
}
val updateTageMeta = updateMeta
when (updateValids(w) && updateTageMeta.providers(w).valid) {
val scPred = updateSCMeta.scPreds(w)
val tagePred = updateTageMeta.takens(w)
val taken = update.br_taken_mask(w)
val scOldCtrs = updateSCMeta.ctrs(w)
val pvdrCtr = updateTageMeta.providerResps(w).ctr
val tableSum = ParallelSingedExpandingAdd(scOldCtrs.map(getCentered))
val totalSumAbs = (tableSum +& getPvdrCentered(pvdrCtr)).abs.asUInt
val updateThres = updateThresholds(w)
when(updateValids(w) && updateTageMeta.providers(w).valid) {
val scPred = updateSCMeta.scPreds(w)
val tagePred = updateTageMeta.takens(w)
val taken = update.br_taken_mask(w)
val scOldCtrs = updateSCMeta.ctrs(w)
val pvdrCtr = updateTageMeta.providerResps(w).ctr
val tableSum = ParallelSingedExpandingAdd(scOldCtrs.map(getCentered))
val totalSumAbs = (tableSum +& getPvdrCentered(pvdrCtr)).abs.asUInt
val updateThres = updateThresholds(w)
val sumAboveThreshold = aboveThreshold(tableSum, getPvdrCentered(pvdrCtr), updateThres)
scUpdateTagePreds(w) := tagePred
scUpdateTakens(w) := taken
(scUpdateOldCtrs(w) zip scOldCtrs).foreach{case (t, c) => t := c}
scUpdateTakens(w) := taken
(scUpdateOldCtrs(w) zip scOldCtrs).foreach { case (t, c) => t := c }
update_sc_used(w) := true.B
update_unconf(w) := !sumAboveThreshold
update_conf(w) := sumAboveThreshold
update_agree(w) := scPred === tagePred
update_disagree(w) := scPred =/= tagePred
update_sc_used(w) := true.B
update_unconf(w) := !sumAboveThreshold
update_conf(w) := sumAboveThreshold
update_agree(w) := scPred === tagePred
update_disagree(w) := scPred =/= tagePred
sc_corr_tage_misp(w) := scPred === taken && tagePred =/= taken && update_conf(w)
sc_misp_tage_corr(w) := scPred =/= taken && tagePred === taken && update_conf(w)
val thres = useThresholds(w)
when (scPred =/= tagePred && totalSumAbs >= thres - 4.U && totalSumAbs <= thres - 2.U) {
when(scPred =/= tagePred && totalSumAbs >= thres - 4.U && totalSumAbs <= thres - 2.U) {
val newThres = scThresholds(w).update(scPred =/= taken)
scThresholds(w) := newThres
XSDebug(p"scThres $w update: old ${useThresholds(w)} --> new ${newThres.thres}\n")
}
when (scPred =/= taken || !sumAboveThreshold) {
when(scPred =/= taken || !sumAboveThreshold) {
scUpdateMask(w).foreach(_ := true.B)
XSDebug(tableSum < 0.S,
XSDebug(
tableSum < 0.S,
p"scUpdate: bank(${w}), scPred(${scPred}), tagePred(${tagePred}), " +
p"scSum(-${tableSum.abs}), mispred: sc(${scPred =/= taken}), tage(${updateMisPreds(w)})\n"
p"scSum(-${tableSum.abs}), mispred: sc(${scPred =/= taken}), tage(${updateMisPreds(w)})\n"
)
XSDebug(tableSum >= 0.S,
XSDebug(
tableSum >= 0.S,
p"scUpdate: bank(${w}), scPred(${scPred}), tagePred(${tagePred}), " +
p"scSum(+${tableSum.abs}), mispred: sc(${scPred =/= taken}), tage(${updateMisPreds(w)})\n"
p"scSum(+${tableSum.abs}), mispred: sc(${scPred =/= taken}), tage(${updateMisPreds(w)})\n"
)
XSDebug(p"bank(${w}), update: sc: ${updateSCMeta}\n")
update_on_mispred(w) := scPred =/= taken
update_on_unconf(w) := scPred === taken
update_on_unconf(w) := scPred === taken
}
}
}
val realWens = scUpdateMask.transpose.map(v => v.reduce(_ | _))
for (b <- 0 until TageBanks) {
for (i <- 0 until SCNTables) {
val realWen = realWens(i)
scTables(i).io.update.mask(b) := RegNext(scUpdateMask(b)(i))
scTables(i).io.update.mask(b) := RegNext(scUpdateMask(b)(i))
scTables(i).io.update.tagePreds(b) := RegEnable(scUpdateTagePreds(b), realWen)
scTables(i).io.update.takens(b) := RegEnable(scUpdateTakens(b), realWen)
scTables(i).io.update.oldCtrs(b) := RegEnable(scUpdateOldCtrs(b)(i), realWen)
scTables(i).io.update.pc := RegEnable(update.pc, realWen)
scTables(i).io.update.ghist := RegEnable(io.update.bits.ghist, realWen)
scTables(i).io.update.takens(b) := RegEnable(scUpdateTakens(b), realWen)
scTables(i).io.update.oldCtrs(b) := RegEnable(scUpdateOldCtrs(b)(i), realWen)
scTables(i).io.update.pc := RegEnable(update.pc, realWen)
scTables(i).io.update.ghist := RegEnable(io.update.bits.ghist, realWen)
}
}
@ -428,8 +441,8 @@ trait HasSC extends HasSCParameter with HasPerfEvents { this: Tage =>
override val perfEvents = Seq(
("tage_tht_hit ", PopCount(updateMeta.providers.map(_.valid))),
("sc_update_on_mispred ", PopCount(update_on_mispred) ),
("sc_update_on_unconf ", PopCount(update_on_unconf) ),
("sc_update_on_mispred ", PopCount(update_on_mispred)),
("sc_update_on_unconf ", PopCount(update_on_unconf))
)
generatePerfEvent()
}

File diff suppressed because it is too large Load Diff

View File

@ -15,41 +15,47 @@
***************************************************************************************/
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.cache.mmu.CAMTemplate
class WrBypass[T <: Data](gen: T, val numEntries: Int, val idxWidth: Int,
val numWays: Int = 1, val tagWidth: Int = 0, val extraPort: Option[Boolean] = None)(implicit p: Parameters) extends XSModule {
class WrBypass[T <: Data](
gen: T,
val numEntries: Int,
val idxWidth: Int,
val numWays: Int = 1,
val tagWidth: Int = 0,
val extraPort: Option[Boolean] = None
)(implicit p: Parameters) extends XSModule {
require(numEntries >= 0)
require(idxWidth > 0)
require(numWays >= 1)
require(tagWidth >= 0)
def hasTag = tagWidth > 0
def hasTag = tagWidth > 0
def multipleWays = numWays > 1
val io = IO(new Bundle {
val wen = Input(Bool())
val write_idx = Input(UInt(idxWidth.W))
val write_tag = if (hasTag) Some(Input(UInt(tagWidth.W))) else None
val write_data = Input(Vec(numWays, gen))
val wen = Input(Bool())
val write_idx = Input(UInt(idxWidth.W))
val write_tag = if (hasTag) Some(Input(UInt(tagWidth.W))) else None
val write_data = Input(Vec(numWays, gen))
val write_way_mask = if (multipleWays) Some(Input(Vec(numWays, Bool()))) else None
val conflict_valid = if(extraPort.isDefined) Some(Input(Bool())) else None
val conflict_write_data = if(extraPort.isDefined) Some(Input(Vec(numWays, gen))) else None
val conflict_way_mask = if(extraPort.isDefined) Some(Input(UInt(numBr.W))) else None
val conflict_valid = if (extraPort.isDefined) Some(Input(Bool())) else None
val conflict_write_data = if (extraPort.isDefined) Some(Input(Vec(numWays, gen))) else None
val conflict_way_mask = if (extraPort.isDefined) Some(Input(UInt(numBr.W))) else None
val hit = Output(Bool())
val hit_data = Vec(numWays, Valid(gen))
val has_conflict = if(extraPort.isDefined) Some(Output(Bool())) else None
val update_idx = if(extraPort.isDefined) Some(Output(UInt(idxWidth.W))) else None
val update_data = if(extraPort.isDefined) Some(Output(Vec(numWays, gen))) else None
val update_way_mask = if(extraPort.isDefined) Some(Output(UInt(numBr.W))) else None
val hit = Output(Bool())
val hit_data = Vec(numWays, Valid(gen))
val has_conflict = if (extraPort.isDefined) Some(Output(Bool())) else None
val update_idx = if (extraPort.isDefined) Some(Output(UInt(idxWidth.W))) else None
val update_data = if (extraPort.isDefined) Some(Output(Vec(numWays, gen))) else None
val update_way_mask = if (extraPort.isDefined) Some(Output(UInt(numBr.W))) else None
val conflict_clean = if(extraPort.isDefined) Some(Input(Bool())) else None
val conflict_clean = if (extraPort.isDefined) Some(Input(Bool())) else None
})
class Idx_Tag extends Bundle {
@ -62,16 +68,15 @@ class WrBypass[T <: Data](gen: T, val numEntries: Int, val idxWidth: Int,
}
val idx_tag_cam = Module(new IndexableCAMTemplate(new Idx_Tag, numEntries, 1, isIndexable = extraPort.isDefined))
val data_mem = Mem(numEntries, Vec(numWays, gen))
val data_mem = Mem(numEntries, Vec(numWays, gen))
val valids = RegInit(0.U.asTypeOf(Vec(numEntries, Vec(numWays, Bool()))))
val valids = RegInit(0.U.asTypeOf(Vec(numEntries, Vec(numWays, Bool()))))
val ever_written = RegInit(0.U.asTypeOf(Vec(numEntries, Bool())))
idx_tag_cam.io.r.req(0)(io.write_idx, io.write_tag.getOrElse(0.U))
val hits_oh = idx_tag_cam.io.r.resp(0).zip(ever_written).map {case (h, ew) => h && ew}
val hits_oh = idx_tag_cam.io.r.resp(0).zip(ever_written).map { case (h, ew) => h && ew }
val hit_idx = OHToUInt(hits_oh)
val hit = hits_oh.reduce(_||_)
val hit = hits_oh.reduce(_ || _)
io.hit := hit
for (i <- 0 until numWays) {
@ -83,32 +88,32 @@ class WrBypass[T <: Data](gen: T, val numEntries: Int, val idxWidth: Int,
// Because data_mem can only write to one index
// Implementing a per-way replacer is meaningless
// So here use one replacer for all ways
val replacer = ReplacementPolicy.fromString("plru", numEntries) // numEntries in total
val replacer = ReplacementPolicy.fromString("plru", numEntries) // numEntries in total
val replacer_touch_ways = Wire(Vec(1, Valid(UInt(log2Ceil(numEntries).W)))) // One index at a time
val enq_idx = replacer.way
val full_mask = Fill(numWays, 1.U(1.W)).asTypeOf(Vec(numWays, Bool()))
val update_way_mask = io.write_way_mask.getOrElse(full_mask)
val enq_idx = replacer.way
val full_mask = Fill(numWays, 1.U(1.W)).asTypeOf(Vec(numWays, Bool()))
val update_way_mask = io.write_way_mask.getOrElse(full_mask)
// write data on every request
when (io.wen) {
when(io.wen) {
val data_write_idx = Mux(hit, hit_idx, enq_idx)
data_mem.write(data_write_idx, io.write_data, update_way_mask)
}
replacer_touch_ways(0).valid := io.wen
replacer_touch_ways(0).bits := Mux(hit, hit_idx, enq_idx)
replacer_touch_ways(0).bits := Mux(hit, hit_idx, enq_idx)
replacer.access(replacer_touch_ways)
// update valids
for (i <- 0 until numWays) {
when (io.wen) {
when (hit) {
when (update_way_mask(i)) {
when(io.wen) {
when(hit) {
when(update_way_mask(i)) {
valids(hit_idx)(i) := true.B
}
}.otherwise {
ever_written(enq_idx) := true.B
valids(enq_idx)(i) := false.B
when (update_way_mask(i)) {
valids(enq_idx)(i) := false.B
when(update_way_mask(i)) {
valids(enq_idx)(i) := true.B
}
}
@ -116,39 +121,45 @@ class WrBypass[T <: Data](gen: T, val numEntries: Int, val idxWidth: Int,
}
val enq_en = io.wen && !hit
idx_tag_cam.io.w.valid := enq_en
idx_tag_cam.io.w.valid := enq_en
idx_tag_cam.io.w.bits.index := enq_idx
idx_tag_cam.io.w.bits.data(io.write_idx, io.write_tag.getOrElse(0.U))
//Extra ports are used to handle dual port read/write conflicts
// Extra ports are used to handle dual port read/write conflicts
if (extraPort.isDefined) {
val conflict_flags = RegInit(0.U.asTypeOf(Vec(numEntries, Bool())))
val conflict_flags = RegInit(0.U.asTypeOf(Vec(numEntries, Bool())))
val conflict_way_mask = RegInit(0.U.asTypeOf(io.conflict_way_mask.get))
val conflict_data = RegInit(VecInit(Seq.tabulate(numWays)( i => 0.U.asTypeOf(gen))))
val conflict_idx = OHToUInt(conflict_flags)
val conflict_data = RegInit(VecInit(Seq.tabulate(numWays)(i => 0.U.asTypeOf(gen))))
val conflict_idx = OHToUInt(conflict_flags)
idx_tag_cam.io.ridx.get := conflict_idx
when (io.wen && io.conflict_valid.getOrElse(false.B)) {
when(io.wen && io.conflict_valid.getOrElse(false.B)) {
conflict_flags(Mux(hit, hit_idx, enq_idx)) := true.B
conflict_way_mask := io.conflict_way_mask.get
conflict_data := io.conflict_write_data.get
conflict_way_mask := io.conflict_way_mask.get
conflict_data := io.conflict_write_data.get
}
when (io.conflict_clean.getOrElse(false.B)) {
when(io.conflict_clean.getOrElse(false.B)) {
conflict_flags(conflict_idx) := false.B
}
// for update the cached data
io.has_conflict.get := conflict_flags.reduce(_||_)
io.update_idx.get := idx_tag_cam.io.rdata.get.idx
io.has_conflict.get := conflict_flags.reduce(_ || _)
io.update_idx.get := idx_tag_cam.io.rdata.get.idx
io.update_way_mask.get := conflict_way_mask
io.update_data.foreach(_ := conflict_data)
} else None
XSPerfAccumulate("wrbypass_hit", io.wen && hit)
XSPerfAccumulate("wrbypass_hit", io.wen && hit)
XSPerfAccumulate("wrbypass_miss", io.wen && !hit)
XSDebug(io.wen && hit, p"wrbypass hit entry #${hit_idx}, idx ${io.write_idx}" +
p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n")
XSDebug(io.wen && !hit, p"wrbypass enq entry #${enq_idx}, idx ${io.write_idx}" +
p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n")
XSDebug(
io.wen && hit,
p"wrbypass hit entry #${hit_idx}, idx ${io.write_idx}" +
p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n"
)
XSDebug(
io.wen && !hit,
p"wrbypass enq entry #${enq_idx}, idx ${io.write_idx}" +
p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n"
)
}

View File

@ -15,14 +15,17 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
package xiangshan.frontend.icache
package xiangshan.frontend.icache
import chisel3._
import chisel3.util._
import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp}
import freechips.rocketchip.diplomacy.IdRange
import freechips.rocketchip.diplomacy.LazyModule
import freechips.rocketchip.diplomacy.LazyModuleImp
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.BundleFieldBase
import huancun.{AliasField, PrefetchField}
import huancun.AliasField
import huancun.PrefetchField
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
@ -31,19 +34,18 @@ import xiangshan.cache._
import xiangshan.cache.mmu.TlbRequestIO
import xiangshan.frontend._
class FIFOReg[T <: Data](
val gen: T,
val entries: Int,
val pipe: Boolean = false,
val hasFlush: Boolean = false
val gen: T,
val entries: Int,
val pipe: Boolean = false,
val hasFlush: Boolean = false
) extends Module() {
require(entries > 0, "Queue must have non-negative number of entries")
val io = IO(new Bundle {
val enq = Flipped(DecoupledIO(gen))
val deq = DecoupledIO(gen)
val flush = if (hasFlush) Some(Input(Bool())) else None
val enq = Flipped(DecoupledIO(gen))
val deq = DecoupledIO(gen)
val flush = if (hasFlush) Some(Input(Bool())) else None
})
val flush = io.flush.getOrElse(false.B)
@ -52,7 +54,7 @@ class FIFOReg[T <: Data](
object FIFOPtr {
def apply(f: Bool, v: UInt): FIFOPtr = {
val ptr = Wire(new FIFOPtr)
ptr.flag := f
ptr.flag := f
ptr.value := v
ptr
}
@ -86,6 +88,6 @@ class FIFOReg[T <: Data](
io.deq.valid := !empty
io.enq.ready := !full
if (pipe) {
when(io.deq.ready) { io.enq.ready := true.B }
when(io.deq.ready)(io.enq.ready := true.B)
}
}
}

View File

@ -15,14 +15,17 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
package xiangshan.frontend.icache
package xiangshan.frontend.icache
import chisel3._
import chisel3.util._
import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp}
import freechips.rocketchip.diplomacy.IdRange
import freechips.rocketchip.diplomacy.LazyModule
import freechips.rocketchip.diplomacy.LazyModuleImp
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.BundleFieldBase
import huancun.{AliasField, PrefetchField}
import huancun.AliasField
import huancun.PrefetchField
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
@ -32,64 +35,64 @@ import xiangshan.cache.mmu.TlbRequestIO
import xiangshan.frontend._
case class ICacheParameters(
nSets: Int = 256,
nWays: Int = 4,
rowBits: Int = 64,
nTLBEntries: Int = 32,
tagECC: Option[String] = None,
dataECC: Option[String] = None,
replacer: Option[String] = Some("random"),
PortNumber: Int = 2,
nFetchMshr: Int = 4,
nPrefetchMshr: Int = 10,
nWayLookupSize: Int = 32,
DataCodeUnit: Int = 64,
ICacheDataBanks: Int = 8,
nSets: Int = 256,
nWays: Int = 4,
rowBits: Int = 64,
nTLBEntries: Int = 32,
tagECC: Option[String] = None,
dataECC: Option[String] = None,
replacer: Option[String] = Some("random"),
PortNumber: Int = 2,
nFetchMshr: Int = 4,
nPrefetchMshr: Int = 10,
nWayLookupSize: Int = 32,
DataCodeUnit: Int = 64,
ICacheDataBanks: Int = 8,
ICacheDataSRAMWidth: Int = 66,
// TODO: hard code, need delete
partWayNum: Int = 4,
nMMIOs: Int = 1,
nMMIOs: Int = 1,
blockBytes: Int = 64
)extends L1CacheParameters {
) extends L1CacheParameters {
val setBytes = nSets * blockBytes
val aliasBitsOpt = DCacheParameters().aliasBitsOpt //if(setBytes > pageSize) Some(log2Ceil(setBytes / pageSize)) else None
val aliasBitsOpt =
DCacheParameters().aliasBitsOpt // if(setBytes > pageSize) Some(log2Ceil(setBytes / pageSize)) else None
val reqFields: Seq[BundleFieldBase] = Seq(
PrefetchField(),
ReqSourceField()
) ++ aliasBitsOpt.map(AliasField)
val echoFields: Seq[BundleFieldBase] = Nil
def tagCode: Code = Code.fromString(tagECC)
def dataCode: Code = Code.fromString(dataECC)
def replacement = ReplacementPolicy.fromString(replacer,nWays,nSets)
def tagCode: Code = Code.fromString(tagECC)
def dataCode: Code = Code.fromString(dataECC)
def replacement = ReplacementPolicy.fromString(replacer, nWays, nSets)
}
trait HasICacheParameters extends HasL1CacheParameters with HasInstrMMIOConst with HasIFUConst{
trait HasICacheParameters extends HasL1CacheParameters with HasInstrMMIOConst with HasIFUConst {
val cacheParams = icacheParameters
def ICacheSets = cacheParams.nSets
def ICacheWays = cacheParams.nWays
def PortNumber = cacheParams.PortNumber
def nFetchMshr = cacheParams.nFetchMshr
def nPrefetchMshr = cacheParams.nPrefetchMshr
def nWayLookupSize = cacheParams.nWayLookupSize
def DataCodeUnit = cacheParams.DataCodeUnit
def ICacheDataBanks = cacheParams.ICacheDataBanks
def ICacheDataSRAMWidth = cacheParams.ICacheDataSRAMWidth
def partWayNum = cacheParams.partWayNum
def ICacheSets = cacheParams.nSets
def ICacheWays = cacheParams.nWays
def PortNumber = cacheParams.PortNumber
def nFetchMshr = cacheParams.nFetchMshr
def nPrefetchMshr = cacheParams.nPrefetchMshr
def nWayLookupSize = cacheParams.nWayLookupSize
def DataCodeUnit = cacheParams.DataCodeUnit
def ICacheDataBanks = cacheParams.ICacheDataBanks
def ICacheDataSRAMWidth = cacheParams.ICacheDataSRAMWidth
def partWayNum = cacheParams.partWayNum
def ICacheMetaBits = tagBits // FIXME: unportable: maybe use somemethod to get width
def ICacheMetaCodeBits = 1 // FIXME: unportable: maybe use cacheParams.tagCode.somemethod to get width
def ICacheMetaEntryBits = ICacheMetaBits + ICacheMetaCodeBits
def ICacheMetaBits = tagBits // FIXME: unportable: maybe use somemethod to get width
def ICacheMetaCodeBits = 1 // FIXME: unportable: maybe use cacheParams.tagCode.somemethod to get width
def ICacheMetaEntryBits = ICacheMetaBits + ICacheMetaCodeBits
def ICacheDataBits = blockBits / ICacheDataBanks
def ICacheDataCodeSegs = math.ceil(ICacheDataBits / DataCodeUnit).toInt // split data to segments for ECC checking
def ICacheDataCodeBits = ICacheDataCodeSegs * 1 // FIXME: unportable: maybe use cacheParams.dataCode.somemethod to get width
def ICacheDataEntryBits = ICacheDataBits + ICacheDataCodeBits
def ICacheBankVisitNum = 32 * 8 / ICacheDataBits + 1
def highestIdxBit = log2Ceil(nSets) - 1
def ICacheDataBits = blockBits / ICacheDataBanks
def ICacheDataCodeSegs = math.ceil(ICacheDataBits / DataCodeUnit).toInt // split data to segments for ECC checking
def ICacheDataCodeBits =
ICacheDataCodeSegs * 1 // FIXME: unportable: maybe use cacheParams.dataCode.somemethod to get width
def ICacheDataEntryBits = ICacheDataBits + ICacheDataCodeBits
def ICacheBankVisitNum = 32 * 8 / ICacheDataBits + 1
def highestIdxBit = log2Ceil(nSets) - 1
require((ICacheDataBanks >= 2) && isPow2(ICacheDataBanks))
require(ICacheDataSRAMWidth >= ICacheDataEntryBits)
@ -99,39 +102,36 @@ trait HasICacheParameters extends HasL1CacheParameters with HasInstrMMIOConst wi
def getBits(num: Int) = log2Ceil(num).W
def generatePipeControl(lastFire: Bool, thisFire: Bool, thisFlush: Bool, lastFlush: Bool): Bool = {
val valid = RegInit(false.B)
when(thisFlush) {valid := false.B}
.elsewhen(lastFire && !lastFlush) {valid := true.B}
.elsewhen(thisFire) {valid := false.B}
val valid = RegInit(false.B)
when(thisFlush)(valid := false.B)
.elsewhen(lastFire && !lastFlush)(valid := true.B)
.elsewhen(thisFire)(valid := false.B)
valid
}
def ResultHoldBypass[T<:Data](data: T, valid: Bool): T = {
def ResultHoldBypass[T <: Data](data: T, valid: Bool): T =
Mux(valid, data, RegEnable(data, valid))
}
def ResultHoldBypass[T <: Data](data: T, init: T, valid: Bool): T = {
def ResultHoldBypass[T <: Data](data: T, init: T, valid: Bool): T =
Mux(valid, data, RegEnable(data, init, valid))
}
def holdReleaseLatch(valid: Bool, release: Bool, flush: Bool): Bool ={
def holdReleaseLatch(valid: Bool, release: Bool, flush: Bool): Bool = {
val bit = RegInit(false.B)
when(flush) { bit := false.B }
.elsewhen(valid && !release) { bit := true.B }
.elsewhen(release) { bit := false.B }
when(flush)(bit := false.B)
.elsewhen(valid && !release)(bit := true.B)
.elsewhen(release)(bit := false.B)
bit || valid
}
def blockCounter(block: Bool, flush: Bool, threshold: Int): Bool = {
val counter = RegInit(0.U(log2Up(threshold + 1).W))
when (block) { counter := counter + 1.U }
when (flush) { counter := 0.U}
when(block)(counter := counter + 1.U)
when(flush)(counter := 0.U)
counter > threshold.U
}
def InitQueue[T <: Data](entry: T, size: Int): Vec[T] ={
def InitQueue[T <: Data](entry: T, size: Int): Vec[T] =
return RegInit(VecInit(Seq.fill(size)(0.U.asTypeOf(entry.cloneType))))
}
def encodeMetaECC(meta: UInt): UInt = {
require(meta.getWidth == ICacheMetaBits)
@ -147,33 +147,38 @@ trait HasICacheParameters extends HasL1CacheParameters with HasInstrMMIOConst wi
}
def getBankSel(blkOffset: UInt, valid: Bool = true.B): Vec[UInt] = {
val bankIdxLow = Cat(0.U(1.W), blkOffset) >> log2Ceil(blockBytes/ICacheDataBanks)
val bankIdxHigh = (Cat(0.U(1.W), blkOffset) + 32.U) >> log2Ceil(blockBytes/ICacheDataBanks)
val bankSel = VecInit((0 until ICacheDataBanks * 2).map(i => (i.U >= bankIdxLow) && (i.U <= bankIdxHigh)))
assert(!valid || PopCount(bankSel) === ICacheBankVisitNum.U, "The number of bank visits must be %d, but bankSel=0x%x", ICacheBankVisitNum.U, bankSel.asUInt)
val bankIdxLow = Cat(0.U(1.W), blkOffset) >> log2Ceil(blockBytes / ICacheDataBanks)
val bankIdxHigh = (Cat(0.U(1.W), blkOffset) + 32.U) >> log2Ceil(blockBytes / ICacheDataBanks)
val bankSel = VecInit((0 until ICacheDataBanks * 2).map(i => (i.U >= bankIdxLow) && (i.U <= bankIdxHigh)))
assert(
!valid || PopCount(bankSel) === ICacheBankVisitNum.U,
"The number of bank visits must be %d, but bankSel=0x%x",
ICacheBankVisitNum.U,
bankSel.asUInt
)
bankSel.asTypeOf(UInt((ICacheDataBanks * 2).W)).asTypeOf(Vec(2, UInt(ICacheDataBanks.W)))
}
def getLineSel(blkOffset: UInt)(implicit p: Parameters): Vec[Bool] = {
val bankIdxLow = blkOffset >> log2Ceil(blockBytes/ICacheDataBanks)
val lineSel = VecInit((0 until ICacheDataBanks).map(i => i.U < bankIdxLow))
val bankIdxLow = blkOffset >> log2Ceil(blockBytes / ICacheDataBanks)
val lineSel = VecInit((0 until ICacheDataBanks).map(i => i.U < bankIdxLow))
lineSel
}
def getBlkAddr(addr: UInt) = addr >> blockOffBits
def getPhyTagFromBlk(addr: UInt): UInt = addr >> (pgUntagBits - blockOffBits)
def getIdxFromBlk(addr: UInt) = addr(idxBits - 1, 0)
def getBlkAddr(addr: UInt) = addr >> blockOffBits
def getPhyTagFromBlk(addr: UInt): UInt = addr >> (pgUntagBits - blockOffBits)
def getIdxFromBlk(addr: UInt) = addr(idxBits - 1, 0)
def get_paddr_from_ptag(vaddr: UInt, ptag: UInt) = Cat(ptag, vaddr(pgUntagBits - 1, 0))
}
abstract class ICacheBundle(implicit p: Parameters) extends XSBundle
with HasICacheParameters
with HasICacheParameters
abstract class ICacheModule(implicit p: Parameters) extends XSModule
with HasICacheParameters
with HasICacheParameters
abstract class ICacheArray(implicit p: Parameters) extends XSModule
with HasICacheParameters
with HasICacheParameters
class ICacheMetadata(implicit p: Parameters) extends ICacheBundle {
val tag = UInt(tagBits.W)
@ -187,9 +192,7 @@ object ICacheMetadata {
}
}
class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
{
class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray {
class ICacheMetaEntry(implicit p: Parameters) extends ICacheBundle {
val meta: ICacheMetadata = new ICacheMetadata
val code: UInt = UInt(ICacheMetaCodeBits.W)
@ -214,10 +217,10 @@ class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
val fencei = Input(Bool())
})
val port_0_read_0 = io.read.valid && !io.read.bits.vSetIdx(0)(0)
val port_0_read_1 = io.read.valid && io.read.bits.vSetIdx(0)(0)
val port_1_read_1 = io.read.valid && io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
val port_1_read_0 = io.read.valid && !io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
val port_0_read_0 = io.read.valid && !io.read.bits.vSetIdx(0)(0)
val port_0_read_1 = io.read.valid && io.read.bits.vSetIdx(0)(0)
val port_1_read_1 = io.read.valid && io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
val port_1_read_0 = io.read.valid && !io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
val port_0_read_0_reg = RegEnable(port_0_read_0, 0.U.asTypeOf(port_0_read_0), io.read.fire)
val port_0_read_1_reg = RegEnable(port_0_read_1, 0.U.asTypeOf(port_0_read_1), io.read.fire)
@ -229,54 +232,64 @@ class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
val bank_idx = Seq(bank_0_idx, bank_1_idx)
val write_bank_0 = io.write.valid && !io.write.bits.bankIdx
val write_bank_1 = io.write.valid && io.write.bits.bankIdx
val write_bank_1 = io.write.valid && io.write.bits.bankIdx
val write_meta_bits = ICacheMetaEntry(meta = ICacheMetadata(
tag = io.write.bits.phyTag
))
val write_meta_bits = ICacheMetaEntry(meta =
ICacheMetadata(
tag = io.write.bits.phyTag
)
)
val tagArrays = (0 until 2) map { bank =>
val tagArray = Module(new SRAMTemplate(
new ICacheMetaEntry(),
set=nSets/2,
way=nWays,
set = nSets / 2,
way = nWays,
shouldReset = true,
holdRead = true,
singlePort = true
))
//meta connection
if(bank == 0) {
// meta connection
if (bank == 0) {
tagArray.io.r.req.valid := port_0_read_0 || port_1_read_0
tagArray.io.r.req.bits.apply(setIdx=bank_0_idx(highestIdxBit,1))
tagArray.io.r.req.bits.apply(setIdx = bank_0_idx(highestIdxBit, 1))
tagArray.io.w.req.valid := write_bank_0
tagArray.io.w.req.bits.apply(data=write_meta_bits, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
}
else {
tagArray.io.w.req.bits.apply(
data = write_meta_bits,
setIdx = io.write.bits.virIdx(highestIdxBit, 1),
waymask = io.write.bits.waymask
)
} else {
tagArray.io.r.req.valid := port_0_read_1 || port_1_read_1
tagArray.io.r.req.bits.apply(setIdx=bank_1_idx(highestIdxBit,1))
tagArray.io.r.req.bits.apply(setIdx = bank_1_idx(highestIdxBit, 1))
tagArray.io.w.req.valid := write_bank_1
tagArray.io.w.req.bits.apply(data=write_meta_bits, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
tagArray.io.w.req.bits.apply(
data = write_meta_bits,
setIdx = io.write.bits.virIdx(highestIdxBit, 1),
waymask = io.write.bits.waymask
)
}
tagArray
}
val read_set_idx_next = RegEnable(io.read.bits.vSetIdx, 0.U.asTypeOf(io.read.bits.vSetIdx), io.read.fire)
val valid_array = RegInit(VecInit(Seq.fill(nWays)(0.U(nSets.W))))
val valid_metas = Wire(Vec(PortNumber, Vec(nWays, Bool())))
val valid_array = RegInit(VecInit(Seq.fill(nWays)(0.U(nSets.W))))
val valid_metas = Wire(Vec(PortNumber, Vec(nWays, Bool())))
// valid read
(0 until PortNumber).foreach( i =>
(0 until nWays).foreach( way =>
(0 until PortNumber).foreach(i =>
(0 until nWays).foreach(way =>
valid_metas(i)(way) := valid_array(way)(read_set_idx_next(i))
))
)
)
io.readResp.entryValid := valid_metas
io.read.ready := !io.write.valid && !io.fencei && tagArrays.map(_.io.r.req.ready).reduce(_&&_)
io.read.ready := !io.write.valid && !io.fencei && tagArrays.map(_.io.r.req.ready).reduce(_ && _)
// valid write
val way_num = OHToUInt(io.write.bits.waymask)
when (io.write.valid) {
when(io.write.valid) {
valid_array(way_num) := valid_array(way_num).bitSet(io.write.bits.virIdx, true.B)
}
@ -284,29 +297,27 @@ class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
io.readResp.metas <> DontCare
io.readResp.codes <> DontCare
val readMetaEntries = tagArrays.map{ port =>
port.io.r.resp.asTypeOf(Vec(nWays, new ICacheMetaEntry()))
}
val readMetas = readMetaEntries.map(_.map(_.meta))
val readCodes = readMetaEntries.map(_.map(_.code))
val readMetaEntries = tagArrays.map(port => port.io.r.resp.asTypeOf(Vec(nWays, new ICacheMetaEntry())))
val readMetas = readMetaEntries.map(_.map(_.meta))
val readCodes = readMetaEntries.map(_.map(_.code))
// TEST: force ECC to fail by setting readCodes to 0
if (ICacheForceMetaECCError) {
readCodes.foreach(_.foreach(_ := 0.U))
}
when(port_0_read_0_reg){
when(port_0_read_0_reg) {
io.readResp.metas(0) := readMetas(0)
io.readResp.codes(0) := readCodes(0)
}.elsewhen(port_0_read_1_reg){
}.elsewhen(port_0_read_1_reg) {
io.readResp.metas(0) := readMetas(1)
io.readResp.codes(0) := readCodes(1)
}
when(port_1_read_0_reg){
when(port_1_read_0_reg) {
io.readResp.metas(1) := readMetas(0)
io.readResp.codes(1) := readCodes(0)
}.elsewhen(port_1_read_1_reg){
}.elsewhen(port_1_read_1_reg) {
io.readResp.metas(1) := readMetas(1)
io.readResp.codes(1) := readCodes(1)
}
@ -314,15 +325,14 @@ class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
io.write.ready := true.B // TODO : has bug ? should be !io.cacheOp.req.valid
// fencei logic : reset valid_array
when (io.fencei) {
(0 until nWays).foreach( way =>
when(io.fencei) {
(0 until nWays).foreach(way =>
valid_array(way) := 0.U
)
}
}
class ICacheDataArray(implicit p: Parameters) extends ICacheArray
{
class ICacheDataArray(implicit p: Parameters) extends ICacheArray {
class ICacheDataEntry(implicit p: Parameters) extends ICacheBundle {
val data = UInt(ICacheDataBits.W)
val code = UInt(ICacheDataCodeBits.W)
@ -337,12 +347,14 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
}
}
val io=IO{new Bundle{
val write = Flipped(DecoupledIO(new ICacheDataWriteBundle))
// TODO: fix hard code
val read = Flipped(Vec(4, DecoupledIO(new ICacheReadBundle)))
val readResp = Output(new ICacheDataRespBundle)
}}
val io = IO {
new Bundle {
val write = Flipped(DecoupledIO(new ICacheDataWriteBundle))
// TODO: fix hard code
val read = Flipped(Vec(4, DecoupledIO(new ICacheReadBundle)))
val readResp = Output(new ICacheDataRespBundle)
}
}
/**
******************************************************************************
@ -352,23 +364,26 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
val writeDatas = io.write.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt(ICacheDataBits.W)))
val writeEntries = writeDatas.map(ICacheDataEntry(_).asUInt)
val bankSel = getBankSel(io.read(0).bits.blkOffset, io.read(0).valid)
val lineSel = getLineSel(io.read(0).bits.blkOffset)
val bankSel = getBankSel(io.read(0).bits.blkOffset, io.read(0).valid)
val lineSel = getLineSel(io.read(0).bits.blkOffset)
val waymasks = io.read(0).bits.wayMask
val masks = Wire(Vec(nWays, Vec(ICacheDataBanks, Bool())))
(0 until nWays).foreach{way =>
(0 until ICacheDataBanks).foreach{bank =>
masks(way)(bank) := Mux(lineSel(bank), waymasks(1)(way) && bankSel(1)(bank).asBool,
waymasks(0)(way) && bankSel(0)(bank).asBool)
val masks = Wire(Vec(nWays, Vec(ICacheDataBanks, Bool())))
(0 until nWays).foreach { way =>
(0 until ICacheDataBanks).foreach { bank =>
masks(way)(bank) := Mux(
lineSel(bank),
waymasks(1)(way) && bankSel(1)(bank).asBool,
waymasks(0)(way) && bankSel(0)(bank).asBool
)
}
}
val dataArrays = (0 until nWays).map{ way =>
val dataArrays = (0 until nWays).map { way =>
(0 until ICacheDataBanks).map { bank =>
val sramBank = Module(new SRAMTemplateWithFixedWidth(
UInt(ICacheDataEntryBits.W),
set=nSets,
width=ICacheDataSRAMWidth,
set = nSets,
width = ICacheDataSRAMWidth,
shouldReset = true,
holdRead = true,
singlePort = true
@ -376,14 +391,14 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
// read
sramBank.io.r.req.valid := io.read(bank % 4).valid && masks(way)(bank)
sramBank.io.r.req.bits.apply(setIdx=Mux(lineSel(bank),
io.read(bank % 4).bits.vSetIdx(1),
io.read(bank % 4).bits.vSetIdx(0)))
sramBank.io.r.req.bits.apply(setIdx =
Mux(lineSel(bank), io.read(bank % 4).bits.vSetIdx(1), io.read(bank % 4).bits.vSetIdx(0))
)
// write
sramBank.io.w.req.valid := io.write.valid && io.write.bits.waymask(way).asBool
sramBank.io.w.req.bits.apply(
data = writeEntries(bank),
setIdx = io.write.bits.virIdx,
data = writeEntries(bank),
setIdx = io.write.bits.virIdx,
// waymask is invalid when way of SRAMTemplate <= 1
waymask = 0.U
)
@ -396,13 +411,13 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
* read logic
******************************************************************************
*/
val masksReg = RegEnable(masks, 0.U.asTypeOf(masks), io.read(0).valid)
val readDataWithCode = (0 until ICacheDataBanks).map(bank =>
Mux1H(VecInit(masksReg.map(_(bank))).asTypeOf(UInt(nWays.W)),
dataArrays.map(_(bank).io.r.resp.asUInt)))
val readEntries = readDataWithCode.map(_.asTypeOf(new ICacheDataEntry()))
val readDatas = VecInit(readEntries.map(_.data))
val readCodes = VecInit(readEntries.map(_.code))
val masksReg = RegEnable(masks, 0.U.asTypeOf(masks), io.read(0).valid)
val readDataWithCode = (0 until ICacheDataBanks).map(bank =>
Mux1H(VecInit(masksReg.map(_(bank))).asTypeOf(UInt(nWays.W)), dataArrays.map(_(bank).io.r.resp.asUInt))
)
val readEntries = readDataWithCode.map(_.asTypeOf(new ICacheDataEntry()))
val readDatas = VecInit(readEntries.map(_.data))
val readCodes = VecInit(readEntries.map(_.code))
// TEST: force ECC to fail by setting readCodes to 0
if (ICacheForceDataECCError) {
@ -414,64 +429,69 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
* IO
******************************************************************************
*/
io.readResp.datas := readDatas
io.readResp.codes := readCodes
io.write.ready := true.B
io.read.foreach( _.ready := !io.write.valid)
io.readResp.datas := readDatas
io.readResp.codes := readCodes
io.write.ready := true.B
io.read.foreach(_.ready := !io.write.valid)
}
class ICacheReplacer(implicit p: Parameters) extends ICacheModule {
val io = IO(new Bundle {
val touch = Vec(PortNumber, Flipped(ValidIO(new ReplacerTouch)))
val victim = Flipped(new ReplacerVictim)
val touch = Vec(PortNumber, Flipped(ValidIO(new ReplacerTouch)))
val victim = Flipped(new ReplacerVictim)
})
val replacers = Seq.fill(PortNumber)(ReplacementPolicy.fromString(cacheParams.replacer,nWays,nSets/PortNumber))
val replacers = Seq.fill(PortNumber)(ReplacementPolicy.fromString(cacheParams.replacer, nWays, nSets / PortNumber))
// touch
val touch_sets = Seq.fill(PortNumber)(Wire(Vec(2, UInt(log2Ceil(nSets/2).W))))
val touch_sets = Seq.fill(PortNumber)(Wire(Vec(2, UInt(log2Ceil(nSets / 2).W))))
val touch_ways = Seq.fill(PortNumber)(Wire(Vec(2, Valid(UInt(log2Ceil(nWays).W)))))
(0 until PortNumber).foreach {i =>
touch_sets(i)(0) := Mux(io.touch(i).bits.vSetIdx(0), io.touch(1).bits.vSetIdx(highestIdxBit, 1), io.touch(0).bits.vSetIdx(highestIdxBit, 1))
touch_ways(i)(0).bits := Mux(io.touch(i).bits.vSetIdx(0), io.touch(1).bits.way, io.touch(0).bits.way)
touch_ways(i)(0).valid := Mux(io.touch(i).bits.vSetIdx(0), io.touch(1).valid, io.touch(0).valid)
(0 until PortNumber).foreach { i =>
touch_sets(i)(0) := Mux(
io.touch(i).bits.vSetIdx(0),
io.touch(1).bits.vSetIdx(highestIdxBit, 1),
io.touch(0).bits.vSetIdx(highestIdxBit, 1)
)
touch_ways(i)(0).bits := Mux(io.touch(i).bits.vSetIdx(0), io.touch(1).bits.way, io.touch(0).bits.way)
touch_ways(i)(0).valid := Mux(io.touch(i).bits.vSetIdx(0), io.touch(1).valid, io.touch(0).valid)
}
// victim
io.victim.way := Mux(io.victim.vSetIdx.bits(0),
replacers(1).way(io.victim.vSetIdx.bits(highestIdxBit, 1)),
replacers(0).way(io.victim.vSetIdx.bits(highestIdxBit, 1)))
io.victim.way := Mux(
io.victim.vSetIdx.bits(0),
replacers(1).way(io.victim.vSetIdx.bits(highestIdxBit, 1)),
replacers(0).way(io.victim.vSetIdx.bits(highestIdxBit, 1))
)
// touch the victim in next cycle
val victim_vSetIdx_reg = RegEnable(io.victim.vSetIdx.bits, 0.U.asTypeOf(io.victim.vSetIdx.bits), io.victim.vSetIdx.valid)
val victim_way_reg = RegEnable(io.victim.way, 0.U.asTypeOf(io.victim.way), io.victim.vSetIdx.valid)
(0 until PortNumber).foreach {i =>
touch_sets(i)(1) := victim_vSetIdx_reg(highestIdxBit, 1)
touch_ways(i)(1).bits := victim_way_reg
touch_ways(i)(1).valid := RegNext(io.victim.vSetIdx.valid) && (victim_vSetIdx_reg(0) === i.U)
val victim_vSetIdx_reg =
RegEnable(io.victim.vSetIdx.bits, 0.U.asTypeOf(io.victim.vSetIdx.bits), io.victim.vSetIdx.valid)
val victim_way_reg = RegEnable(io.victim.way, 0.U.asTypeOf(io.victim.way), io.victim.vSetIdx.valid)
(0 until PortNumber).foreach { i =>
touch_sets(i)(1) := victim_vSetIdx_reg(highestIdxBit, 1)
touch_ways(i)(1).bits := victim_way_reg
touch_ways(i)(1).valid := RegNext(io.victim.vSetIdx.valid) && (victim_vSetIdx_reg(0) === i.U)
}
((replacers zip touch_sets) zip touch_ways).map{case ((r, s),w) => r.access(s,w)}
((replacers zip touch_sets) zip touch_ways).map { case ((r, s), w) => r.access(s, w) }
}
class ICacheIO(implicit p: Parameters) extends ICacheBundle
{
val hartId = Input(UInt(hartIdLen.W))
class ICacheIO(implicit p: Parameters) extends ICacheBundle {
val hartId = Input(UInt(hartIdLen.W))
val ftqPrefetch = Flipped(new FtqToPrefetchIO)
val softPrefetch = Vec(backendParams.LduCnt, Flipped(Valid(new SoftIfetchPrefetchBundle)))
val stop = Input(Bool())
val fetch = new ICacheMainPipeBundle
val toIFU = Output(Bool())
val pmp = Vec(2 * PortNumber, new ICachePMPBundle)
val itlb = Vec(PortNumber, new TlbRequestIO)
val perfInfo = Output(new ICachePerfInfo)
val error = ValidIO(new L1CacheErrorInfo)
val stop = Input(Bool())
val fetch = new ICacheMainPipeBundle
val toIFU = Output(Bool())
val pmp = Vec(2 * PortNumber, new ICachePMPBundle)
val itlb = Vec(PortNumber, new TlbRequestIO)
val perfInfo = Output(new ICachePerfInfo)
val error = ValidIO(new L1CacheErrorInfo)
/* CSR control signal */
val csr_pf_enable = Input(Bool())
val csr_pf_enable = Input(Bool())
val csr_parity_enable = Input(Bool())
val fencei = Input(Bool())
val flush = Input(Bool())
val fencei = Input(Bool())
val flush = Input(Bool())
}
class ICache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
@ -480,7 +500,7 @@ class ICache()(implicit p: Parameters) extends LazyModule with HasICacheParamete
val clientParameters = TLMasterPortParameters.v1(
Seq(TLMasterParameters.v1(
name = "icache",
sourceId = IdRange(0, cacheParams.nFetchMshr + cacheParams.nPrefetchMshr + 1),
sourceId = IdRange(0, cacheParams.nFetchMshr + cacheParams.nPrefetchMshr + 1)
)),
requestFields = cacheParams.reqFields,
echoFields = cacheParams.echoFields
@ -495,35 +515,35 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
val io = IO(new ICacheIO)
println("ICache:")
println(" TagECC: " + cacheParams.tagECC)
println(" DataECC: " + cacheParams.dataECC)
println(" ICacheSets: " + cacheParams.nSets)
println(" ICacheWays: " + cacheParams.nWays)
println(" PortNumber: " + cacheParams.PortNumber)
println(" nFetchMshr: " + cacheParams.nFetchMshr)
println(" nPrefetchMshr: " + cacheParams.nPrefetchMshr)
println(" nWayLookupSize: " + cacheParams.nWayLookupSize)
println(" DataCodeUnit: " + cacheParams.DataCodeUnit)
println(" ICacheDataBanks: " + cacheParams.ICacheDataBanks)
println(" ICacheDataSRAMWidth: " + cacheParams.ICacheDataSRAMWidth)
println(" TagECC: " + cacheParams.tagECC)
println(" DataECC: " + cacheParams.dataECC)
println(" ICacheSets: " + cacheParams.nSets)
println(" ICacheWays: " + cacheParams.nWays)
println(" PortNumber: " + cacheParams.PortNumber)
println(" nFetchMshr: " + cacheParams.nFetchMshr)
println(" nPrefetchMshr: " + cacheParams.nPrefetchMshr)
println(" nWayLookupSize: " + cacheParams.nWayLookupSize)
println(" DataCodeUnit: " + cacheParams.DataCodeUnit)
println(" ICacheDataBanks: " + cacheParams.ICacheDataBanks)
println(" ICacheDataSRAMWidth: " + cacheParams.ICacheDataSRAMWidth)
val (bus, edge) = outer.clientNode.out.head
val metaArray = Module(new ICacheMetaArray)
val dataArray = Module(new ICacheDataArray)
val mainPipe = Module(new ICacheMainPipe)
val missUnit = Module(new ICacheMissUnit(edge))
val replacer = Module(new ICacheReplacer)
val prefetcher = Module(new IPrefetchPipe)
val wayLookup = Module(new WayLookup)
val metaArray = Module(new ICacheMetaArray)
val dataArray = Module(new ICacheDataArray)
val mainPipe = Module(new ICacheMainPipe)
val missUnit = Module(new ICacheMissUnit(edge))
val replacer = Module(new ICacheReplacer)
val prefetcher = Module(new IPrefetchPipe)
val wayLookup = Module(new WayLookup)
dataArray.io.write <> missUnit.io.data_write
dataArray.io.read <> mainPipe.io.dataArray.toIData
dataArray.io.write <> missUnit.io.data_write
dataArray.io.read <> mainPipe.io.dataArray.toIData
dataArray.io.readResp <> mainPipe.io.dataArray.fromIData
metaArray.io.fencei := io.fencei
metaArray.io.write <> missUnit.io.meta_write
metaArray.io.read <> prefetcher.io.metaRead.toIMeta
metaArray.io.fencei := io.fencei
metaArray.io.write <> missUnit.io.meta_write
metaArray.io.read <> prefetcher.io.metaRead.toIMeta
metaArray.io.readResp <> prefetcher.io.metaRead.fromIMeta
prefetcher.io.flush := io.flush
@ -533,7 +553,7 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
prefetcher.io.flushFromBpu := io.ftqPrefetch.flushFromBpu
// cache softPrefetch
private val softPrefetchValid = RegInit(false.B)
private val softPrefetch = RegInit(0.U.asTypeOf(new IPrefetchReq))
private val softPrefetch = RegInit(0.U.asTypeOf(new IPrefetchReq))
/* FIXME:
* If there is already a pending softPrefetch request, it will be overwritten.
* Also, if there are multiple softPrefetch requests in the same cycle, only the first one will be accepted.
@ -541,46 +561,46 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
* However, the impact on performance still needs to be assessed.
* Considering that the frequency of prefetch.i may not be high, let's start with a temporary dummy solution.
*/
when (io.softPrefetch.map(_.valid).reduce(_||_)) {
when(io.softPrefetch.map(_.valid).reduce(_ || _)) {
softPrefetchValid := true.B
softPrefetch.fromSoftPrefetch(MuxCase(
0.U.asTypeOf(new SoftIfetchPrefetchBundle),
io.softPrefetch.map(req => (req.valid -> req.bits))
io.softPrefetch.map(req => req.valid -> req.bits)
))
}.elsewhen (prefetcher.io.req.fire) {
}.elsewhen(prefetcher.io.req.fire) {
softPrefetchValid := false.B
}
// pass ftqPrefetch
private val ftqPrefetch = WireInit(0.U.asTypeOf(new IPrefetchReq))
ftqPrefetch.fromFtqICacheInfo(io.ftqPrefetch.req.bits)
// software prefetch has higher priority
prefetcher.io.req.valid := softPrefetchValid || io.ftqPrefetch.req.valid
prefetcher.io.req.bits := Mux(softPrefetchValid, softPrefetch, ftqPrefetch)
prefetcher.io.req.valid := softPrefetchValid || io.ftqPrefetch.req.valid
prefetcher.io.req.bits := Mux(softPrefetchValid, softPrefetch, ftqPrefetch)
io.ftqPrefetch.req.ready := prefetcher.io.req.ready && !softPrefetchValid
missUnit.io.hartId := io.hartId
missUnit.io.fencei := io.fencei
missUnit.io.flush := io.flush
missUnit.io.fetch_req <> mainPipe.io.mshr.req
missUnit.io.prefetch_req <> prefetcher.io.MSHRReq
missUnit.io.mem_grant.valid := false.B
missUnit.io.mem_grant.bits := DontCare
missUnit.io.mem_grant <> bus.d
missUnit.io.hartId := io.hartId
missUnit.io.fencei := io.fencei
missUnit.io.flush := io.flush
missUnit.io.fetch_req <> mainPipe.io.mshr.req
missUnit.io.prefetch_req <> prefetcher.io.MSHRReq
missUnit.io.mem_grant.valid := false.B
missUnit.io.mem_grant.bits := DontCare
missUnit.io.mem_grant <> bus.d
mainPipe.io.flush := io.flush
mainPipe.io.respStall := io.stop
mainPipe.io.csr_parity_enable := io.csr_parity_enable
mainPipe.io.hartId := io.hartId
mainPipe.io.mshr.resp := missUnit.io.fetch_resp
mainPipe.io.fetch.req <> io.fetch.req
mainPipe.io.wayLookupRead <> wayLookup.io.read
mainPipe.io.fetch.req <> io.fetch.req
mainPipe.io.wayLookupRead <> wayLookup.io.read
wayLookup.io.flush := io.flush
wayLookup.io.write <> prefetcher.io.wayLookupWrite
wayLookup.io.update := missUnit.io.fetch_resp
wayLookup.io.flush := io.flush
wayLookup.io.write <> prefetcher.io.wayLookupWrite
wayLookup.io.update := missUnit.io.fetch_resp
replacer.io.touch <> mainPipe.io.touch
replacer.io.victim <> missUnit.io.victim
replacer.io.touch <> mainPipe.io.touch
replacer.io.victim <> missUnit.io.victim
io.pmp(0) <> mainPipe.io.pmp(0)
io.pmp(1) <> mainPipe.io.pmp(1)
@ -590,11 +610,11 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
io.itlb(0) <> prefetcher.io.itlb(0)
io.itlb(1) <> prefetcher.io.itlb(1)
//notify IFU that Icache pipeline is available
io.toIFU := mainPipe.io.fetch.req.ready
// notify IFU that Icache pipeline is available
io.toIFU := mainPipe.io.fetch.req.ready
io.perfInfo := mainPipe.io.perfInfo
io.fetch.resp <> mainPipe.io.fetch.resp
io.fetch.resp <> mainPipe.io.fetch.resp
io.fetch.topdownIcacheMiss := mainPipe.io.fetch.topdownIcacheMiss
io.fetch.topdownItlbMiss := mainPipe.io.fetch.topdownItlbMiss
@ -606,91 +626,104 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
bus.a <> missUnit.io.mem_acquire
//Parity error port
val errors = mainPipe.io.errors
// Parity error port
val errors = mainPipe.io.errors
val errors_valid = errors.map(e => e.valid).reduce(_ | _)
io.error.bits <> RegEnable(Mux1H(errors.map(e => e.valid -> e.bits)), 0.U.asTypeOf(errors(0).bits), errors_valid)
io.error.valid := RegNext(errors_valid, false.B)
XSPerfAccumulate("softPrefetch_drop_not_ready", io.softPrefetch.map(_.valid).reduce(_||_) && softPrefetchValid && !prefetcher.io.req.fire)
XSPerfAccumulate(
"softPrefetch_drop_not_ready",
io.softPrefetch.map(_.valid).reduce(_ || _) && softPrefetchValid && !prefetcher.io.req.fire
)
XSPerfAccumulate("softPrefetch_drop_multi_req", PopCount(io.softPrefetch.map(_.valid)) > 1.U)
XSPerfAccumulate("softPrefetch_block_ftq", softPrefetchValid && io.ftqPrefetch.req.valid)
val perfEvents = Seq(
("icache_miss_cnt ", false.B),
("icache_miss_penalty", BoolStopWatch(start = false.B, stop = false.B || false.B, startHighPriority = true)),
("icache_miss_penalty", BoolStopWatch(start = false.B, stop = false.B || false.B, startHighPriority = true))
)
generatePerfEvent()
}
class ICachePartWayReadBundle[T <: Data](gen: T, pWay: Int)(implicit p: Parameters)
extends ICacheBundle
{
val req = Flipped(Vec(PortNumber, Decoupled(new Bundle{
val ridx = UInt((log2Ceil(nSets) - 1).W)
})))
val resp = Output(new Bundle{
val rdata = Vec(PortNumber,Vec(pWay, gen))
extends ICacheBundle {
val req = Flipped(Vec(
PortNumber,
Decoupled(new Bundle {
val ridx = UInt((log2Ceil(nSets) - 1).W)
})
))
val resp = Output(new Bundle {
val rdata = Vec(PortNumber, Vec(pWay, gen))
})
}
class ICacheWriteBundle[T <: Data](gen: T, pWay: Int)(implicit p: Parameters)
extends ICacheBundle
{
val wdata = gen
val widx = UInt((log2Ceil(nSets) - 1).W)
extends ICacheBundle {
val wdata = gen
val widx = UInt((log2Ceil(nSets) - 1).W)
val wbankidx = Bool()
val wmask = Vec(pWay, Bool())
val wmask = Vec(pWay, Bool())
}
class ICachePartWayArray[T <: Data](gen: T, pWay: Int)(implicit p: Parameters) extends ICacheArray
{
class ICachePartWayArray[T <: Data](gen: T, pWay: Int)(implicit p: Parameters) extends ICacheArray {
//including part way data
val io = IO{new Bundle {
val read = new ICachePartWayReadBundle(gen,pWay)
val write = Flipped(ValidIO(new ICacheWriteBundle(gen, pWay)))
}}
// including part way data
val io = IO {
new Bundle {
val read = new ICachePartWayReadBundle(gen, pWay)
val write = Flipped(ValidIO(new ICacheWriteBundle(gen, pWay)))
}
}
io.read.req.map(_.ready := !io.write.valid)
val srams = (0 until PortNumber) map { bank =>
val sramBank = Module(new SRAMTemplate(
gen,
set=nSets/2,
way=pWay,
set = nSets / 2,
way = pWay,
shouldReset = true,
holdRead = true,
singlePort = true
))
sramBank.io.r.req.valid := io.read.req(bank).valid
sramBank.io.r.req.bits.apply(setIdx= io.read.req(bank).bits.ridx)
sramBank.io.r.req.bits.apply(setIdx = io.read.req(bank).bits.ridx)
if(bank == 0) sramBank.io.w.req.valid := io.write.valid && !io.write.bits.wbankidx
else sramBank.io.w.req.valid := io.write.valid && io.write.bits.wbankidx
sramBank.io.w.req.bits.apply(data=io.write.bits.wdata, setIdx=io.write.bits.widx, waymask=io.write.bits.wmask.asUInt)
if (bank == 0) sramBank.io.w.req.valid := io.write.valid && !io.write.bits.wbankidx
else sramBank.io.w.req.valid := io.write.valid && io.write.bits.wbankidx
sramBank.io.w.req.bits.apply(
data = io.write.bits.wdata,
setIdx = io.write.bits.widx,
waymask = io.write.bits.wmask.asUInt
)
sramBank
}
io.read.req.map(_.ready := !io.write.valid && srams.map(_.io.r.req.ready).reduce(_&&_))
io.read.req.map(_.ready := !io.write.valid && srams.map(_.io.r.req.ready).reduce(_ && _))
io.read.resp.rdata := VecInit(srams.map(bank => bank.io.r.resp.asTypeOf(Vec(pWay,gen))))
io.read.resp.rdata := VecInit(srams.map(bank => bank.io.r.resp.asTypeOf(Vec(pWay, gen))))
}
// Automatically partition the SRAM based on the width of the data and the desired width.
// final SRAM width = width * way
class SRAMTemplateWithFixedWidth[T <: Data]
(
gen: T, set: Int, width: Int, way: Int = 1,
shouldReset: Boolean = false, holdRead: Boolean = false,
singlePort: Boolean = false, bypassWrite: Boolean = false
class SRAMTemplateWithFixedWidth[T <: Data](
gen: T,
set: Int,
width: Int,
way: Int = 1,
shouldReset: Boolean = false,
holdRead: Boolean = false,
singlePort: Boolean = false,
bypassWrite: Boolean = false
) extends Module {
val dataBits = gen.getWidth
val bankNum = math.ceil(dataBits.toDouble / width.toDouble).toInt
val bankNum = math.ceil(dataBits.toDouble / width.toDouble).toInt
val totalBits = bankNum * width
val io = IO(new Bundle {
@ -698,7 +731,7 @@ class SRAMTemplateWithFixedWidth[T <: Data]
val w = Flipped(new SRAMWriteBus(gen, set, way))
})
val wordType = UInt(width.W)
val wordType = UInt(width.W)
val writeDatas = (0 until bankNum).map(bank =>
VecInit((0 until way).map(i =>
io.w.req.bits.data(i).asTypeOf(UInt(totalBits.W)).asTypeOf(Vec(bankNum, wordType))(bank)
@ -708,12 +741,12 @@ class SRAMTemplateWithFixedWidth[T <: Data]
val srams = (0 until bankNum) map { bank =>
val sramBank = Module(new SRAMTemplate(
wordType,
set=set,
way=way,
set = set,
way = way,
shouldReset = shouldReset,
holdRead = holdRead,
singlePort = singlePort,
bypassWrite = bypassWrite,
bypassWrite = bypassWrite
))
// read req
sramBank.io.r.req.valid := io.r.req.valid
@ -729,12 +762,12 @@ class SRAMTemplateWithFixedWidth[T <: Data]
}
io.r.req.ready := !io.w.req.valid
(0 until way).foreach{i =>
(0 until way).foreach { i =>
io.r.resp.data(i) := VecInit((0 until bankNum).map(bank =>
srams(bank).io.r.resp.data(i)
)).asTypeOf(UInt(totalBits.W))(dataBits-1, 0).asTypeOf(gen.cloneType)
srams(bank).io.r.resp.data(i)
)).asTypeOf(UInt(totalBits.W))(dataBits - 1, 0).asTypeOf(gen.cloneType)
}
io.r.req.ready := srams.head.io.r.req.ready
io.w.req.ready := srams.head.io.w.req.ready
}
}

View File

@ -17,46 +17,44 @@
package xiangshan.frontend.icache
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import freechips.rocketchip.tilelink.{ClientMetadata, TLPermissions}
import xiangshan._
import utils._
import freechips.rocketchip.tilelink.ClientMetadata
import freechips.rocketchip.tilelink.TLPermissions
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
class ICacheReadBundle(implicit p: Parameters) extends ICacheBundle
{
val vSetIdx = Vec(2,UInt(log2Ceil(nSets).W))
val wayMask = Vec(2,Vec(nWays, Bool()))
val blkOffset = UInt(log2Ceil(blockBytes).W)
val isDoubleLine = Bool()
class ICacheReadBundle(implicit p: Parameters) extends ICacheBundle {
val vSetIdx = Vec(2, UInt(log2Ceil(nSets).W))
val wayMask = Vec(2, Vec(nWays, Bool()))
val blkOffset = UInt(log2Ceil(blockBytes).W)
val isDoubleLine = Bool()
}
class ICacheMetaWriteBundle(implicit p: Parameters) extends ICacheBundle
{
class ICacheMetaWriteBundle(implicit p: Parameters) extends ICacheBundle {
val virIdx = UInt(idxBits.W)
val phyTag = UInt(tagBits.W)
val waymask = UInt(nWays.W)
val bankIdx = Bool()
def generate(tag:UInt, idx:UInt, waymask:UInt, bankIdx: Bool): Unit = {
def generate(tag: UInt, idx: UInt, waymask: UInt, bankIdx: Bool): Unit = {
this.virIdx := idx
this.phyTag := tag
this.waymask := waymask
this.bankIdx := bankIdx
this.bankIdx := bankIdx
}
}
class ICacheDataWriteBundle(implicit p: Parameters) extends ICacheBundle
{
class ICacheDataWriteBundle(implicit p: Parameters) extends ICacheBundle {
val virIdx = UInt(idxBits.W)
val data = UInt(blockBits.W)
val waymask = UInt(nWays.W)
val bankIdx = Bool()
def generate(data:UInt, idx:UInt, waymask:UInt, bankIdx: Bool): Unit = {
def generate(data: UInt, idx: UInt, waymask: UInt, bankIdx: Bool): Unit = {
this.virIdx := idx
this.data := data
this.waymask := waymask
@ -65,26 +63,23 @@ class ICacheDataWriteBundle(implicit p: Parameters) extends ICacheBundle
}
class ICacheMetaRespBundle(implicit p: Parameters) extends ICacheBundle
{
class ICacheMetaRespBundle(implicit p: Parameters) extends ICacheBundle {
val metas = Vec(PortNumber, Vec(nWays, new ICacheMetadata))
val codes = Vec(PortNumber, Vec(nWays, UInt(ICacheMetaCodeBits.W)))
val entryValid = Vec(PortNumber, Vec(nWays, Bool()))
// for compatibility
def tags = VecInit(metas.map(port => VecInit(port.map( way => way.tag ))))
def tags = VecInit(metas.map(port => VecInit(port.map(way => way.tag))))
}
class ICacheDataRespBundle(implicit p: Parameters) extends ICacheBundle
{
val datas = Vec(ICacheDataBanks, UInt(ICacheDataBits.W))
val codes = Vec(ICacheDataBanks, UInt(ICacheDataCodeBits.W))
class ICacheDataRespBundle(implicit p: Parameters) extends ICacheBundle {
val datas = Vec(ICacheDataBanks, UInt(ICacheDataBits.W))
val codes = Vec(ICacheDataBanks, UInt(ICacheDataCodeBits.W))
}
class ICacheMetaReadBundle(implicit p: Parameters) extends ICacheBundle
{
val req = Flipped(DecoupledIO(new ICacheReadBundle))
val resp = Output(new ICacheMetaRespBundle)
class ICacheMetaReadBundle(implicit p: Parameters) extends ICacheBundle {
val req = Flipped(DecoupledIO(new ICacheReadBundle))
val resp = Output(new ICacheMetaRespBundle)
}
class ReplacerTouch(implicit p: Parameters) extends ICacheBundle {
@ -95,4 +90,4 @@ class ReplacerTouch(implicit p: Parameters) extends ICacheBundle {
class ReplacerVictim(implicit p: Parameters) extends ICacheBundle {
val vSetIdx = ValidIO(UInt(log2Ceil(nSets).W))
val way = Input(UInt(log2Ceil(nWays).W))
}
}

View File

@ -16,132 +16,132 @@
package xiangshan.frontend.icache
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import difftest._
import freechips.rocketchip.tilelink.ClientStates
import xiangshan._
import xiangshan.cache.mmu._
import utils._
import org.chipsalliance.cde.config.Parameters
import utility._
import xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
import xiangshan.frontend.{FtqICacheInfo, FtqToICacheRequestBundle, ExceptionType}
import utils._
import xiangshan._
import xiangshan.backend.fu.PMPReqBundle
import xiangshan.backend.fu.PMPRespBundle
import xiangshan.cache.mmu._
import xiangshan.frontend.ExceptionType
import xiangshan.frontend.FtqICacheInfo
import xiangshan.frontend.FtqToICacheRequestBundle
class ICacheMainPipeReq(implicit p: Parameters) extends ICacheBundle
{
val vaddr = UInt(VAddrBits.W)
class ICacheMainPipeReq(implicit p: Parameters) extends ICacheBundle {
val vaddr = UInt(VAddrBits.W)
def vSetIdx = get_idx(vaddr)
}
class ICacheMainPipeResp(implicit p: Parameters) extends ICacheBundle
{
val vaddr = UInt(VAddrBits.W)
val data = UInt((blockBits).W)
val paddr = UInt(PAddrBits.W)
val gpaddr = UInt(GPAddrBits.W)
val isForVSnonLeafPTE = Bool()
val exception = UInt(ExceptionType.width.W)
val pmp_mmio = Bool()
val itlb_pbmt = UInt(Pbmt.width.W)
class ICacheMainPipeResp(implicit p: Parameters) extends ICacheBundle {
val vaddr = UInt(VAddrBits.W)
val data = UInt(blockBits.W)
val paddr = UInt(PAddrBits.W)
val gpaddr = UInt(GPAddrBits.W)
val isForVSnonLeafPTE = Bool()
val exception = UInt(ExceptionType.width.W)
val pmp_mmio = Bool()
val itlb_pbmt = UInt(Pbmt.width.W)
val exceptionFromBackend = Bool()
}
class ICacheMainPipeBundle(implicit p: Parameters) extends ICacheBundle
{
val req = Flipped(Decoupled(new FtqToICacheRequestBundle))
val resp = Vec(PortNumber, ValidIO(new ICacheMainPipeResp))
class ICacheMainPipeBundle(implicit p: Parameters) extends ICacheBundle {
val req = Flipped(Decoupled(new FtqToICacheRequestBundle))
val resp = Vec(PortNumber, ValidIO(new ICacheMainPipeResp))
val topdownIcacheMiss = Output(Bool())
val topdownItlbMiss = Output(Bool())
val topdownItlbMiss = Output(Bool())
}
class ICacheMetaReqBundle(implicit p: Parameters) extends ICacheBundle{
val toIMeta = DecoupledIO(new ICacheReadBundle)
val fromIMeta = Input(new ICacheMetaRespBundle)
class ICacheMetaReqBundle(implicit p: Parameters) extends ICacheBundle {
val toIMeta = DecoupledIO(new ICacheReadBundle)
val fromIMeta = Input(new ICacheMetaRespBundle)
}
class ICacheDataReqBundle(implicit p: Parameters) extends ICacheBundle{
val toIData = Vec(partWayNum, DecoupledIO(new ICacheReadBundle))
val fromIData = Input(new ICacheDataRespBundle)
class ICacheDataReqBundle(implicit p: Parameters) extends ICacheBundle {
val toIData = Vec(partWayNum, DecoupledIO(new ICacheReadBundle))
val fromIData = Input(new ICacheDataRespBundle)
}
class ICacheMSHRBundle(implicit p: Parameters) extends ICacheBundle{
val req = Decoupled(new ICacheMissReq)
val resp = Flipped(ValidIO(new ICacheMissResp))
class ICacheMSHRBundle(implicit p: Parameters) extends ICacheBundle {
val req = Decoupled(new ICacheMissReq)
val resp = Flipped(ValidIO(new ICacheMissResp))
}
class ICachePMPBundle(implicit p: Parameters) extends ICacheBundle{
class ICachePMPBundle(implicit p: Parameters) extends ICacheBundle {
val req = Valid(new PMPReqBundle())
val resp = Input(new PMPRespBundle())
}
class ICachePerfInfo(implicit p: Parameters) extends ICacheBundle{
val only_0_hit = Bool()
val only_0_miss = Bool()
val hit_0_hit_1 = Bool()
val hit_0_miss_1 = Bool()
val miss_0_hit_1 = Bool()
val miss_0_miss_1 = Bool()
val hit_0_except_1 = Bool()
class ICachePerfInfo(implicit p: Parameters) extends ICacheBundle {
val only_0_hit = Bool()
val only_0_miss = Bool()
val hit_0_hit_1 = Bool()
val hit_0_miss_1 = Bool()
val miss_0_hit_1 = Bool()
val miss_0_miss_1 = Bool()
val hit_0_except_1 = Bool()
val miss_0_except_1 = Bool()
val except_0 = Bool()
val bank_hit = Vec(2,Bool())
val hit = Bool()
val except_0 = Bool()
val bank_hit = Vec(2, Bool())
val hit = Bool()
}
class ICacheMainPipeInterface(implicit p: Parameters) extends ICacheBundle {
val hartId = Input(UInt(hartIdLen.W))
/*** internal interface ***/
val dataArray = new ICacheDataReqBundle
val dataArray = new ICacheDataReqBundle
/** prefetch io */
val touch = Vec(PortNumber,ValidIO(new ReplacerTouch))
val touch = Vec(PortNumber, ValidIO(new ReplacerTouch))
val wayLookupRead = Flipped(DecoupledIO(new WayLookupInfo))
val mshr = new ICacheMSHRBundle
val errors = Output(Vec(PortNumber, ValidIO(new L1CacheErrorInfo)))
val mshr = new ICacheMSHRBundle
val errors = Output(Vec(PortNumber, ValidIO(new L1CacheErrorInfo)))
/*** outside interface ***/
//val fetch = Vec(PortNumber, new ICacheMainPipeBundle)
// val fetch = Vec(PortNumber, new ICacheMainPipeBundle)
/* when ftq.valid is high in T + 1 cycle
* the ftq component must be valid in T cycle
*/
val fetch = new ICacheMainPipeBundle
val pmp = Vec(PortNumber, new ICachePMPBundle)
val respStall = Input(Bool())
val fetch = new ICacheMainPipeBundle
val pmp = Vec(PortNumber, new ICachePMPBundle)
val respStall = Input(Bool())
val csr_parity_enable = Input(Bool())
val flush = Input(Bool())
val flush = Input(Bool())
val perfInfo = Output(new ICachePerfInfo)
}
class ICacheDB(implicit p: Parameters) extends ICacheBundle {
val blk_vaddr = UInt((VAddrBits - blockOffBits).W)
val blk_paddr = UInt((PAddrBits - blockOffBits).W)
val hit = Bool()
val blk_vaddr = UInt((VAddrBits - blockOffBits).W)
val blk_paddr = UInt((PAddrBits - blockOffBits).W)
val hit = Bool()
}
class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
{
class ICacheMainPipe(implicit p: Parameters) extends ICacheModule {
val io = IO(new ICacheMainPipeInterface)
/** Input/Output port */
val (fromFtq, toIFU) = (io.fetch.req, io.fetch.resp)
val (toData, fromData) = (io.dataArray.toIData, io.dataArray.fromIData)
val (toMSHR, fromMSHR) = (io.mshr.req, io.mshr.resp)
val (toPMP, fromPMP) = (io.pmp.map(_.req), io.pmp.map(_.resp))
val fromWayLookup = io.wayLookupRead
val (fromFtq, toIFU) = (io.fetch.req, io.fetch.resp)
val (toData, fromData) = (io.dataArray.toIData, io.dataArray.fromIData)
val (toMSHR, fromMSHR) = (io.mshr.req, io.mshr.resp)
val (toPMP, fromPMP) = (io.pmp.map(_.req), io.pmp.map(_.resp))
val fromWayLookup = io.wayLookupRead
// Statistics on the frequency distribution of FTQ fire interval
val cntFtqFireInterval = RegInit(0.U(32.W))
cntFtqFireInterval := Mux(fromFtq.fire, 1.U, cntFtqFireInterval + 1.U)
XSPerfHistogram("ftq2icache_fire",
cntFtqFireInterval, fromFtq.fire,
1, 300, 1, right_strict = true)
XSPerfHistogram("ftq2icache_fire", cntFtqFireInterval, fromFtq.fire, 1, 300, 1, right_strict = true)
/** pipeline control signal */
val s1_ready, s2_ready = Wire(Bool())
val s0_fire, s1_fire , s2_fire = Wire(Bool())
val s0_flush, s1_flush , s2_flush = Wire(Bool())
val s1_ready, s2_ready = Wire(Bool())
val s0_fire, s1_fire, s2_fire = Wire(Bool())
val s0_flush, s1_flush, s2_flush = Wire(Bool())
/**
******************************************************************************
@ -154,19 +154,20 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
/** s0 control */
// 0,1,2,3 -> dataArray(data); 4 -> mainPipe
// Ftq RegNext Register
val fromFtqReq = fromFtq.bits.pcMemRead
val s0_valid = fromFtq.valid
val s0_req_valid_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i))
val s0_req_vaddr_all = (0 until partWayNum + 1).map(i => VecInit(Seq(fromFtqReq(i).startAddr, fromFtqReq(i).nextlineStart)))
val s0_req_vSetIdx_all = (0 until partWayNum + 1).map(i => VecInit(s0_req_vaddr_all(i).map(get_idx)))
val s0_req_offset_all = (0 until partWayNum + 1).map(i => s0_req_vaddr_all(i)(0)(log2Ceil(blockBytes)-1, 0))
val s0_doubleline_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && fromFtqReq(i).crossCacheline)
val fromFtqReq = fromFtq.bits.pcMemRead
val s0_valid = fromFtq.valid
val s0_req_valid_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i))
val s0_req_vaddr_all =
(0 until partWayNum + 1).map(i => VecInit(Seq(fromFtqReq(i).startAddr, fromFtqReq(i).nextlineStart)))
val s0_req_vSetIdx_all = (0 until partWayNum + 1).map(i => VecInit(s0_req_vaddr_all(i).map(get_idx)))
val s0_req_offset_all = (0 until partWayNum + 1).map(i => s0_req_vaddr_all(i)(0)(log2Ceil(blockBytes) - 1, 0))
val s0_doubleline_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && fromFtqReq(i).crossCacheline)
val s0_req_vaddr = s0_req_vaddr_all.last
val s0_req_vSetIdx = s0_req_vSetIdx_all.last
val s0_doubleline = s0_doubleline_all.last
val s0_req_vaddr = s0_req_vaddr_all.last
val s0_req_vSetIdx = s0_req_vSetIdx_all.last
val s0_doubleline = s0_doubleline_all.last
val s0_ftq_exception = VecInit((0 until PortNumber).map(i => ExceptionType.fromFtq(fromFtq.bits)))
val s0_ftq_exception = VecInit((0 until PortNumber).map(i => ExceptionType.fromFtq(fromFtq.bits)))
val s0_excp_fromBackend = fromFtq.bits.backendIaf || fromFtq.bits.backendIpf || fromFtq.bits.backendIgpf
/**
@ -175,23 +176,29 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
******************************************************************************
*/
fromWayLookup.ready := s0_fire
val s0_waymasks = VecInit(fromWayLookup.bits.waymask.map(_.asTypeOf(Vec(nWays, Bool()))))
val s0_req_ptags = fromWayLookup.bits.ptag
val s0_req_gpaddr = fromWayLookup.bits.gpaddr
val s0_req_isForVSnonLeafPTE = fromWayLookup.bits.isForVSnonLeafPTE
val s0_itlb_exception = fromWayLookup.bits.itlb_exception
val s0_itlb_pbmt = fromWayLookup.bits.itlb_pbmt
val s0_meta_codes = fromWayLookup.bits.meta_codes
val s0_hits = VecInit(fromWayLookup.bits.waymask.map(_.orR))
val s0_waymasks = VecInit(fromWayLookup.bits.waymask.map(_.asTypeOf(Vec(nWays, Bool()))))
val s0_req_ptags = fromWayLookup.bits.ptag
val s0_req_gpaddr = fromWayLookup.bits.gpaddr
val s0_req_isForVSnonLeafPTE = fromWayLookup.bits.isForVSnonLeafPTE
val s0_itlb_exception = fromWayLookup.bits.itlb_exception
val s0_itlb_pbmt = fromWayLookup.bits.itlb_pbmt
val s0_meta_codes = fromWayLookup.bits.meta_codes
val s0_hits = VecInit(fromWayLookup.bits.waymask.map(_.orR))
when(s0_fire){
assert((0 until PortNumber).map(i => s0_req_vSetIdx(i) === fromWayLookup.bits.vSetIdx(i)).reduce(_&&_),
"vSetIdxs from ftq and wayLookup are different! vaddr0=0x%x ftq: vidx0=0x%x vidx1=0x%x wayLookup: vidx0=0x%x vidx1=0x%x",
s0_req_vaddr(0), s0_req_vSetIdx(0), s0_req_vSetIdx(1), fromWayLookup.bits.vSetIdx(0), fromWayLookup.bits.vSetIdx(1))
when(s0_fire) {
assert(
(0 until PortNumber).map(i => s0_req_vSetIdx(i) === fromWayLookup.bits.vSetIdx(i)).reduce(_ && _),
"vSetIdxs from ftq and wayLookup are different! vaddr0=0x%x ftq: vidx0=0x%x vidx1=0x%x wayLookup: vidx0=0x%x vidx1=0x%x",
s0_req_vaddr(0),
s0_req_vSetIdx(0),
s0_req_vSetIdx(1),
fromWayLookup.bits.vSetIdx(0),
fromWayLookup.bits.vSetIdx(1)
)
}
val s0_exception_out = ExceptionType.merge(
s0_ftq_exception, // backend-requested exception has the highest priority
s0_ftq_exception, // backend-requested exception has the highest priority
s0_itlb_exception
)
@ -200,7 +207,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* data SRAM request
******************************************************************************
*/
for(i <- 0 until partWayNum) {
for (i <- 0 until partWayNum) {
toData(i).valid := s0_req_valid_all(i)
toData(i).bits.isDoubleLine := s0_doubleline_all(i)
toData(i).bits.vSetIdx := s0_req_vSetIdx_all(i)
@ -209,8 +216,8 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
}
val s0_can_go = toData.last.ready && fromWayLookup.valid && s1_ready
s0_flush := io.flush
s0_fire := s0_valid && s0_can_go && !s0_flush
s0_flush := io.flush
s0_fire := s0_valid && s0_can_go && !s0_flush
fromFtq.ready := s0_can_go
@ -224,28 +231,28 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
*/
val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = s1_flush, lastFlush = false.B)
val s1_req_vaddr = RegEnable(s0_req_vaddr, 0.U.asTypeOf(s0_req_vaddr), s0_fire)
val s1_req_ptags = RegEnable(s0_req_ptags, 0.U.asTypeOf(s0_req_ptags), s0_fire)
val s1_req_gpaddr = RegEnable(s0_req_gpaddr, 0.U.asTypeOf(s0_req_gpaddr), s0_fire)
val s1_req_isForVSnonLeafPTE = RegEnable(s0_req_isForVSnonLeafPTE, 0.U.asTypeOf(s0_req_isForVSnonLeafPTE), s0_fire)
val s1_doubleline = RegEnable(s0_doubleline, 0.U.asTypeOf(s0_doubleline), s0_fire)
val s1_SRAMhits = RegEnable(s0_hits, 0.U.asTypeOf(s0_hits), s0_fire)
val s1_itlb_exception = RegEnable(s0_exception_out, 0.U.asTypeOf(s0_exception_out), s0_fire)
val s1_excp_fromBackend = RegEnable(s0_excp_fromBackend, false.B, s0_fire)
val s1_itlb_pbmt = RegEnable(s0_itlb_pbmt, 0.U.asTypeOf(s0_itlb_pbmt), s0_fire)
val s1_waymasks = RegEnable(s0_waymasks, 0.U.asTypeOf(s0_waymasks), s0_fire)
val s1_meta_codes = RegEnable(s0_meta_codes, 0.U.asTypeOf(s0_meta_codes), s0_fire)
val s1_req_vaddr = RegEnable(s0_req_vaddr, 0.U.asTypeOf(s0_req_vaddr), s0_fire)
val s1_req_ptags = RegEnable(s0_req_ptags, 0.U.asTypeOf(s0_req_ptags), s0_fire)
val s1_req_gpaddr = RegEnable(s0_req_gpaddr, 0.U.asTypeOf(s0_req_gpaddr), s0_fire)
val s1_req_isForVSnonLeafPTE = RegEnable(s0_req_isForVSnonLeafPTE, 0.U.asTypeOf(s0_req_isForVSnonLeafPTE), s0_fire)
val s1_doubleline = RegEnable(s0_doubleline, 0.U.asTypeOf(s0_doubleline), s0_fire)
val s1_SRAMhits = RegEnable(s0_hits, 0.U.asTypeOf(s0_hits), s0_fire)
val s1_itlb_exception = RegEnable(s0_exception_out, 0.U.asTypeOf(s0_exception_out), s0_fire)
val s1_excp_fromBackend = RegEnable(s0_excp_fromBackend, false.B, s0_fire)
val s1_itlb_pbmt = RegEnable(s0_itlb_pbmt, 0.U.asTypeOf(s0_itlb_pbmt), s0_fire)
val s1_waymasks = RegEnable(s0_waymasks, 0.U.asTypeOf(s0_waymasks), s0_fire)
val s1_meta_codes = RegEnable(s0_meta_codes, 0.U.asTypeOf(s0_meta_codes), s0_fire)
val s1_req_vSetIdx = s1_req_vaddr.map(get_idx)
val s1_req_paddr = s1_req_vaddr.zip(s1_req_ptags).map{case(vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag)}
val s1_req_offset = s1_req_vaddr(0)(log2Ceil(blockBytes)-1, 0)
val s1_req_vSetIdx = s1_req_vaddr.map(get_idx)
val s1_req_paddr = s1_req_vaddr.zip(s1_req_ptags).map { case (vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag) }
val s1_req_offset = s1_req_vaddr(0)(log2Ceil(blockBytes) - 1, 0)
// do metaArray ECC check
val s1_meta_corrupt = VecInit((s1_req_ptags zip s1_meta_codes zip s1_waymasks).map{ case ((meta, code), waymask) =>
val s1_meta_corrupt = VecInit((s1_req_ptags zip s1_meta_codes zip s1_waymasks).map { case ((meta, code), waymask) =>
val hit_num = PopCount(waymask)
// NOTE: if not hit, encodeMetaECC(meta) =/= code can also be true, but we don't care about it
(encodeMetaECC(meta) =/= code && hit_num === 1.U) || // hit one way, but parity code does not match, ECC failure
hit_num > 1.U // hit multi way, must be a ECC failure
(encodeMetaECC(meta) =/= code && hit_num === 1.U) || // hit one way, but parity code does not match, ECC failure
hit_num > 1.U // hit multi way, must be a ECC failure
})
/**
@ -253,9 +260,9 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* update replacement status register
******************************************************************************
*/
(0 until PortNumber).foreach{ i =>
io.touch(i).bits.vSetIdx := s1_req_vSetIdx(i)
io.touch(i).bits.way := OHToUInt(s1_waymasks(i))
(0 until PortNumber).foreach { i =>
io.touch(i).bits.vSetIdx := s1_req_vSetIdx(i)
io.touch(i).bits.way := OHToUInt(s1_waymasks(i))
}
io.touch(0).valid := RegNext(s0_fire) && s1_SRAMhits(0)
io.touch(1).valid := RegNext(s0_fire) && s1_SRAMhits(1) && s1_doubleline
@ -269,7 +276,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
// if itlb has exception, paddr can be invalid, therefore pmp check can be skipped
p.valid := s1_valid // && s1_itlb_exception === ExceptionType.none
p.bits.addr := s1_req_paddr(i)
p.bits.size := 3.U // TODO
p.bits.size := 3.U // TODO
p.bits.cmd := TlbCmd.exec
}
val s1_pmp_exception = VecInit(fromPMP.map(ExceptionType.fromPMPResp))
@ -292,21 +299,27 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* select data from MSHR, SRAM
******************************************************************************
*/
val s1_MSHR_match = VecInit((0 until PortNumber).map(i => (s1_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) &&
(s1_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
fromMSHR.valid && !fromMSHR.bits.corrupt))
val s1_MSHR_hits = Seq(s1_valid && s1_MSHR_match(0),
s1_valid && (s1_MSHR_match(1) && s1_doubleline))
val s1_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits/ICacheDataBanks).W)))
val s1_MSHR_match = VecInit((0 until PortNumber).map(i =>
(s1_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) &&
(s1_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
fromMSHR.valid && !fromMSHR.bits.corrupt
))
val s1_MSHR_hits = Seq(s1_valid && s1_MSHR_match(0), s1_valid && (s1_MSHR_match(1) && s1_doubleline))
val s1_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits / ICacheDataBanks).W)))
val s1_hits = (0 until PortNumber).map(i => ValidHoldBypass(s1_MSHR_hits(i) || (RegNext(s0_fire) && s1_SRAMhits(i)), s1_fire || s1_flush))
val s1_hits = (0 until PortNumber).map(i =>
ValidHoldBypass(s1_MSHR_hits(i) || (RegNext(s0_fire) && s1_SRAMhits(i)), s1_fire || s1_flush)
)
val s1_bankIdxLow = s1_req_offset >> log2Ceil(blockBytes/ICacheDataBanks)
val s1_bankMSHRHit = VecInit((0 until ICacheDataBanks).map(i => (i.U >= s1_bankIdxLow) && s1_MSHR_hits(0) ||
(i.U < s1_bankIdxLow) && s1_MSHR_hits(1)))
val s1_datas = VecInit((0 until ICacheDataBanks).map(i => DataHoldBypass(Mux(s1_bankMSHRHit(i), s1_MSHR_datas(i), fromData.datas(i)),
s1_bankMSHRHit(i) || RegNext(s0_fire))))
val s1_codes = DataHoldBypass(fromData.codes, RegNext(s0_fire))
val s1_bankIdxLow = s1_req_offset >> log2Ceil(blockBytes / ICacheDataBanks)
val s1_bankMSHRHit = VecInit((0 until ICacheDataBanks).map(i =>
(i.U >= s1_bankIdxLow) && s1_MSHR_hits(0) ||
(i.U < s1_bankIdxLow) && s1_MSHR_hits(1)
))
val s1_datas = VecInit((0 until ICacheDataBanks).map(i =>
DataHoldBypass(Mux(s1_bankMSHRHit(i), s1_MSHR_datas(i), fromData.datas(i)), s1_bankMSHRHit(i) || RegNext(s0_fire))
))
val s1_codes = DataHoldBypass(fromData.codes, RegNext(s0_fire))
s1_flush := io.flush
s1_ready := s2_ready || !s1_valid
@ -323,24 +336,25 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
val s2_valid = generatePipeControl(lastFire = s1_fire, thisFire = s2_fire, thisFlush = s2_flush, lastFlush = false.B)
val s2_req_vaddr = RegEnable(s1_req_vaddr, 0.U.asTypeOf(s1_req_vaddr), s1_fire)
val s2_req_ptags = RegEnable(s1_req_ptags, 0.U.asTypeOf(s1_req_ptags), s1_fire)
val s2_req_gpaddr = RegEnable(s1_req_gpaddr, 0.U.asTypeOf(s1_req_gpaddr), s1_fire)
val s2_req_isForVSnonLeafPTE = RegEnable(s1_req_isForVSnonLeafPTE, 0.U.asTypeOf(s1_req_isForVSnonLeafPTE), s1_fire)
val s2_doubleline = RegEnable(s1_doubleline, 0.U.asTypeOf(s1_doubleline), s1_fire)
val s2_exception = RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_fire) // includes itlb/pmp/meta exception
val s2_excp_fromBackend = RegEnable(s1_excp_fromBackend, false.B, s1_fire)
val s2_pmp_mmio = RegEnable(s1_pmp_mmio, 0.U.asTypeOf(s1_pmp_mmio), s1_fire)
val s2_itlb_pbmt = RegEnable(s1_itlb_pbmt, 0.U.asTypeOf(s1_itlb_pbmt), s1_fire)
val s2_req_vaddr = RegEnable(s1_req_vaddr, 0.U.asTypeOf(s1_req_vaddr), s1_fire)
val s2_req_ptags = RegEnable(s1_req_ptags, 0.U.asTypeOf(s1_req_ptags), s1_fire)
val s2_req_gpaddr = RegEnable(s1_req_gpaddr, 0.U.asTypeOf(s1_req_gpaddr), s1_fire)
val s2_req_isForVSnonLeafPTE = RegEnable(s1_req_isForVSnonLeafPTE, 0.U.asTypeOf(s1_req_isForVSnonLeafPTE), s1_fire)
val s2_doubleline = RegEnable(s1_doubleline, 0.U.asTypeOf(s1_doubleline), s1_fire)
val s2_exception =
RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_fire) // includes itlb/pmp/meta exception
val s2_excp_fromBackend = RegEnable(s1_excp_fromBackend, false.B, s1_fire)
val s2_pmp_mmio = RegEnable(s1_pmp_mmio, 0.U.asTypeOf(s1_pmp_mmio), s1_fire)
val s2_itlb_pbmt = RegEnable(s1_itlb_pbmt, 0.U.asTypeOf(s1_itlb_pbmt), s1_fire)
val s2_req_vSetIdx = s2_req_vaddr.map(get_idx)
val s2_req_offset = s2_req_vaddr(0)(log2Ceil(blockBytes)-1, 0)
val s2_req_paddr = s2_req_vaddr.zip(s2_req_ptags).map{case(vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag)}
val s2_req_vSetIdx = s2_req_vaddr.map(get_idx)
val s2_req_offset = s2_req_vaddr(0)(log2Ceil(blockBytes) - 1, 0)
val s2_req_paddr = s2_req_vaddr.zip(s2_req_ptags).map { case (vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag) }
val s2_SRAMhits = RegEnable(s1_SRAMhits, 0.U.asTypeOf(s1_SRAMhits), s1_fire)
val s2_codes = RegEnable(s1_codes, 0.U.asTypeOf(s1_codes), s1_fire)
val s2_hits = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
val s2_datas = RegInit(VecInit(Seq.fill(ICacheDataBanks)(0.U((blockBits/ICacheDataBanks).W))))
val s2_SRAMhits = RegEnable(s1_SRAMhits, 0.U.asTypeOf(s1_SRAMhits), s1_fire)
val s2_codes = RegEnable(s1_codes, 0.U.asTypeOf(s1_codes), s1_fire)
val s2_hits = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
val s2_datas = RegInit(VecInit(Seq.fill(ICacheDataBanks)(0.U((blockBits / ICacheDataBanks).W))))
/**
******************************************************************************
@ -348,23 +362,28 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
******************************************************************************
*/
// check data error
val s2_bankSel = getBankSel(s2_req_offset, s2_valid)
val s2_bank_corrupt = (0 until ICacheDataBanks).map(i => (encodeDataECC(s2_datas(i)) =/= s2_codes(i)))
val s2_data_corrupt = (0 until PortNumber).map(port => (0 until ICacheDataBanks).map(bank =>
s2_bank_corrupt(bank) && s2_bankSel(port)(bank).asBool).reduce(_||_) && s2_SRAMhits(port))
val s2_bankSel = getBankSel(s2_req_offset, s2_valid)
val s2_bank_corrupt = (0 until ICacheDataBanks).map(i => encodeDataECC(s2_datas(i)) =/= s2_codes(i))
val s2_data_corrupt = (0 until PortNumber).map(port =>
(0 until ICacheDataBanks).map(bank =>
s2_bank_corrupt(bank) && s2_bankSel(port)(bank).asBool
).reduce(_ || _) && s2_SRAMhits(port)
)
// meta error is checked in prefetch pipeline
val s2_meta_corrupt = RegEnable(s1_meta_corrupt, 0.U.asTypeOf(s1_meta_corrupt), s1_fire)
// send errors to top
(0 until PortNumber).map{ i =>
io.errors(i).valid := io.csr_parity_enable && RegNext(s1_fire) && (s2_meta_corrupt(i) || s2_data_corrupt(i))
io.errors(i).bits.report_to_beu := io.csr_parity_enable && RegNext(s1_fire) && (s2_meta_corrupt(i) || s2_data_corrupt(i))
io.errors(i).bits.paddr := s2_req_paddr(i)
io.errors(i).bits.source := DontCare
io.errors(i).bits.source.tag := s2_meta_corrupt(i)
io.errors(i).bits.source.data := s2_data_corrupt(i)
io.errors(i).bits.source.l2 := false.B
io.errors(i).bits.opType := DontCare
io.errors(i).bits.opType.fetch := true.B
(0 until PortNumber).map { i =>
io.errors(i).valid := io.csr_parity_enable && RegNext(s1_fire) && (s2_meta_corrupt(i) || s2_data_corrupt(i))
io.errors(i).bits.report_to_beu := io.csr_parity_enable && RegNext(s1_fire) && (s2_meta_corrupt(
i
) || s2_data_corrupt(i))
io.errors(i).bits.paddr := s2_req_paddr(i)
io.errors(i).bits.source := DontCare
io.errors(i).bits.source.tag := s2_meta_corrupt(i)
io.errors(i).bits.source.data := s2_data_corrupt(i)
io.errors(i).bits.source.l2 := false.B
io.errors(i).bits.opType := DontCare
io.errors(i).bits.opType.fetch := true.B
}
/**
@ -372,21 +391,20 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* monitor missUint response port
******************************************************************************
*/
val s2_MSHR_match = VecInit((0 until PortNumber).map( i =>
val s2_MSHR_match = VecInit((0 until PortNumber).map(i =>
(s2_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) &&
(s2_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
fromMSHR.valid // we don't care about whether it's corrupt here
(s2_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
fromMSHR.valid // we don't care about whether it's corrupt here
))
val s2_MSHR_hits = Seq(s2_valid && s2_MSHR_match(0),
s2_valid && s2_MSHR_match(1) && s2_doubleline)
val s2_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits/ICacheDataBanks).W)))
val s2_MSHR_hits = Seq(s2_valid && s2_MSHR_match(0), s2_valid && s2_MSHR_match(1) && s2_doubleline)
val s2_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits / ICacheDataBanks).W)))
val s2_bankIdxLow = s2_req_offset >> log2Ceil(blockBytes/ICacheDataBanks)
val s2_bankMSHRHit = VecInit((0 until ICacheDataBanks).map( i =>
val s2_bankIdxLow = s2_req_offset >> log2Ceil(blockBytes / ICacheDataBanks)
val s2_bankMSHRHit = VecInit((0 until ICacheDataBanks).map(i =>
((i.U >= s2_bankIdxLow) && s2_MSHR_hits(0)) || ((i.U < s2_bankIdxLow) && s2_MSHR_hits(1))
))
(0 until ICacheDataBanks).foreach{ i =>
(0 until ICacheDataBanks).foreach { i =>
when(s1_fire) {
s2_datas := s1_datas
}.elsewhen(s2_bankMSHRHit(i) && !fromMSHR.bits.corrupt) {
@ -395,7 +413,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
}
}
(0 until PortNumber).foreach{ i =>
(0 until PortNumber).foreach { i =>
when(s1_fire) {
s2_hits := s1_hits
}.elsewhen(s2_MSHR_hits(i)) {
@ -405,7 +423,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
}
val s2_l2_corrupt = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
(0 until PortNumber).foreach{ i =>
(0 until PortNumber).foreach { i =>
when(s1_fire) {
s2_l2_corrupt(i) := false.B
}.elsewhen(s2_MSHR_hits(i)) {
@ -420,7 +438,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
*/
// merge pmp mmio and itlb pbmt
val s2_mmio = VecInit((s2_pmp_mmio zip s2_itlb_pbmt).map{ case (mmio, pbmt) =>
val s2_mmio = VecInit((s2_pmp_mmio zip s2_itlb_pbmt).map { case (mmio, pbmt) =>
mmio || Pbmt.isUncache(pbmt)
})
@ -429,16 +447,16 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* also, if previous has exception, latter port should also not be fetched
*/
val s2_miss = VecInit((0 until PortNumber).map { i =>
!s2_hits(i) && (if (i==0) true.B else s2_doubleline) &&
s2_exception.take(i+1).map(_ === ExceptionType.none).reduce(_&&_) &&
s2_mmio.take(i+1).map(!_).reduce(_&&_)
!s2_hits(i) && (if (i == 0) true.B else s2_doubleline) &&
s2_exception.take(i + 1).map(_ === ExceptionType.none).reduce(_ && _) &&
s2_mmio.take(i + 1).map(!_).reduce(_ && _)
})
val toMSHRArbiter = Module(new Arbiter(new ICacheMissReq, PortNumber))
// To avoid sending duplicate requests.
val has_send = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
(0 until PortNumber).foreach{ i =>
(0 until PortNumber).foreach { i =>
when(s1_fire) {
has_send(i) := false.B
}.elsewhen(toMSHRArbiter.io.in(i).fire) {
@ -446,16 +464,16 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
}
}
(0 until PortNumber).map{ i =>
toMSHRArbiter.io.in(i).valid := s2_valid && s2_miss(i) && !has_send(i) && !s2_flush
toMSHRArbiter.io.in(i).bits.blkPaddr := getBlkAddr(s2_req_paddr(i))
toMSHRArbiter.io.in(i).bits.vSetIdx := s2_req_vSetIdx(i)
(0 until PortNumber).map { i =>
toMSHRArbiter.io.in(i).valid := s2_valid && s2_miss(i) && !has_send(i) && !s2_flush
toMSHRArbiter.io.in(i).bits.blkPaddr := getBlkAddr(s2_req_paddr(i))
toMSHRArbiter.io.in(i).bits.vSetIdx := s2_req_vSetIdx(i)
}
toMSHR <> toMSHRArbiter.io.out
XSPerfAccumulate("to_missUnit_stall", toMSHR.valid && !toMSHR.ready)
XSPerfAccumulate("to_missUnit_stall", toMSHR.valid && !toMSHR.ready)
val s2_fetch_finish = !s2_miss.reduce(_||_)
val s2_fetch_finish = !s2_miss.reduce(_ || _)
// also raise af if data/l2 corrupt is detected
val s2_data_exception = VecInit(s2_data_corrupt.map(ExceptionType.fromECC(io.csr_parity_enable, _)))
@ -463,7 +481,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
// merge s2 exceptions, itlb has the highest priority, meta next, meta/data/l2 lowest (and we dont care about prioritizing between this three)
val s2_exception_out = ExceptionType.merge(
s2_exception, // includes itlb/pmp/meta exception
s2_exception, // includes itlb/pmp/meta exception
s2_data_exception,
s2_l2_exception
)
@ -473,11 +491,11 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* response to IFU
******************************************************************************
*/
(0 until PortNumber).foreach{ i =>
if(i == 0) {
(0 until PortNumber).foreach { i =>
if (i == 0) {
toIFU(i).valid := s2_fire
toIFU(i).bits.exception := s2_exception_out(i)
toIFU(i).bits.pmp_mmio := s2_pmp_mmio(i) // pass pmp_mmio instead of merged mmio to IFU
toIFU(i).bits.pmp_mmio := s2_pmp_mmio(i) // pass pmp_mmio instead of merged mmio to IFU
toIFU(i).bits.itlb_pbmt := s2_itlb_pbmt(i)
toIFU(i).bits.data := s2_datas.asTypeOf(UInt(blockBits.W))
} else {
@ -488,10 +506,10 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
toIFU(i).bits.data := DontCare
}
toIFU(i).bits.exceptionFromBackend := s2_excp_fromBackend
toIFU(i).bits.vaddr := s2_req_vaddr(i)
toIFU(i).bits.paddr := s2_req_paddr(i)
toIFU(i).bits.gpaddr := s2_req_gpaddr // Note: toIFU(1).bits.gpaddr is actually DontCare in current design
toIFU(i).bits.isForVSnonLeafPTE := s2_req_isForVSnonLeafPTE
toIFU(i).bits.vaddr := s2_req_vaddr(i)
toIFU(i).bits.paddr := s2_req_paddr(i)
toIFU(i).bits.gpaddr := s2_req_gpaddr // Note: toIFU(1).bits.gpaddr is actually DontCare in current design
toIFU(i).bits.isForVSnonLeafPTE := s2_req_isForVSnonLeafPTE
}
s2_flush := io.flush
@ -503,14 +521,14 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* report Tilelink corrupt error
******************************************************************************
*/
(0 until PortNumber).map{ i =>
when(RegNext(s2_fire && s2_l2_corrupt(i))){
io.errors(i).valid := true.B
io.errors(i).bits.report_to_beu := false.B // l2 should have report that to bus error unit, no need to do it again
io.errors(i).bits.paddr := RegNext(s2_req_paddr(i))
io.errors(i).bits.source.tag := false.B
io.errors(i).bits.source.data := false.B
io.errors(i).bits.source.l2 := true.B
(0 until PortNumber).map { i =>
when(RegNext(s2_fire && s2_l2_corrupt(i))) {
io.errors(i).valid := true.B
io.errors(i).bits.report_to_beu := false.B // l2 should have report that to bus error unit, no need to do it again
io.errors(i).bits.paddr := RegNext(s2_req_paddr(i))
io.errors(i).bits.source.tag := false.B
io.errors(i).bits.source.data := false.B
io.errors(i).bits.source.l2 := true.B
}
}
@ -519,25 +537,25 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
* performance info. TODO: need to simplify the logic
***********************************************************s*******************
*/
io.perfInfo.only_0_hit := s2_hits(0) && !s2_doubleline
io.perfInfo.only_0_hit := s2_hits(0) && !s2_doubleline
io.perfInfo.only_0_miss := !s2_hits(0) && !s2_doubleline
io.perfInfo.hit_0_hit_1 := s2_hits(0) && s2_hits(1) && s2_doubleline
io.perfInfo.hit_0_miss_1 := s2_hits(0) && !s2_hits(1) && s2_doubleline
io.perfInfo.miss_0_hit_1 := !s2_hits(0) && s2_hits(1) && s2_doubleline
io.perfInfo.hit_0_hit_1 := s2_hits(0) && s2_hits(1) && s2_doubleline
io.perfInfo.hit_0_miss_1 := s2_hits(0) && !s2_hits(1) && s2_doubleline
io.perfInfo.miss_0_hit_1 := !s2_hits(0) && s2_hits(1) && s2_doubleline
io.perfInfo.miss_0_miss_1 := !s2_hits(0) && !s2_hits(1) && s2_doubleline
io.perfInfo.hit_0_except_1 := s2_hits(0) && (s2_exception(1) =/= ExceptionType.none) && s2_doubleline
io.perfInfo.hit_0_except_1 := s2_hits(0) && (s2_exception(1) =/= ExceptionType.none) && s2_doubleline
io.perfInfo.miss_0_except_1 := !s2_hits(0) && (s2_exception(1) =/= ExceptionType.none) && s2_doubleline
io.perfInfo.bank_hit(0) := s2_hits(0)
io.perfInfo.bank_hit(1) := s2_hits(1) && s2_doubleline
io.perfInfo.except_0 := s2_exception(0) =/= ExceptionType.none
io.perfInfo.hit := s2_hits(0) && (!s2_doubleline || s2_hits(1))
io.perfInfo.bank_hit(0) := s2_hits(0)
io.perfInfo.bank_hit(1) := s2_hits(1) && s2_doubleline
io.perfInfo.except_0 := s2_exception(0) =/= ExceptionType.none
io.perfInfo.hit := s2_hits(0) && (!s2_doubleline || s2_hits(1))
/** <PERF> fetch bubble generated by icache miss */
XSPerfAccumulate("icache_bubble_s2_miss", s2_valid && !s2_fetch_finish )
XSPerfAccumulate("icache_bubble_s2_miss", s2_valid && !s2_fetch_finish)
XSPerfAccumulate("icache_bubble_s0_wayLookup", s0_valid && !fromWayLookup.ready)
io.fetch.topdownIcacheMiss := !s2_fetch_finish
io.fetch.topdownItlbMiss := s0_valid && !fromWayLookup.ready
io.fetch.topdownItlbMiss := s0_valid && !fromWayLookup.ready
// class ICacheTouchDB(implicit p: Parameters) extends ICacheBundle{
// val blkPaddr = UInt((PAddrBits - blockOffBits).W)
@ -577,17 +595,20 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
(0 until ICacheDataBanks).map { i =>
val diffMainPipeOut = DifftestModule(new DiffRefillEvent, dontCare = true)
diffMainPipeOut.coreid := io.hartId
diffMainPipeOut.index := (3 + i).U
diffMainPipeOut.index := (3 + i).U
val bankSel = getBankSel(s2_req_offset, s2_valid).reduce(_|_)
val bankSel = getBankSel(s2_req_offset, s2_valid).reduce(_ | _)
val lineSel = getLineSel(s2_req_offset)
diffMainPipeOut.valid := s2_fire && bankSel(i).asBool && Mux(lineSel(i), !discards(1), !discards(0))
diffMainPipeOut.addr := Mux(lineSel(i), blkPaddrAll(1) + (i.U << (log2Ceil(blockBytes/ICacheDataBanks))),
blkPaddrAll(0) + (i.U << (log2Ceil(blockBytes/ICacheDataBanks))))
diffMainPipeOut.addr := Mux(
lineSel(i),
blkPaddrAll(1) + (i.U << (log2Ceil(blockBytes / ICacheDataBanks))),
blkPaddrAll(0) + (i.U << (log2Ceil(blockBytes / ICacheDataBanks)))
)
diffMainPipeOut.data := s2_datas(i).asTypeOf(diffMainPipeOut.data)
diffMainPipeOut.data := s2_datas(i).asTypeOf(diffMainPipeOut.data)
diffMainPipeOut.idtfr := DontCare
}
}
}
}

View File

@ -16,61 +16,57 @@
package xiangshan.frontend.icache
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import difftest._
import freechips.rocketchip.diplomacy.IdRange
import freechips.rocketchip.tilelink._
import freechips.rocketchip.tilelink.ClientStates._
import freechips.rocketchip.tilelink.TLPermissions._
import freechips.rocketchip.tilelink._
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.cache._
import utils._
import utility._
import difftest._
abstract class ICacheMissUnitModule(implicit p: Parameters) extends XSModule
with HasICacheParameters
with HasICacheParameters
abstract class ICacheMissUnitBundle(implicit p: Parameters) extends XSBundle
with HasICacheParameters
with HasICacheParameters
class Demultiplexer[T <: Data](val gen: T, val n: Int) extends Module {
class Demultiplexer[T <: Data](val gen: T, val n: Int) extends Module
{
/** Hardware module that is used to sequence 1 producers into n consumer.
* Priority is given to lower producer.
*/
require(n >= 2)
val io = IO(new Bundle {
val in = Flipped(DecoupledIO(gen))
val out = Vec(n, DecoupledIO(gen))
val chosen = Output(UInt(log2Ceil(n).W))
val in = Flipped(DecoupledIO(gen))
val out = Vec(n, DecoupledIO(gen))
val chosen = Output(UInt(log2Ceil(n).W))
})
val grant = false.B +: (1 until n).map(i=> (0 until i).map(io.out(_).ready).reduce(_||_))
val grant = false.B +: (1 until n).map(i => (0 until i).map(io.out(_).ready).reduce(_ || _))
for (i <- 0 until n) {
io.out(i).bits := io.in.bits
io.out(i).bits := io.in.bits
io.out(i).valid := !grant(i) && io.in.valid
}
io.in.ready := grant.last || io.out.last.ready
io.chosen := PriorityEncoder(VecInit(io.out.map(_.ready)))
io.chosen := PriorityEncoder(VecInit(io.out.map(_.ready)))
}
class MuxBundle[T <: Data](val gen: T, val n: Int) extends Module
{
class MuxBundle[T <: Data](val gen: T, val n: Int) extends Module {
require(n >= 2)
val io = IO(new Bundle {
val sel = Input(UInt(log2Ceil(n).W))
val in = Flipped(Vec(n, DecoupledIO(gen)))
val out = DecoupledIO(gen)
val sel = Input(UInt(log2Ceil(n).W))
val in = Flipped(Vec(n, DecoupledIO(gen)))
val out = DecoupledIO(gen)
})
io.in <> DontCare
io.out <> DontCare
io.in <> DontCare
io.out <> DontCare
for (i <- 0 until n) {
when(io.sel === i.U) {
io.out <> io.in(i)
@ -79,35 +75,30 @@ class MuxBundle[T <: Data](val gen: T, val n: Int) extends Module
}
}
class ICacheMissReq(implicit p: Parameters) extends ICacheBundle {
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
}
class ICacheMissResp(implicit p: Parameters) extends ICacheBundle {
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(nWays.W)
val data = UInt(blockBits.W)
val corrupt = Bool()
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(nWays.W)
val data = UInt(blockBits.W)
val corrupt = Bool()
}
class LookUpMSHR(implicit p: Parameters) extends ICacheBundle {
val info = ValidIO(new ICacheMissReq)
val hit = Input(Bool())
val info = ValidIO(new ICacheMissReq)
val hit = Input(Bool())
}
class MSHRResp(implicit p: Parameters) extends ICacheBundle {
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(log2Ceil(nWays).W)
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(log2Ceil(nWays).W)
}
class MSHRAcquire(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
val acquire = new TLBundleA(edge.bundle)
val vSetIdx = UInt(idxBits.W)
@ -115,34 +106,34 @@ class MSHRAcquire(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle
class ICacheMSHR(edge: TLEdgeOut, isFetch: Boolean, ID: Int)(implicit p: Parameters) extends ICacheMissUnitModule {
val io = IO(new Bundle {
val fencei = Input(Bool())
val flush = Input(Bool())
val invalid = Input(Bool())
val req = Flipped(DecoupledIO(new ICacheMissReq))
val acquire = DecoupledIO(new MSHRAcquire(edge))
val lookUps = Flipped(Vec(2, new LookUpMSHR))
val resp = ValidIO(new MSHRResp)
val victimWay = Input(UInt(log2Ceil(nWays).W))
val fencei = Input(Bool())
val flush = Input(Bool())
val invalid = Input(Bool())
val req = Flipped(DecoupledIO(new ICacheMissReq))
val acquire = DecoupledIO(new MSHRAcquire(edge))
val lookUps = Flipped(Vec(2, new LookUpMSHR))
val resp = ValidIO(new MSHRResp)
val victimWay = Input(UInt(log2Ceil(nWays).W))
})
val valid = RegInit(Bool(), false.B)
val valid = RegInit(Bool(), false.B)
// this MSHR doesn't respones to fetch and sram
val flush = RegInit(Bool(), false.B)
val fencei = RegInit(Bool(), false.B)
val flush = RegInit(Bool(), false.B)
val fencei = RegInit(Bool(), false.B)
// this MSHR has been issued
val issue = RegInit(Bool(), false.B)
val issue = RegInit(Bool(), false.B)
val blkPaddr = RegInit(UInt((PAddrBits - blockOffBits).W), 0.U)
val vSetIdx = RegInit(UInt(idxBits.W), 0.U)
val waymask = RegInit(UInt(log2Ceil(nWays).W), 0.U)
val blkPaddr = RegInit(UInt((PAddrBits - blockOffBits).W), 0.U)
val vSetIdx = RegInit(UInt(idxBits.W), 0.U)
val waymask = RegInit(UInt(log2Ceil(nWays).W), 0.U)
// look up and return result at the same cycle
val hits = io.lookUps.map(lookup => valid && !fencei && !flush && (lookup.info.bits.vSetIdx === vSetIdx) &&
(lookup.info.bits.blkPaddr === blkPaddr))
val hits = io.lookUps.map(lookup =>
valid && !fencei && !flush && (lookup.info.bits.vSetIdx === vSetIdx) &&
(lookup.info.bits.blkPaddr === blkPaddr)
)
// Decoupling valid and bits
(0 until 2).foreach { i =>
io.lookUps(i).hit := hits(i)
}
(0 until 2).foreach(i => io.lookUps(i).hit := hits(i))
// disable wake up when hit MSHR (fencei is low)
// when(hit) {
@ -151,8 +142,8 @@ class ICacheMSHR(edge: TLEdgeOut, isFetch: Boolean, ID: Int)(implicit p: Paramet
// invalid when the req hasn't been issued
when(io.fencei || io.flush) {
fencei := true.B
flush := true.B
fencei := true.B
flush := true.B
when(!issue) {
valid := false.B
}
@ -161,20 +152,20 @@ class ICacheMSHR(edge: TLEdgeOut, isFetch: Boolean, ID: Int)(implicit p: Paramet
// receive request and register
io.req.ready := !valid && !io.flush && !io.fencei
when(io.req.fire) {
valid := true.B
flush := false.B
issue := false.B
fencei := false.B
blkPaddr := io.req.bits.blkPaddr
vSetIdx := io.req.bits.vSetIdx
valid := true.B
flush := false.B
issue := false.B
fencei := false.B
blkPaddr := io.req.bits.blkPaddr
vSetIdx := io.req.bits.vSetIdx
}
// send request to L2
io.acquire.valid := valid && !issue && !io.flush && !io.fencei
val getBlock = edge.Get(
fromSource = ID.U,
toAddress = Cat(blkPaddr, 0.U(blockOffBits.W)),
lgSize = (log2Up(cacheParams.blockBytes)).U
val getBlock = edge.Get(
fromSource = ID.U,
toAddress = Cat(blkPaddr, 0.U(blockOffBits.W)),
lgSize = log2Up(cacheParams.blockBytes).U
)._2
io.acquire.bits.acquire := getBlock
io.acquire.bits.acquire.user.lift(ReqSourceKey).foreach(_ := MemReqSource.CPUInst.id.U)
@ -198,32 +189,30 @@ class ICacheMSHR(edge: TLEdgeOut, isFetch: Boolean, ID: Int)(implicit p: Paramet
io.resp.bits.waymask := waymask
}
class ICacheMissBundle(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle{
class ICacheMissBundle(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
// difftest
val hartId = Input(Bool())
val hartId = Input(Bool())
// control
val fencei = Input(Bool())
val flush = Input(Bool())
val fencei = Input(Bool())
val flush = Input(Bool())
// fetch
val fetch_req = Flipped(DecoupledIO(new ICacheMissReq))
val fetch_resp = ValidIO(new ICacheMissResp)
val fetch_req = Flipped(DecoupledIO(new ICacheMissReq))
val fetch_resp = ValidIO(new ICacheMissResp)
// prefetch
val prefetch_req = Flipped(DecoupledIO(new ICacheMissReq))
val prefetch_req = Flipped(DecoupledIO(new ICacheMissReq))
// SRAM Write Req
val meta_write = DecoupledIO(new ICacheMetaWriteBundle)
val data_write = DecoupledIO(new ICacheDataWriteBundle)
val meta_write = DecoupledIO(new ICacheMetaWriteBundle)
val data_write = DecoupledIO(new ICacheDataWriteBundle)
// get victim from replacer
val victim = new ReplacerVictim
val victim = new ReplacerVictim
// Tilelink
val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
}
class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMissUnitModule
{
class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMissUnitModule {
val io = IO(new ICacheMissBundle(edge))
/**
******************************************************************************
* fetch have higher priority
@ -249,26 +238,26 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
val prefetchDemux = Module(new Demultiplexer(new ICacheMissReq, nPrefetchMshr))
val prefetchArb = Module(new MuxBundle(new MSHRAcquire(edge), nPrefetchMshr))
val acquireArb = Module(new Arbiter(new MSHRAcquire(edge), nFetchMshr + 1))
// To avoid duplicate request reception.
val fetchHit, prefetchHit = Wire(Bool())
fetchDemux.io.in <> io.fetch_req
fetchDemux.io.in.valid := io.fetch_req.valid && !fetchHit
io.fetch_req.ready := fetchDemux.io.in.ready || fetchHit
prefetchDemux.io.in <> io.prefetch_req
prefetchDemux.io.in.valid := io.prefetch_req.valid && !prefetchHit
io.prefetch_req.ready := prefetchDemux.io.in.ready || prefetchHit
acquireArb.io.in.last <> prefetchArb.io.out
val fetchHit, prefetchHit = Wire(Bool())
fetchDemux.io.in <> io.fetch_req
fetchDemux.io.in.valid := io.fetch_req.valid && !fetchHit
io.fetch_req.ready := fetchDemux.io.in.ready || fetchHit
prefetchDemux.io.in <> io.prefetch_req
prefetchDemux.io.in.valid := io.prefetch_req.valid && !prefetchHit
io.prefetch_req.ready := prefetchDemux.io.in.ready || prefetchHit
acquireArb.io.in.last <> prefetchArb.io.out
// mem_acquire connect
io.mem_acquire.valid := acquireArb.io.out.valid
io.mem_acquire.bits := acquireArb.io.out.bits.acquire
acquireArb.io.out.ready := io.mem_acquire.ready
io.mem_acquire.valid := acquireArb.io.out.valid
io.mem_acquire.bits := acquireArb.io.out.bits.acquire
acquireArb.io.out.ready := io.mem_acquire.ready
val fetchMSHRs = (0 until nFetchMshr).map { i =>
val mshr = Module(new ICacheMSHR(edge, true, i))
mshr.io.flush := false.B
mshr.io.fencei := io.fencei
mshr.io.flush := false.B
mshr.io.fencei := io.fencei
mshr.io.req <> fetchDemux.io.out(i)
mshr.io.lookUps(0).info.valid := io.fetch_req.valid
mshr.io.lookUps(0).info.bits := io.fetch_req.bits
@ -281,8 +270,8 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
val prefetchMSHRs = (0 until nPrefetchMshr).map { i =>
val mshr = Module(new ICacheMSHR(edge, false, nFetchMshr + i))
mshr.io.flush := io.flush
mshr.io.fencei := io.fencei
mshr.io.flush := io.flush
mshr.io.fencei := io.fencei
mshr.io.req <> prefetchDemux.io.out(i)
mshr.io.lookUps(0).info.valid := io.fetch_req.valid
mshr.io.lookUps(0).info.bits := io.fetch_req.bits
@ -299,12 +288,12 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
* - look up all mshr
******************************************************************************
*/
val allMSHRs = (fetchMSHRs ++ prefetchMSHRs)
val allMSHRs = fetchMSHRs ++ prefetchMSHRs
val prefetchHitFetchReq = (io.prefetch_req.bits.blkPaddr === io.fetch_req.bits.blkPaddr) &&
(io.prefetch_req.bits.vSetIdx === io.fetch_req.bits.vSetIdx) &&
io.fetch_req.valid
fetchHit := allMSHRs.map(mshr => mshr.io.lookUps(0).hit).reduce(_||_)
prefetchHit := allMSHRs.map(mshr => mshr.io.lookUps(1).hit).reduce(_||_) || prefetchHitFetchReq
(io.prefetch_req.bits.vSetIdx === io.fetch_req.bits.vSetIdx) &&
io.fetch_req.valid
fetchHit := allMSHRs.map(mshr => mshr.io.lookUps(0).hit).reduce(_ || _)
prefetchHit := allMSHRs.map(mshr => mshr.io.lookUps(1).hit).reduce(_ || _) || prefetchHitFetchReq
/**
******************************************************************************
@ -317,28 +306,34 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
// When the FIFO is full, enqueue and dequeue operations do not occur at the same cycle.
// So the depth of the FIFO is set to match the number of MSHRs.
// val priorityFIFO = Module(new Queue(UInt(log2Ceil(nPrefetchMshr).W), nPrefetchMshr, hasFlush=true))
val priorityFIFO = Module(new FIFOReg(UInt(log2Ceil(nPrefetchMshr).W), nPrefetchMshr, hasFlush=true))
val priorityFIFO = Module(new FIFOReg(UInt(log2Ceil(nPrefetchMshr).W), nPrefetchMshr, hasFlush = true))
priorityFIFO.io.flush.get := io.flush || io.fencei
priorityFIFO.io.enq.valid := prefetchDemux.io.in.fire
priorityFIFO.io.enq.bits := prefetchDemux.io.chosen
priorityFIFO.io.deq.ready := prefetchArb.io.out.fire
prefetchArb.io.sel := priorityFIFO.io.deq.bits
assert(!(priorityFIFO.io.enq.fire ^ prefetchDemux.io.in.fire), "priorityFIFO.io.enq and io.prefetch_req must fire at the same cycle")
assert(!(priorityFIFO.io.deq.fire ^ prefetchArb.io.out.fire), "priorityFIFO.io.deq and prefetchArb.io.out must fire at the same cycle")
assert(
!(priorityFIFO.io.enq.fire ^ prefetchDemux.io.in.fire),
"priorityFIFO.io.enq and io.prefetch_req must fire at the same cycle"
)
assert(
!(priorityFIFO.io.deq.fire ^ prefetchArb.io.out.fire),
"priorityFIFO.io.deq and prefetchArb.io.out must fire at the same cycle"
)
/**
******************************************************************************
* Tilelink D channel (grant)
******************************************************************************
*/
//cacheline register
// cacheline register
val readBeatCnt = RegInit(UInt(log2Up(refillCycles).W), 0.U)
val respDataReg = RegInit(VecInit(Seq.fill(refillCycles)(0.U(beatBits.W))))
val wait_last = readBeatCnt === (refillCycles - 1).U
when(io.mem_grant.fire && edge.hasData(io.mem_grant.bits)) {
respDataReg(readBeatCnt) := io.mem_grant.bits.data
readBeatCnt := Mux(wait_last, 0.U, readBeatCnt + 1.U)
readBeatCnt := Mux(wait_last, 0.U, readBeatCnt + 1.U)
}
// last transition finsh or corrupt
@ -352,8 +347,8 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
val id_r = RegNext(io.mem_grant.bits.source)
// if any beat is corrupt, the whole response (to mainPipe/metaArray/dataArray) is corrupt
val corrupt_r = RegInit(false.B)
when (io.mem_grant.fire && edge.hasData(io.mem_grant.bits) && io.mem_grant.bits.corrupt) {
val corrupt_r = RegInit(false.B)
when(io.mem_grant.fire && edge.hasData(io.mem_grant.bits) && io.mem_grant.bits.corrupt) {
corrupt_r := true.B
}.elsewhen(io.fetch_resp.fire) {
corrupt_r := false.B
@ -364,9 +359,7 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
* invalid mshr when finish transition
******************************************************************************
*/
(0 until (nFetchMshr + nPrefetchMshr)).foreach{ i =>
allMSHRs(i).io.invalid := last_fire_r && (id_r === i.U)
}
(0 until (nFetchMshr + nPrefetchMshr)).foreach(i => allMSHRs(i).io.invalid := last_fire_r && (id_r === i.U))
/**
******************************************************************************
@ -375,7 +368,7 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
*/
// get request information from MSHRs
val allMSHRs_resp = VecInit(allMSHRs.map(mshr => mshr.io.resp))
val mshr_resp = allMSHRs_resp(id_r)
val mshr_resp = allMSHRs_resp(id_r)
// get waymask from replacer when acquire fire
io.victim.vSetIdx.valid := acquireArb.io.out.fire
@ -389,14 +382,18 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
val write_sram_valid = fetch_resp_valid && !corrupt_r && !io.flush && !io.fencei
// write SRAM
io.meta_write.bits.generate(tag = getPhyTagFromBlk(mshr_resp.bits.blkPaddr),
idx = mshr_resp.bits.vSetIdx,
waymask = waymask,
bankIdx = mshr_resp.bits.vSetIdx(0))
io.data_write.bits.generate(data = respDataReg.asUInt,
idx = mshr_resp.bits.vSetIdx,
waymask = waymask,
bankIdx = mshr_resp.bits.vSetIdx(0))
io.meta_write.bits.generate(
tag = getPhyTagFromBlk(mshr_resp.bits.blkPaddr),
idx = mshr_resp.bits.vSetIdx,
waymask = waymask,
bankIdx = mshr_resp.bits.vSetIdx(0)
)
io.data_write.bits.generate(
data = respDataReg.asUInt,
idx = mshr_resp.bits.vSetIdx,
waymask = waymask,
bankIdx = mshr_resp.bits.vSetIdx(0)
)
io.meta_write.valid := write_sram_valid
io.data_write.valid := write_sram_valid
@ -415,30 +412,31 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
******************************************************************************
*/
// Duplicate requests will be excluded.
XSPerfAccumulate("enq_fetch_req", fetchDemux.io.in.fire)
XSPerfAccumulate("enq_prefetch_req", prefetchDemux.io.in.fire)
XSPerfAccumulate("enq_fetch_req", fetchDemux.io.in.fire)
XSPerfAccumulate("enq_prefetch_req", prefetchDemux.io.in.fire)
/**
******************************************************************************
* ChiselDB: record ICache SRAM write log
******************************************************************************
*/
class ICacheSRAMDB(implicit p: Parameters) extends ICacheBundle{
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(log2Ceil(nWays).W)
class ICacheSRAMDB(implicit p: Parameters) extends ICacheBundle {
val blkPaddr = UInt((PAddrBits - blockOffBits).W)
val vSetIdx = UInt(idxBits.W)
val waymask = UInt(log2Ceil(nWays).W)
}
val isWriteICacheSRAMTable = WireInit(Constantin.createRecord("isWriteICacheSRAMTable" + p(XSCoreParamsKey).HartId.toString))
val isWriteICacheSRAMTable =
WireInit(Constantin.createRecord("isWriteICacheSRAMTable" + p(XSCoreParamsKey).HartId.toString))
val ICacheSRAMTable = ChiselDB.createTable("ICacheSRAMTable" + p(XSCoreParamsKey).HartId.toString, new ICacheSRAMDB)
val ICacheSRAMDBDumpData = Wire(new ICacheSRAMDB)
ICacheSRAMDBDumpData.blkPaddr := mshr_resp.bits.blkPaddr
ICacheSRAMDBDumpData.vSetIdx := mshr_resp.bits.vSetIdx
ICacheSRAMDBDumpData.waymask := OHToUInt(waymask)
ICacheSRAMDBDumpData.blkPaddr := mshr_resp.bits.blkPaddr
ICacheSRAMDBDumpData.vSetIdx := mshr_resp.bits.vSetIdx
ICacheSRAMDBDumpData.waymask := OHToUInt(waymask)
ICacheSRAMTable.log(
data = ICacheSRAMDBDumpData,
en = write_sram_valid,
data = ICacheSRAMDBDumpData,
en = write_sram_valid,
clock = clock,
reset = reset
)
@ -457,4 +455,4 @@ class ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMiss
difftest.data := respDataReg.asTypeOf(difftest.data)
difftest.idtfr := DontCare
}
}
}

View File

@ -16,42 +16,43 @@
package xiangshan.frontend.icache
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import difftest._
import freechips.rocketchip.tilelink._
import huancun.PreferCacheKey
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan.SoftIfetchPrefetchBundle
import xiangshan.XSCoreParamsKey
import xiangshan.backend.fu.PMPReqBundle
import xiangshan.backend.fu.PMPRespBundle
import xiangshan.cache.mmu._
import xiangshan.frontend._
import xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
import huancun.PreferCacheKey
import xiangshan.XSCoreParamsKey
import xiangshan.SoftIfetchPrefetchBundle
import utility._
abstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle
abstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule
class IPrefetchReq(implicit p: Parameters) extends IPrefetchBundle {
val startAddr : UInt = UInt(VAddrBits.W)
val nextlineStart : UInt = UInt(VAddrBits.W)
val ftqIdx : FtqPtr = new FtqPtr
val startAddr: UInt = UInt(VAddrBits.W)
val nextlineStart: UInt = UInt(VAddrBits.W)
val ftqIdx: FtqPtr = new FtqPtr
val isSoftPrefetch: Bool = Bool()
def crossCacheline: Bool = startAddr(blockOffBits - 1) === 1.U
def fromFtqICacheInfo(info: FtqICacheInfo): IPrefetchReq = {
this.startAddr := info.startAddr
this.nextlineStart := info.nextlineStart
this.ftqIdx := info.ftqIdx
this.startAddr := info.startAddr
this.nextlineStart := info.nextlineStart
this.ftqIdx := info.ftqIdx
this.isSoftPrefetch := false.B
this
}
def fromSoftPrefetch(req: SoftIfetchPrefetchBundle): IPrefetchReq = {
this.startAddr := req.vaddr
this.nextlineStart := req.vaddr + (1 << blockOffBits).U
this.ftqIdx := DontCare
this.startAddr := req.vaddr
this.nextlineStart := req.vaddr + (1 << blockOffBits).U
this.ftqIdx := DontCare
this.isSoftPrefetch := true.B
this
}
@ -63,31 +64,30 @@ class IPrefetchIO(implicit p: Parameters) extends IPrefetchBundle {
val csr_parity_enable = Input(Bool())
val flush = Input(Bool())
val req = Flipped(Decoupled(new IPrefetchReq))
val flushFromBpu = Flipped(new BpuFlushInfo)
val itlb = Vec(PortNumber, new TlbRequestIO)
val pmp = Vec(PortNumber, new ICachePMPBundle)
val metaRead = new ICacheMetaReqBundle
val MSHRReq = DecoupledIO(new ICacheMissReq)
val MSHRResp = Flipped(ValidIO(new ICacheMissResp))
val wayLookupWrite = DecoupledIO(new WayLookupInfo)
val req = Flipped(Decoupled(new IPrefetchReq))
val flushFromBpu = Flipped(new BpuFlushInfo)
val itlb = Vec(PortNumber, new TlbRequestIO)
val pmp = Vec(PortNumber, new ICachePMPBundle)
val metaRead = new ICacheMetaReqBundle
val MSHRReq = DecoupledIO(new ICacheMissReq)
val MSHRResp = Flipped(ValidIO(new ICacheMissResp))
val wayLookupWrite = DecoupledIO(new WayLookupInfo)
}
class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
{
class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule {
val io: IPrefetchIO = IO(new IPrefetchIO)
val (toITLB, fromITLB) = (io.itlb.map(_.req), io.itlb.map(_.resp))
val (toPMP, fromPMP) = (io.pmp.map(_.req), io.pmp.map(_.resp))
val (toMeta, fromMeta) = (io.metaRead.toIMeta, io.metaRead.fromIMeta)
val (toMSHR, fromMSHR) = (io.MSHRReq, io.MSHRResp)
val toWayLookup = io.wayLookupWrite
val (toITLB, fromITLB) = (io.itlb.map(_.req), io.itlb.map(_.resp))
val (toPMP, fromPMP) = (io.pmp.map(_.req), io.pmp.map(_.resp))
val (toMeta, fromMeta) = (io.metaRead.toIMeta, io.metaRead.fromIMeta)
val (toMSHR, fromMSHR) = (io.MSHRReq, io.MSHRResp)
val toWayLookup = io.wayLookupWrite
val s0_fire, s1_fire, s2_fire = WireInit(false.B)
val s0_discard, s2_discard = WireInit(false.B)
val s0_ready, s1_ready, s2_ready = WireInit(false.B)
val s0_flush, s1_flush, s2_flush = WireInit(false.B)
val from_bpu_s0_flush, from_bpu_s1_flush = WireInit(false.B)
val s0_fire, s1_fire, s2_fire = WireInit(false.B)
val s0_discard, s2_discard = WireInit(false.B)
val s0_ready, s1_ready, s2_ready = WireInit(false.B)
val s0_flush, s1_flush, s2_flush = WireInit(false.B)
val from_bpu_s0_flush, from_bpu_s1_flush = WireInit(false.B)
/**
******************************************************************************
@ -97,21 +97,21 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
* - 3. send req to Meta SRAM
******************************************************************************
*/
val s0_valid = io.req.valid
val s0_valid = io.req.valid
/**
******************************************************************************
* receive ftq req
******************************************************************************
*/
val s0_req_vaddr = VecInit(Seq(io.req.bits.startAddr, io.req.bits.nextlineStart))
val s0_req_ftqIdx = io.req.bits.ftqIdx
val s0_req_vaddr = VecInit(Seq(io.req.bits.startAddr, io.req.bits.nextlineStart))
val s0_req_ftqIdx = io.req.bits.ftqIdx
val s0_isSoftPrefetch = io.req.bits.isSoftPrefetch
val s0_doubleline = io.req.bits.crossCacheline
val s0_req_vSetIdx = s0_req_vaddr.map(get_idx)
val s0_doubleline = io.req.bits.crossCacheline
val s0_req_vSetIdx = s0_req_vaddr.map(get_idx)
from_bpu_s0_flush := !s0_isSoftPrefetch && (io.flushFromBpu.shouldFlushByStage2(s0_req_ftqIdx) ||
io.flushFromBpu.shouldFlushByStage3(s0_req_ftqIdx))
io.flushFromBpu.shouldFlushByStage3(s0_req_ftqIdx))
s0_flush := io.flush || from_bpu_s0_flush || s1_flush
val s0_can_go = s1_ready && toITLB(0).ready && toITLB(1).ready && toMeta.ready
@ -130,16 +130,16 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
*/
val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = s1_flush, lastFlush = false.B)
val s1_req_vaddr = RegEnable(s0_req_vaddr, 0.U.asTypeOf(s0_req_vaddr), s0_fire)
val s1_req_vaddr = RegEnable(s0_req_vaddr, 0.U.asTypeOf(s0_req_vaddr), s0_fire)
val s1_isSoftPrefetch = RegEnable(s0_isSoftPrefetch, 0.U.asTypeOf(s0_isSoftPrefetch), s0_fire)
val s1_doubleline = RegEnable(s0_doubleline, 0.U.asTypeOf(s0_doubleline), s0_fire)
val s1_req_ftqIdx = RegEnable(s0_req_ftqIdx, 0.U.asTypeOf(s0_req_ftqIdx), s0_fire)
val s1_req_vSetIdx = VecInit(s1_req_vaddr.map(get_idx))
val s1_doubleline = RegEnable(s0_doubleline, 0.U.asTypeOf(s0_doubleline), s0_fire)
val s1_req_ftqIdx = RegEnable(s0_req_ftqIdx, 0.U.asTypeOf(s0_req_ftqIdx), s0_fire)
val s1_req_vSetIdx = VecInit(s1_req_vaddr.map(get_idx))
val m_idle :: m_itlbResend :: m_metaResend :: m_enqWay :: m_enterS2 :: Nil = Enum(5)
val state = RegInit(m_idle)
val next_state = WireDefault(state)
val s0_fire_r = RegNext(s0_fire)
val state = RegInit(m_idle)
val next_state = WireDefault(state)
val s0_fire_r = RegNext(s0_fire)
dontTouch(state)
dontTouch(next_state)
state := next_state
@ -149,7 +149,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
* resend itlb req if miss
******************************************************************************
*/
val s1_wait_itlb = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
val s1_wait_itlb = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
(0 until PortNumber).foreach { i =>
when(s1_flush) {
s1_wait_itlb(i) := false.B
@ -159,15 +159,20 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
s1_wait_itlb(i) := false.B
}
}
val s1_need_itlb = VecInit(Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && fromITLB(0).bits.miss,
(RegNext(s0_fire) || s1_wait_itlb(1)) && fromITLB(1).bits.miss && s1_doubleline))
val tlb_valid_pulse = VecInit(Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && !fromITLB(0).bits.miss,
(RegNext(s0_fire) || s1_wait_itlb(1)) && !fromITLB(1).bits.miss && s1_doubleline))
val tlb_valid_latch = VecInit((0 until PortNumber).map(i => ValidHoldBypass(tlb_valid_pulse(i), s1_fire, flush=s1_flush)))
val itlb_finish = tlb_valid_latch(0) && (!s1_doubleline || tlb_valid_latch(1))
val s1_need_itlb = VecInit(Seq(
(RegNext(s0_fire) || s1_wait_itlb(0)) && fromITLB(0).bits.miss,
(RegNext(s0_fire) || s1_wait_itlb(1)) && fromITLB(1).bits.miss && s1_doubleline
))
val tlb_valid_pulse = VecInit(Seq(
(RegNext(s0_fire) || s1_wait_itlb(0)) && !fromITLB(0).bits.miss,
(RegNext(s0_fire) || s1_wait_itlb(1)) && !fromITLB(1).bits.miss && s1_doubleline
))
val tlb_valid_latch =
VecInit((0 until PortNumber).map(i => ValidHoldBypass(tlb_valid_pulse(i), s1_fire, flush = s1_flush)))
val itlb_finish = tlb_valid_latch(0) && (!s1_doubleline || tlb_valid_latch(1))
for (i <- 0 until PortNumber) {
toITLB(i).valid := s1_need_itlb(i) || (s0_valid && (if(i == 0) true.B else s0_doubleline))
toITLB(i).valid := s1_need_itlb(i) || (s0_valid && (if (i == 0) true.B else s0_doubleline))
toITLB(i).bits := DontCare
toITLB(i).bits.size := 3.U
toITLB(i).bits.vaddr := Mux(s1_need_itlb(i), s1_req_vaddr(i), s0_req_vaddr(i))
@ -183,24 +188,40 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
* Receive resp from ITLB
******************************************************************************
*/
val s1_req_paddr_wire = VecInit(fromITLB.map(_.bits.paddr(0)))
val s1_req_paddr_reg = VecInit((0 until PortNumber).map( i =>
val s1_req_paddr_wire = VecInit(fromITLB.map(_.bits.paddr(0)))
val s1_req_paddr_reg = VecInit((0 until PortNumber).map(i =>
RegEnable(s1_req_paddr_wire(i), 0.U(PAddrBits.W), tlb_valid_pulse(i))
))
val s1_req_paddr = VecInit((0 until PortNumber).map( i =>
val s1_req_paddr = VecInit((0 until PortNumber).map(i =>
Mux(tlb_valid_pulse(i), s1_req_paddr_wire(i), s1_req_paddr_reg(i))
))
val s1_req_gpaddr_tmp = VecInit((0 until PortNumber).map( i =>
ResultHoldBypass(valid = tlb_valid_pulse(i), init = 0.U.asTypeOf(fromITLB(i).bits.gpaddr(0)), data = fromITLB(i).bits.gpaddr(0))
val s1_req_gpaddr_tmp = VecInit((0 until PortNumber).map(i =>
ResultHoldBypass(
valid = tlb_valid_pulse(i),
init = 0.U.asTypeOf(fromITLB(i).bits.gpaddr(0)),
data = fromITLB(i).bits.gpaddr(0)
)
))
val s1_req_isForVSnonLeafPTE_tmp = VecInit((0 until PortNumber).map( i =>
ResultHoldBypass(valid = tlb_valid_pulse(i), init = 0.U.asTypeOf(fromITLB(i).bits.isForVSnonLeafPTE), data = fromITLB(i).bits.isForVSnonLeafPTE)
val s1_req_isForVSnonLeafPTE_tmp = VecInit((0 until PortNumber).map(i =>
ResultHoldBypass(
valid = tlb_valid_pulse(i),
init = 0.U.asTypeOf(fromITLB(i).bits.isForVSnonLeafPTE),
data = fromITLB(i).bits.isForVSnonLeafPTE
)
))
val s1_itlb_exception = VecInit((0 until PortNumber).map( i =>
ResultHoldBypass(valid = tlb_valid_pulse(i), init = 0.U(ExceptionType.width.W), data = ExceptionType.fromTlbResp(fromITLB(i).bits))
val s1_itlb_exception = VecInit((0 until PortNumber).map(i =>
ResultHoldBypass(
valid = tlb_valid_pulse(i),
init = 0.U(ExceptionType.width.W),
data = ExceptionType.fromTlbResp(fromITLB(i).bits)
)
))
val s1_itlb_pbmt = VecInit((0 until PortNumber).map( i =>
ResultHoldBypass(valid = tlb_valid_pulse(i), init = 0.U.asTypeOf(fromITLB(i).bits.pbmt(0)), data = fromITLB(i).bits.pbmt(0))
val s1_itlb_pbmt = VecInit((0 until PortNumber).map(i =>
ResultHoldBypass(
valid = tlb_valid_pulse(i),
init = 0.U.asTypeOf(fromITLB(i).bits.pbmt(0)),
data = fromITLB(i).bits.pbmt(0)
)
))
val s1_itlb_exception_gpf = VecInit(s1_itlb_exception.map(_ === ExceptionType.gpf))
@ -226,12 +247,12 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
******************************************************************************
*/
val s1_need_meta = ((state === m_itlbResend) && itlb_finish) || (state === m_metaResend)
toMeta.valid := s1_need_meta || s0_valid
toMeta.bits := DontCare
toMeta.bits.isDoubleLine := Mux(s1_need_meta, s1_doubleline, s0_doubleline)
toMeta.valid := s1_need_meta || s0_valid
toMeta.bits := DontCare
toMeta.bits.isDoubleLine := Mux(s1_need_meta, s1_doubleline, s0_doubleline)
for (i <- 0 until PortNumber) {
toMeta.bits.vSetIdx(i) := Mux(s1_need_meta, s1_req_vSetIdx(i), s0_req_vSetIdx(i))
toMeta.bits.vSetIdx(i) := Mux(s1_need_meta, s1_req_vSetIdx(i), s0_req_vSetIdx(i))
}
/**
@ -239,16 +260,19 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
* Receive resp from IMeta and check
******************************************************************************
*/
val s1_req_ptags = VecInit(s1_req_paddr.map(get_phy_tag))
val s1_req_ptags = VecInit(s1_req_paddr.map(get_phy_tag))
val s1_meta_ptags = fromMeta.tags
val s1_meta_valids = fromMeta.entryValid
val s1_meta_ptags = fromMeta.tags
val s1_meta_valids = fromMeta.entryValid
def get_waymask(paddrs: Vec[UInt]): Vec[UInt] = {
val ptags = paddrs.map(get_phy_tag)
val tag_eq_vec = VecInit((0 until PortNumber).map( p => VecInit((0 until nWays).map( w => s1_meta_ptags(p)(w) === ptags(p)))))
val tag_match_vec = VecInit((0 until PortNumber).map( k => VecInit(tag_eq_vec(k).zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && s1_meta_valids(k)(w)})))
val waymasks = VecInit(tag_match_vec.map(_.asUInt))
val ptags = paddrs.map(get_phy_tag)
val tag_eq_vec =
VecInit((0 until PortNumber).map(p => VecInit((0 until nWays).map(w => s1_meta_ptags(p)(w) === ptags(p)))))
val tag_match_vec = VecInit((0 until PortNumber).map(k =>
VecInit(tag_eq_vec(k).zipWithIndex.map { case (way_tag_eq, w) => way_tag_eq && s1_meta_valids(k)(w) })
))
val waymasks = VecInit(tag_match_vec.map(_.asUInt))
waymasks
}
@ -282,7 +306,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
require(mask.getWidth == nWays)
val new_mask = WireInit(mask)
val new_code = WireInit(code)
val valid = fromMSHR.valid && !fromMSHR.bits.corrupt
val valid = fromMSHR.valid && !fromMSHR.bits.corrupt
val vset_same = fromMSHR.bits.vSetIdx === vSetIdx
val ptag_same = getPhyTagFromBlk(fromMSHR.bits.blkPaddr) === ptag
val way_same = fromMSHR.bits.waymask === mask
@ -300,18 +324,18 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
(new_mask, new_code)
}
val s1_SRAM_valid = s0_fire_r || RegNext(s1_need_meta && toMeta.ready)
val s1_MSHR_valid = fromMSHR.valid && !fromMSHR.bits.corrupt
val s1_waymasks = WireInit(VecInit(Seq.fill(PortNumber)(0.U(nWays.W))))
val s1_waymasks_r = RegEnable(s1_waymasks, 0.U.asTypeOf(s1_waymasks), s1_SRAM_valid || s1_MSHR_valid)
val s1_SRAM_valid = s0_fire_r || RegNext(s1_need_meta && toMeta.ready)
val s1_MSHR_valid = fromMSHR.valid && !fromMSHR.bits.corrupt
val s1_waymasks = WireInit(VecInit(Seq.fill(PortNumber)(0.U(nWays.W))))
val s1_waymasks_r = RegEnable(s1_waymasks, 0.U.asTypeOf(s1_waymasks), s1_SRAM_valid || s1_MSHR_valid)
val s1_meta_codes = WireInit(VecInit(Seq.fill(PortNumber)(0.U(ICacheMetaCodeBits.W))))
val s1_meta_codes_r = RegEnable(s1_meta_codes, 0.U.asTypeOf(s1_meta_codes), s1_SRAM_valid || s1_MSHR_valid)
// update waymasks and meta_codes
(0 until PortNumber).foreach{i =>
val old_waymask = Mux(s1_SRAM_valid, s1_SRAM_waymasks(i), s1_waymasks_r(i))
(0 until PortNumber).foreach { i =>
val old_waymask = Mux(s1_SRAM_valid, s1_SRAM_waymasks(i), s1_waymasks_r(i))
val old_meta_codes = Mux(s1_SRAM_valid, s1_SRAM_meta_codes(i), s1_meta_codes_r(i))
val new_info = update_meta_info(old_waymask, s1_req_vSetIdx(i), s1_req_ptags(i), old_meta_codes)
val new_info = update_meta_info(old_waymask, s1_req_vSetIdx(i), s1_req_ptags(i), old_meta_codes)
s1_waymasks(i) := new_info._1
s1_meta_codes(i) := new_info._2
}
@ -322,16 +346,17 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
******** **********************************************************************
*/
// Disallow enqueuing wayLookup when SRAM write occurs.
toWayLookup.valid := ((state === m_enqWay) || ((state === m_idle) && itlb_finish)) &&
!s1_flush && !fromMSHR.valid && !s1_isSoftPrefetch // do not enqueue soft prefetch
toWayLookup.bits.vSetIdx := s1_req_vSetIdx
toWayLookup.bits.waymask := s1_waymasks
toWayLookup.bits.ptag := s1_req_ptags
toWayLookup.bits.gpaddr := s1_req_gpaddr
toWayLookup.bits.isForVSnonLeafPTE := s1_req_isForVSnonLeafPTE
toWayLookup.bits.meta_codes := s1_meta_codes
toWayLookup.valid := ((state === m_enqWay) || ((state === m_idle) && itlb_finish)) &&
!s1_flush && !fromMSHR.valid && !s1_isSoftPrefetch // do not enqueue soft prefetch
toWayLookup.bits.vSetIdx := s1_req_vSetIdx
toWayLookup.bits.waymask := s1_waymasks
toWayLookup.bits.ptag := s1_req_ptags
toWayLookup.bits.gpaddr := s1_req_gpaddr
toWayLookup.bits.isForVSnonLeafPTE := s1_req_isForVSnonLeafPTE
toWayLookup.bits.meta_codes := s1_meta_codes
(0 until PortNumber).foreach { i =>
val excpValid = (if (i == 0) true.B else s1_doubleline) // exception in first line is always valid, in second line is valid iff is doubleline request
val excpValid = if (i == 0) true.B
else s1_doubleline // exception in first line is always valid, in second line is valid iff is doubleline request
// Send s1_itlb_exception to WayLookup (instead of s1_exception_out) for better timing. Will check pmp again in mainPipe
toWayLookup.bits.itlb_exception(i) := Mux(excpValid, s1_itlb_exception(i), ExceptionType.none)
toWayLookup.bits.itlb_pbmt(i) := Mux(excpValid, s1_itlb_pbmt(i), Pbmt.pma)
@ -339,10 +364,18 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
val s1_waymasks_vec = s1_waymasks.map(_.asTypeOf(Vec(nWays, Bool())))
when(toWayLookup.fire) {
assert(PopCount(s1_waymasks_vec(0)) <= 1.U && (PopCount(s1_waymasks_vec(1)) <= 1.U || !s1_doubleline),
assert(
PopCount(s1_waymasks_vec(0)) <= 1.U && (PopCount(s1_waymasks_vec(1)) <= 1.U || !s1_doubleline),
"Multiple hit in main pipe, port0:is=%d,ptag=0x%x,vidx=0x%x,vaddr=0x%x port1:is=%d,ptag=0x%x,vidx=0x%x,vaddr=0x%x ",
PopCount(s1_waymasks_vec(0)) > 1.U, s1_req_ptags(0), get_idx(s1_req_vaddr(0)), s1_req_vaddr(0),
PopCount(s1_waymasks_vec(1)) > 1.U && s1_doubleline, s1_req_ptags(1), get_idx(s1_req_vaddr(1)), s1_req_vaddr(1))
PopCount(s1_waymasks_vec(0)) > 1.U,
s1_req_ptags(0),
get_idx(s1_req_vaddr(0)),
s1_req_vaddr(0),
PopCount(s1_waymasks_vec(1)) > 1.U && s1_doubleline,
s1_req_ptags(1),
get_idx(s1_req_vaddr(1)),
s1_req_vaddr(1)
)
}
/**
@ -354,7 +387,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
// if itlb has exception, paddr can be invalid, therefore pmp check can be skipped
p.valid := s1_valid // && s1_itlb_exception === ExceptionType.none
p.bits.addr := s1_req_paddr(i)
p.bits.size := 3.U // TODO
p.bits.size := 3.U // TODO
p.bits.cmd := TlbCmd.exec
}
val s1_pmp_exception = VecInit(fromPMP.map(ExceptionType.fromPMPResp))
@ -368,7 +401,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
)
// merge pmp mmio and itlb pbmt
val s1_mmio = VecInit((s1_pmp_mmio zip s1_itlb_pbmt).map{ case (mmio, pbmt) =>
val s1_mmio = VecInit((s1_pmp_mmio zip s1_itlb_pbmt).map { case (mmio, pbmt) =>
mmio || Pbmt.isUncache(pbmt)
})
@ -383,12 +416,12 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
when(s1_valid) {
when(!itlb_finish) {
next_state := m_itlbResend
}.elsewhen(!toWayLookup.fire) { // itlb_finish
}.elsewhen(!toWayLookup.fire) { // itlb_finish
next_state := m_enqWay
}.elsewhen(!s2_ready) { // itlb_finish && toWayLookup.fire
}.elsewhen(!s2_ready) { // itlb_finish && toWayLookup.fire
next_state := m_enterS2
} // .otherwise { next_state := m_idle }
} // .otherwise { next_state := m_idle } // !s1_valid
} // .otherwise { next_state := m_idle } // !s1_valid
}
is(m_itlbResend) {
when(itlb_finish) {
@ -406,9 +439,9 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
}
is(m_enqWay) {
when(toWayLookup.fire || s1_isSoftPrefetch) {
when (!s2_ready) {
when(!s2_ready) {
next_state := m_enterS2
}.otherwise { // s2_ready
}.otherwise { // s2_ready
next_state := m_idle
}
} // .otherwise { next_state := m_enqWay }
@ -426,11 +459,11 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
/** Stage 1 control */
from_bpu_s1_flush := s1_valid && !s1_isSoftPrefetch && io.flushFromBpu.shouldFlushByStage3(s1_req_ftqIdx)
s1_flush := io.flush || from_bpu_s1_flush
s1_flush := io.flush || from_bpu_s1_flush
s1_ready := next_state === m_idle
s1_fire := (next_state === m_idle) && s1_valid && !s1_flush // used to clear s1_valid & itlb_valid_latch
val s1_real_fire = s1_fire && io.csr_pf_enable // real "s1 fire" that s1 enters s2
s1_ready := next_state === m_idle
s1_fire := (next_state === m_idle) && s1_valid && !s1_flush // used to clear s1_valid & itlb_valid_latch
val s1_real_fire = s1_fire && io.csr_pf_enable // real "s1 fire" that s1 enters s2
/**
******************************************************************************
@ -439,20 +472,22 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
* - 2. send req to missUnit
******************************************************************************
*/
val s2_valid = generatePipeControl(lastFire = s1_real_fire, thisFire = s2_fire, thisFlush = s2_flush, lastFlush = false.B)
val s2_valid =
generatePipeControl(lastFire = s1_real_fire, thisFire = s2_fire, thisFlush = s2_flush, lastFlush = false.B)
val s2_req_vaddr = RegEnable(s1_req_vaddr, 0.U.asTypeOf(s1_req_vaddr), s1_real_fire)
val s2_req_vaddr = RegEnable(s1_req_vaddr, 0.U.asTypeOf(s1_req_vaddr), s1_real_fire)
val s2_isSoftPrefetch = RegEnable(s1_isSoftPrefetch, 0.U.asTypeOf(s1_isSoftPrefetch), s1_real_fire)
val s2_doubleline = RegEnable(s1_doubleline, 0.U.asTypeOf(s1_doubleline), s1_real_fire)
val s2_req_paddr = RegEnable(s1_req_paddr, 0.U.asTypeOf(s1_req_paddr), s1_real_fire)
val s2_exception = RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_real_fire) // includes itlb/pmp exception
val s2_doubleline = RegEnable(s1_doubleline, 0.U.asTypeOf(s1_doubleline), s1_real_fire)
val s2_req_paddr = RegEnable(s1_req_paddr, 0.U.asTypeOf(s1_req_paddr), s1_real_fire)
val s2_exception =
RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_real_fire) // includes itlb/pmp exception
// val s2_exception_in = RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_real_fire) // disabled for timing consideration
val s2_mmio = RegEnable(s1_mmio, 0.U.asTypeOf(s1_mmio), s1_real_fire)
val s2_waymasks = RegEnable(s1_waymasks, 0.U.asTypeOf(s1_waymasks), s1_real_fire)
val s2_mmio = RegEnable(s1_mmio, 0.U.asTypeOf(s1_mmio), s1_real_fire)
val s2_waymasks = RegEnable(s1_waymasks, 0.U.asTypeOf(s1_waymasks), s1_real_fire)
// val s2_meta_codes = RegEnable(s1_meta_codes, 0.U.asTypeOf(s1_meta_codes), s1_real_fire) // disabled for timing consideration
val s2_req_vSetIdx = s2_req_vaddr.map(get_idx)
val s2_req_ptags = s2_req_paddr.map(get_phy_tag)
val s2_req_vSetIdx = s2_req_vaddr.map(get_idx)
val s2_req_ptags = s2_req_paddr.map(get_phy_tag)
// disabled for timing consideration
// // do metaArray ECC check
@ -481,22 +516,22 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
*/
val s2_MSHR_match = VecInit((0 until PortNumber).map(i =>
(s2_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) &&
(s2_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
s2_valid && fromMSHR.valid && !fromMSHR.bits.corrupt
(s2_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) &&
s2_valid && fromMSHR.valid && !fromMSHR.bits.corrupt
))
val s2_MSHR_hits = (0 until PortNumber).map(i => ValidHoldBypass(s2_MSHR_match(i), s2_fire || s2_flush))
val s2_SRAM_hits = s2_waymasks.map(_.orR)
val s2_hits = VecInit((0 until PortNumber).map(i => s2_MSHR_hits(i) || s2_SRAM_hits(i)))
val s2_hits = VecInit((0 until PortNumber).map(i => s2_MSHR_hits(i) || s2_SRAM_hits(i)))
/* s2_exception includes itlb pf/gpf/af, pmp af and meta corruption (af), neither of which should be prefetched
* mmio should not be prefetched
* also, if previous has exception, latter port should also not be prefetched
*/
val s2_miss = VecInit((0 until PortNumber).map { i =>
!s2_hits(i) && (if (i==0) true.B else s2_doubleline) &&
s2_exception.take(i+1).map(_ === ExceptionType.none).reduce(_&&_) &&
s2_mmio.take(i+1).map(!_).reduce(_&&_)
!s2_hits(i) && (if (i == 0) true.B else s2_doubleline) &&
s2_exception.take(i + 1).map(_ === ExceptionType.none).reduce(_ && _) &&
s2_mmio.take(i + 1).map(!_).reduce(_ && _)
})
/**
@ -508,7 +543,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
// To avoid sending duplicate requests.
val has_send = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
(0 until PortNumber).foreach{ i =>
(0 until PortNumber).foreach { i =>
when(s1_real_fire) {
has_send(i) := false.B
}.elsewhen(toMSHRArbiter.io.in(i).fire) {
@ -516,10 +551,10 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
}
}
(0 until PortNumber).map{ i =>
toMSHRArbiter.io.in(i).valid := s2_valid && s2_miss(i) && !has_send(i)
toMSHRArbiter.io.in(i).bits.blkPaddr := getBlkAddr(s2_req_paddr(i))
toMSHRArbiter.io.in(i).bits.vSetIdx := s2_req_vSetIdx(i)
(0 until PortNumber).map { i =>
toMSHRArbiter.io.in(i).valid := s2_valid && s2_miss(i) && !has_send(i)
toMSHRArbiter.io.in(i).bits.blkPaddr := getBlkAddr(s2_req_paddr(i))
toMSHRArbiter.io.in(i).bits.vSetIdx := s2_req_vSetIdx(i)
}
toMSHR <> toMSHRArbiter.io.out
@ -528,9 +563,9 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
// toMSHRArbiter.io.in(i).fire is not used here for timing consideration
// val s2_finish = (0 until PortNumber).map(i => has_send(i) || !s2_miss(i) || toMSHRArbiter.io.in(i).fire).reduce(_&&_)
val s2_finish = (0 until PortNumber).map(i => has_send(i) || !s2_miss(i)).reduce(_&&_)
s2_ready := s2_finish || !s2_valid
s2_fire := s2_valid && s2_finish && !s2_flush
val s2_finish = (0 until PortNumber).map(i => has_send(i) || !s2_miss(i)).reduce(_ && _)
s2_ready := s2_finish || !s2_valid
s2_fire := s2_valid && s2_finish && !s2_flush
/** PerfAccumulate */
// the number of bpu flush
@ -545,6 +580,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
XSPerfAccumulate("prefetch_req_send_hw", toMSHR.fire && !s2_isSoftPrefetch)
XSPerfAccumulate("prefetch_req_send_sw", toMSHR.fire && s2_isSoftPrefetch)
XSPerfAccumulate("to_missUnit_stall", toMSHR.valid && !toMSHR.ready)
/**
* Count the number of requests that are filtered for various reasons.
* The number of prefetch discard in Performance Accumulator may be
@ -561,4 +597,4 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule
// XSPerfAccumulate("fdip_prefetch_discard_by_pmp", p2_discard && p2_pmp_except)
// // discard prefetch request by hit mainPipe info
// // XSPerfAccumulate("fdip_prefetch_discard_by_mainPipe", p2_discard && p2_mainPipe_hit)
}
}

View File

@ -18,31 +18,38 @@ package xiangshan.frontend.icache
import chisel3._
import chisel3.util._
import utils._
import utility._
import freechips.rocketchip.diplomacy.IdRange
import freechips.rocketchip.diplomacy.LazyModule
import freechips.rocketchip.diplomacy.LazyModuleImp
import freechips.rocketchip.diplomacy.TransferSizes
import freechips.rocketchip.tilelink.TLArbiter
import freechips.rocketchip.tilelink.TLBundleA
import freechips.rocketchip.tilelink.TLBundleD
import freechips.rocketchip.tilelink.TLClientNode
import freechips.rocketchip.tilelink.TLEdgeOut
import freechips.rocketchip.tilelink.TLMasterParameters
import freechips.rocketchip.tilelink.TLMasterPortParameters
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes}
import freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters}
import utility._
import utils._
import xiangshan._
import xiangshan.frontend._
class InsUncacheReq(implicit p: Parameters) extends ICacheBundle
{
val addr = UInt(PAddrBits.W)
class InsUncacheReq(implicit p: Parameters) extends ICacheBundle {
val addr = UInt(PAddrBits.W)
}
class InsUncacheResp(implicit p: Parameters) extends ICacheBundle
{
class InsUncacheResp(implicit p: Parameters) extends ICacheBundle {
val data = UInt(maxInstrLen.W)
}
// One miss entry deals with one mmio request
class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters with HasIFUConst
{
class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters
with HasIFUConst {
val io = IO(new Bundle {
val id = Input(UInt(log2Up(cacheParams.nMMIOs).W))
// client requests
val req = Flipped(DecoupledIO(new InsUncacheReq))
val req = Flipped(DecoupledIO(new InsUncacheReq))
val resp = DecoupledIO(new InsUncacheResp)
val mmio_acquire = DecoupledIO(new TLBundleA(edge.bundle))
@ -51,92 +58,92 @@ class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule w
val flush = Input(Bool())
})
val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
val state = RegInit(s_invalid)
val req = Reg(new InsUncacheReq )
val req = Reg(new InsUncacheReq)
val respDataReg = Reg(UInt(mmioBusWidth.W))
// assign default values to output signals
io.req.ready := false.B
io.resp.valid := false.B
io.resp.bits := DontCare
io.req.ready := false.B
io.resp.valid := false.B
io.resp.bits := DontCare
io.mmio_acquire.valid := false.B
io.mmio_acquire.bits := DontCare
io.mmio_acquire.valid := false.B
io.mmio_acquire.bits := DontCare
io.mmio_grant.ready := false.B
io.mmio_grant.ready := false.B
val needFlush = RegInit(false.B)
when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp)){ needFlush := true.B }
.elsewhen((state=== s_send_resp) && needFlush){ needFlush := false.B }
when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp))(needFlush := true.B)
.elsewhen((state === s_send_resp) && needFlush)(needFlush := false.B)
// --------------------------------------------
// s_invalid: receive requests
when (state === s_invalid) {
when(state === s_invalid) {
io.req.ready := true.B
when (io.req.fire) {
when(io.req.fire) {
req := io.req.bits
state := s_refill_req
}
}
when (state === s_refill_req) {
when(state === s_refill_req) {
val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes))
io.mmio_acquire.valid := true.B
io.mmio_acquire.bits := edge.Get(
fromSource = io.id,
toAddress = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
lgSize = log2Ceil(mmioBusBytes).U
)._2
io.mmio_acquire.bits := edge.Get(
fromSource = io.id,
toAddress = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
lgSize = log2Ceil(mmioBusBytes).U
)._2
when (io.mmio_acquire.fire) {
when(io.mmio_acquire.fire) {
state := s_refill_resp
}
}
val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant)
when (state === s_refill_resp) {
when(state === s_refill_resp) {
io.mmio_grant.ready := true.B
when (io.mmio_grant.fire) {
when(io.mmio_grant.fire) {
respDataReg := io.mmio_grant.bits.data
state := s_send_resp
state := s_send_resp
}
}
def getDataFromBus(pc: UInt) = {
val respData = Wire(UInt(maxInstrLen.W))
respData := Mux(pc(2,1) === "b00".U, respDataReg(31,0),
Mux(pc(2,1) === "b01".U, respDataReg(47,16),
Mux(pc(2,1) === "b10".U, respDataReg(63,32),
Cat(0.U, respDataReg(63,48))
)
)
respData := Mux(
pc(2, 1) === "b00".U,
respDataReg(31, 0),
Mux(
pc(2, 1) === "b01".U,
respDataReg(47, 16),
Mux(pc(2, 1) === "b10".U, respDataReg(63, 32), Cat(0.U, respDataReg(63, 48)))
)
)
respData
}
when (state === s_send_resp) {
when(state === s_send_resp) {
io.resp.valid := !needFlush
io.resp.bits.data := getDataFromBus(req.addr)
io.resp.bits.data := getDataFromBus(req.addr)
// meta data should go with the response
when (io.resp.fire || needFlush) {
when(io.resp.fire || needFlush) {
state := s_invalid
}
}
}
class InstrUncacheIO(implicit p: Parameters) extends ICacheBundle {
val req = Flipped(DecoupledIO(new InsUncacheReq ))
val resp = DecoupledIO(new InsUncacheResp)
val flush = Input(Bool())
val req = Flipped(DecoupledIO(new InsUncacheReq))
val resp = DecoupledIO(new InsUncacheResp)
val flush = Input(Bool())
}
class InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
@ -155,23 +162,22 @@ class InstrUncache()(implicit p: Parameters) extends LazyModule with HasICachePa
}
class InstrUncacheImp(outer: InstrUncache)
extends LazyModuleImp(outer)
extends LazyModuleImp(outer)
with HasICacheParameters
with HasTLDump
{
with HasTLDump {
val io = IO(new InstrUncacheIO)
val (bus, edge) = outer.clientNode.out.head
val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs))
val req = io.req
val resp = io.resp
val req = io.req
val resp = io.resp
val mmio_acquire = bus.a
val mmio_grant = bus.d
val entry_alloc_idx = Wire(UInt())
val req_ready = WireInit(false.B)
val req_ready = WireInit(false.B)
// assign default values to output signals
bus.b.ready := false.B
@ -184,13 +190,13 @@ class InstrUncacheImp(outer: InstrUncache)
val entries = (0 until cacheParams.nMMIOs) map { i =>
val entry = Module(new InstrMMIOEntry(edge))
entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W)
entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W)
entry.io.flush := io.flush
// entry req
entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
entry.io.req.bits := req.bits
when (i.U === entry_alloc_idx) {
when(i.U === entry_alloc_idx) {
req_ready := entry.io.req.ready
}
@ -199,16 +205,16 @@ class InstrUncacheImp(outer: InstrUncache)
entry.io.mmio_grant.valid := false.B
entry.io.mmio_grant.bits := DontCare
when (mmio_grant.bits.source === i.U) {
when(mmio_grant.bits.source === i.U) {
entry.io.mmio_grant <> mmio_grant
}
entry
}
entry_alloc_idx := PriorityEncoder(entries.map(m=>m.io.req.ready))
entry_alloc_idx := PriorityEncoder(entries.map(m => m.io.req.ready))
req.ready := req_ready
resp <> resp_arb.io.out
req.ready := req_ready
resp <> resp_arb.io.out
TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire))
}

View File

@ -16,12 +16,12 @@
package xiangshan.frontend.icache
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import utility._
import xiangshan.frontend.ExceptionType
import xiangshan.cache.mmu.Pbmt
import xiangshan.frontend.ExceptionType
/* WayLookupEntry is for internal storage, while WayLookupInfo is for interface
* Notes:
@ -30,17 +30,17 @@ import xiangshan.cache.mmu.Pbmt
* to save area, we separate those signals from WayLookupEntry and store only once.
*/
class WayLookupEntry(implicit p: Parameters) extends ICacheBundle {
val vSetIdx : Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
val waymask : Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
val ptag : Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
val itlb_exception : Vec[UInt] = Vec(PortNumber, UInt(ExceptionType.width.W))
val itlb_pbmt : Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
val meta_codes : Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
val ptag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
val itlb_exception: Vec[UInt] = Vec(PortNumber, UInt(ExceptionType.width.W))
val itlb_pbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
val meta_codes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
}
class WayLookupGPFEntry(implicit p: Parameters) extends ICacheBundle {
val gpaddr : UInt = UInt(GPAddrBits.W)
val isForVSnonLeafPTE : Bool = Bool()
val gpaddr: UInt = UInt(GPAddrBits.W)
val isForVSnonLeafPTE: Bool = Bool()
}
class WayLookupInfo(implicit p: Parameters) extends ICacheBundle {
@ -48,21 +48,21 @@ class WayLookupInfo(implicit p: Parameters) extends ICacheBundle {
val gpf = new WayLookupGPFEntry
// for compatibility
def vSetIdx : Vec[UInt] = entry.vSetIdx
def waymask : Vec[UInt] = entry.waymask
def ptag : Vec[UInt] = entry.ptag
def itlb_exception : Vec[UInt] = entry.itlb_exception
def itlb_pbmt : Vec[UInt] = entry.itlb_pbmt
def meta_codes : Vec[UInt] = entry.meta_codes
def gpaddr : UInt = gpf.gpaddr
def isForVSnonLeafPTE : Bool = gpf.isForVSnonLeafPTE
def vSetIdx: Vec[UInt] = entry.vSetIdx
def waymask: Vec[UInt] = entry.waymask
def ptag: Vec[UInt] = entry.ptag
def itlb_exception: Vec[UInt] = entry.itlb_exception
def itlb_pbmt: Vec[UInt] = entry.itlb_pbmt
def meta_codes: Vec[UInt] = entry.meta_codes
def gpaddr: UInt = gpf.gpaddr
def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE
}
class WayLookupInterface(implicit p: Parameters) extends ICacheBundle {
val flush = Input(Bool())
val read = DecoupledIO(new WayLookupInfo)
val write = Flipped(DecoupledIO(new WayLookupInfo))
val update = Flipped(ValidIO(new ICacheMissResp))
val flush = Input(Bool())
val read = DecoupledIO(new WayLookupInfo)
val write = Flipped(DecoupledIO(new WayLookupInfo))
val update = Flipped(ValidIO(new ICacheMissResp))
}
class WayLookup(implicit p: Parameters) extends ICacheModule {
@ -72,7 +72,7 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
private object WayLookupPtr {
def apply(f: Bool, v: UInt)(implicit p: Parameters): WayLookupPtr = {
val ptr = Wire(new WayLookupPtr)
ptr.flag := f
ptr.flag := f
ptr.value := v
ptr
}
@ -115,12 +115,12 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
******************************************************************************
*/
private val hits = Wire(Vec(nWayLookupSize, Bool()))
entries.zip(hits).foreach{ case(entry, hit) =>
entries.zip(hits).foreach { case (entry, hit) =>
val hit_vec = Wire(Vec(PortNumber, Bool()))
(0 until PortNumber).foreach { i =>
val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid
val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i)
val way_same = io.update.bits.waymask === entry.waymask(i)
val way_same = io.update.bits.waymask === entry.waymask(i)
when(vset_same) {
when(ptag_same) {
// miss -> hit
@ -136,7 +136,7 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
}
hit_vec(i) := vset_same && (ptag_same || way_same)
}
hit := hit_vec.reduce(_||_)
hit := hit_vec.reduce(_ || _)
}
/**
@ -147,17 +147,17 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
// if the entry is empty, but there is a valid write, we can bypass it to read port (maybe timing critical)
private val can_bypass = empty && io.write.valid
io.read.valid := !empty || io.write.valid
when (can_bypass) {
when(can_bypass) {
io.read.bits := io.write.bits
}.otherwise { // can't bypass
}.otherwise { // can't bypass
io.read.bits.entry := entries(readPtr.value)
when(gpf_hit) { // ptr match && entry valid
when(gpf_hit) { // ptr match && entry valid
io.read.bits.gpf := gpf_entry.bits
// also clear gpf_entry.valid when it's read, note this will be override by write (L175)
when (io.read.fire) {
when(io.read.fire) {
gpf_entry.valid := false.B
}
}.otherwise { // gpf not hit
}.otherwise { // gpf not hit
io.read.bits.gpf := 0.U.asTypeOf(new WayLookupGPFEntry)
}
}
@ -172,12 +172,12 @@ class WayLookup(implicit p: Parameters) extends ICacheModule {
io.write.ready := !full && !gpf_stall
when(io.write.fire) {
entries(writePtr.value) := io.write.bits.entry
when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_||_)) {
when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_ || _)) {
// if gpf_entry is bypassed, we don't need to save it
// note this will override the read (L156)
gpf_entry.valid := !(can_bypass && io.read.fire)
gpf_entry.bits := io.write.bits.gpf
gpfPtr := writePtr
gpfPtr := writePtr
}
}
}

View File

@ -16,73 +16,69 @@
***************************************************************************************/
package xiangshan.frontend
import org.chipsalliance.cde.config.Parameters
import chisel3._
import chisel3.util._
import utils._
import org.chipsalliance.cde.config.Parameters
import utility._
import utils._
import xiangshan._
import xiangshan.frontend._
class RASEntry()(implicit p: Parameters) extends XSBundle {
val retAddr = UInt(VAddrBits.W)
val ctr = UInt(RasCtrSize.W) // layer of nested call functions
def =/=(that: RASEntry) = this.retAddr =/= that.retAddr || this.ctr =/= that.ctr
val retAddr = UInt(VAddrBits.W)
val ctr = UInt(RasCtrSize.W) // layer of nested call functions
def =/=(that: RASEntry) = this.retAddr =/= that.retAddr || this.ctr =/= that.ctr
}
class RASPtr(implicit p: Parameters) extends CircularQueuePtr[RASPtr](
p => p(XSCoreParamsKey).RasSpecSize
){
}
class RASPtr(implicit p: Parameters) extends CircularQueuePtr[RASPtr](p => p(XSCoreParamsKey).RasSpecSize) {}
object RASPtr {
def apply(f: Bool, v: UInt)(implicit p: Parameters): RASPtr = {
val ptr = Wire(new RASPtr)
ptr.flag := f
ptr.flag := f
ptr.value := v
ptr
}
def inverse(ptr: RASPtr)(implicit p: Parameters): RASPtr = {
def inverse(ptr: RASPtr)(implicit p: Parameters): RASPtr =
apply(!ptr.flag, ptr.value)
}
}
class RASInternalMeta(implicit p: Parameters) extends XSBundle {
val ssp = UInt(log2Up(RasSize).W)
val ssp = UInt(log2Up(RasSize).W)
val sctr = UInt(RasCtrSize.W)
val TOSW = new RASPtr
val TOSR = new RASPtr
val NOS = new RASPtr
val NOS = new RASPtr
}
object RASInternalMeta {
def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters):RASInternalMeta = {
def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASInternalMeta = {
val e = Wire(new RASInternalMeta)
e.ssp := ssp
e.ssp := ssp
e.TOSW := TOSW
e.TOSR := TOSR
e.NOS := NOS
e.NOS := NOS
e
}
}
class RASMeta(implicit p: Parameters) extends XSBundle {
val ssp = UInt(log2Up(RasSize).W)
val ssp = UInt(log2Up(RasSize).W)
val TOSW = new RASPtr
}
object RASMeta {
def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters):RASMeta = {
def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASMeta = {
val e = Wire(new RASMeta)
e.ssp := ssp
e.ssp := ssp
e.TOSW := TOSW
e
}
}
class RASDebug(implicit p: Parameters) extends XSBundle {
val spec_queue = Output(Vec(RasSpecSize, new RASEntry))
val spec_nos = Output(Vec(RasSpecSize, new RASPtr))
val spec_queue = Output(Vec(RasSpecSize, new RASEntry))
val spec_nos = Output(Vec(RasSpecSize, new RASPtr))
val commit_stack = Output(Vec(RasSize, new RASEntry))
}
@ -93,53 +89,52 @@ class RAS(implicit p: Parameters) extends BasePredictor {
def apply(retAddr: UInt, ctr: UInt): RASEntry = {
val e = Wire(new RASEntry)
e.retAddr := retAddr
e.ctr := ctr
e.ctr := ctr
e
}
}
class RASStack(rasSize: Int, rasSpecSize: Int) extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new Bundle {
val spec_push_valid = Input(Bool())
val spec_pop_valid = Input(Bool())
val spec_push_addr = Input(UInt(VAddrBits.W))
val spec_pop_valid = Input(Bool())
val spec_push_addr = Input(UInt(VAddrBits.W))
// for write bypass between s2 and s3
val s2_fire = Input(Bool())
val s3_fire = Input(Bool())
val s3_cancel = Input(Bool())
val s3_meta = Input(new RASInternalMeta)
val s3_missed_pop = Input(Bool())
val s2_fire = Input(Bool())
val s3_fire = Input(Bool())
val s3_cancel = Input(Bool())
val s3_meta = Input(new RASInternalMeta)
val s3_missed_pop = Input(Bool())
val s3_missed_push = Input(Bool())
val s3_pushAddr = Input(UInt(VAddrBits.W))
val spec_pop_addr = Output(UInt(VAddrBits.W))
val s3_pushAddr = Input(UInt(VAddrBits.W))
val spec_pop_addr = Output(UInt(VAddrBits.W))
val commit_valid = Input(Bool())
val commit_push_valid = Input(Bool())
val commit_pop_valid = Input(Bool())
val commit_push_addr = Input(UInt(VAddrBits.W))
val commit_meta_TOSW = Input(new RASPtr)
val commit_pop_valid = Input(Bool())
val commit_push_addr = Input(UInt(VAddrBits.W))
val commit_meta_TOSW = Input(new RASPtr)
// for debug purpose only
val commit_meta_ssp = Input(UInt(log2Up(RasSize).W))
val redirect_valid = Input(Bool())
val redirect_isCall = Input(Bool())
val redirect_isRet = Input(Bool())
val redirect_meta_ssp = Input(UInt(log2Up(RasSize).W))
val redirect_valid = Input(Bool())
val redirect_isCall = Input(Bool())
val redirect_isRet = Input(Bool())
val redirect_meta_ssp = Input(UInt(log2Up(RasSize).W))
val redirect_meta_sctr = Input(UInt(RasCtrSize.W))
val redirect_meta_TOSW = Input(new RASPtr)
val redirect_meta_TOSR = Input(new RASPtr)
val redirect_meta_NOS = Input(new RASPtr)
val redirect_callAddr = Input(UInt(VAddrBits.W))
val redirect_meta_NOS = Input(new RASPtr)
val redirect_callAddr = Input(UInt(VAddrBits.W))
val ssp = Output(UInt(log2Up(RasSize).W))
val ssp = Output(UInt(log2Up(RasSize).W))
val sctr = Output(UInt(RasCtrSize.W))
val nsp = Output(UInt(log2Up(RasSize).W))
val nsp = Output(UInt(log2Up(RasSize).W))
val TOSR = Output(new RASPtr)
val TOSW = Output(new RASPtr)
val NOS = Output(new RASPtr)
val BOS = Output(new RASPtr)
val NOS = Output(new RASPtr)
val BOS = Output(new RASPtr)
val spec_near_overflow = Output(Bool())
@ -147,8 +142,8 @@ class RAS(implicit p: Parameters) extends BasePredictor {
})
val commit_stack = RegInit(VecInit(Seq.fill(RasSize)(RASEntry(0.U, 0.U))))
val spec_queue = RegInit(VecInit(Seq.fill(rasSpecSize)(RASEntry(0.U, 0.U))))
val spec_nos = RegInit(VecInit(Seq.fill(rasSpecSize)(RASPtr(false.B, 0.U))))
val spec_queue = RegInit(VecInit(Seq.fill(rasSpecSize)(RASEntry(0.U, 0.U))))
val spec_nos = RegInit(VecInit(Seq.fill(rasSpecSize)(RASPtr(false.B, 0.U))))
val nsp = RegInit(0.U(log2Up(rasSize).W))
val ssp = RegInit(0.U(log2Up(rasSize).W))
@ -156,35 +151,34 @@ class RAS(implicit p: Parameters) extends BasePredictor {
val sctr = RegInit(0.U(RasCtrSize.W))
val TOSR = RegInit(RASPtr(true.B, (RasSpecSize - 1).U))
val TOSW = RegInit(RASPtr(false.B, 0.U))
val BOS = RegInit(RASPtr(false.B, 0.U))
val BOS = RegInit(RASPtr(false.B, 0.U))
val spec_near_overflowed = RegInit(false.B)
val writeBypassEntry = Reg(new RASEntry)
val writeBypassNos = Reg(new RASPtr)
val writeBypassNos = Reg(new RASPtr)
val writeBypassValid = RegInit(0.B)
val writeBypassValid = RegInit(0.B)
val writeBypassValidWire = Wire(Bool())
def TOSRinRange(currentTOSR: RASPtr, currentTOSW: RASPtr) = {
val inflightValid = WireInit(false.B)
// if in range, TOSR should be no younger than BOS and strictly younger than TOSW
when (!isBefore(currentTOSR, BOS) && isBefore(currentTOSR, currentTOSW)) {
when(!isBefore(currentTOSR, BOS) && isBefore(currentTOSR, currentTOSW)) {
inflightValid := true.B
}
inflightValid
}
def getCommitTop(currentSsp: UInt) = {
def getCommitTop(currentSsp: UInt) =
commit_stack(currentSsp)
}
def getTopNos(currentTOSR: RASPtr, allowBypass: Boolean):RASPtr = {
def getTopNos(currentTOSR: RASPtr, allowBypass: Boolean): RASPtr = {
val ret = Wire(new RASPtr)
if (allowBypass){
when (writeBypassValid) {
if (allowBypass) {
when(writeBypassValid) {
ret := writeBypassNos
} .otherwise {
}.otherwise {
ret := spec_nos(TOSR.value)
}
} else {
@ -193,20 +187,26 @@ class RAS(implicit p: Parameters) extends BasePredictor {
ret
}
def getTop(currentSsp: UInt, currentSctr: UInt, currentTOSR: RASPtr, currentTOSW: RASPtr, allowBypass: Boolean):RASEntry = {
def getTop(
currentSsp: UInt,
currentSctr: UInt,
currentTOSR: RASPtr,
currentTOSW: RASPtr,
allowBypass: Boolean
): RASEntry = {
val ret = Wire(new RASEntry)
if (allowBypass) {
when (writeBypassValid) {
when(writeBypassValid) {
ret := writeBypassEntry
} .elsewhen (TOSRinRange(currentTOSR, currentTOSW)) {
}.elsewhen(TOSRinRange(currentTOSR, currentTOSW)) {
ret := spec_queue(currentTOSR.value)
} .otherwise {
}.otherwise {
ret := getCommitTop(currentSsp)
}
} else {
when (TOSRinRange(currentTOSR, currentTOSW)) {
when(TOSRinRange(currentTOSR, currentTOSW)) {
ret := spec_queue(currentTOSR.value)
} .otherwise {
}.otherwise {
ret := getCommitTop(currentSsp)
}
}
@ -223,139 +223,149 @@ class RAS(implicit p: Parameters) extends BasePredictor {
def specPtrInc(ptr: RASPtr) = ptr + 1.U
def specPtrDec(ptr: RASPtr) = ptr - 1.U
when (io.redirect_valid && io.redirect_isCall) {
when(io.redirect_valid && io.redirect_isCall) {
writeBypassValidWire := true.B
writeBypassValid := true.B
} .elsewhen (io.redirect_valid) {
writeBypassValid := true.B
}.elsewhen(io.redirect_valid) {
// clear current top writeBypass if doing redirect
writeBypassValidWire := false.B
writeBypassValid := false.B
} .elsewhen (io.s2_fire) {
writeBypassValid := false.B
}.elsewhen(io.s2_fire) {
writeBypassValidWire := io.spec_push_valid
writeBypassValid := io.spec_push_valid
} .elsewhen (io.s3_fire) {
writeBypassValid := io.spec_push_valid
}.elsewhen(io.s3_fire) {
writeBypassValidWire := false.B
writeBypassValid := false.B
} .otherwise {
writeBypassValid := false.B
}.otherwise {
writeBypassValidWire := writeBypassValid
}
val topEntry = getTop(ssp, sctr, TOSR, TOSW, true)
val topNos = getTopNos(TOSR, true)
val redirectTopEntry = getTop(io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, false)
val topNos = getTopNos(TOSR, true)
val redirectTopEntry =
getTop(io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, false)
val redirectTopNos = io.redirect_meta_NOS
val s3TopEntry = getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false)
val s3TopNos = io.s3_meta.NOS
val s3TopEntry = getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false)
val s3TopNos = io.s3_meta.NOS
val writeEntry = Wire(new RASEntry)
val writeNos = Wire(new RASPtr)
writeEntry.retAddr := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_callAddr, io.spec_push_addr)
writeEntry.ctr := Mux(io.redirect_valid && io.redirect_isCall,
Mux(redirectTopEntry.retAddr === io.redirect_callAddr && redirectTopEntry.ctr < ctrMax, io.redirect_meta_sctr + 1.U, 0.U),
Mux(topEntry.retAddr === io.spec_push_addr && topEntry.ctr < ctrMax, sctr + 1.U, 0.U))
val writeNos = Wire(new RASPtr)
writeEntry.retAddr := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_callAddr, io.spec_push_addr)
writeEntry.ctr := Mux(
io.redirect_valid && io.redirect_isCall,
Mux(
redirectTopEntry.retAddr === io.redirect_callAddr && redirectTopEntry.ctr < ctrMax,
io.redirect_meta_sctr + 1.U,
0.U
),
Mux(topEntry.retAddr === io.spec_push_addr && topEntry.ctr < ctrMax, sctr + 1.U, 0.U)
)
writeNos := Mux(io.redirect_valid && io.redirect_isCall,
io.redirect_meta_TOSR, TOSR)
writeNos := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR)
when (io.spec_push_valid || (io.redirect_valid && io.redirect_isCall)) {
when(io.spec_push_valid || (io.redirect_valid && io.redirect_isCall)) {
writeBypassEntry := writeEntry
writeBypassNos := writeNos
writeBypassNos := writeNos
}
val realPush = Wire(Bool())
val realPush = Wire(Bool())
val realWriteEntry = Wire(new RASEntry)
val timingTop = RegInit(0.U.asTypeOf(new RASEntry))
val timingNos = RegInit(0.U.asTypeOf(new RASPtr))
val timingTop = RegInit(0.U.asTypeOf(new RASEntry))
val timingNos = RegInit(0.U.asTypeOf(new RASPtr))
when (writeBypassValidWire) {
when ((io.redirect_valid && io.redirect_isCall) || io.spec_push_valid) {
when(writeBypassValidWire) {
when((io.redirect_valid && io.redirect_isCall) || io.spec_push_valid) {
timingTop := writeEntry
timingNos := writeNos
} .otherwise {
}.otherwise {
timingTop := writeBypassEntry
timingNos := writeBypassNos
}
} .elsewhen (io.redirect_valid && io.redirect_isRet) {
}.elsewhen(io.redirect_valid && io.redirect_isRet) {
// getTop using redirect Nos as TOSR
val popRedSsp = Wire(UInt(log2Up(rasSize).W))
val popRedSsp = Wire(UInt(log2Up(rasSize).W))
val popRedSctr = Wire(UInt(RasCtrSize.W))
val popRedTOSR = io.redirect_meta_NOS
val popRedTOSW = io.redirect_meta_TOSW
when (io.redirect_meta_sctr > 0.U) {
when(io.redirect_meta_sctr > 0.U) {
popRedSctr := io.redirect_meta_sctr - 1.U
popRedSsp := io.redirect_meta_ssp
} .elsewhen (TOSRinRange(popRedTOSR, TOSW)) {
popRedSsp := ptrDec(io.redirect_meta_ssp)
popRedSsp := io.redirect_meta_ssp
}.elsewhen(TOSRinRange(popRedTOSR, TOSW)) {
popRedSsp := ptrDec(io.redirect_meta_ssp)
popRedSctr := spec_queue(popRedTOSR.value).ctr
} .otherwise {
popRedSsp := ptrDec(io.redirect_meta_ssp)
}.otherwise {
popRedSsp := ptrDec(io.redirect_meta_ssp)
popRedSctr := getCommitTop(ptrDec(io.redirect_meta_ssp)).ctr
}
// We are deciding top for the next cycle, no need to use bypass here
timingTop := getTop(popRedSsp, popRedSctr, popRedTOSR, popRedTOSW, false)
} .elsewhen (io.redirect_valid) {
}.elsewhen(io.redirect_valid) {
// Neither call nor ret
val popSsp = io.redirect_meta_ssp
val popSsp = io.redirect_meta_ssp
val popSctr = io.redirect_meta_sctr
val popTOSR = io.redirect_meta_TOSR
val popTOSW = io.redirect_meta_TOSW
timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false)
} .elsewhen (io.spec_pop_valid) {
}.elsewhen(io.spec_pop_valid) {
// getTop using current Nos as TOSR
val popSsp = Wire(UInt(log2Up(rasSize).W))
val popSsp = Wire(UInt(log2Up(rasSize).W))
val popSctr = Wire(UInt(RasCtrSize.W))
val popTOSR = topNos
val popTOSW = TOSW
when (sctr > 0.U) {
when(sctr > 0.U) {
popSctr := sctr - 1.U
popSsp := ssp
} .elsewhen (TOSRinRange(popTOSR, TOSW)) {
popSsp := ptrDec(ssp)
popSsp := ssp
}.elsewhen(TOSRinRange(popTOSR, TOSW)) {
popSsp := ptrDec(ssp)
popSctr := spec_queue(popTOSR.value).ctr
} .otherwise {
popSsp := ptrDec(ssp)
}.otherwise {
popSsp := ptrDec(ssp)
popSctr := getCommitTop(ptrDec(ssp)).ctr
}
// We are deciding top for the next cycle, no need to use bypass here
timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false)
} .elsewhen (realPush) {
}.elsewhen(realPush) {
// just updating spec queue, cannot read from there
timingTop := realWriteEntry
} .elsewhen (io.s3_cancel) {
}.elsewhen(io.s3_cancel) {
// s3 is different with s2
timingTop := getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false)
when (io.s3_missed_push) {
when(io.s3_missed_push) {
val writeEntry_s3 = Wire(new RASEntry)
timingTop := writeEntry_s3
timingTop := writeEntry_s3
writeEntry_s3.retAddr := io.s3_pushAddr
writeEntry_s3.ctr := Mux(timingTop.retAddr === io.s3_pushAddr && io.s3_meta.sctr < ctrMax, io.s3_meta.sctr + 1.U, 0.U)
} .elsewhen (io.s3_missed_pop) {
val popRedSsp_s3 = Wire(UInt(log2Up(rasSize).W))
writeEntry_s3.ctr := Mux(
timingTop.retAddr === io.s3_pushAddr && io.s3_meta.sctr < ctrMax,
io.s3_meta.sctr + 1.U,
0.U
)
}.elsewhen(io.s3_missed_pop) {
val popRedSsp_s3 = Wire(UInt(log2Up(rasSize).W))
val popRedSctr_s3 = Wire(UInt(RasCtrSize.W))
val popRedTOSR_s3 = io.s3_meta.NOS
val popRedTOSW_s3 = io.s3_meta.TOSW
when (io.s3_meta.sctr > 0.U) {
when(io.s3_meta.sctr > 0.U) {
popRedSctr_s3 := io.s3_meta.sctr - 1.U
popRedSsp_s3 := io.s3_meta.ssp
} .elsewhen (TOSRinRange(popRedTOSR_s3, popRedTOSW_s3)) {
popRedSsp_s3 := ptrDec(io.s3_meta.ssp)
popRedSsp_s3 := io.s3_meta.ssp
}.elsewhen(TOSRinRange(popRedTOSR_s3, popRedTOSW_s3)) {
popRedSsp_s3 := ptrDec(io.s3_meta.ssp)
popRedSctr_s3 := spec_queue(popRedTOSR_s3.value).ctr
} .otherwise {
popRedSsp_s3 := ptrDec(io.s3_meta.ssp)
}.otherwise {
popRedSsp_s3 := ptrDec(io.s3_meta.ssp)
popRedSctr_s3 := getCommitTop(ptrDec(io.s3_meta.ssp)).ctr
}
// We are deciding top for the next cycle, no need to use bypass here
timingTop := getTop(popRedSsp_s3, popRedSctr_s3, popRedTOSR_s3, popRedTOSW_s3, false)
}
} .otherwise {
}.otherwise {
// easy case
val popSsp = ssp
val popSsp = ssp
val popSctr = sctr
val popTOSR = TOSR
val popTOSW = TOSW
@ -367,96 +377,121 @@ class RAS(implicit p: Parameters) extends BasePredictor {
// could diff when more pop than push and a commit stack is updated with inflight info
val realWriteEntry_next = RegEnable(writeEntry, io.s2_fire || io.redirect_isCall)
val s3_missPushEntry = Wire(new RASEntry)
val s3_missPushAddr = Wire(new RASPtr)
val s3_missPushNos = Wire(new RASPtr)
val s3_missPushEntry = Wire(new RASEntry)
val s3_missPushAddr = Wire(new RASPtr)
val s3_missPushNos = Wire(new RASPtr)
s3_missPushEntry.retAddr := io.s3_pushAddr
s3_missPushEntry.ctr := Mux(s3TopEntry.retAddr === io.s3_pushAddr && s3TopEntry.ctr < ctrMax, io.s3_meta.sctr + 1.U, 0.U)
s3_missPushEntry.ctr := Mux(
s3TopEntry.retAddr === io.s3_pushAddr && s3TopEntry.ctr < ctrMax,
io.s3_meta.sctr + 1.U,
0.U
)
s3_missPushAddr := io.s3_meta.TOSW
s3_missPushNos := io.s3_meta.TOSR
s3_missPushNos := io.s3_meta.TOSR
realWriteEntry := Mux(io.redirect_isCall, realWriteEntry_next,
Mux(io.s3_missed_push, s3_missPushEntry,
realWriteEntry_next))
realWriteEntry := Mux(
io.redirect_isCall,
realWriteEntry_next,
Mux(io.s3_missed_push, s3_missPushEntry, realWriteEntry_next)
)
val realWriteAddr_next = RegEnable(Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSW, TOSW), io.s2_fire || (io.redirect_valid && io.redirect_isCall))
val realWriteAddr = Mux(io.redirect_isCall, realWriteAddr_next,
Mux(io.s3_missed_push, s3_missPushAddr,
realWriteAddr_next))
val realNos_next = RegEnable(Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR), io.s2_fire || (io.redirect_valid && io.redirect_isCall))
val realNos = Mux(io.redirect_isCall, realNos_next,
Mux(io.s3_missed_push, s3_missPushNos,
realNos_next))
val realWriteAddr_next = RegEnable(
Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSW, TOSW),
io.s2_fire || (io.redirect_valid && io.redirect_isCall)
)
val realWriteAddr =
Mux(io.redirect_isCall, realWriteAddr_next, Mux(io.s3_missed_push, s3_missPushAddr, realWriteAddr_next))
val realNos_next = RegEnable(
Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR),
io.s2_fire || (io.redirect_valid && io.redirect_isCall)
)
val realNos = Mux(io.redirect_isCall, realNos_next, Mux(io.s3_missed_push, s3_missPushNos, realNos_next))
realPush := (io.s3_fire && (!io.s3_cancel && RegEnable(io.spec_push_valid, io.s2_fire) || io.s3_missed_push)) || RegNext(io.redirect_valid && io.redirect_isCall)
realPush := (io.s3_fire && (!io.s3_cancel && RegEnable(
io.spec_push_valid,
io.s2_fire
) || io.s3_missed_push)) || RegNext(io.redirect_valid && io.redirect_isCall)
when (realPush) {
when(realPush) {
spec_queue(realWriteAddr.value) := realWriteEntry
spec_nos(realWriteAddr.value) := realNos
spec_nos(realWriteAddr.value) := realNos
}
def specPush(retAddr: UInt, currentSsp: UInt, currentSctr: UInt, currentTOSR: RASPtr, currentTOSW: RASPtr, topEntry: RASEntry) = {
def specPush(
retAddr: UInt,
currentSsp: UInt,
currentSctr: UInt,
currentTOSR: RASPtr,
currentTOSW: RASPtr,
topEntry: RASEntry
) = {
TOSR := currentTOSW
TOSW := specPtrInc(currentTOSW)
// spec sp and ctr should always be maintained
when (topEntry.retAddr === retAddr && currentSctr < ctrMax) {
when(topEntry.retAddr === retAddr && currentSctr < ctrMax) {
sctr := currentSctr + 1.U
} .otherwise {
ssp := ptrInc(currentSsp)
}.otherwise {
ssp := ptrInc(currentSsp)
sctr := 0.U
}
}
when (io.spec_push_valid) {
when(io.spec_push_valid) {
specPush(io.spec_push_addr, ssp, sctr, TOSR, TOSW, topEntry)
}
def specPop(currentSsp: UInt, currentSctr: UInt, currentTOSR: RASPtr, currentTOSW: RASPtr, currentTopNos: RASPtr) = {
def specPop(
currentSsp: UInt,
currentSctr: UInt,
currentTOSR: RASPtr,
currentTOSW: RASPtr,
currentTopNos: RASPtr
) = {
// TOSR is only maintained when spec queue is not empty
when (TOSRinRange(currentTOSR, currentTOSW)) {
when(TOSRinRange(currentTOSR, currentTOSW)) {
TOSR := currentTopNos
}
// spec sp and ctr should always be maintained
when (currentSctr > 0.U) {
when(currentSctr > 0.U) {
sctr := currentSctr - 1.U
} .elsewhen (TOSRinRange(currentTopNos, currentTOSW)) {
}.elsewhen(TOSRinRange(currentTopNos, currentTOSW)) {
// in range, use inflight data
ssp := ptrDec(currentSsp)
ssp := ptrDec(currentSsp)
sctr := spec_queue(currentTopNos.value).ctr
} .otherwise {
}.otherwise {
// NOS not in range, use commit data
ssp := ptrDec(currentSsp)
ssp := ptrDec(currentSsp)
sctr := getCommitTop(ptrDec(currentSsp)).ctr
// in overflow state, we cannot determine the next sctr, sctr here is not accurate
}
}
when (io.spec_pop_valid) {
when(io.spec_pop_valid) {
specPop(ssp, sctr, TOSR, TOSW, topNos)
}
// io.spec_pop_addr := Mux(writeBypassValid, writeBypassEntry.retAddr, topEntry.retAddr)
io.spec_pop_addr := timingTop.retAddr
io.BOS := BOS
io.TOSW := TOSW
io.TOSR := TOSR
io.NOS := topNos
io.ssp := ssp
io.sctr := sctr
io.nsp := nsp
io.BOS := BOS
io.TOSW := TOSW
io.TOSR := TOSR
io.NOS := topNos
io.ssp := ssp
io.sctr := sctr
io.nsp := nsp
when (io.s3_cancel) {
when(io.s3_cancel) {
// recovery of all related pointers
TOSR := io.s3_meta.TOSR
TOSW := io.s3_meta.TOSW
ssp := io.s3_meta.ssp
ssp := io.s3_meta.ssp
sctr := io.s3_meta.sctr
// for missing pop, we also need to do a pop here
when (io.s3_missed_pop) {
when(io.s3_missed_pop) {
specPop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, io.s3_meta.NOS)
}
when (io.s3_missed_push) {
when(io.s3_missed_push) {
// do not use any bypass from f2
specPush(io.s3_pushAddr, io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, s3TopEntry)
}
@ -464,21 +499,21 @@ class RAS(implicit p: Parameters) extends BasePredictor {
val commitTop = commit_stack(nsp)
when (io.commit_pop_valid) {
when(io.commit_pop_valid) {
val nsp_update = Wire(UInt(log2Up(rasSize).W))
when (io.commit_meta_ssp =/= nsp) {
when(io.commit_meta_ssp =/= nsp) {
// force set nsp to commit ssp to avoid permanent errors
nsp_update := io.commit_meta_ssp
} .otherwise {
}.otherwise {
nsp_update := nsp
}
// if ctr > 0, --ctr in stack, otherwise --nsp
when (commitTop.ctr > 0.U) {
when(commitTop.ctr > 0.U) {
commit_stack(nsp_update).ctr := commitTop.ctr - 1.U
nsp := nsp_update
} .otherwise {
nsp := nsp_update
}.otherwise {
nsp := ptrDec(nsp_update);
}
// XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp")
@ -486,106 +521,124 @@ class RAS(implicit p: Parameters) extends BasePredictor {
val commit_push_addr = spec_queue(io.commit_meta_TOSW.value).retAddr
when (io.commit_push_valid) {
when(io.commit_push_valid) {
val nsp_update = Wire(UInt(log2Up(rasSize).W))
when (io.commit_meta_ssp =/= nsp) {
when(io.commit_meta_ssp =/= nsp) {
// force set nsp to commit ssp to avoid permanent errors
nsp_update := io.commit_meta_ssp
} .otherwise {
}.otherwise {
nsp_update := nsp
}
// if ctr < max && topAddr == push addr, ++ctr, otherwise ++nsp
when (commitTop.ctr < ctrMax && commitTop.retAddr === commit_push_addr) {
when(commitTop.ctr < ctrMax && commitTop.retAddr === commit_push_addr) {
commit_stack(nsp_update).ctr := commitTop.ctr + 1.U
nsp := nsp_update
} .otherwise {
nsp := ptrInc(nsp_update)
nsp := nsp_update
}.otherwise {
nsp := ptrInc(nsp_update)
commit_stack(ptrInc(nsp_update)).retAddr := commit_push_addr
commit_stack(ptrInc(nsp_update)).ctr := 0.U
commit_stack(ptrInc(nsp_update)).ctr := 0.U
}
// XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp")
// XSError(io.commit_push_addr =/= commit_push_addr, "addr from commit mismatch with addr from spec")
}
when (io.commit_push_valid) {
when(io.commit_push_valid) {
BOS := io.commit_meta_TOSW
} .elsewhen(io.commit_valid && (distanceBetween(io.commit_meta_TOSW,BOS) > 2.U)) {
}.elsewhen(io.commit_valid && (distanceBetween(io.commit_meta_TOSW, BOS) > 2.U)) {
BOS := specPtrDec(io.commit_meta_TOSW)
}
when (io.redirect_valid) {
when(io.redirect_valid) {
TOSR := io.redirect_meta_TOSR
TOSW := io.redirect_meta_TOSW
ssp := io.redirect_meta_ssp
ssp := io.redirect_meta_ssp
sctr := io.redirect_meta_sctr
when (io.redirect_isCall) {
specPush(io.redirect_callAddr, io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, redirectTopEntry)
when(io.redirect_isCall) {
specPush(
io.redirect_callAddr,
io.redirect_meta_ssp,
io.redirect_meta_sctr,
io.redirect_meta_TOSR,
io.redirect_meta_TOSW,
redirectTopEntry
)
}
when (io.redirect_isRet) {
specPop(io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, redirectTopNos)
when(io.redirect_isRet) {
specPop(
io.redirect_meta_ssp,
io.redirect_meta_sctr,
io.redirect_meta_TOSR,
io.redirect_meta_TOSW,
redirectTopNos
)
}
}
when(distanceBetween(TOSW,BOS) > (rasSpecSize - 4).U){
spec_near_overflowed := true.B
}.otherwise{
spec_near_overflowed := false.B
when(distanceBetween(TOSW, BOS) > (rasSpecSize - 4).U) {
spec_near_overflowed := true.B
}.otherwise {
spec_near_overflowed := false.B
}
io.spec_near_overflow := spec_near_overflowed
io.spec_near_overflow := spec_near_overflowed
XSPerfAccumulate("spec_near_overflow", spec_near_overflowed)
io.debug.commit_stack.zipWithIndex.foreach{case (a, i) => a := commit_stack(i)}
io.debug.spec_nos.zipWithIndex.foreach{case (a, i) => a := spec_nos(i)}
io.debug.spec_queue.zipWithIndex.foreach{ case (a, i) => a := spec_queue(i)}
io.debug.commit_stack.zipWithIndex.foreach { case (a, i) => a := commit_stack(i) }
io.debug.spec_nos.zipWithIndex.foreach { case (a, i) => a := spec_nos(i) }
io.debug.spec_queue.zipWithIndex.foreach { case (a, i) => a := spec_queue(i) }
}
val stack = Module(new RASStack(RasSize, RasSpecSize)).io
val s2_spec_push = WireInit(false.B)
val s2_spec_pop = WireInit(false.B)
val s2_spec_pop = WireInit(false.B)
val s2_full_pred = io.in.bits.resp_in(0).s2.full_pred(2)
// when last inst is an rvi call, fall through address would be set to the middle of it, so an addition is needed
val s2_spec_new_addr = s2_full_pred.fallThroughAddr + Mux(s2_full_pred.last_may_be_rvi_call, 2.U, 0.U)
stack.spec_push_valid := s2_spec_push
stack.spec_pop_valid := s2_spec_pop
stack.spec_push_addr := s2_spec_new_addr
stack.spec_push_addr := s2_spec_new_addr
// confirm that the call/ret is the taken cfi
s2_spec_push := io.s2_fire(2) && s2_full_pred.hit_taken_on_call && !io.s3_redirect(2)
s2_spec_pop := io.s2_fire(2) && s2_full_pred.hit_taken_on_ret && !io.s3_redirect(2)
s2_spec_pop := io.s2_fire(2) && s2_full_pred.hit_taken_on_ret && !io.s3_redirect(2)
//val s2_jalr_target = io.out.s2.full_pred.jalr_target
//val s2_last_target_in = s2_full_pred.targets.last
// val s2_jalr_target = io.out.s2.full_pred.jalr_target
// val s2_last_target_in = s2_full_pred.targets.last
// val s2_last_target_out = io.out.s2.full_pred(2).targets.last
val s2_is_jalr = s2_full_pred.is_jalr
val s2_is_ret = s2_full_pred.is_ret
val s2_top = stack.spec_pop_addr
val s2_is_ret = s2_full_pred.is_ret
val s2_top = stack.spec_pop_addr
// assert(is_jalr && is_ret || !is_ret)
when(s2_is_ret && io.ctrl.ras_enable) {
io.out.s2.full_pred.map(_.jalr_target).foreach(_ := s2_top)
// FIXME: should use s1 globally
}
//s2_last_target_out := Mux(s2_is_jalr, s2_jalr_target, s2_last_target_in)
io.out.s2.full_pred.zipWithIndex.foreach{ case (a, i) =>
a.targets.last := Mux(s2_is_jalr, io.out.s2.full_pred(i).jalr_target, io.in.bits.resp_in(0).s2.full_pred(i).targets.last)
// s2_last_target_out := Mux(s2_is_jalr, s2_jalr_target, s2_last_target_in)
io.out.s2.full_pred.zipWithIndex.foreach { case (a, i) =>
a.targets.last := Mux(
s2_is_jalr,
io.out.s2.full_pred(i).jalr_target,
io.in.bits.resp_in(0).s2.full_pred(i).targets.last
)
}
val s2_meta = Wire(new RASInternalMeta)
s2_meta.ssp := stack.ssp
s2_meta.ssp := stack.ssp
s2_meta.sctr := stack.sctr
s2_meta.TOSR := stack.TOSR
s2_meta.TOSW := stack.TOSW
s2_meta.NOS := stack.NOS
s2_meta.NOS := stack.NOS
val s3_top = RegEnable(stack.spec_pop_addr, io.s2_fire(2))
val s3_top = RegEnable(stack.spec_pop_addr, io.s2_fire(2))
val s3_spec_new_addr = RegEnable(s2_spec_new_addr, io.s2_fire(2))
// val s3_jalr_target = io.out.s3.full_pred.jalr_target
// val s3_last_target_in = io.in.bits.resp_in(0).s3.full_pred(2).targets.last
// val s3_last_target_out = io.out.s3.full_pred(2).targets.last
val s3_is_jalr = io.in.bits.resp_in(0).s3.full_pred(2).is_jalr && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_is_jalr =
io.in.bits.resp_in(0).s3.full_pred(2).is_jalr && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_is_ret = io.in.bits.resp_in(0).s3.full_pred(2).is_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
// assert(is_jalr && is_ret || !is_ret)
when(s3_is_ret && io.ctrl.ras_enable) {
@ -593,14 +646,20 @@ class RAS(implicit p: Parameters) extends BasePredictor {
// FIXME: should use s1 globally
}
// s3_last_target_out := Mux(s3_is_jalr, s3_jalr_target, s3_last_target_in)
io.out.s3.full_pred.zipWithIndex.foreach{ case (a, i) =>
a.targets.last := Mux(s3_is_jalr, io.out.s3.full_pred(i).jalr_target, io.in.bits.resp_in(0).s3.full_pred(i).targets.last)
io.out.s3.full_pred.zipWithIndex.foreach { case (a, i) =>
a.targets.last := Mux(
s3_is_jalr,
io.out.s3.full_pred(i).jalr_target,
io.in.bits.resp_in(0).s3.full_pred(i).targets.last
)
}
val s3_pushed_in_s2 = RegEnable(s2_spec_push, io.s2_fire(2))
val s3_popped_in_s2 = RegEnable(s2_spec_pop, io.s2_fire(2))
val s3_push = io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_call && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_pop = io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_popped_in_s2 = RegEnable(s2_spec_pop, io.s2_fire(2))
val s3_push =
io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_call && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_pop =
io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr
val s3_cancel = io.s3_fire(2) && (s3_pushed_in_s2 =/= s3_push || s3_popped_in_s2 =/= s3_pop)
stack.s2_fire := io.s2_fire(2)
@ -610,81 +669,95 @@ class RAS(implicit p: Parameters) extends BasePredictor {
val s3_meta = RegEnable(s2_meta, io.s2_fire(2))
stack.s3_meta := s3_meta
stack.s3_missed_pop := s3_pop && !s3_popped_in_s2
stack.s3_meta := s3_meta
stack.s3_missed_pop := s3_pop && !s3_popped_in_s2
stack.s3_missed_push := s3_push && !s3_pushed_in_s2
stack.s3_pushAddr := s3_spec_new_addr
stack.s3_pushAddr := s3_spec_new_addr
// no longer need the top Entry, but TOSR, TOSW, ssp sctr
// TODO: remove related signals
val last_stage_meta = Wire(new RASMeta)
last_stage_meta.ssp := s3_meta.ssp
last_stage_meta.ssp := s3_meta.ssp
last_stage_meta.TOSW := s3_meta.TOSW
io.s1_ready := !stack.spec_near_overflow
io.s1_ready := !stack.spec_near_overflow
io.out.last_stage_spec_info.sctr := s3_meta.sctr
io.out.last_stage_spec_info.ssp := s3_meta.ssp
io.out.last_stage_spec_info.TOSW := s3_meta.TOSW
io.out.last_stage_spec_info.TOSR := s3_meta.TOSR
io.out.last_stage_spec_info.NOS := s3_meta.NOS
io.out.last_stage_spec_info.sctr := s3_meta.sctr
io.out.last_stage_spec_info.ssp := s3_meta.ssp
io.out.last_stage_spec_info.TOSW := s3_meta.TOSW
io.out.last_stage_spec_info.TOSR := s3_meta.TOSR
io.out.last_stage_spec_info.NOS := s3_meta.NOS
io.out.last_stage_spec_info.topAddr := s3_top
io.out.last_stage_meta := last_stage_meta.asUInt
io.out.last_stage_meta := last_stage_meta.asUInt
val redirect = RegNextWithEnable(io.redirect)
val do_recover = redirect.valid
val redirect = RegNextWithEnable(io.redirect)
val do_recover = redirect.valid
val recover_cfi = redirect.bits.cfiUpdate
val retMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isRet
val callMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isCall
// when we mispredict a call, we must redo a push operation
// similarly, when we mispredict a return, we should redo a pop
stack.redirect_valid := do_recover
stack.redirect_isCall := callMissPred
stack.redirect_isRet := retMissPred
stack.redirect_meta_ssp := recover_cfi.ssp
stack.redirect_valid := do_recover
stack.redirect_isCall := callMissPred
stack.redirect_isRet := retMissPred
stack.redirect_meta_ssp := recover_cfi.ssp
stack.redirect_meta_sctr := recover_cfi.sctr
stack.redirect_meta_TOSW := recover_cfi.TOSW
stack.redirect_meta_TOSR := recover_cfi.TOSR
stack.redirect_meta_NOS := recover_cfi.NOS
stack.redirect_callAddr := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U)
stack.redirect_meta_NOS := recover_cfi.NOS
stack.redirect_callAddr := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U)
val update = io.update.bits
val updateMeta = io.update.bits.meta.asTypeOf(new RASMeta)
val update = io.update.bits
val updateMeta = io.update.bits.meta.asTypeOf(new RASMeta)
val updateValid = io.update.valid
stack.commit_valid := updateValid
stack.commit_valid := updateValid
stack.commit_push_valid := updateValid && update.is_call_taken
stack.commit_pop_valid := updateValid && update.is_ret_taken
stack.commit_push_addr := update.ftb_entry.getFallThrough(update.pc) + Mux(update.ftb_entry.last_may_be_rvi_call, 2.U, 0.U)
stack.commit_pop_valid := updateValid && update.is_ret_taken
stack.commit_push_addr := update.ftb_entry.getFallThrough(update.pc) + Mux(
update.ftb_entry.last_may_be_rvi_call,
2.U,
0.U
)
stack.commit_meta_TOSW := updateMeta.TOSW
stack.commit_meta_ssp := updateMeta.ssp
stack.commit_meta_ssp := updateMeta.ssp
XSPerfAccumulate("ras_s3_cancel", s3_cancel)
XSPerfAccumulate("ras_redirect_recover", redirect.valid)
XSPerfAccumulate("ras_s3_and_redirect_recover_at_the_same_time", s3_cancel && redirect.valid)
val spec_debug = stack.debug
XSDebug(io.s2_fire(2), "----------------RAS----------------\n")
XSDebug(io.s2_fire(2), " TopRegister: 0x%x\n",stack.spec_pop_addr)
XSDebug(io.s2_fire(2), " TopRegister: 0x%x\n", stack.spec_pop_addr)
XSDebug(io.s2_fire(2), " index addr ctr nos (spec part)\n")
for(i <- 0 until RasSpecSize){
XSDebug(io.s2_fire(2), " (%d) 0x%x %d %d",i.U,spec_debug.spec_queue(i).retAddr,spec_debug.spec_queue(i).ctr, spec_debug.spec_nos(i).value)
when(i.U === stack.TOSW.value){XSDebug(io.s2_fire(2), " <----TOSW")}
when(i.U === stack.TOSR.value){XSDebug(io.s2_fire(2), " <----TOSR")}
when(i.U === stack.BOS.value){XSDebug(io.s2_fire(2), " <----BOS")}
XSDebug(io.s2_fire(2), "\n")
for (i <- 0 until RasSpecSize) {
XSDebug(
io.s2_fire(2),
" (%d) 0x%x %d %d",
i.U,
spec_debug.spec_queue(i).retAddr,
spec_debug.spec_queue(i).ctr,
spec_debug.spec_nos(i).value
)
when(i.U === stack.TOSW.value)(XSDebug(io.s2_fire(2), " <----TOSW"))
when(i.U === stack.TOSR.value)(XSDebug(io.s2_fire(2), " <----TOSR"))
when(i.U === stack.BOS.value)(XSDebug(io.s2_fire(2), " <----BOS"))
XSDebug(io.s2_fire(2), "\n")
}
XSDebug(io.s2_fire(2), " index addr ctr (committed part)\n")
for(i <- 0 until RasSize){
XSDebug(io.s2_fire(2), " (%d) 0x%x %d",i.U,spec_debug.commit_stack(i).retAddr,spec_debug.commit_stack(i).ctr)
when(i.U === stack.ssp){XSDebug(io.s2_fire(2), " <----ssp")}
when(i.U === stack.nsp){XSDebug(io.s2_fire(2), " <----nsp")}
XSDebug(io.s2_fire(2), "\n")
for (i <- 0 until RasSize) {
XSDebug(
io.s2_fire(2),
" (%d) 0x%x %d",
i.U,
spec_debug.commit_stack(i).retAddr,
spec_debug.commit_stack(i).ctr
)
when(i.U === stack.ssp)(XSDebug(io.s2_fire(2), " <----ssp"))
when(i.U === stack.nsp)(XSDebug(io.s2_fire(2), " <----nsp"))
XSDebug(io.s2_fire(2), "\n")
}
/*
XSDebug(s2_spec_push, "s2_spec_push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n",
@ -699,7 +772,7 @@ class RAS(implicit p: Parameters) extends BasePredictor {
XSDebug(do_recover && retMissPred, "redirect_recover_pop\n")
XSDebug(do_recover, "redirect_recover(SP:%d retAddr:%x ctr:%d) \n",
redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr)
*/
*/
generatePerfEvent()
}