未验证 提交 ca2f90a6 编写于 作者: L Lemover 提交者: GitHub

pma: add pmp-like pma, software can read and write (#1169)

remove the old hard-wired pma and turn to pmp-like csr registers. the pma config is writen in pma register.
1. pma are m-priv csr, so only m-mode csrrw can change pma
2. even in m-mode, pma should be always checked, no matter lock or not
3. so carefully write pma, make sure not to "suicide"

* pma: add pmp-like pma, just module/bundle added, not to circuit

use reserved 2 bits as atomic and cached

* pma: add pmp-like pma into pmp module

pma have two more attribute than pmp
1. atmoic;
2. c/cache, if false, go to mmio.

pma uses 16+4 machine-level custom ready write csr.
pma will always be checked even in m-mode.

* pma: remove the old MemMap in tlb, mmio arrives next cycle

* pma: ptw raise af when mmio

* pma: fix bug of match's zip with last entry

* pma: fix bug of pass reset signal through method's parameter

strange bug, want to reset, pass reset signal to a method, does not
work.
import chisel3.Module.reset, the method can access reset it's self.

* pma: move some method to trait and fix bug of pma_init value

* pma: fix bug of pma init value assign way

* tlb: fix stupid bug that pf.ld not & fault_valid

* loadunit: fix bug that uop is flushed, pmp's dcache kill failed also

* ifu: mmio access needs f2_valid now

* loadunit: if mmio and have sent fastUop, flush pipe when commit

* storeunit: stu->lsq at stage1 and re-in lsq at stage2 to update mmio
上级 496c0adf
......@@ -180,6 +180,7 @@ case class XSCoreParameters
),
l2tlbParameters: L2TLBParameters = L2TLBParameters(),
NumPMP: Int = 16, // 0 or 16 or 64
NumPMA: Int = 16,
NumPerfCounters: Int = 16,
icacheParameters: ICacheParameters = ICacheParameters(
tagECC = Some("parity"),
......@@ -322,6 +323,7 @@ trait HasXSParameter {
val btlbParams = coreParams.btlbParameters
val l2tlbParams = coreParams.l2tlbParameters
val NumPMP = coreParams.NumPMP
val NumPMA = coreParams.NumPMA
val PlatformGrain: Int = log2Up(coreParams.RefillSize/8) // set PlatformGrain to avoid itlb, dtlb, ptw size conflict
val NumPerfCounters = coreParams.NumPerfCounters
......
......@@ -184,6 +184,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
val pmp_check = VecInit(Seq.fill(exuParameters.LduCnt + exuParameters.StuCnt)(Module(new PMPChecker(3)).io))
for ((p,d) <- pmp_check zip dtlb.map(_.pmp(0))) {
p.env.pmp := pmp.io.pmp
p.env.pma := pmp.io.pma
p.env.mode := tlbcsr.priv.dmode
p.req := d
require(p.req.bits.size.getWidth == d.bits.size.getWidth)
......@@ -246,6 +247,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
stu.io.isFirstIssue <> io.rsfeedback(exuParameters.LduCnt + i).isFirstIssue
stu.io.stin <> io.issue(exuParameters.LduCnt + i)
stu.io.lsq <> lsq.io.storeIn(i)
stu.io.lsq_replenish <> lsq.io.storeInRe(i)
// dtlb
stu.io.tlb <> dtlb_st(i).requestor(0)
stu.io.pmp <> pmp_check(i+exuParameters.LduCnt).resp
......@@ -350,6 +352,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
atomicsUnit.io.dtlb.resp.valid := false.B
atomicsUnit.io.dtlb.resp.bits := DontCare
atomicsUnit.io.dtlb.req.ready := amoTlb.req.ready
atomicsUnit.io.pmpResp := pmp_check(0).resp
atomicsUnit.io.dcache <> dcache.io.lsu.atomics
atomicsUnit.io.flush_sbuffer.empty := sbuffer.io.flush.empty
......
......@@ -198,7 +198,7 @@ class CSRFileIO(implicit p: Parameters) extends XSBundle {
// distributed csr w
}
class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMPConst
class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMPMethod with PMAMethod
{
val csrio = IO(new CSRFileIO)
......@@ -385,41 +385,11 @@ class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMP
val mscratch = RegInit(UInt(XLEN.W), 0.U)
// PMP Mapping
val pmp = Wire(Vec(NumPMP, new PMPBase()))
val pmpMapping = if (NumPMP > 0) { // TODO: remove duplicate codes
val pmpCfgPerCSR = XLEN / new PMPConfig().getWidth
def pmpCfgIndex(i: Int) = (XLEN / 32) * (i / pmpCfgPerCSR)
/** to fit MaskedRegMap's write, declare cfgs as Merged CSRs and split them into each pmp */
val cfgMerged = RegInit(VecInit(Seq.fill(NumPMP / pmpCfgPerCSR)(0.U(XLEN.W))))
val cfgs = WireInit(cfgMerged).asTypeOf(Vec(NumPMP, new PMPConfig()))
val addr = Reg(Vec(NumPMP, UInt((PAddrBits-PMPOffBits).W)))
for (i <- pmp.indices) {
pmp(i).gen(cfgs(i), addr(i))
}
val pmp = Wire(Vec(NumPMP, new PMPEntry())) // just used for method parameter
val pma = Wire(Vec(NumPMA, new PMPEntry())) // just used for method parameter
val pmpMapping = pmp_gen_mapping(pmp_init, NumPMP, PmpcfgBase, PmpaddrBase, pmp)
val pmaMapping = pmp_gen_mapping(pma_init, NumPMA, PmacfgBase, PmaaddrBase, pma)
val cfg_mapping = (0 until NumPMP by pmpCfgPerCSR).map(i => {Map(
MaskedRegMap(
addr = PmpcfgBase + pmpCfgIndex(i),
reg = cfgMerged(i/pmpCfgPerCSR),
wmask = WritableMask,
wfn = new PMPConfig().write_cfg_vec
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes
val addr_mapping = (0 until NumPMP).map(i => {Map(
MaskedRegMap(
addr = PmpaddrBase + i,
reg = addr(i),
wmask = WritableMask,
wfn = { if (i != NumPMP-1) pmp(i).write_addr(pmp(i+1)) else pmp(i).write_addr },
rmask = WritableMask,
rfn = new PMPBase().read_addr(pmp(i).cfg)
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes.
cfg_mapping ++ addr_mapping
} else {
Map()
}
// Superviser-Level CSRs
// val sstatus = RegInit(UInt(XLEN.W), "h00000000".U)
......@@ -774,6 +744,7 @@ class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMP
val mapping = basicPrivMapping ++
perfCntMapping ++
pmpMapping ++
pmaMapping ++
emuPerfCntsLoMapping ++
(if (XLEN == 32) emuPerfCntsHiMapping else Nil) ++
(if (HasFPU) fcsrMapping else Nil) ++
......
/***************************************************************************************
* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
* Copyright (c) 2020-2021 Peng Cheng Laboratory
*
* XiangShan is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
package xiangshan.backend.fu
import chipsalliance.rocketchip.config.Parameters
import chisel3._
import chisel3.internal.naming.chiselName
import chisel3.util._
import xiangshan.{HasXSParameter, XSModule}
import xiangshan.backend.fu.util.HasCSRConst
import xiangshan.cache.mmu.TlbCmd
trait PMAMethod extends HasXSParameter with PMPConst { this: XSModule =>
/**
def SimpleMemMapList = List(
// Base address Top address Width Description Mode (RWXIDSAC)
MemMap("h00_0000_0000", "h00_0FFF_FFFF", "h0", "Reserved", "RW"),
MemMap("h00_1000_0000", "h00_1FFF_FFFF", "h0", "QSPI_Flash", "RWX"),
MemMap("h00_2000_0000", "h00_2FFF_FFFF", "h0", "Reserved", "RW"),
MemMap("h00_3000_0000", "h00_3000_FFFF", "h0", "DMA", "RW"),
MemMap("h00_3001_0000", "h00_3004_FFFF", "h0", "GPU", "RWC"),
MemMap("h00_3005_0000", "h00_3006_FFFF", "h0", "USB/SDMMC", "RW"),
MemMap("h00_3007_0000", "h00_30FF_FFFF", "h0", "Reserved", "RW"),
MemMap("h00_3100_0000", "h00_3111_FFFF", "h0", "MMIO", "RW"),
MemMap("h00_3112_0000", "h00_37FF_FFFF", "h0", "Reserved", "RW"),
MemMap("h00_3800_0000", "h00_3800_FFFF", "h0", "CLINT", "RW"),
MemMap("h00_3801_0000", "h00_3801_FFFF", "h0", "BEU", "RW"),
MemMap("h00_3802_0000", "h00_3802_0FFF", "h0", "DebugModule", "RWX"),
MemMap("h00_3802_1000", "h00_3BFF_FFFF", "h0", "Reserved", ""),
MemMap("h00_3C00_0000", "h00_3FFF_FFFF", "h0", "PLIC", "RW"),
MemMap("h00_4000_0000", "h00_7FFF_FFFF", "h0", "PCIe", "RW"),
MemMap("h00_8000_0000", "h1F_FFFF_FFFF", "h0", "DDR", "RWXIDSA"),
)
*/
def pma_init() : (Vec[UInt], Vec[UInt], Vec[UInt]) = {
// the init value is zero
// from 0 to num(default 16) - 1, lower priority
// according to simple map, 9 entries is needed, pick 6-14, leave 0-5 & 15 unusedcfgMerged.map(_ := 0.U)
val num = NumPMA
require(num >= 16)
val cfg = WireInit(0.U.asTypeOf(Vec(num, new PMPConfig())))
val addr = Wire(Vec(num, UInt((PAddrBits-PMPOffBits).W)))
val mask = Wire(Vec(NumPMP, UInt(PAddrBits.W)))
addr := DontCare
mask := DontCare
// use tor instead of napot, for napot may be confusing and hard to understand
addr(14) := shift_addr( 0x2000000000L)
cfg(14).a := 1.U; cfg(14).r := true.B; cfg(14).w := true.B; cfg(14).x := true.B; cfg(14).c := true.B; cfg(14).atomic := true.B
addr(13) := shift_addr(0x80000000L)
cfg(13).a := 1.U; cfg(13).r := true.B; cfg(13).w := true.B
addr(12) := shift_addr(0x3C000000)
cfg(12).a := 1.U
addr(11) := shift_addr(0x38021000)
cfg(11).a := 1.U; cfg(11).r := true.B; cfg(11).w := true.B; cfg(11).x := true.B
addr(10) := shift_addr(0x38020000)
cfg(10).a := 1.U; cfg(10).r := true.B; cfg(10).w := true.B
addr(9) := shift_addr( 0x30050000)
cfg(9).a := 1.U; cfg(9).r := true.B; cfg(9).w := true.B; cfg(8).c := true.B
addr(8) := shift_addr( 0x30010000)
cfg(8).a := 1.U; cfg(8).r := true.B; cfg(8).w := true.B
addr(7) := shift_addr( 0x20000000)
cfg(7).a := 1.U; cfg(7).r := true.B; cfg(7).w := true.B; cfg(7).x := true.B
addr(6) := shift_addr( 0x10000000)
cfg(6).a := 1.U; cfg(6).r := true.B; cfg(6).w := true.B
addr(5) := shift_addr(0)
val cfgInitMerge = cfg.asTypeOf(Vec(num/8, UInt(XLEN.W)))
(cfgInitMerge, addr, mask)
}
def shift_addr(addr: BigInt) = {
(addr >> 2).U
}
}
trait PMACheckMethod extends HasXSParameter with HasCSRConst { this: PMPChecker =>
def pma_check(cmd: UInt, cfg: PMPConfig) = {
val resp = Wire(new PMPRespBundle)
resp.ld := TlbCmd.isRead(cmd) && !TlbCmd.isAtom(cmd) && !cfg.r
resp.st := (TlbCmd.isWrite(cmd) || TlbCmd.isAtom(cmd) && cfg.atomic) && !cfg.w
resp.instr := TlbCmd.isExec(cmd) && !cfg.x
resp.mmio := !cfg.c
resp
}
def pma_match_res(addr: UInt, size: UInt, pmaEntries: Vec[PMPEntry], mode: UInt, lgMaxSize: Int) = {
val num = pmaEntries.size
require(num == NumPMA)
// pma should always be checked, could not be ignored
// like amo and cached, it is the attribute not protection
// so it must have initialization.
require(!pmaEntries.isEmpty)
val default = if (pmaEntries.isEmpty) true.B else (mode > ModeS)
val pmpMinuxOne = WireInit(0.U.asTypeOf(new PMPEntry()))
val res = pmaEntries.zip(pmpMinuxOne +: pmaEntries.take(num-1)).zipWithIndex
.reverse.foldLeft(pmpMinuxOne) { case (prev, ((pma, last_pma), i)) =>
val is_match = pma.is_match(addr, size, lgMaxSize, last_pma)
val aligned = pma.aligned(addr, size, lgMaxSize, last_pma)
val cur = WireInit(pma)
cur.cfg.r := aligned && pma.cfg.r
cur.cfg.w := aligned && pma.cfg.w
cur.cfg.x := aligned && pma.cfg.x
cur.cfg.atomic := aligned && pma.cfg.atomic
cur.cfg.c := aligned && pma.cfg.c
Mux(is_match, cur, prev)
}
res
}
}
\ No newline at end of file
......@@ -39,12 +39,14 @@ abstract class PMPModule(implicit p: Parameters) extends XSModule with PMPConst
@chiselName
class PMPConfig(implicit p: Parameters) extends PMPBundle {
val l = Bool()
val res = UInt(2.W)
val c = Bool() // res(1), unuse in pmp
val atomic = Bool() // res(0), unuse in pmp
val a = UInt(2.W)
val x = Bool()
val w = Bool()
val r = Bool()
def res: UInt = Cat(c, atomic) // in pmp, unused
def off = a === 0.U
def tor = a === 1.U
def na4 = { if (CoarserGrain) false.B else a === 2.U }
......@@ -55,14 +57,16 @@ class PMPConfig(implicit p: Parameters) extends PMPBundle {
def locked = l
def addr_locked: Bool = locked
def addr_locked(next: PMPConfig): Bool = locked || (next.locked && next.tor)
}
trait PMPReadWriteMethod extends PMPConst { this: PMPBase =>
def write_cfg_vec(cfgs: UInt): UInt = {
val cfgVec = Wire(Vec(cfgs.getWidth/8, new PMPConfig))
for (i <- cfgVec.indices) {
val tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
cfgVec(i) := tmp
cfgVec(i).w := tmp.w && tmp.r
if (CoarserGrain) { cfgVec(i).a := Cat(tmp.a(1), tmp.a.orR) }
val cfg_w_tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
cfgVec(i) := cfg_w_tmp
cfgVec(i).w := cfg_w_tmp.w && cfg_w_tmp.r
if (CoarserGrain) { cfgVec(i).a := Cat(cfg_w_tmp.a(1), cfg_w_tmp.a.orR) }
}
cfgVec.asUInt
}
......@@ -70,10 +74,10 @@ class PMPConfig(implicit p: Parameters) extends PMPBundle {
def write_cfg_vec(mask: Vec[UInt], addr: Vec[UInt], index: Int)(cfgs: UInt): UInt = {
val cfgVec = Wire(Vec(cfgs.getWidth/8, new PMPConfig))
for (i <- cfgVec.indices) {
val tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
cfgVec(i) := tmp
cfgVec(i).w := tmp.w && tmp.r
if (CoarserGrain) { cfgVec(i).a := Cat(tmp.a(1), tmp.a.orR) }
val cfg_w_m_tmp = cfgs((i+1)*8-1, i*8).asUInt.asTypeOf(new PMPConfig)
cfgVec(i) := cfg_w_m_tmp
cfgVec(i).w := cfg_w_m_tmp.w && cfg_w_m_tmp.r
if (CoarserGrain) { cfgVec(i).a := Cat(cfg_w_m_tmp.a(1), cfg_w_m_tmp.a.orR) }
when (cfgVec(i).na4_napot) {
mask(index + i) := new PMPEntry().match_mask(cfgVec(i), addr(index + i))
}
......@@ -81,25 +85,11 @@ class PMPConfig(implicit p: Parameters) extends PMPBundle {
cfgVec.asUInt
}
def reset() = {
l := false.B
a := 0.U
}
}
/** PMPBase for CSR unit
* with only read and write logic
*/
@chiselName
class PMPBase(implicit p: Parameters) extends PMPBundle {
val cfg = new PMPConfig
val addr = UInt((PAddrBits - PMPOffBits).W)
/** In general, the PMP grain is 2**{G+2} bytes. when G >= 1, na4 is not selectable.
* When G >= 2 and cfg.a(1) is set(then the mode is napot), the bits addr(G-2, 0) read as zeros.
* When G >= 1 and cfg.a(1) is clear(the mode is off or tor), the addr(G-1, 0) read as zeros.
* The low OffBits is dropped
*/
* When G >= 2 and cfg.a(1) is set(then the mode is napot), the bits addr(G-2, 0) read as zeros.
* When G >= 1 and cfg.a(1) is clear(the mode is off or tor), the addr(G-1, 0) read as zeros.
* The low OffBits is dropped
*/
def read_addr(): UInt = {
read_addr(cfg)(addr)
}
......@@ -116,9 +106,9 @@ class PMPBase(implicit p: Parameters) extends PMPBundle {
}
}
/** addr for inside addr, drop OffBits with.
* compare_addr for inside addr for comparing.
* paddr for outside addr.
*/
* compare_addr for inside addr for comparing.
* paddr for outside addr.
*/
def write_addr(next: PMPBase)(paddr: UInt) = {
Mux(!cfg.addr_locked(next.cfg), paddr, addr)
}
......@@ -138,6 +128,15 @@ class PMPBase(implicit p: Parameters) extends PMPBundle {
if (num == 0) { data }
else { Cat(data(data.getWidth-1, num), 0.U(num.W)) }
}
}
/** PMPBase for CSR unit
* with only read and write logic
*/
@chiselName
class PMPBase(implicit p: Parameters) extends PMPBundle with PMPReadWriteMethod {
val cfg = new PMPConfig
val addr = UInt((PAddrBits - PMPOffBits).W)
def gen(cfg: PMPConfig, addr: UInt) = {
require(addr.getWidth == this.addr.getWidth)
......@@ -146,32 +145,16 @@ class PMPBase(implicit p: Parameters) extends PMPBundle {
}
}
/** PMPEntry for outside pmp copies
* with one more elements mask to help napot match
* TODO: make mask an element, not an method, for timing opt
*/
@chiselName
class PMPEntry(implicit p: Parameters) extends PMPBase {
val mask = UInt(PAddrBits.W) // help to match in napot
trait PMPMatchMethod extends PMPConst { this: PMPEntry =>
/** compare_addr is used to compare with input addr */
def compare_addr = ((addr << PMPOffBits) & ~(((1 << PlatformGrain) - 1).U(PAddrBits.W))).asUInt
def compare_addr: UInt = ((addr << PMPOffBits) & ~(((1 << PlatformGrain) - 1).U(PAddrBits.W))).asUInt
def write_addr(next: PMPBase, mask: UInt)(paddr: UInt) = {
mask := Mux(!cfg.addr_locked(next.cfg), match_mask(paddr), mask)
Mux(!cfg.addr_locked(next.cfg), paddr, addr)
}
def write_addr(mask: UInt)(paddr: UInt) = {
mask := Mux(!cfg.addr_locked, match_mask(paddr), mask)
Mux(!cfg.addr_locked, paddr, addr)
}
/** size and maxSize are all log2 Size
* for dtlb, the maxSize is bXLEN which is 8
* for itlb and ptw, the maxSize is log2(512) ?
* but we may only need the 64 bytes? how to prevent the bugs?
* TODO: handle the special case that itlb & ptw & dcache access wider size than XLEN
*/
* for dtlb, the maxSize is bXLEN which is 8
* for itlb and ptw, the maxSize is log2(512) ?
* but we may only need the 64 bytes? how to prevent the bugs?
* TODO: handle the special case that itlb & ptw & dcache access wider size than XLEN
*/
def is_match(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last_pmp: PMPEntry): Bool = {
Mux(cfg.na4_napot, napotMatch(paddr, lgSize, lgMaxSize),
Mux(cfg.tor, torMatch(paddr, lgSize, lgMaxSize, last_pmp), false.B))
......@@ -179,18 +162,18 @@ class PMPEntry(implicit p: Parameters) extends PMPBase {
/** generate match mask to help match in napot mode */
def match_mask(paddr: UInt) = {
val tmp_addr = Cat(paddr, cfg.a(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
Cat(tmp_addr & ~(tmp_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
val match_mask_addr: UInt = Cat(paddr, cfg.a(0)).asUInt() | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
Cat(match_mask_addr & ~(match_mask_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
}
def match_mask(cfg: PMPConfig, paddr: UInt) = {
val tmp_addr = Cat(paddr, cfg.a(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
Cat(tmp_addr & ~(tmp_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
val match_mask_c_addr = Cat(paddr, cfg.a(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
Cat(match_mask_c_addr & ~(match_mask_c_addr + 1.U), ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
}
def boundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int) = {
def boundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int): Bool = {
if (lgMaxSize <= PlatformGrain) {
paddr < compare_addr
(paddr < compare_addr)
} else {
val highLess = (paddr >> lgMaxSize) < (compare_addr >> lgMaxSize)
val highEqual = (paddr >> lgMaxSize) === (compare_addr >> lgMaxSize)
......@@ -199,7 +182,7 @@ class PMPEntry(implicit p: Parameters) extends PMPBase {
}
}
def lowerBoundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int) = {
def lowerBoundMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int): Bool = {
!boundMatch(paddr, lgSize, lgMaxSize)
}
......@@ -207,7 +190,7 @@ class PMPEntry(implicit p: Parameters) extends PMPBase {
boundMatch(paddr, 0.U, lgMaxSize)
}
def torMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last_pmp: PMPEntry) = {
def torMatch(paddr: UInt, lgSize: UInt, lgMaxSize: Int, last_pmp: PMPEntry): Bool = {
last_pmp.lowerBoundMatch(paddr, lgSize, lgMaxSize) && higherBoundMatch(paddr, lgMaxSize)
}
......@@ -240,6 +223,25 @@ class PMPEntry(implicit p: Parameters) extends PMPBase {
Mux(cfg.na4_napot, napotAligned, torAligned)
}
}
}
/** PMPEntry for outside pmp copies
* with one more elements mask to help napot match
* TODO: make mask an element, not an method, for timing opt
*/
@chiselName
class PMPEntry(implicit p: Parameters) extends PMPBase with PMPMatchMethod {
val mask = UInt(PAddrBits.W) // help to match in napot
def write_addr(next: PMPBase, mask: UInt)(paddr: UInt) = {
mask := Mux(!cfg.addr_locked(next.cfg), match_mask(paddr), mask)
Mux(!cfg.addr_locked(next.cfg), paddr, addr)
}
def write_addr(mask: UInt)(paddr: UInt) = {
mask := Mux(!cfg.addr_locked, match_mask(paddr), mask)
Mux(!cfg.addr_locked, paddr, addr)
}
def gen(cfg: PMPConfig, addr: UInt, mask: UInt) = {
require(addr.getWidth == this.addr.getWidth)
......@@ -247,62 +249,89 @@ class PMPEntry(implicit p: Parameters) extends PMPBase {
this.addr := addr
this.mask := mask
}
}
trait PMPMethod extends HasXSParameter with PMPConst { this: XSModule =>
def pmp_init() : (Vec[UInt], Vec[UInt], Vec[UInt])= {
val cfg = WireInit(0.U.asTypeOf(Vec(NumPMP/8, UInt(XLEN.W))))
val addr = Wire(Vec(NumPMP, UInt((PAddrBits-PMPOffBits).W)))
val mask = Wire(Vec(NumPMP, UInt(PAddrBits.W)))
addr := DontCare
mask := DontCare
(cfg, addr, mask)
}
def pmp_gen_mapping
(
init: () => (Vec[UInt], Vec[UInt], Vec[UInt]),
num: Int = 16,
cfgBase: Int,
addrBase: Int,
entries: Vec[PMPEntry]
) = {
val pmpCfgPerCSR = XLEN / new PMPConfig().getWidth
def pmpCfgIndex(i: Int) = (XLEN / 32) * (i / pmpCfgPerCSR)
val init_value = init()
/** to fit MaskedRegMap's write, declare cfgs as Merged CSRs and split them into each pmp */
val cfgMerged = RegInit(init_value._1) //(Vec(num / pmpCfgPerCSR, UInt(XLEN.W))) // RegInit(VecInit(Seq.fill(num / pmpCfgPerCSR)(0.U(XLEN.W))))
val cfgs = WireInit(cfgMerged).asTypeOf(Vec(num, new PMPConfig()))
val addr = RegInit(init_value._2) // (Vec(num, UInt((PAddrBits-PMPOffBits).W)))
val mask = RegInit(init_value._3) // (Vec(num, UInt(PAddrBits.W)))
for (i <- entries.indices) {
entries(i).gen(cfgs(i), addr(i), mask(i))
}
val cfg_mapping = (0 until num by pmpCfgPerCSR).map(i => {Map(
MaskedRegMap(
addr = cfgBase + pmpCfgIndex(i),
reg = cfgMerged(i/pmpCfgPerCSR),
wmask = WritableMask,
wfn = new PMPBase().write_cfg_vec(mask, addr, i)
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes
val addr_mapping = (0 until num).map(i => {Map(
MaskedRegMap(
addr = addrBase + i,
reg = addr(i),
wmask = WritableMask,
wfn = { if (i != num-1) entries(i).write_addr(entries(i+1), mask(i)) else entries(i).write_addr(mask(i)) },
rmask = WritableMask,
rfn = new PMPBase().read_addr(entries(i).cfg)
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes.
def reset() = {
cfg.l := 0.U
cfg.a := 0.U
cfg_mapping ++ addr_mapping
}
}
@chiselName
class PMP(implicit p: Parameters) extends PMPModule {
class PMP(implicit p: Parameters) extends PMPModule with PMPMethod with PMAMethod {
val io = IO(new Bundle {
val distribute_csr = Flipped(new DistributedCSRIO())
val pmp = Output(Vec(NumPMP, new PMPEntry()))
val pma = Output(Vec(NumPMA, new PMPEntry()))
})
val w = io.distribute_csr.w
val pmp = Wire(Vec(NumPMP, new PMPEntry()))
val pma = Wire(Vec(NumPMA, new PMPEntry()))
val pmpCfgPerCSR = XLEN / new PMPConfig().getWidth
def pmpCfgIndex(i: Int) = (XLEN / 32) * (i / pmpCfgPerCSR)
/** to fit MaskedRegMap's write, declare cfgs as Merged CSRs and split them into each pmp */
val cfgMerged = RegInit(VecInit(Seq.fill(NumPMP / pmpCfgPerCSR)(0.U(XLEN.W))))
val cfgs = WireInit(cfgMerged).asTypeOf(Vec(NumPMP, new PMPConfig()))
val addr = Reg(Vec(NumPMP, UInt((PAddrBits-PMPOffBits).W)))
val mask = Reg(Vec(NumPMP, UInt(PAddrBits.W)))
for (i <- pmp.indices) {
pmp(i).gen(cfgs(i), addr(i), mask(i))
}
val cfg_mapping = (0 until NumPMP by pmpCfgPerCSR).map(i => {Map(
MaskedRegMap(
addr = PmpcfgBase + pmpCfgIndex(i),
reg = cfgMerged(i/pmpCfgPerCSR),
wmask = WritableMask,
wfn = new PMPConfig().write_cfg_vec(mask, addr, i)
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes
val addr_mapping = (0 until NumPMP).map(i => {Map(
MaskedRegMap(
addr = PmpaddrBase + i,
reg = addr(i),
wmask = WritableMask,
wfn = { if (i != NumPMP-1) pmp(i).write_addr(pmp(i+1), mask(i)) else pmp(i).write_addr(mask(i)) },
rmask = WritableMask,
rfn = new PMPBase().read_addr(pmp(i).cfg)
))
}).fold(Map())((a, b) => a ++ b) // ugly code, hit me if u have better codes.
val pmpMapping = cfg_mapping ++ addr_mapping
val pmpMapping = pmp_gen_mapping(pmp_init, NumPMP, PmpcfgBase, PmpaddrBase, pmp)
val pmaMapping = pmp_gen_mapping(pma_init, NumPMA, PmacfgBase, PmaaddrBase, pma)
val mapping = pmpMapping ++ pmaMapping
val rdata = Wire(UInt(XLEN.W))
MaskedRegMap.generate(pmpMapping, w.bits.addr, rdata, w.valid, w.bits.data)
MaskedRegMap.generate(mapping, w.bits.addr, rdata, w.valid, w.bits.data)
io.pmp := pmp
io.pma := pma
}
class PMPReqBundle(lgMaxSize: Int = 3)(implicit p: Parameters) extends PMPBundle {
......@@ -313,72 +342,88 @@ class PMPReqBundle(lgMaxSize: Int = 3)(implicit p: Parameters) extends PMPBundle
override def cloneType = (new PMPReqBundle(lgMaxSize)).asInstanceOf[this.type]
}
class PMPRespBundle(implicit p: Parameters) extends TlbExceptionBundle
class PMPRespBundle(implicit p: Parameters) extends TlbExceptionBundle {
val mmio = Output(Bool())
def |(resp: PMPRespBundle): PMPRespBundle = {
val res = Wire(new PMPRespBundle())
res.ld := this.ld || resp.ld
res.st := this.st || resp.st
res.instr := this.instr || resp.instr
res.mmio := this.mmio || resp.mmio
res
}
}
trait PMPCheckMethod extends HasXSParameter with HasCSRConst { this: PMPChecker =>
def pmp_check(cmd: UInt, cfg: PMPConfig)(implicit p: Parameters) = {
val resp = Wire(new PMPRespBundle)
resp.ld := TlbCmd.isRead(cmd) && !TlbCmd.isAtom(cmd) && !cfg.r
resp.st := (TlbCmd.isWrite(cmd) || TlbCmd.isAtom(cmd)) && !cfg.w
resp.instr := TlbCmd.isExec(cmd) && !cfg.x
resp.mmio := false.B
resp
}
def pmp_match_res(addr: UInt, size: UInt, pmpEntries: Vec[PMPEntry], mode: UInt, lgMaxSize: Int) = {
val num = pmpEntries.size
require(num == NumPMP)
val passThrough = if (pmpEntries.isEmpty) true.B else (mode > ModeS)
val pmpMinuxOne = WireInit(0.U.asTypeOf(new PMPEntry()))
pmpMinuxOne.cfg.r := passThrough
pmpMinuxOne.cfg.w := passThrough
pmpMinuxOne.cfg.x := passThrough
val res = pmpEntries.zip(pmpMinuxOne +: pmpEntries.take(num-1)).zipWithIndex
.reverse.foldLeft(pmpMinuxOne) { case (prev, ((pmp, last_pmp), i)) =>
val is_match = pmp.is_match(addr, size, lgMaxSize, last_pmp)
val ignore = passThrough && !pmp.cfg.l
val aligned = pmp.aligned(addr, size, lgMaxSize, last_pmp)
val cur = WireInit(pmp)
cur.cfg.r := aligned && (pmp.cfg.r || ignore)
cur.cfg.w := aligned && (pmp.cfg.w || ignore)
cur.cfg.x := aligned && (pmp.cfg.x || ignore)
Mux(is_match, cur, prev)
}
res
}
}
@chiselName
class PMPChecker(lgMaxSize: Int = 3, sameCycle: Boolean = false)(implicit p: Parameters) extends PMPModule {
class PMPChecker
(
lgMaxSize: Int = 3,
sameCycle: Boolean = false
)(implicit p: Parameters)
extends PMPModule
with PMPCheckMethod
with PMACheckMethod
{
val io = IO(new Bundle{
val env = Input(new Bundle {
val mode = Input(UInt(2.W))
val pmp = Input(Vec(NumPMP, new PMPEntry()))
val pma = Input(Vec(NumPMA, new PMPEntry()))
})
val req = Flipped(Valid(new PMPReqBundle(lgMaxSize))) // usage: assign the valid to fire signal
val resp = Output(new PMPRespBundle())
val resp = new PMPRespBundle()
})
val req = io.req.bits
val passThrough = if (io.env.pmp.isEmpty) true.B else (io.env.mode > ModeS)
val pmpMinuxOne = WireInit(0.U.asTypeOf(new PMPEntry()))
pmpMinuxOne.cfg.r := passThrough
pmpMinuxOne.cfg.w := passThrough
pmpMinuxOne.cfg.x := passThrough
val match_wave = Wire(Vec(NumPMP, Bool()))
val ignore_wave = Wire(Vec(NumPMP, Bool()))
val aligned_wave = Wire(Vec(NumPMP, Bool()))
val prev_wave = Wire(Vec(NumPMP, new PMPEntry()))
val cur_wave = Wire(Vec(NumPMP, new PMPEntry()))
dontTouch(match_wave)
dontTouch(ignore_wave)
dontTouch(aligned_wave)
dontTouch(prev_wave)
dontTouch(cur_wave)
val res = io.env.pmp.zip(pmpMinuxOne +: io.env.pmp.take(NumPMP-1)).zipWithIndex
.reverse.foldLeft(pmpMinuxOne) { case (prev, ((pmp, last_pmp), i)) =>
val is_match = pmp.is_match(req.addr, req.size, lgMaxSize, last_pmp)
val ignore = passThrough && !pmp.cfg.l
val aligned = pmp.aligned(req.addr, req.size, lgMaxSize, last_pmp)
val cur = WireInit(pmp)
cur.cfg.r := aligned && (pmp.cfg.r || ignore)
cur.cfg.w := aligned && (pmp.cfg.w || ignore)
cur.cfg.x := aligned && (pmp.cfg.x || ignore)
match_wave(i) := is_match
ignore_wave(i) := ignore
aligned_wave(i) := aligned
cur_wave(i) := cur
prev_wave(i) := prev
XSDebug(p"pmp${i.U} cfg:${Hexadecimal(pmp.cfg.asUInt)} addr:${Hexadecimal(pmp.addr)} mask:${Hexadecimal(pmp.mask)} is_match:${is_match} aligned:${aligned}")
Mux(is_match, cur, prev)
}
val res_pmp = pmp_match_res(req.addr, req.size, io.env.pmp, io.env.mode, lgMaxSize)
val res_pma = pma_match_res(req.addr, req.size, io.env.pma, io.env.mode, lgMaxSize)
val resp_pmp = pmp_check(req.cmd, res_pmp.cfg)
val resp_pma = pma_check(req.cmd, res_pma.cfg)
val resp = resp_pmp | resp_pma
// NOTE: if itlb or dtlb may get blocked, this may also need do it
val ld = TlbCmd.isRead(req.cmd) && !TlbCmd.isAtom(req.cmd) && !res.cfg.r
val st = (TlbCmd.isWrite(req.cmd) || TlbCmd.isAtom(req.cmd)) && !res.cfg.w
val instr = TlbCmd.isExec(req.cmd) && !res.cfg.x
if (sameCycle) {
io.resp.ld := ld
io.resp.st := st
io.resp.instr := instr
io.resp := resp
} else {
io.resp.ld := RegEnable(ld, io.req.valid)
io.resp.st := RegEnable(st, io.req.valid)
io.resp.instr := RegEnable(instr, io.req.valid)
io.resp := RegEnable(resp, io.req.valid)
}
}
}
\ No newline at end of file
......@@ -102,6 +102,9 @@ trait HasCSRConst {
// TBD
val PmpcfgBase = 0x3A0
val PmpaddrBase = 0x3B0
// Machine level PMA
val PmacfgBase = 0x7C0
val PmaaddrBase = 0x7C8 // 84 entry at most
// Machine Counter/Timers
// Currently, we uses perfcnt csr set instead of standard Machine Counter/Timers
......
......@@ -179,8 +179,9 @@ class L2TlbMissQueue(implicit p: Parameters) extends XSModule with HasPtwConst {
!(mem_arb.io.out.fire && dup(entries(enq_ptr_reg).req_info.vpn, mem_arb.io.out.bits.req_info.vpn))) {
// NOTE: when pmp resp but state is not addr check, then the entry is dup with other entry, the state was changed before
// when dup with the req-ing entry, set to mem_waiting (above codes), and the ld must be false, so dontcare
entries(enq_ptr_reg).af := io.pmp.resp.ld
state(enq_ptr_reg) := Mux(io.pmp.resp.ld, state_mem_out, state_mem_req)
val accessFault = io.pmp.resp.ld || io.pmp.resp.mmio
entries(enq_ptr_reg).af := accessFault
state(enq_ptr_reg) := Mux(accessFault, state_mem_out, state_mem_req)
}
val flush = io.sfence.valid || io.csr.satp.changed
......
......@@ -30,12 +30,6 @@ import xiangshan.backend.fu.PMPReqBundle
abstract class TlbBundle(implicit p: Parameters) extends XSBundle with HasTlbConst
abstract class TlbModule(implicit p: Parameters) extends XSModule with HasTlbConst
// case class ITLBKey
// case class LDTLBKey
// case class STTLBKey
class VaBundle(implicit p: Parameters) extends TlbBundle {
val vpn = UInt(vpnLen.W)
val off = UInt(offLen.W)
......@@ -67,13 +61,6 @@ class TlbPermBundle(implicit p: Parameters) extends TlbBundle {
val x = Bool()
val w = Bool()
val r = Bool()
// pma perm (hardwired)
val pr = Bool() //readable
val pw = Bool() //writeable
val pe = Bool() //executable
val pa = Bool() //atom op permitted
val pi = Bool() //icacheable
val pd = Bool() //dcacheable
override def toPrintable: Printable = {
p"pf:${pf} af:${af} d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"
......@@ -163,15 +150,6 @@ class TlbData(superpage: Boolean = false)(implicit p: Parameters) extends TlbBun
this.perm.w := ptePerm.w
this.perm.r := ptePerm.r
// get pma perm
val (pmaMode, accessWidth) = AddressSpace.memmapAddrMatch(Cat(ppn, 0.U(12.W)))
this.perm.pr := PMAMode.read(pmaMode)
this.perm.pw := PMAMode.write(pmaMode)
this.perm.pe := PMAMode.execute(pmaMode)
this.perm.pa := PMAMode.atomic(pmaMode)
this.perm.pi := PMAMode.icache(pmaMode)
this.perm.pd := PMAMode.dcache(pmaMode)
this
}
......@@ -230,15 +208,6 @@ class TlbEntry(pageNormal: Boolean, pageSuper: Boolean)(implicit p: Parameters)
this.perm.w := ptePerm.w
this.perm.r := ptePerm.r
// get pma perm
val (pmaMode, accessWidth) = AddressSpace.memmapAddrMatch(Cat(item.entry.ppn, 0.U(12.W)))
this.perm.pr := PMAMode.read(pmaMode)
this.perm.pw := PMAMode.write(pmaMode)
this.perm.pe := PMAMode.execute(pmaMode)
this.perm.pa := PMAMode.atomic(pmaMode)
this.perm.pi := PMAMode.icache(pmaMode)
this.perm.pd := PMAMode.dcache(pmaMode)
this
}
......@@ -359,13 +328,13 @@ class TlbReplaceIO(Width: Int, q: TLBParameters)(implicit p: Parameters) extends
}
class TlbReq(implicit p: Parameters) extends TlbBundle {
val vaddr = UInt(VAddrBits.W)
val cmd = TlbCmd()
val size = UInt(log2Ceil(log2Ceil(XLEN/8)+1).W)
val robIdx = new RobPtr
val vaddr = Output(UInt(VAddrBits.W))
val cmd = Output(TlbCmd())
val size = Output(UInt(log2Ceil(log2Ceil(XLEN/8)+1).W))
val robIdx = Output(new RobPtr)
val debug = new Bundle {
val pc = UInt(XLEN.W)
val isFirstIssue = Bool()
val pc = Output(UInt(XLEN.W))
val isFirstIssue = Output(Bool())
}
override def toPrintable: Printable = {
......@@ -380,14 +349,13 @@ class TlbExceptionBundle(implicit p: Parameters) extends TlbBundle {
}
class TlbResp(implicit p: Parameters) extends TlbBundle {
val paddr = UInt(PAddrBits.W)
val miss = Bool()
val mmio = Bool()
val paddr = Output(UInt(PAddrBits.W))
val miss = Output(Bool())
val excp = new Bundle {
val pf = new TlbExceptionBundle()
val af = new TlbExceptionBundle()
}
val ptwBack = Bool() // when ptw back, wake up replay rs's state
val ptwBack = Output(Bool()) // when ptw back, wake up replay rs's state
override def toPrintable: Printable = {
p"paddr:0x${Hexadecimal(paddr)} miss:${miss} excp.pf: ld:${excp.pf.ld} st:${excp.pf.st} instr:${excp.pf.instr} ptwBack:${ptwBack}"
......
......@@ -86,6 +86,7 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) with H
for (p <- pmp_check) {
p.env.mode := ModeS
p.env.pmp := pmp.io.pmp
p.env.pma := pmp.io.pma
}
val missQueue = Module(new L2TlbMissQueue)
......
......@@ -80,7 +80,7 @@ class PtwFsm()(implicit p: Parameters) extends XSModule with HasPtwConst {
val finish = WireInit(false.B)
val sent_to_pmp = state === s_addr_check || (state === s_check_pte && !finish)
val accessFault = RegEnable(io.pmp.resp.ld, sent_to_pmp)
val accessFault = RegEnable(io.pmp.resp.ld || io.pmp.resp.mmio, sent_to_pmp)
val pageFault = memPte.isPf(level)
switch (state) {
is (s_idle) {
......
......@@ -154,28 +154,18 @@ class TLB(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModul
val instrPermFail = !(modeCheck && perm.x)
val ldPf = (ldPermFail || pf) && (TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg))
val stPf = (stPermFail || pf) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg))
val fault_valid = vmEnable && hit
val instrPf = (instrPermFail || pf) && TlbCmd.isExec(cmdReg)
resp(i).bits.excp.pf.ld := (ldPf || ldUpdate) && vmEnable && hit && !af
resp(i).bits.excp.pf.st := (stPf || stUpdate) && vmEnable && hit && !af
resp(i).bits.excp.pf.instr := (instrPf || instrUpdate) && vmEnable && hit && !af
resp(i).bits.excp.pf.ld := (ldPf || ldUpdate) && fault_valid && !af
resp(i).bits.excp.pf.st := (stPf || stUpdate) && fault_valid && !af
resp(i).bits.excp.pf.instr := (instrPf || instrUpdate) && fault_valid && !af
// NOTE: pf need && with !af, page fault has higher priority than access fault
// but ptw may also have access fault, then af happens, the translation is wrong.
// In this case, pf has lower priority than af
// if vmenable, use pre-calcuated pma check result
resp(i).bits.mmio := Mux(TlbCmd.isExec(cmdReg), !perm.pi, !perm.pd) && vmEnable && hit
resp(i).bits.excp.af.ld := (af || Mux(TlbCmd.isAtom(cmdReg), !perm.pa, !perm.pr) && TlbCmd.isRead(cmdReg)) && vmEnable && hit
resp(i).bits.excp.af.st := (af || Mux(TlbCmd.isAtom(cmdReg), !perm.pa, !perm.pw) && TlbCmd.isWrite(cmdReg)) && vmEnable && hit
resp(i).bits.excp.af.instr := (af || Mux(TlbCmd.isAtom(cmdReg), false.B, !perm.pe)) && vmEnable && hit
// if !vmenable, check pma
val (pmaMode, accessWidth) = AddressSpace.memmapAddrMatch(resp(i).bits.paddr)
when(!vmEnable) {
resp(i).bits.mmio := Mux(TlbCmd.isExec(cmdReg), !PMAMode.icache(pmaMode), !PMAMode.dcache(pmaMode))
resp(i).bits.excp.af.ld := Mux(TlbCmd.isAtom(cmdReg), !PMAMode.atomic(pmaMode), !PMAMode.read(pmaMode)) && TlbCmd.isRead(cmdReg)
resp(i).bits.excp.af.st := Mux(TlbCmd.isAtom(cmdReg), !PMAMode.atomic(pmaMode), !PMAMode.write(pmaMode)) && TlbCmd.isWrite(cmdReg)
resp(i).bits.excp.af.instr := Mux(TlbCmd.isAtom(cmdReg), false.B, !PMAMode.execute(pmaMode))
}
resp(i).bits.excp.af.ld := af && TlbCmd.isRead(cmdReg) && fault_valid
resp(i).bits.excp.af.st := af && TlbCmd.isWrite(cmdReg) && fault_valid
resp(i).bits.excp.af.instr := af && TlbCmd.isExec(cmdReg) && fault_valid
(hit, miss, validReg)
}
......
......@@ -74,6 +74,7 @@ class FrontendImp (outer: Frontend) extends LazyModuleImp(outer)
pmp.io.distribute_csr := io.csrCtrl.distribute_csr
for (i <- pmp_check.indices) {
pmp_check(i).env.pmp := pmp.io.pmp
pmp_check(i).env.pma := pmp.io.pma
pmp_check(i).env.mode := tlbCsr.priv.imode
pmp_check(i).req <> ifu.io.pmp(i).req
ifu.io.pmp(i).resp <> pmp_check(i).resp
......@@ -112,7 +113,7 @@ class FrontendImp (outer: Frontend) extends LazyModuleImp(outer)
}
icache.io.missQueue.flush := ifu.io.ftqInter.fromFtq.redirect.valid || (ifu.io.ftqInter.toFtq.pdWb.valid && ifu.io.ftqInter.toFtq.pdWb.bits.misOffset.valid)
icache.io.csr.distribute_csr <> io.csrCtrl.distribute_csr
icache.io.csr.update <> io.csrUpdate
......
......@@ -69,7 +69,7 @@ class NewIFUIO(implicit p: Parameters) extends XSBundle {
val uncacheInter = new UncacheInterface
val pmp = Vec(2, new Bundle {
val req = Valid(new PMPReqBundle())
val resp = Input(new PMPRespBundle())
val resp = Flipped(new PMPRespBundle())
})
}
......@@ -207,11 +207,10 @@ class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters
fromITLB.map(_.ready := true.B)
val (tlbRespValid, tlbRespPAddr) = (fromITLB.map(_.valid), VecInit(fromITLB.map(_.bits.paddr)))
val (tlbRespMiss, tlbRespMMIO) = (fromITLB.map(port => port.bits.miss && port.valid), fromITLB.map(port => port.bits.mmio && port.valid))
val (tlbRespMiss) = (fromITLB.map(port => port.bits.miss && port.valid))
val (tlbExcpPF, tlbExcpAF) = (fromITLB.map(port => port.bits.excp.pf.instr && port.valid),
fromITLB.map(port => (port.bits.excp.af.instr) && port.valid)) //TODO: Temp treat mmio req as access fault
tlbRespAllValid := tlbRespValid(0) && (tlbRespValid(1) || !f1_doubleLine)
val f1_pAddrs = tlbRespPAddr //TODO: Temporary assignment
......@@ -226,7 +225,7 @@ class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters
//MMIO
//MMIO only need 1 instruction
val f1_mmio = tlbRespMMIO(0) && f1_valid
// val f1_mmio = tlbRespMMIO(0) && f1_valid
val replacers = Seq.fill(2)(ReplacementPolicy.fromString(Some("random"),nWays,nSets/2))
......@@ -282,6 +281,7 @@ class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters
.elsewhen(f2_fire) {f2_valid := false.B}
val pmpExcpAF = fromPMP.map(port => port.instr)
val mmio = fromPMP.map(port => port.mmio) // TODO: handle it
val f2_pAddrs = RegEnable(next = f1_pAddrs, enable = f1_fire)
......@@ -296,12 +296,8 @@ class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters
val f2_except = VecInit((0 until 2).map{i => f2_except_pf(i) || f2_except_af(i)})
val f2_has_except = f2_valid && (f2_except_af.reduce(_||_) || f2_except_pf.reduce(_||_))
//MMIO
val f2_mmio = RegInit(false.B)
val f2_mmio = DataHoldBypass(Cat(io.pmp.map(_.resp.mmio)).orR, RegNext(f1_fire)).asBool()
when(f2_flush) {f2_mmio := false.B}
.elsewhen(f1_fire && f1_mmio && !f1_flush) {f2_mmio := true.B }
.elsewhen(f2_fire) {f2_mmio := false.B}
//
io.pmp.zipWithIndex.map { case (p, i) =>
p.req.valid := f2_fire
p.req.bits.addr := f2_pAddrs(i)
......@@ -340,7 +336,7 @@ class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters
switch(wait_state){
is(wait_idle){
when(f2_mmio && !f2_except_af(0) && !f2_except_pf(0)){
when(f2_mmio && f2_valid && !f2_except_af(0) && !f2_except_pf(0)){
wait_state := wait_send_mmio
}.elsewhen(miss_0_except_1){
wait_state := Mux(toMissQueue(0).ready, wait_queue_ready ,wait_idle )
......
......@@ -59,6 +59,7 @@ class LsqWrappper(implicit p: Parameters) extends XSModule with HasDCacheParamet
val brqRedirect = Flipped(ValidIO(new Redirect))
val loadIn = Vec(LoadPipelineWidth, Flipped(Valid(new LsPipelineBundle)))
val storeIn = Vec(StorePipelineWidth, Flipped(Valid(new LsPipelineBundle)))
val storeInRe = Vec(StorePipelineWidth, Input(new LsPipelineBundle()))
val storeDataIn = Vec(StorePipelineWidth, Flipped(Valid(new StoreDataBundle))) // store data, send to sq from rs
val loadDataForwarded = Vec(LoadPipelineWidth, Input(Bool()))
val needReplayFromRS = Vec(LoadPipelineWidth, Input(Bool()))
......@@ -122,6 +123,7 @@ class LsqWrappper(implicit p: Parameters) extends XSModule with HasDCacheParamet
// storeQueue.io <> DontCare
storeQueue.io.brqRedirect <> io.brqRedirect
storeQueue.io.storeIn <> io.storeIn
storeQueue.io.storeInRe <> io.storeInRe
storeQueue.io.storeDataIn <> io.storeDataIn
storeQueue.io.sbuffer <> io.sbuffer
storeQueue.io.mmioStout <> io.mmioStout
......
......@@ -56,6 +56,7 @@ class StoreQueue(implicit p: Parameters) extends XSModule with HasDCacheParamete
val enq = new SqEnqIO
val brqRedirect = Flipped(ValidIO(new Redirect))
val storeIn = Vec(StorePipelineWidth, Flipped(Valid(new LsPipelineBundle))) // store addr, data is not included
val storeInRe = Vec(StorePipelineWidth, Input(new LsPipelineBundle())) // store more mmio and exception
val storeDataIn = Vec(StorePipelineWidth, Flipped(Valid(new StoreDataBundle))) // store data, send to sq from rs
val sbuffer = Vec(StorePipelineWidth, Decoupled(new DCacheWordReqWithVaddr)) // write commited store to sbuffer
val mmioStout = DecoupledIO(new ExuOutput) // writeback uncached store
......@@ -214,7 +215,7 @@ class StoreQueue(implicit p: Parameters) extends XSModule with HasDCacheParamete
val stWbIndex = io.storeIn(i).bits.uop.sqIdx.value
when (io.storeIn(i).fire()) {
addrvalid(stWbIndex) := true.B//!io.storeIn(i).bits.mmio
pending(stWbIndex) := io.storeIn(i).bits.mmio
// pending(stWbIndex) := io.storeIn(i).bits.mmio
dataModule.io.mask.waddr(i) := stWbIndex
dataModule.io.mask.wdata(i) := io.storeIn(i).bits.mask
......@@ -232,7 +233,7 @@ class StoreQueue(implicit p: Parameters) extends XSModule with HasDCacheParamete
debug_paddr(paddrModule.io.waddr(i)) := paddrModule.io.wdata(i)
mmio(stWbIndex) := io.storeIn(i).bits.mmio
// mmio(stWbIndex) := io.storeIn(i).bits.mmio
uop(stWbIndex).debugInfo := io.storeIn(i).bits.uop.debugInfo
XSInfo("store addr write to sq idx %d pc 0x%x vaddr %x paddr %x mmio %x\n",
......@@ -244,6 +245,14 @@ class StoreQueue(implicit p: Parameters) extends XSModule with HasDCacheParamete
)
}
// re-replinish mmio, for pma/pmp will get mmio one cycle later
val storeInFireReg = RegNext(io.storeIn(i).fire())
val stWbIndexReg = RegNext(stWbIndex)
when (storeInFireReg) {
pending(stWbIndexReg) := io.storeInRe(i).mmio
mmio(stWbIndexReg) := io.storeInRe(i).mmio
}
when(vaddrModule.io.wen(i)){
debug_vaddr(vaddrModule.io.waddr(i)) := vaddrModule.io.wdata(i)
}
......
......@@ -22,8 +22,9 @@ import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.{DCacheWordIOWithVaddr, MemoryOpConstants}
import xiangshan.cache.mmu.{TlbRequestIO, TlbCmd}
import xiangshan.cache.mmu.{TlbCmd, TlbRequestIO}
import difftest._
import xiangshan.backend.fu.PMPRespBundle
class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstants{
val io = IO(new Bundle() {
......@@ -32,6 +33,7 @@ class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstant
val out = Decoupled(new ExuOutput)
val dcache = new DCacheWordIOWithVaddr
val dtlb = new TlbRequestIO
val pmpResp = Flipped(new PMPRespBundle())
val rsIdx = Input(UInt(log2Up(IssQueSize).W))
val flush_sbuffer = new SbufferFlushBundle
val feedbackSlow = ValidIO(new RSFeedback)
......@@ -42,7 +44,7 @@ class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstant
//-------------------------------------------------------
// Atomics Memory Accsess FSM
//-------------------------------------------------------
val s_invalid :: s_tlb :: s_flush_sbuffer_req :: s_flush_sbuffer_resp :: s_cache_req :: s_cache_resp :: s_finish :: Nil = Enum(7)
val s_invalid :: s_tlb :: s_pm :: s_flush_sbuffer_req :: s_flush_sbuffer_resp :: s_cache_req :: s_cache_resp :: s_finish :: Nil = Enum(8)
val state = RegInit(s_invalid)
val data_valid = RegInit(false.B)
val in = Reg(new ExuInput())
......@@ -140,7 +142,6 @@ class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstant
io.dtlb.resp.bits.excp.pf.ld ||
io.dtlb.resp.bits.excp.af.st ||
io.dtlb.resp.bits.excp.af.ld
is_mmio := io.dtlb.resp.bits.mmio
when (exception) {
// check for exceptions
// if there are exceptions, no need to execute it
......@@ -148,11 +149,21 @@ class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstant
atom_override_xtval := true.B
} .otherwise {
paddr := io.dtlb.resp.bits.paddr
state := s_flush_sbuffer_req
state := s_pm
}
}
}
when (state === s_pm) {
is_mmio := io.pmpResp.mmio
val exception = io.pmpResp.st
when (exception) {
state := s_finish
atom_override_xtval := true.B
}.otherwise {
state := s_flush_sbuffer_req
}
}
when (state === s_flush_sbuffer_req) {
io.flush_sbuffer.valid := true.B
......
......@@ -78,7 +78,7 @@ class LoadUnit_S0(implicit p: Parameters) extends XSModule with HasDCacheParamet
val s0_mask = Mux(io.loadFastMatch.orR, fastpath_mask, slowpath_mask)
XSPerfAccumulate("load_to_load_forward", io.loadFastMatch.orR && io.in.fire())
val isSoftPrefetch = Wire(Bool())
val isSoftPrefetch = Wire(Bool())
isSoftPrefetch := s0_uop.ctrl.isORI //it's a ORI but it exists in ldu, which means it's a softprefecth
val isSoftPrefetchRead = Wire(Bool())
val isSoftPrefetchWrite = Wire(Bool())
......@@ -101,7 +101,7 @@ class LoadUnit_S0(implicit p: Parameters) extends XSModule with HasDCacheParamet
}.elsewhen (isSoftPrefetchWrite) {
io.dcacheReq.bits.cmd := MemoryOpConstants.M_PFW
}.otherwise {
io.dcacheReq.bits.cmd := MemoryOpConstants.M_XRD
io.dcacheReq.bits.cmd := MemoryOpConstants.M_XRD
}
io.dcacheReq.bits.addr := s0_vaddr
io.dcacheReq.bits.mask := s0_mask
......@@ -131,7 +131,7 @@ class LoadUnit_S0(implicit p: Parameters) extends XSModule with HasDCacheParamet
io.out.bits.uop.cf.exceptionVec(loadAddrMisaligned) := !addrAligned
io.out.bits.rsIdx := io.rsIdx
io.out.bits.isFirstIssue := io.isFirstIssue
io.out.bits.isSoftPrefetch := isSoftPrefetch
io.out.bits.isSoftPrefetch := isSoftPrefetch
io.in.ready := !io.in.valid || (io.out.ready && io.dcacheReq.ready)
......@@ -169,19 +169,10 @@ class LoadUnit_S1(implicit p: Parameters) extends XSModule {
val needLdVioCheckRedo = Output(Bool())
})
val isSoftPrefetch = io.in.bits.isSoftPrefetch
val actually_execpt = io.dtlbResp.bits.excp.pf.ld || io.dtlbResp.bits.excp.af.ld || io.out.bits.uop.cf.exceptionVec(loadAddrMisaligned)
val actually_mmio = !io.dtlbResp.bits.miss && io.dtlbResp.bits.mmio
val softprefecth_mmio = isSoftPrefetch && actually_mmio //TODO, fix it
val softprefecth_excep = isSoftPrefetch && actually_execpt //TODO, fix it
val s1_uop = io.in.bits.uop
val s1_paddr = io.dtlbResp.bits.paddr
val s1_exception = selectLoad(io.out.bits.uop.cf.exceptionVec, false).asUInt.orR // af & pf exception were modified below.
val s1_tlb_miss = io.dtlbResp.bits.miss
//val s1_mmio = !s1_tlb_miss && io.dtlbResp.bits.mmio
val s1_mmio = !isSoftPrefetch && actually_mmio
val s1_mask = io.in.bits.mask
val s1_bank_conflict = io.dcacheBankConflict
......@@ -192,7 +183,7 @@ class LoadUnit_S1(implicit p: Parameters) extends XSModule {
// TOOD: PMA check
io.dcachePAddr := s1_paddr
//io.dcacheKill := s1_tlb_miss || s1_exception || s1_mmio
io.dcacheKill := s1_tlb_miss || actually_mmio || actually_execpt
io.dcacheKill := s1_tlb_miss || s1_exception
// load forward query datapath
io.sbuffer.valid := io.in.valid && !(s1_exception || s1_tlb_miss)
......@@ -235,25 +226,21 @@ class LoadUnit_S1(implicit p: Parameters) extends XSModule {
io.rsFeedback.bits.sourceType := Mux(s1_bank_conflict, RSFeedbackType.bankConflict, RSFeedbackType.ldVioCheckRedo)
io.rsFeedback.bits.dataInvalidSqIdx := DontCare
// if replay is detected in load_s1,
// load inst will be canceled immediately
io.out.valid := io.in.valid && !io.rsFeedback.valid
// if replay is detected in load_s1,
// load inst will be canceled immediately
io.out.valid := io.in.valid && !io.rsFeedback.valid
io.out.bits.paddr := s1_paddr
io.out.bits.mmio := s1_mmio && !s1_exception
io.out.bits.tlbMiss := s1_tlb_miss
// current ori test will cause the case of ldest == 0, below will be modifeid in the future.
// current ori test will cause the case of ldest == 0, below will be modifeid in the future.
// af & pf exception were modified
io.out.bits.uop.cf.exceptionVec(loadPageFault) := !isSoftPrefetch && io.dtlbResp.bits.excp.pf.ld
io.out.bits.uop.cf.exceptionVec(loadAccessFault) := !isSoftPrefetch && io.dtlbResp.bits.excp.af.ld
io.out.bits.uop.cf.exceptionVec(loadPageFault) := io.dtlbResp.bits.excp.pf.ld
io.out.bits.uop.cf.exceptionVec(loadAccessFault) := io.dtlbResp.bits.excp.af.ld
io.out.bits.ptwBack := io.dtlbResp.bits.ptwBack
io.out.bits.rsIdx := io.in.bits.rsIdx
// soft prefetch stuff
io.out.bits.isSoftPrefetch := io.in.bits.isSoftPrefetch
io.out.bits.isSoftPreExcept := softprefecth_excep
io.out.bits.isSoftPremmio := softprefecth_mmio
io.out.bits.isSoftPrefetch := io.in.bits.isSoftPrefetch
io.in.ready := !io.in.valid || io.out.ready
......@@ -273,7 +260,7 @@ class LoadUnit_S2(implicit p: Parameters) extends XSModule with HasLoadHelper {
val out = Decoupled(new LsPipelineBundle)
val rsFeedback = ValidIO(new RSFeedback)
val dcacheResp = Flipped(DecoupledIO(new DCacheWordResp))
val pmpResp = Input(new PMPRespBundle())
val pmpResp = Flipped(new PMPRespBundle())
val lsq = new LoadForwardQueryIO
val dataInvalidSqIdx = Input(UInt())
val sbuffer = new LoadForwardQueryIO
......@@ -284,32 +271,36 @@ class LoadUnit_S2(implicit p: Parameters) extends XSModule with HasLoadHelper {
val dcache_kill = Output(Bool())
val loadViolationQueryResp = Flipped(Valid(new LoadViolationQueryResp))
val csrCtrl = Flipped(new CustomCSRCtrlIO)
val sentFastUop = Input(Bool())
})
val isSoftPrefetch = io.in.bits.isSoftPrefetch
val excep = WireInit(io.in.bits.uop.cf.exceptionVec)
excep(loadAccessFault) := io.in.bits.uop.cf.exceptionVec(loadAccessFault) || io.pmpResp.ld
when (isSoftPrefetch) {
excep := 0.U.asTypeOf(excep.cloneType)
}
val s2_exception = selectLoad(excep, false).asUInt.orR
val actually_mmio = io.pmpResp.mmio
val s2_uop = io.in.bits.uop
val s2_mask = io.in.bits.mask
val s2_paddr = io.in.bits.paddr
val s2_tlb_miss = io.in.bits.tlbMiss
val s2_data_invalid = io.lsq.dataInvalid
val s2_mmio = io.in.bits.mmio && !s2_exception
val s2_mmio = !isSoftPrefetch && actually_mmio && !s2_exception
val s2_cache_miss = io.dcacheResp.bits.miss
val s2_cache_replay = io.dcacheResp.bits.replay
val s2_cache_miss_enter = io.dcacheResp.bits.miss_enter //missReq enter the mshr successfully
val isSoftPreExcept = io.in.bits.isSoftPreExcept
val isSoftPremmio = io.in.bits.isSoftPremmio
val isSoftPremmio = isSoftPrefetch && actually_mmio //TODO, fix it
// val cnt = RegInit(127.U)
// cnt := cnt + io.in.valid.asUInt
// val s2_forward_fail = io.lsq.matchInvalid || io.sbuffer.matchInvalid || cnt === 0.U
val s2_forward_fail = io.lsq.matchInvalid || io.sbuffer.matchInvalid
// assert(!s2_forward_fail)
io.dcache_kill := io.in.valid && io.pmpResp.ld
io.dcache_kill := false.B // move pmp resp kill to outside
io.dcacheResp.ready := true.B
val dcacheShouldResp = !(s2_tlb_miss || s2_exception || s2_mmio)
assert(!(io.in.valid && (dcacheShouldResp && !io.dcacheResp.valid) && (!isSoftPreExcept) && (!isSoftPremmio)), "DCache response got lost")
......@@ -368,7 +359,7 @@ class LoadUnit_S2(implicit p: Parameters) extends XSModule with HasLoadHelper {
when(io.in.bits.isSoftPrefetch) {
io.out.bits.miss := s2_cache_miss && !s2_exception && !s2_forward_fail && !s2_cache_miss_enter && !isSoftPreExcept && !isSoftPremmio
}.otherwise {
io.out.bits.miss := s2_cache_miss && !s2_exception && !s2_forward_fail
io.out.bits.miss := s2_cache_miss && !s2_exception && !s2_forward_fail
}
}
io.out.bits.uop.ctrl.fpWen := io.in.bits.uop.ctrl.fpWen && !s2_exception
......@@ -380,6 +371,7 @@ class LoadUnit_S2(implicit p: Parameters) extends XSModule with HasLoadHelper {
RegNext(io.csrCtrl.ldld_vio_check)
io.out.bits.uop.ctrl.replayInst := forwardFailReplay || ldldVioReplay
io.out.bits.mmio := s2_mmio
io.out.bits.uop.ctrl.flushPipe := io.in.bits.uop.ctrl.flushPipe || (s2_mmio && io.sentFastUop)
io.out.bits.uop.cf.exceptionVec := excep
// For timing reasons, sometimes we can not let
......@@ -395,7 +387,6 @@ class LoadUnit_S2(implicit p: Parameters) extends XSModule with HasLoadHelper {
io.in.ready := io.out.ready || !io.in.valid
// feedback tlb result to RS
io.rsFeedback.valid := io.in.valid
when (io.in.bits.isSoftPrefetch) {
......@@ -457,7 +448,7 @@ class LoadUnit(implicit p: Parameters) extends XSModule with HasLoadHelper {
val fastUop = ValidIO(new MicroOp) // early wakeup signal generated in load_s1
val tlb = new TlbRequestIO
val pmp = Input(new PMPRespBundle()) // arrive same to tlb now
val pmp = Flipped(new PMPRespBundle()) // arrive same to tlb now
val fastpathOut = Output(new LoadToLoadIO)
val fastpathIn = Input(Vec(LoadPipelineWidth, new LoadToLoadIO))
......@@ -491,7 +482,7 @@ class LoadUnit(implicit p: Parameters) extends XSModule with HasLoadHelper {
PipelineConnect(load_s1.io.out, load_s2.io.in, true.B, load_s1.io.out.bits.uop.robIdx.needFlush(io.redirect))
io.dcache.s2_kill <> load_s2.io.dcache_kill
io.dcache.s2_kill := load_s2.io.dcache_kill || (io.pmp.ld || io.pmp.mmio) // to kill mmio resp which are redirected
load_s2.io.dcacheResp <> io.dcache.resp
load_s2.io.pmpResp <> io.pmp
load_s2.io.lsq.forwardData <> io.lsq.forward.forwardData
......@@ -509,6 +500,7 @@ class LoadUnit(implicit p: Parameters) extends XSModule with HasLoadHelper {
load_s2.io.dataInvalidSqIdx := io.lsq.forward.dataInvalidSqIdx // provide dataInvalidSqIdx to make wakeup faster
load_s2.io.loadViolationQueryResp <> io.lsq.loadViolationQuery.resp
load_s2.io.csrCtrl <> io.csrCtrl
load_s2.io.sentFastUop := RegEnable(io.fastUop.valid, load_s1.io.out.fire()) // RegNext is also ok
io.lsq.needReplayFromRS := load_s2.io.needReplayFromRS
// feedback tlb miss / dcache miss queue full
......@@ -519,7 +511,7 @@ class LoadUnit(implicit p: Parameters) extends XSModule with HasLoadHelper {
io.feedbackFast.bits := load_s1.io.rsFeedback.bits
io.feedbackFast.valid := load_s1.io.rsFeedback.valid
// If replay is reported at load_s1, inst will be canceled (will not enter load_s2),
// in that case:
// in that case:
// * replay should not be reported twice
assert(!(RegNext(RegNext(io.feedbackFast.valid)) && io.feedbackSlow.valid))
// * io.fastUop.valid should not be reported
......
......@@ -94,7 +94,6 @@ class StoreUnit_S1(implicit p: Parameters) extends XSModule {
val io = IO(new Bundle() {
val in = Flipped(Decoupled(new LsPipelineBundle))
val out = Decoupled(new LsPipelineBundle)
val lsq = ValidIO(new LsPipelineBundle)
val dtlbResp = Flipped(DecoupledIO(new TlbResp))
val rsFeedback = ValidIO(new RSFeedback)
})
......@@ -106,7 +105,7 @@ class StoreUnit_S1(implicit p: Parameters) extends XSModule {
val s1_paddr = io.dtlbResp.bits.paddr
val s1_tlb_miss = io.dtlbResp.bits.miss
val s1_mmio = io.dtlbResp.bits.mmio || is_mmio_cbo
val s1_mmio = is_mmio_cbo
val s1_exception = selectStore(io.out.bits.uop.cf.exceptionVec, false).asUInt.orR
io.in.ready := true.B
......@@ -128,17 +127,16 @@ class StoreUnit_S1(implicit p: Parameters) extends XSModule {
// get paddr from dtlb, check if rollback is needed
// writeback store inst to lsq
io.lsq.valid := io.in.valid && !s1_tlb_miss
io.lsq.bits := io.in.bits
io.lsq.bits.paddr := s1_paddr
io.lsq.bits.miss := false.B
io.lsq.bits.mmio := s1_mmio && !s1_exception
io.lsq.bits.uop.cf.exceptionVec(storePageFault) := io.dtlbResp.bits.excp.pf.st
io.lsq.bits.uop.cf.exceptionVec(storeAccessFault) := io.dtlbResp.bits.excp.af.st
io.out.valid := io.in.valid && !s1_tlb_miss
io.out.bits := io.in.bits
io.out.bits.paddr := s1_paddr
io.out.bits.miss := false.B
io.out.bits.mmio := s1_mmio
io.out.bits.uop.cf.exceptionVec(storePageFault) := io.dtlbResp.bits.excp.pf.st
io.out.bits.uop.cf.exceptionVec(storeAccessFault) := io.dtlbResp.bits.excp.af.st
// mmio inst with exception will be writebacked immediately
io.out.valid := io.in.valid && (!io.out.bits.mmio || s1_exception) && !s1_tlb_miss
io.out.bits := io.lsq.bits
// io.out.valid := io.in.valid && (!io.out.bits.mmio || s1_exception) && !s1_tlb_miss
XSPerfAccumulate("in_valid", io.in.valid)
XSPerfAccumulate("in_fire", io.in.fire)
......@@ -150,15 +148,17 @@ class StoreUnit_S1(implicit p: Parameters) extends XSModule {
class StoreUnit_S2(implicit p: Parameters) extends XSModule {
val io = IO(new Bundle() {
val in = Flipped(Decoupled(new LsPipelineBundle))
val pmpResp = Input(new PMPRespBundle)
val pmpResp = Flipped(new PMPRespBundle)
val out = Decoupled(new LsPipelineBundle)
})
val s2_exception = selectStore(io.out.bits.uop.cf.exceptionVec, false).asUInt.orR
io.in.ready := true.B
io.out.bits := io.in.bits
io.out.bits.mmio := (io.in.bits.mmio || io.pmpResp.mmio) && !s2_exception
io.out.bits.uop.cf.exceptionVec(storeAccessFault) := io.in.bits.uop.cf.exceptionVec(storeAccessFault) || io.pmpResp.st
io.out.valid := io.in.valid
io.out.valid := io.in.valid && (!io.out.bits.mmio || s2_exception)
}
class StoreUnit_S3(implicit p: Parameters) extends XSModule {
......@@ -187,10 +187,11 @@ class StoreUnit(implicit p: Parameters) extends XSModule {
val redirect = Flipped(ValidIO(new Redirect))
val feedbackSlow = ValidIO(new RSFeedback)
val tlb = new TlbRequestIO()
val pmp = Input(new PMPRespBundle())
val pmp = Flipped(new PMPRespBundle())
val rsIdx = Input(UInt(log2Up(IssQueSize).W))
val isFirstIssue = Input(Bool())
val lsq = ValidIO(new LsPipelineBundle)
val lsq_replenish = Output(new LsPipelineBundle())
val stout = DecoupledIO(new ExuOutput) // writeback store
})
......@@ -206,13 +207,16 @@ class StoreUnit(implicit p: Parameters) extends XSModule {
PipelineConnect(store_s0.io.out, store_s1.io.in, true.B, store_s0.io.out.bits.uop.robIdx.needFlush(io.redirect))
store_s1.io.lsq <> io.lsq // send result to sq
store_s1.io.dtlbResp <> io.tlb.resp
store_s1.io.rsFeedback <> io.feedbackSlow
io.lsq.bits := store_s1.io.out.bits
io.lsq.valid := store_s1.io.out.valid
PipelineConnect(store_s1.io.out, store_s2.io.in, true.B, store_s1.io.out.bits.uop.robIdx.needFlush(io.redirect))
store_s2.io.pmpResp <> io.pmp
io.lsq_replenish := store_s2.io.out.bits // mmio and exception
PipelineConnect(store_s2.io.out, store_s3.io.in, true.B, store_s2.io.out.bits.uop.robIdx.needFlush(io.redirect))
store_s3.io.stout <> io.stout
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册