style(Frontend): use scalafmt formatting frontend (#3370)
Format frontend according to the scalafmt file drafted in #3061.
This commit is contained in:
parent
b9dc808db3
commit
cf7d6b7a1a
|
@ -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
|
|
@ -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"]
|
6
Makefile
6
Makefile
|
@ -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)
|
||||
|
|
3
build.sc
3
build.sc
|
@ -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
|
@ -121,4 +121,4 @@ class BIM(implicit p: Parameters) extends BasePredictor with BimParams with BPUU
|
|||
}
|
||||
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -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
|
@ -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()
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,4 +306,4 @@ class RAS(implicit p: Parameters) extends BasePredictor {
|
|||
|
||||
generatePerfEvent()
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue