提交 5d20caa2 编写于 作者: J jinyue110

Merge branch 'master' into dev-icache

......@@ -13,12 +13,15 @@ jobs:
name: Make EMU
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Set env
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
- name: Build EMU
run: make ./build/emu SIM_ARGS=--disable-log NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
run:
make ./build/emu SIM_ARGS=--disable-log NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
cputest:
runs-on: self-hosted
......
......@@ -5,9 +5,10 @@ package bus.axi4
import chisel3._
import chisel3.util._
import noop.HasNOOPParameter
// import noop.HasNOOPParameter
import xiangshan.HasXSParameter
object AXI4Parameters extends HasNOOPParameter {
object AXI4Parameters extends HasXSParameter {
// These are all fixed by the AXI4 standard:
val lenBits = 8
val sizeBits = 3
......
......@@ -39,7 +39,6 @@ class MMIOTLToAXI4(params: TLParameters) extends XSModule
assert(innerBeatSize == outerBeatSize)
val axi4_size = log2Up(outerBeatBytes).U
val s_idle :: s_wait_awready :: s_mem_write :: s_wait_bresp :: s_wait_arready :: s_mem_read :: s_send_resp :: Nil = Enum(7)
val state = RegInit(s_idle)
......
......@@ -100,6 +100,8 @@ sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheMod
val out = Decoupled(new Stage1IO)
val metaReadBus = CacheMetaArrayReadBus()
val dataReadBus = CacheDataArrayReadBus()
val s2s3Empty = Input(Bool()) // FIXME: remove me when do not use nut's cache
})
if (ro) when (io.in.fire()) { assert(!io.in.bits.isWrite()) }
......@@ -117,8 +119,8 @@ sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheMod
io.dataReadBus.apply(valid = readBusValid, setIdx = getDataIdx(io.in.bits.addr))
io.out.bits.req := io.in.bits
io.out.valid := io.in.valid && io.metaReadBus.req.ready && io.dataReadBus.req.ready
io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready
io.out.valid := io.in.valid && io.metaReadBus.req.ready && io.dataReadBus.req.ready && io.s2s3Empty // FIXME: remove me when do not use nut's cache
io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready && io.s2s3Empty // FIXME: remove me when do not use nut's cache
Debug() {
if (debug) {
......@@ -181,7 +183,7 @@ sealed class CacheStage2(implicit val cacheConfig: CacheConfig) extends CacheMod
io.out.bits.hit := io.in.valid && hitVec.orR
io.out.bits.waymask := waymask
io.out.bits.datas := io.dataReadResp
io.out.bits.mmio := xiangshan.AddressSpace.isMMIO(req.addr)
io.out.bits.mmio := xiangshan.AddressSpace.isMMIO(ZeroExt(req.addr, 40)) // FIXME: isMMIO should have PAddrBits Length ??
val isForwardData = io.in.valid && (io.dataWriteBus.req match { case r =>
r.valid && r.bits.setIdx === getDataIdx(req.addr)
......@@ -484,6 +486,7 @@ class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule {
io.out.mem <> s3.io.mem
io.mmio <> s3.io.mmio
io.empty := !s2.io.in.valid && !s3.io.in.valid
s1.io.s2s3Empty := io.empty // FIXME: remove me when do not use nut's cache
io.in.resp.valid := Mux(s3.io.out.valid && s3.io.out.bits.isPrefetch(), false.B, s3.io.out.valid || s3.io.dataReadRespToL1)
......@@ -527,7 +530,7 @@ class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule {
when (s1.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S1]: ${s1.io.in.bits}\n") }
when (s2.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S2]: ${s2.io.in.bits.req}\n") }
when (s3.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S3]: ${s3.io.in.bits.req}\n") }
//s3.io.mem.dump(cacheName + ".mem")
// s3.io.mem.dump(cacheName + ".mem")
}}
}
}
......
......@@ -226,3 +226,35 @@ class FrontendToBackendIO extends XSBundle {
val outOfOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
val inOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
}
class TlbCsrBundle extends XSBundle {
val satp = new Bundle {
val mode = UInt(4.W) // TODO: may change number to parameter
val asid = UInt(16.W)
val ppn = UInt(44.W) // just use PAddrBits - 3 - vpnnLen
}
val priv = new Bundle {
val mxr = Bool()
val sum = Bool()
val imode = UInt(2.W)
val dmode = UInt(2.W)
}
override def toPrintable: Printable = {
p"Satp mode:0x${Hexadecimal(satp.mode)} asid:0x${Hexadecimal(satp.asid)} ppn:0x${Hexadecimal(satp.ppn)} " +
p"Priv mxr:${priv.mxr} sum:${priv.sum} imode:${priv.imode} dmode:${priv.dmode}"
}
}
class SfenceBundle extends XSBundle {
val valid = Bool()
val bits = new Bundle {
val rs1 = Bool()
val rs2 = Bool()
val addr = UInt(VAddrBits.W)
}
override def toPrintable: Printable = {
p"valid:0x${Hexadecimal(valid)} rs1:${bits.rs1} rs2:${bits.rs2} addr:${Hexadecimal(bits.addr)}"
}
}
\ No newline at end of file
......@@ -9,7 +9,7 @@ import xiangshan.backend.dispatch.DispatchParameters
import xiangshan.backend.exu.ExuParameters
import xiangshan.frontend._
import xiangshan.mem._
import xiangshan.cache.{ICache,DCache, DCacheParameters, ICacheParameters, Uncache}
import xiangshan.cache.{ICache,DCache, DCacheParameters, ICacheParameters, PTW, Uncache}
import chipsalliance.rocketchip.config
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLBundleParameters, TLCacheCork, TLClientNode, TLIdentityNode, TLXbar}
......@@ -26,7 +26,7 @@ case class XSCoreParameters
EnableStoreQueue: Boolean = true,
AddrBits: Int = 64,
VAddrBits: Int = 39,
PAddrBits: Int = 32,
PAddrBits: Int = 40,
HasFPU: Boolean = true,
FectchWidth: Int = 8,
EnableBPU: Boolean = true,
......@@ -80,7 +80,11 @@ case class XSCoreParameters
LoadPipelineWidth: Int = 2,
StorePipelineWidth: Int = 2,
StoreBufferSize: Int = 16,
RefillSize: Int = 512
RefillSize: Int = 512,
TlbEntrySize: Int = 32,
TlbL2EntrySize: Int = 256, // or 512
PtwL1EntrySize: Int = 16,
PtwL2EntrySize: Int = 256
)
trait HasXSParameter {
......@@ -148,6 +152,11 @@ trait HasXSParameter {
val StorePipelineWidth = core.StorePipelineWidth
val StoreBufferSize = core.StoreBufferSize
val RefillSize = core.RefillSize
val DTLBWidth = core.LoadPipelineWidth + core.StorePipelineWidth
val TlbEntrySize = core.TlbEntrySize
val TlbL2EntrySize = core.TlbL2EntrySize
val PtwL1EntrySize = core.PtwL1EntrySize
val PtwL2EntrySize = core.PtwL2EntrySize
val l1BusDataWidth = 64
......@@ -210,6 +219,7 @@ class XSCore()(implicit p: config.Parameters) extends LazyModule {
val dcache = LazyModule(new DCache())
val uncache = LazyModule(new Uncache())
val icache = LazyModule(new ICache())
val ptw = LazyModule(new PTW())
// TODO: crossbar Icache/Dcache/PTW here
val mem = TLXbar()
......@@ -217,6 +227,7 @@ class XSCore()(implicit p: config.Parameters) extends LazyModule {
mem := TLCacheCork(sinkIds = 1) := dcache.clientNode
mem := TLCacheCork(sinkIds = 1) := icache.clientNode
mem := TLCacheCork(sinkIds = 1) := ptw.node
lazy val module = new XSCoreImp(this)
}
......@@ -230,6 +241,7 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer) with HasXSParameter
val dcache = outer.dcache.module
val uncache = outer.uncache.module
val icache = outer.icache.module
val ptw = outer.ptw.module
// TODO: connect this
dcache.io.lsu.misc <> DontCare
......@@ -239,11 +251,13 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer) with HasXSParameter
icache.io.req <> front.io.icacheReq
icache.io.flush <> front.io.icacheFlush
mem.io.backend <> backend.io.mem
ptw.io.tlb(0) <> mem.io.ptw
ptw.io.tlb(1) <> DontCare
dcache.io.lsu.load <> mem.io.loadUnitToDcacheVec
dcache.io.lsu.lsroq <> mem.io.miscToDcache
dcache.io.lsu.store <> mem.io.sbufferToDcache
uncache.io.lsroq <> mem.io.uncache
backend.io.memMMU.imem <> DontCare
backend.io.memMMU.dmem <> DontCare
}
......@@ -24,14 +24,12 @@ import utils.ParallelOR
class Backend extends XSModule
with NeedImpl {
val io = IO(new Bundle {
// val dmem = new SimpleBusUC(addrBits = VAddrBits)
val memMMU = Flipped(new MemMMUIO)
val frontend = Flipped(new FrontendToBackendIO)
val mem = Flipped(new MemToBackendIO)
})
val aluExeUnits = Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
val aluExeUnits = Module(new AluExeUnit(hasSfence = true)) +: Array.tabulate(exuParameters.AluCnt-1)(_ => Module(new AluExeUnit(hasSfence = false)))
val jmpExeUnit = Module(new JmpExeUnit)
val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
......
......@@ -131,19 +131,20 @@ class Decoder extends XSModule with HasInstrType {
io.out.ctrl.src1Type := Mux(instr(6,0) === "b0110111".U || instr(15, 13) === "b011".U && instr(1, 0) === "b01".U, SrcType.reg, src1Type)
io.out.ctrl.src2Type := src2Type
val vmEnable = WireInit(false.B)
BoringUtils.addSink(vmEnable, "DTLBENABLE")
// val vmEnable = WireInit(false.B)
// BoringUtils.addSink(vmEnable, "DTLBENABLE")
io.out.cf.exceptionVec.map(_ := false.B)
io.out.cf.exceptionVec(illegalInstr) := instrType === InstrN
io.out.cf.exceptionVec(instrPageFault) := io.in.exceptionVec(instrPageFault)
io.out.cf.exceptionVec(instrAccessFault) := io.in.pc(VAddrBits - 1, PAddrBits).orR && !vmEnable
// io.out.cf.exceptionVec(instrAccessFault) := io.in.pc(VAddrBits - 1, PAddrBits).orR && !vmEnable // NOTE: PAddrBits is larger than VAddrBits, so comment it
io.out.ctrl.isXSTrap := (instr === XSTrap.TRAP)
when(io.out.ctrl.isXSTrap){
io.out.ctrl.lsrc1 := 10.U // a0
}
io.out.ctrl.noSpecExec := io.out.ctrl.isXSTrap || io.out.ctrl.fuType===FuType.csr || io.out.ctrl.fuType===FuType.mou
io.out.ctrl.noSpecExec := io.out.ctrl.isXSTrap || io.out.ctrl.fuType===FuType.csr || io.out.ctrl.fuType===FuType.mou || (io.out.ctrl.fuType===FuType.alu && io.out.ctrl.fuOpType===ALUOpType.sfence/*noSpecExec make it sent to alu0,for roq is empty*/)
//io.out.ctrl.isBlocked := (io.out.ctrl.fuType===FuType.alu && io.out.ctrl.fuOpType===ALUOpType.sfence) // TOOD: check it
XSDebug("in: instr=%x pc=%x excepVec=%b intrVec=%b crossPageIPFFix=%d\n",
......
......@@ -19,8 +19,8 @@ object Privileged extends HasInstrType {
val table = Array(
ECALL -> List(InstrI, FuType.csr, CSROpType.jmp),
MRET -> List(InstrI, FuType.csr, CSROpType.jmp),
SRET -> List(InstrI, FuType.csr, CSROpType.jmp)
// SFANCE_VMA -> List(InstrR, FuType.mou, MOUOpType.sfence_vma),
SRET -> List(InstrI, FuType.csr, CSROpType.jmp),
SFANCE_VMA -> List(InstrR, FuType.alu, ALUOpType.sfence)
// FENCE -> List(InstrS, FuType.alu, ALUOpType.add), // nop InstrS -> !wen
// WFI -> List(InstrI, FuType.alu, ALUOpType.add) // nop
// FENCE -> List(InstrB, FuType.mou, MOUOpType.fencei)
......
......@@ -2,6 +2,7 @@ package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import xiangshan._
import xiangshan.FuType._
import utils._
......@@ -9,7 +10,7 @@ import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
class AluExeUnit(hasSfence: Boolean) extends Exu(Exu.aluExeUnitCfg) {
val (iovalid, src1, src2, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, io.in.bits.src2,
io.in.bits.uop.ctrl.imm, io.in.bits.uop.ctrl.fuOpType, SignExt(io.in.bits.uop.cf.pc, AddrBits), io.in.bits.uop)
......@@ -17,7 +18,7 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
val redirectHit = uop.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw) && !ALUOpType.isJump(func)
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw)
val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
val xorRes = src1 ^ src2
val sltu = !adderRes(XLEN)
......@@ -46,19 +47,13 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
ALUOpType.getBranchType(ALUOpType.bltu) -> sltu
)
val isBru = ALUOpType.isBru(func)
// val isBranch = io.in.bits.uop.cf.isBr// ALUOpType.isBranch(func)
val isBranch = ALUOpType.isBranch(func)
val isJump = ALUOpType.isJump(func)
val isBranch = uop.cf.brUpdate.pd.isBr// ALUOpType.isBranch(func)
val isRVC = uop.cf.brUpdate.pd.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, pc + offset, adderRes)(VAddrBits-1,0)
val isRVC = uop.cf.brUpdate.pd.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
io.in.ready := io.out.ready
val pcLatchSlot = Mux(isRVC, pc + 2.U, pc + 4.U)
io.out.bits.redirectValid := io.out.valid && isBru//isBranch
io.out.bits.redirectValid := io.out.valid && isBranch
io.out.bits.redirect.pc := uop.cf.pc
io.out.bits.redirect.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.redirect.brTag := uop.brTag
......@@ -76,10 +71,32 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
io.out.bits.brUpdate.taken := isBranch && taken
// io.out.bits.brUpdate.fetchIdx := uop.cf.brUpdate.fetchOffset >> 1.U //TODO: consider RVC
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := Mux(isJump, pcLatchSlot, aluRes)
if (hasSfence) { // Sfence && fence.i here. // TODO: add fence.i
val waitSbuffer = ALUOpType.waitSbuffer(func)
val sbEmpty = WireInit(true.B) // TODO: use tileLink and init is false.B
val validNeg = RegInit(true.B)
when (io.out.fire()) { validNeg := true.B }
when (io.in.valid && !io.out.valid) { validNeg := false.B }
val sfence = Wire(new SfenceBundle)
sfence.valid := valid && validNeg && ALUOpType.sfence===func
sfence.bits.rs1 := uop.ctrl.lsrc1===0.U
sfence.bits.rs2 := uop.ctrl.lsrc2===0.U
sfence.bits.addr := src1
BoringUtils.addSource(sfence, "SfenceBundle")
io.out.valid := Mux(waitSbuffer, valid && sbEmpty, valid)
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := aluRes
io.in.ready := Mux(waitSbuffer, sbEmpty && io.out.ready, io.out.ready)
} else {
assert(!(ALUOpType.sfence===func && iovalid))
io.in.ready := io.out.ready
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := aluRes
}
XSDebug(io.in.valid,
"In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:f:%d v:%d\n",
io.in.valid,
......@@ -94,6 +111,6 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
)
XSDebug(io.in.valid, "src1:%x src2:%x offset:%x func:%b pc:%x\n",
src1, src2, offset, func, pc)
XSDebug(io.out.valid, "res:%x aluRes:%x isRVC:%d isBru:%d isBranch:%d isJump:%d target:%x taken:%d\n",
io.out.bits.data, aluRes, isRVC, isBru, isBranch, isJump, target, taken)
XSDebug(io.out.valid, "res:%x aluRes:%x isRVC:%d isBranch:%d target:%x taken:%d\n",
io.out.bits.data, aluRes, isRVC, isBranch, target, taken)
}
\ No newline at end of file
......@@ -21,8 +21,6 @@ class JmpExeUnit extends Exu(Exu.jmpExeUnitCfg) {
csr.io.fpu_csr := DontCare
csr.io.exception <> io.exception
csr.io.instrValid := DontCare
csr.io.imemMMU := DontCare
csr.io.dmemMMU := DontCare
csr.io.out.ready := io.out.ready
csr.io.in.bits.src3 := DontCare
val csrOut = csr.access(
......
......@@ -171,8 +171,6 @@ class CSRIO extends FunctionUnitIO {
val instrValid = Input(Bool())
// for differential testing
// val intrNO = Output(UInt(XLEN.W))
val imemMMU = Flipped(new MMUIO)
val dmemMMU = Flipped(new MMUIO)
val wenFix = Output(Bool())
}
......@@ -209,7 +207,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
val pad0 = Output(UInt(9.W))
val tsr = Output(UInt(1.W))
val tw = Output(UInt(1.W))
val tvm = Output(UInt(1.W))
val tvm = Output(UInt(1.W)) // TODO: add excp check
val mxr = Output(UInt(1.W))
val sum = Output(UInt(1.W))
val mprv = Output(UInt(1.W))
......@@ -223,6 +221,12 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
assert(this.getWidth == XLEN)
}
class SatpStruct extends Bundle {
val mode = UInt(4.W)
val asid = UInt(16.W)
val ppn = UInt(44.W)
}
class Interrupt extends Bundle {
val e = new Priv
val t = new Priv
......@@ -268,7 +272,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// | pad0 |
// | tsr |
// | tw |
// | tvm |
// | tvm | // TODO: add excp check 3.1.6.4
// | mxr |
// | sum |
// | mprv |
......@@ -315,15 +319,22 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// val sie = RegInit(0.U(XLEN.W))
val sieMask = "h222".U & mideleg
val sipMask = "h222".U & mideleg
//val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U)
val satp = RegInit(UInt(XLEN.W), 0.U)
val satp = RegInit(0.U(XLEN.W))
// val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U) // only use for tlb naive debug
val satpMask = "hf0000fffffffffff".U // disable asid
// val satp = RegInit(UInt(XLEN.W), 0.U)
val sepc = RegInit(UInt(XLEN.W), 0.U)
val scause = RegInit(UInt(XLEN.W), 0.U)
val stval = Reg(UInt(XLEN.W))
val sscratch = RegInit(UInt(XLEN.W), 0.U)
val scounteren = RegInit(UInt(XLEN.W), 0.U)
// FIXME
// ExcitingUtils.addSource(satp, "CSRSATP")
val tlbBundle = Wire(new TlbCsrBundle)
// val sfence = Wire(new SfenceBundle)
tlbBundle.satp := satp.asTypeOf(new SatpStruct)
// sfence := 0.U.asTypeOf(new SfenceBundle)
BoringUtils.addSource(tlbBundle, "TLBCSRIO")
// BoringUtils.addSource(sfence, "SfenceBundle") // FIXME: move to MOU
// User-Level CSRs
val uepc = Reg(UInt(XLEN.W))
......@@ -431,7 +442,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
MaskedRegMap(Sip, mip.asUInt, sipMask, MaskedRegMap.Unwritable, sipMask),
// Supervisor Protection and Translation
MaskedRegMap(Satp, satp),
MaskedRegMap(Satp, satp, satpMask, MaskedRegMap.NoSideEffect, satpMask),
// Machine Information Registers
MaskedRegMap(Mvendorid, mvendorid, 0.U, MaskedRegMap.Unwritable),
......@@ -482,12 +493,15 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
CSROpType.clri -> (rdata & (~csri).asUInt())
))
val wen = valid && func =/= CSROpType.jmp
// satp wen check
val satpLegalMode = (wdata.asTypeOf(new SatpStruct).mode===0.U) || (wdata.asTypeOf(new SatpStruct).mode===8.U)
val wen = valid && func =/= CSROpType.jmp && Mux(addr===Satp.U, satpLegalMode, true.B)
// TODO: problem: is wen under mode check?
// if satp.mode is illegal, will not write
// Debug(){when(wen){printf("[CSR] addr %x wdata %x func %x rdata %x\n", addr, wdata, func, rdata)}}
MaskedRegMap.generate(mapping, addr, rdata, wen, wdata)
val isIllegalAddr = MaskedRegMap.isIllegalAddr(mapping, addr)
val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
io.out.bits := rdata
val isIllegalAddr = MaskedRegMap.isIllegalAddr(mapping, addr)
// Fix Mip/Sip write
val fixMapping = Map(
......@@ -546,16 +560,14 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// assert(!hasStorePageFault)
//TODO: Havn't test if io.dmemMMU.priviledgeMode is correct yet
io.imemMMU.priviledgeMode := priviledgeMode
io.dmemMMU.priviledgeMode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
io.imemMMU.status_sum := mstatusStruct.sum.asBool
io.dmemMMU.status_sum := mstatusStruct.sum.asBool
io.imemMMU.status_mxr := DontCare
io.dmemMMU.status_mxr := mstatusStruct.mxr.asBool
tlbBundle.priv.mxr := mstatusStruct.mxr.asBool
tlbBundle.priv.sum := mstatusStruct.sum.asBool
tlbBundle.priv.imode := priviledgeMode
tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
val hasInstrPageFault = io.exception.bits.cf.exceptionVec(instrPageFault) && io.exception.valid
val hasLoadPageFault = io.dmemMMU.loadPF
val hasStorePageFault = io.dmemMMU.storePF
val hasLoadPageFault = false.B // FIXME: add ld-pf/st-pf
val hasStorePageFault = false.B
val hasStoreAddrMisaligned = io.exception.bits.cf.exceptionVec(storeAddrMisaligned)
val hasLoadAddrMisaligned = io.exception.bits.cf.exceptionVec(loadAddrMisaligned)
......@@ -567,7 +579,8 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
SignExt(io.exception.bits.cf.pc + 2.U, XLEN),
SignExt(io.exception.bits.cf.pc, XLEN)
),
SignExt(io.dmemMMU.addr, XLEN)
// SignExt(io.dmemMMU.addr, XLEN)
"hffffffff".U // FIXME: add ld/st pf
)
when(priviledgeMode === ModeM){
mtval := tval
......@@ -614,7 +627,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
csrExceptionVec(ecallS) := priviledgeMode === ModeS && io.in.valid && isEcall
csrExceptionVec(ecallU) := priviledgeMode === ModeU && io.in.valid && isEcall
// csrExceptionVec(instrPageFault) := hasInstrPageFault
csrExceptionVec(illegalInstr) := isIllegalAddr && wen // Trigger an illegal instr exception when unimplemented csr is being read/written
csrExceptionVec(illegalInstr) := isIllegalAddr && wen // Trigger an illegal instr exception when unimplemented csr is being read/written // TODO: if csrrw under wrong priv mode will cause illegal instr now ?
csrExceptionVec(loadPageFault) := hasLoadPageFault
csrExceptionVec(storePageFault) := hasStorePageFault
val iduExceptionVec = io.cfIn.exceptionVec
......@@ -632,6 +645,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
val retTarget = Wire(UInt(VAddrBits.W))
val trapTarget = Wire(UInt(VAddrBits.W))
ExcitingUtils.addSource(trapTarget, "trapTarget")
val resetSatp = addr === Satp.U && satpLegalMode && wen // write to satp will cause the pipeline be flushed
io.redirect := DontCare
io.redirectValid := (valid && func === CSROpType.jmp && !isEcall) || resetSatp
//TODO: use pred pc instead pc+4
......@@ -767,7 +781,18 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
"RoqWaitFp" -> (0xb11, "perfCntCondRoqWaitFp" ),
"RoqWaitLoad" -> (0xb12, "perfCntCondRoqWaitLoad" ),
"RoqWaitStore"-> (0xb13, "perfCntCondRoqWaitStore"),
"Dp1Empty" -> (0xb14, "perfCntCondDp1Empty" )
"Dp1Empty" -> (0xb14, "perfCntCondDp1Empty" ),
"DTlbReqCnt0" -> (0xb15, "perfCntDtlbReqCnt0" ),
"DTlbReqCnt1" -> (0xb16, "perfCntDtlbReqCnt1" ),
"DTlbReqCnt2" -> (0xb17, "perfCntDtlbReqCnt2" ),
"DTlbReqCnt3" -> (0xb18, "perfCntDtlbReqCnt3" ),
"DTlbMissCnt0"-> (0xb19, "perfCntDtlbMissCnt0" ),
"DTlbMissCnt1"-> (0xb20, "perfCntDtlbMissCnt1" ),
"DTlbMissCnt2"-> (0xb21, "perfCntDtlbMissCnt2" ),
"DTlbMissCnt3"-> (0xb22, "perfCntDtlbMissCnt3" ),
"PtwReqCnt" -> (0xb23, "perfCntPtwReqCnt" ),
"PtwCycleCnt" -> (0xb24, "perfCntPtwCycleCnt" ),
"PtwL2TlbHit" -> (0xb25, "perfCntPtwL2TlbHit" )
// "Custom1" -> (0xb1b, "Custom1" ),
// "Custom2" -> (0xb1c, "Custom2" ),
// "Custom3" -> (0xb1d, "Custom3" ),
......
......@@ -44,10 +44,6 @@ package object backend {
def isWordOp(func: UInt) = func(5)
// TODO: move jal/jalr/call/ret from ALU to BRU&CSR
// def jal = "b011000".U
// def jalr = "b011010".U
// def cjalr= "b111010".U // pc + 2 instead of 4
def beq = "b010000".U
def bne = "b010001".U
def blt = "b010100".U
......@@ -55,16 +51,15 @@ package object backend {
def bltu = "b010110".U
def bgeu = "b010111".U
// // for RAS
// def call = "b011100".U
// def ret = "b011110".U
// def pcPlus2(func: UInt) = func(5)//[important]
def isBranch(func: UInt) = func(4,3)===2.U
def isBru(func: UInt) = func(4)
def isJump(func: UInt) = func(4,3)===3.U//isBru(func) && !isBranch(func)
def isBranch(func: UInt) = func(4)
def getBranchType(func: UInt) = func(2, 1)
def isBranchInvert(func: UInt) = func(0)
// alu take sfence.vma and fence.i
def sfence = "b110000".U
def fencei = "b110001".U
def waitSbuffer(func: UInt) = func===sfence
}
object MDUOpType {
......@@ -122,8 +117,6 @@ package object backend {
def atomD = "011".U
}
object BTBtype {
def B = "b00".U // branch
def J = "b01".U // jump
......@@ -132,5 +125,4 @@ package object backend {
def apply() = UInt(2.W)
}
}
......@@ -237,7 +237,7 @@ class Roq extends XSModule {
// when redirect, walk back roq entries
when(io.brqRedirect.valid){
state := s_walk
walkPtrExt := Mux(state === s_walk && !walkFinished, walkPtrExt - CommitWidth.U, enqPtrExt - 1.U + dispatchCnt)
walkPtrExt := Mux(state === s_walk && !walkFinished, walkPtrExt - CommitWidth.U, Mux(state === s_extrawalk, walkPtrExt, enqPtrExt - 1.U + dispatchCnt))
walkTgtExt := io.brqRedirect.bits.roqIdx
enqPtrExt := io.brqRedirect.bits.roqIdx + 1.U
}
......
......@@ -261,8 +261,10 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
//----------------------------------------
// store pipe and store miss queue
storeMissQueue.io.lsu <> io.lsu.store
/*
assert(!(storeMissQueue.io.replay.req.fire() && !storeMissQueue.io.replay.req.bits.meta.replay),
"StoreMissQueue should replay requests")
*/
assert(!(io.lsu.store.req.fire() && io.lsu.store.req.bits.meta.replay),
"Sbuffer should not should replay requests")
assert(!(io.lsu.store.req.fire() && io.lsu.store.req.bits.meta.mmio),
......@@ -340,7 +342,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
assert(!(miscReq.fire() && miscReq.bits.meta.tlb_miss),
"TLB missed requests should not go to cache")
assert(!io.lsu.misc.s1_kill, "Lsroq should never use s1 kill on misc")
assert(!io.ptw.s1_kill, "Lsroq should never use s1 kill on misc")
assert(!io.ptw.s1_kill, "Lsroq should never use s1 kill on misc") // TODO: ptw wanna use s1_kill
//----------------------------------------
......
......@@ -4,38 +4,372 @@ import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
import bus.simplebus._
import xiangshan.backend.fu.HasCSRConst
import chisel3.ExcitingUtils._
class DtlbReq extends XSBundle {
trait HasTlbConst extends HasXSParameter {
val Level = 3
val offLen = 12
val ppnLen = PAddrBits - offLen
val vpnnLen = 9
val vpnLen = VAddrBits - offLen
val flagLen = 8
val pteResLen = XLEN - ppnLen - 2 - flagLen
val asidLen = 16
def vaBundle = new Bundle {
val vpn = UInt(vpnLen.W)
val off = UInt(offLen.W)
}
def pteBundle = new Bundle {
val reserved = UInt(pteResLen.W)
val ppn = UInt(ppnLen.W)
val rsw = UInt(2.W)
val perm = new Bundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
val v = Bool()
}
}
}
abstract class TlbBundle extends XSBundle with HasTlbConst
abstract class TlbModule extends XSModule with HasTlbConst
class PermBundle(val hasV: Boolean = true) extends TlbBundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
if (hasV) { val v = Bool() }
override def toPrintable: Printable = {
p"d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"// +
//(if(hasV) (p"v:${v}") else p"")
}
}
class comBundle extends TlbBundle with HasRoqIdx{
val valid = Bool()
val bits = new PtwReq
def isPrior(that: comBundle): Bool = {
(this.valid && !that.valid) || (this.valid && that.valid && (that isAfter this))
}
}
object Compare {
def apply[T<:Data](xs: Seq[comBundle]): comBundle = {
ParallelOperation(xs, (a: comBundle, b: comBundle) => Mux(a isPrior b, a, b))
}
}
class TlbEntry extends TlbBundle {
val vpn = UInt(vpnLen.W) // tag is vpn
val ppn = UInt(ppnLen.W)
val level = UInt(log2Up(Level).W) // 0 for 4KB, 1 for 2MB, 2 for 1GB
// val asid = UInt(asidLen.W), asid maybe expensive to support, but useless
// val v = Bool() // v&g is special, may need sperate storage?
val perm = new PermBundle(hasV = false)
def vpnHit(vpn: UInt):Bool = {
val fullMask = VecInit((Seq.fill(vpnLen)(true.B))).asUInt
val maskLevel = VecInit((Level-1 to 0 by -1).map{i => // NOTE: level 2 for 4KB, 1 for 2MB, 0 for 1GB
VecInit(Seq.fill(vpnLen-i*vpnnLen)(true.B) ++ Seq.fill(i*vpnnLen)(false.B)).asUInt})
val mask = maskLevel(level)
(mask&this.vpn) === (mask&vpn)
}
// def asidHit(asid: UInt) = {
// this.asid === asid
// }
def hit(vpn: UInt/*, asid: UInt*/):Bool = {
vpnHit(vpn) // && asidHit(asid)
}
def genTlbEntry(pte: UInt, level: UInt, vpn: UInt/*, asid: UInt*/) = {
val e = Wire(new TlbEntry)
e.ppn := pte.asTypeOf(pteBundle).ppn
e.level := level
e.vpn := vpn
e.perm := pte.asTypeOf(pteBundle).perm
// e.asid := asid
e
}
override def toPrintable: Printable = {
p"vpn:0x${Hexadecimal(vpn)} ppn:0x${Hexadecimal(ppn)} level:${level} perm:${perm}"
}
}
object TlbCmd {
def read = "b00".U
def write = "b01".U
def exec = "b10".U
def apply() = UInt(2.W)
def isRead(a: UInt) = a===read
def isWrite(a: UInt) = a===write
def isExec(a: UInt) = a===exec
}
class TlbReq extends TlbBundle {
val vaddr = UInt(VAddrBits.W)
val cmd = TlbCmd()
val roqIdx = UInt(RoqIdxWidth.W)
val debug = new Bundle {
val pc = UInt(XLEN.W)
val lsroqIdx = UInt(LsroqIdxWidth.W)
}
override def toPrintable: Printable = {
p"vaddr:0x${Hexadecimal(vaddr)} cmd:${cmd} pc:0x${Hexadecimal(debug.pc)} roqIdx:${roqIdx} lsroqIdx:${debug.lsroqIdx}"
}
}
class DtlbResp extends XSBundle {
class TlbResp extends TlbBundle {
val paddr = UInt(PAddrBits.W)
val miss = Bool()
val excp = new Bundle {
val pf = new Bundle {
val ld = Bool()
val st = Bool()
val instr = Bool()
}
}
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}"
}
}
class TlbRequestIO() extends TlbBundle {
val req = Valid(new TlbReq)
val resp = Flipped(Valid(new TlbResp))
// override def cloneType: this.type = (new TlbRequestIO(Width)).asInstanceOf[this.type]
}
class DtlbToLsuIO extends XSBundle {
val req = Flipped(ValidIO(new DtlbReq))
val resp = ValidIO(new DtlbResp)
class TlbPtwIO extends TlbBundle {
val req = DecoupledIO(new PtwReq)
val resp = Flipped(DecoupledIO(new PtwResp))
}
class DtlbIO extends XSBundle {
val lsu = Vec(LoadPipelineWidth + StorePipelineWidth, new DtlbToLsuIO)
// val l2 = TODO
class TlbIO(Width: Int) extends TlbBundle {
val requestor = Vec(Width, Flipped(new TlbRequestIO))
val ptw = new TlbPtwIO
override def cloneType: this.type = (new TlbIO(Width)).asInstanceOf[this.type]
}
class Dtlb extends XSModule {
val io = IO(new DtlbIO)
// Dtlb has 4 ports: 2 for load, 2 fore store
// fake dtlb
(0 until LoadPipelineWidth + StorePipelineWidth).map(i => {
io.lsu(i).resp.valid := io.lsu(i).req.valid
io.lsu(i).resp.bits.paddr := io.lsu(i).req.bits.vaddr
io.lsu(i).resp.bits.miss := LFSR64()(5, 0) === 0.U
when(io.lsu(i).req.valid){
XSDebug("vaddr %x paddr %x miss %b\n",
io.lsu(i).req.bits.vaddr, io.lsu(i).resp.bits.paddr, io.lsu(i).resp.bits.miss)
class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
val io = IO(new TlbIO(Width))
val req = io.requestor.map(_.req)
val resp = io.requestor.map(_.resp)
val ptw = io.ptw
val sfence = WireInit(0.U.asTypeOf(new SfenceBundle))
val csr = WireInit(0.U.asTypeOf(new TlbCsrBundle))
val satp = csr.satp
val priv = csr.priv
val ifecth = if (isDtlb) false.B else true.B
val mode = if (isDtlb) priv.dmode else priv.imode
val vmEnable = satp.mode === 8.U // && (mode < ModeM) // FIXME: fix me when boot xv6/linux...
BoringUtils.addSink(sfence, "SfenceBundle")
BoringUtils.addSink(csr, "TLBCSRIO")
val reqAddr = req.map(_.bits.vaddr.asTypeOf(vaBundle))
val cmd = req.map(_.bits.cmd)
val valid = req.map(_.valid)
def widthMapSeq[T <: Seq[Data]](f: Int => T) = (0 until Width).map(f)
def widthMap[T <: Data](f: Int => T) = (0 until Width).map(f)
val v = RegInit(0.U(TlbEntrySize.W))
val pf = RegInit(0.U(TlbEntrySize.W)) // TODO: when ptw resp a pf(now only page not found), store here
val entry = Reg(Vec(TlbEntrySize, new TlbEntry))
val g = VecInit(entry.map(_.perm.g)).asUInt // TODO: need check if reverse is needed
val entryHitVec = widthMapSeq{i => VecInit(entry.map(_.hit(reqAddr(i).vpn/*, satp.asid*/))) }
val hitVec = widthMapSeq{ i => (v.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } }
val pfHitVec = widthMapSeq{ i => (pf.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } }
val pfArray = widthMap{ i => ParallelOR(pfHitVec(i)).asBool && valid(i) && vmEnable }
val hit = widthMap{ i => ParallelOR(hitVec(i)).asBool && valid(i) && vmEnable && ~pfArray(i) }
val miss = widthMap{ i => !hit(i) && valid(i) && vmEnable && ~pfArray(i) }
val hitppn = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.ppn)) }
val hitPerm = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.perm)) }
val multiHit = {
val hitSum = widthMap{ i => PopCount(hitVec(i)) }
val pfHitSum = widthMap{ i => PopCount(pfHitVec(i)) }
ParallelOR(widthMap{ i => !(hitSum(i)===0.U || hitSum(i)===1.U) || !(pfHitSum(i)===0.U || pfHitSum(i)===1.U)})
}
// resp // TODO: A/D has not being concerned
for(i <- 0 until Width) {
resp(i).valid := valid(i)
resp(i).bits.paddr := Mux(vmEnable, Cat(hitppn(i), reqAddr(i).off), SignExt(req(i).bits.vaddr, PAddrBits))
resp(i).bits.miss := miss(i)
val perm = hitPerm(i) // NOTE: given the excp, the out module choose one to use?
val update = false.B && hit(i) && (!hitPerm(i).a || !hitPerm(i).d && TlbCmd.isWrite(cmd(i))) // update A/D through exception
val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth))
val ldPf = (pfArray(i) && TlbCmd.isRead(cmd(i)) && true.B /*!isAMO*/) || hit(i) && !(modeCheck && (perm.r || priv.mxr && perm.x)) && (TlbCmd.isRead(cmd(i)) && true.B/*!isAMO*/) // TODO: handle isAMO
val stPf = (pfArray(i) && TlbCmd.isWrite(cmd(i)) || false.B /*isAMO*/ ) || hit(i) && !(modeCheck && perm.w) && (TlbCmd.isWrite(cmd(i)) || false.B/*TODO isAMO. */)
val instrPf = (pfArray(i) && TlbCmd.isExec(cmd(i))) || hit(i) && !(modeCheck && perm.x) && TlbCmd.isExec(cmd(i))
resp(i).bits.excp.pf.ld := ldPf || update
resp(i).bits.excp.pf.st := stPf || update
resp(i).bits.excp.pf.instr := instrPf || update
}
// ptw
val state_idle :: state_wait :: Nil = Enum(2)
val state = RegInit(state_idle)
ptw <> DontCare // TODO: need check it
ptw.req.valid := ParallelOR(miss).asBool && state===state_idle
ptw.resp.ready := state===state_wait
// val ptwReqSeq = Wire(Seq.fill(Width)(new comBundle()))
val ptwReqSeq = Seq.fill(Width)(Wire(new comBundle()))
for (i <- 0 until Width) {
ptwReqSeq(i).valid := valid(i) && miss(i)
ptwReqSeq(i).roqIdx := req(i).bits.roqIdx
ptwReqSeq(i).bits.vpn := reqAddr(i).vpn
}
ptw.req.bits := Compare(ptwReqSeq).bits
switch (state) {
is (state_idle) {
when (ParallelOR(miss).asBool) {
state := state_wait
}
assert(!ptw.resp.valid)
}
})
is (state_wait) {
when (ptw.resp.fire()) {
state := state_idle
}
}
}
// reset pf when pf hit
val pfHitReset = ParallelOR(widthMap{i => Mux(valid(i), VecInit(pfHitVec(i)).asUInt, 0.U) })
val pfHitRefill = ParallelOR(pfHitReset.asBools)
// refill
val refill = ptw.resp.fire()
val randIdx = LFSR64()(log2Up(TlbEntrySize)-1,0)
val priorIdx = PriorityEncoder(~(v|pf))
val tlbfull = ParallelAND((v|pf).asBools)
val refillIdx = Mux(tlbfull, randIdx, priorIdx)
val re2OH = UIntToOH(refillIdx)
when (refill) {
v := Mux(ptw.resp.bits.pf, v & ~re2OH, v | re2OH)
entry(refillIdx) := ptw.resp.bits.entry
XSDebug(p"Refill: idx:${refillIdx} entry:${ptw.resp.bits.entry}\n")
}
// pf update
when (refill) {
when (pfHitRefill) {
pf := Mux(ptw.resp.bits.pf, pf | re2OH, pf & ~re2OH) & ~pfHitReset
} .otherwise {
pf := Mux(ptw.resp.bits.pf, pf | re2OH, pf & ~re2OH)
}
} .otherwise {
when (pfHitRefill) {
pf := pf & ~pfHitReset
}
}
when (PopCount(pf) > 10.U) { // when too much pf, just clear
pf := Mux(refill && ptw.resp.bits.pf, re2OH, 0.U)
}
// sfence (flush)
when (sfence.valid) {
when (sfence.bits.rs1) { // virtual address *.rs1 <- (rs1===0.U)
when (sfence.bits.rs2) { // asid, but i do not want to support asid, *.rs2 <- (rs2===0.U)
// all addr and all asid
v := 0.U
pf := 0.U
}.otherwise {
// all addr but specific asid
v := v & g // TODO: need check if reverse is needed
pf := pf & g
}
}.otherwise {
when (sfence.bits.rs2) {
// specific addr but all asid
v := v & ~VecInit(entry.map(_.hit(sfence.bits.addr.asTypeOf(vaBundle).vpn))).asUInt
pf := pf & ~VecInit(entry.map(_.hit(sfence.bits.addr.asTypeOf(vaBundle).vpn))).asUInt
}.otherwise {
// specific addr and specific asid
v := v & ~VecInit(entry.map(e => e.hit(sfence.bits.addr.asTypeOf(vaBundle).vpn) && (/*e.asid === sfence.bits.asid && */!e.perm.g))).asUInt
pf := pf & ~VecInit(entry.map(e => e.hit(sfence.bits.addr.asTypeOf(vaBundle).vpn) && (/*e.asid === sfence.bits.asid && */!e.perm.g))).asUInt
}
}
}
if (!env.FPGAPlatform) {
ExcitingUtils.addSource(valid(0)/* && vmEnable*/, "perfCntDtlbReqCnt0", Perf)
ExcitingUtils.addSource(valid(1)/* && vmEnable*/, "perfCntDtlbReqCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/, "perfCntDtlbReqCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/, "perfCntDtlbReqCnt3", Perf)
ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && miss(0), "perfCntDtlbMissCnt0", Perf)
ExcitingUtils.addSource(valid(1)/* && vmEnable*/ && miss(1), "perfCntDtlbMissCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/ && miss(2), "perfCntDtlbMissCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/ && miss(3), "perfCntDtlbMissCnt3", Perf)
}
// Log
for(i <- 0 until Width) {
XSDebug(req(i).valid, p"req(${i.U}): ${req(i).bits}\n")
XSDebug(resp(i).valid, p"resp(${i.U}): ${resp(i).bits}\n")
}
XSDebug(sfence.valid, p"Sfence: ${sfence}\n")
XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n")
XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hit).asUInt)} miss:${Binary(VecInit(miss).asUInt)} v:${Hexadecimal(v)} pf:${Hexadecimal(pf)} state:${state}\n")
XSDebug(ptw.req.fire(), p"PTW req:${ptw.req.bits}\n")
XSDebug(ptw.resp.valid, p"PTW resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n")
// assert check, can be remove when tlb can work
for(i <- 0 until Width) {
assert((hit(i)&pfArray(i))===false.B, "hit(%d):%d pfArray(%d):%d v:0x%x pf:0x%x", i.U, hit(i), i.U, pfArray(i), v, pf)
}
for(i <- 0 until Width) {
XSDebug(multiHit, p"vpn:0x${Hexadecimal(reqAddr(i).vpn)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)} pfHitVec:0x${Hexadecimal(VecInit(pfHitVec(i)).asUInt)}\n")
}
for(i <- 0 until TlbEntrySize) {
XSDebug(multiHit, p"entry(${i.U}): v:${v(i)} ${entry(i)}\n")
}
assert(!multiHit) // add multiHit here, later it should be removed (maybe), turn to miss and flush
for (i <- 0 until Width) {
XSDebug(resp(i).valid && hit(i) && !(req(i).bits.vaddr===resp(i).bits.paddr), p"vaddr:0x${Hexadecimal(req(i).bits.vaddr)} paddr:0x${Hexadecimal(resp(i).bits.paddr)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)}}\n")
when (resp(i).valid && hit(i) && !(req(i).bits.vaddr===resp(i).bits.paddr)) {
for (j <- 0 until TlbEntrySize) {
XSDebug(true.B, p"TLBEntry(${j.U}): v:${v(j)} ${entry(j)}\n")
}
} // FIXME: remove me when tlb may be ok
when(resp(i).valid && hit(i)) {
assert(req(i).bits.vaddr===resp(i).bits.paddr, "vaddr:0x%x paddr:0x%x hitVec:%x ", req(i).bits.vaddr, resp(i).bits.paddr, VecInit(hitVec(i)).asUInt)
} // FIXME: remove me when tlb may be ok
}
assert((v&pf)===0.U, "v and pf can't be true at same time: v:0x%x pf:0x%x", v, pf)
}
package xiangshan.cache
import chipsalliance.rocketchip.config.Parameters
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
import chisel3.ExcitingUtils._
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLClientNode, TLMasterParameters, TLMasterPortParameters}
trait HasPtwConst extends HasTlbConst with MemoryOpConstants{
val PtwWidth = 2
def MakeAddr(ppn: UInt, off: UInt) = {
require(off.getWidth == 9)
Cat(ppn, off, 0.U(log2Up(XLEN/8).W))(PAddrBits-1, 0)
}
def getVpnn(vpn: UInt, idx: Int) = {
vpn(vpnnLen*(idx+1)-1, vpnnLen*idx)
}
}
abstract class PtwBundle extends XSBundle with HasPtwConst
abstract class PtwModule(outer: PTW) extends LazyModuleImp(outer)
with HasXSParameter with HasXSLog with HasPtwConst
class PteBundle extends PtwBundle{
val reserved = UInt(pteResLen.W)
val ppn = UInt(ppnLen.W)
val rsw = UInt(2.W)
val perm = new Bundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
val v = Bool()
}
def isPf() = {
!perm.v || (!perm.r && perm.w)
}
def isLeaf() = {
!isPf() && (perm.r || perm.x)
}
override def toPrintable: Printable = {
p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}"
}
}
class PtwEntry(tagLen: Int) extends PtwBundle {
val tag = UInt(tagLen.W)
val ppn = UInt(ppnLen.W)
val perm = new PermBundle
// TODO: add superpage
def hit(addr: UInt) = {
require(addr.getWidth >= PAddrBits)
tag === addr(PAddrBits-1, PAddrBits-tagLen)
}
def refill(addr: UInt, pte: UInt) {
tag := addr(PAddrBits-1, PAddrBits-tagLen)
ppn := pte.asTypeOf(pteBundle).ppn
perm := pte.asTypeOf(pteBundle).perm
}
def genPtwEntry(addr: UInt, pte: UInt) = {
val e = Wire(new PtwEntry(tagLen))
e.tag := addr(PAddrBits-1, PAddrBits-tagLen)
e.ppn := pte.asTypeOf(pteBundle).ppn
e.perm := pte.asTypeOf(pteBundle).perm
e
}
override def cloneType: this.type = (new PtwEntry(tagLen)).asInstanceOf[this.type]
override def toPrintable: Printable = {
p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}"
}
}
class PtwReq extends PtwBundle {
val vpn = UInt(vpnLen.W)
override def toPrintable: Printable = {
p"vpn:0x${Hexadecimal(vpn)}"
}
}
class PtwResp extends PtwBundle {
val entry = new TlbEntry
val pf = Bool() // simple pf no matter cmd
override def toPrintable: Printable = {
p"entry:${entry} pf:${pf}"
}
}
class PtwIO extends PtwBundle {
val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO))
}
object ValidHold {
def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = {
val valid = RegInit(false.B)
when (outfire) { valid := false.B }
when (infire) { valid := true.B }
when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok?
valid
}
}
object OneCycleValid {
def apply(fire: Bool, flush: Bool = false.B) = {
val valid = RegInit(false.B)
when (valid) { valid := false.B }
when (fire) { valid := true.B }
when (false.B) { valid := false.B }
valid
}
}
class PTW()(implicit p: Parameters) extends LazyModule {
val node = TLClientNode(Seq(TLMasterPortParameters.v1(
clients = Seq(TLMasterParameters.v1(
"ptw"
))
)))
lazy val module = new PTWImp(this)
}
class PTWImp(outer: PTW) extends PtwModule(outer){
val (mem, edge) = outer.node.out.head
val io = IO(new PtwIO)
val arb = Module(new Arbiter(new PtwReq, PtwWidth))
arb.io.in <> VecInit(io.tlb.map(_.req))
val arbChosen = RegEnable(arb.io.chosen, arb.io.out.fire())
val req = RegEnable(arb.io.out.bits, arb.io.out.fire())
val resp = VecInit(io.tlb.map(_.resp))
val valid = ValidHold(arb.io.out.fire(), resp(arbChosen).fire())
val validOneCycle = OneCycleValid(arb.io.out.fire())
arb.io.out.ready := !valid || resp(arbChosen).fire()
val sfence = WireInit(0.U.asTypeOf(new SfenceBundle))
val csr = WireInit(0.U.asTypeOf(new TlbCsrBundle))
val satp = csr.satp
val priv = csr.priv
BoringUtils.addSink(sfence, "SfenceBundle")
BoringUtils.addSink(csr, "TLBCSRIO")
// two level: l2-tlb-cache && pde/pte-cache
// l2-tlb-cache is ram-larger-edition tlb
// pde/pte-cache is cache of page-table, speeding up ptw
// may seperate valid bits to speed up sfence's flush
// Reg/Mem/SyncReadMem is not sure now
val tagLen1 = PAddrBits - log2Up(XLEN/8)
val tagLen2 = PAddrBits - log2Up(XLEN/8) - log2Up(PtwL2EntrySize)
val tlbl2 = SyncReadMem(TlbL2EntrySize, new TlbEntry)
val tlbv = RegInit(0.U(TlbL2EntrySize.W)) // valid
val tlbg = RegInit(0.U(TlbL2EntrySize.W)) // global
val ptwl1 = Reg(Vec(PtwL1EntrySize, new PtwEntry(tagLen = tagLen1)))
val l1v = RegInit(0.U(PtwL1EntrySize.W)) // valid
val l1g = VecInit((ptwl1.map(_.perm.g))).asUInt
val ptwl2 = SyncReadMem(PtwL2EntrySize, new PtwEntry(tagLen = tagLen2)) // NOTE: the Mem could be only single port(r&w)
val l2v = RegInit(0.U(PtwL2EntrySize.W)) // valid
val l2g = RegInit(0.U(PtwL2EntrySize.W)) // global
// fsm
val state_idle :: state_req :: state_wait_resp :: state_wait_ready :: Nil = Enum(4)
val state = RegInit(state_idle)
val level = RegInit(0.U(2.W)) // 0/1/2
val levelNext = level + 1.U
val latch = Reg(new PtwResp)
// mem alias
val memRdata = mem.d.bits.data
val memPte = memRdata.asTypeOf(new PteBundle)
val memValid = mem.d.valid
val memRespFire = mem.d.fire()
val memReqReady = mem.a.ready
val memReqFire = mem.a.fire()
/*
* tlbl2
*/
val (tlbHit, tlbHitData) = {
// tlbl2 is by addr
// TODO: optimize tlbl2'l2 tag len
val ramData = tlbl2.read(req.vpn(log2Up(TlbL2EntrySize)-1, 0), validOneCycle)
val vidx = RegEnable(tlbv(req.vpn(log2Up(TlbL2EntrySize)-1, 0)), validOneCycle)
(ramData.hit(req.vpn) && vidx, ramData) // TODO: optimize tag
// TODO: add exception and refill
}
/*
* ptwl1
*/
val l1addr = MakeAddr(satp.ppn, getVpnn(req.vpn, 2))
val (l1Hit, l1HitData) = { // TODO: add excp
// 16 terms may casue long latency, so divide it into 2 stage, like l2tlb
val hitVecT = ptwl1.zipWithIndex.map{case (a,b) => a.hit(l1addr) && l1v(b) }
val hitVec = hitVecT.map(RegEnable(_, validOneCycle)) // TODO: could have useless init value
val hitData = ParallelMux(hitVec zip ptwl1)
val hit = ParallelOR(hitVec).asBool
(hit, hitData)
}
/*
* ptwl2
*/
val l1MemBack = memRespFire && state===state_wait_resp && level===0.U
val l1Res = Mux(l1Hit, l1HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
val l2addr = MakeAddr(l1Res, getVpnn(req.vpn, 1))
val (l2Hit, l2HitData) = { // TODO: add excp
val readRam = (l1Hit && level===0.U && state===state_req) || (memRespFire && state===state_wait_resp && level===0.U)
val ridx = l2addr(log2Up(PtwL2EntrySize)-1+log2Up(XLEN/8), log2Up(XLEN/8))
val ramData = ptwl2.read(ridx, readRam)
val vidx = RegEnable(l2v(ridx), readRam)
(ramData.hit(l2addr), ramData) // TODO: optimize tag
}
/* ptwl3
* ptwl3 has not cache
* ptwl3 may be functional conflict with l2-tlb
* if l2-tlb does not hit, ptwl3 would not hit (mostly)
*/
val l2MemBack = memRespFire && state===state_wait_resp && level===1.U
val l2Res = Mux(l2Hit, l2HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
val l3addr = MakeAddr(l2Res, getVpnn(req.vpn, 0))
/*
* fsm
*/
assert(!(tlbHit && (mem.a.valid || state===state_wait_resp))) // when tlb hit, should not req/resp.valid
val notFound = WireInit(false.B)
switch (state) {
is (state_idle) {
when (valid) {
state := state_req
level := 0.U
}
}
is (state_req) {
when (tlbHit) {
when (resp(arbChosen).ready) {
state := state_idle
}.otherwise {
state := state_wait_ready
}
} .elsewhen (l1Hit && level===0.U || l2Hit && level===1.U) {
level := levelNext // TODO: consider superpage
} .elsewhen (memReqReady) {
state := state_wait_resp
}
}
is (state_wait_resp) {
when (memRespFire) {
when (memPte.isLeaf() || memPte.isPf()) {
when (resp(arbChosen).ready) {
state := state_idle
}.otherwise {
state := state_wait_ready
latch.entry := new TlbEntry().genTlbEntry(memRdata, level, req.vpn)
latch.pf := memPte.isPf()
}
}.otherwise {
level := levelNext
when (level=/=2.U) {
state := state_req
} .otherwise {
notFound := true.B
when (resp(arbChosen).ready) {
state := state_idle
} .otherwise {
state := state_wait_ready
}
}
}
}
}
is (state_wait_ready) {
when (resp(arbChosen).ready) {
state := state_idle
}
}
}
/*
* mem
*/
val memAddr = Mux(level===0.U, l1addr/*when l1Hit, DontCare, when l1miss, l1addr*/,
Mux(level===1.U, Mux(l2Hit, l3addr, l2addr)/*when l2Hit, l3addr, when l2miss, l2addr*/, l3addr))
val pteRead = edge.Get(
fromSource = 0.U/*id*/,
toAddress = memAddr,
lgSize = log2Up(XLEN/8).U
)._2
mem.a.bits := pteRead
mem.a.valid := state === state_req &&
((level===0.U && !tlbHit && !l1Hit) ||
(level===1.U && !l2Hit) ||
(level===2.U))
mem.d.ready := state === state_wait_resp
/*
* resp
*/
val ptwFinish = (state===state_req && tlbHit && level===0.U) || ((memPte.isLeaf() || memPte.isPf() || (!memPte.isLeaf() && level===2.U)) && memRespFire) || state===state_wait_ready
for(i <- 0 until PtwWidth) {
resp(i).valid := valid && arbChosen===i.U && ptwFinish // TODO: add resp valid logic
resp(i).bits.entry := Mux(tlbHit, tlbHitData,
Mux(state===state_wait_ready, latch.entry, new TlbEntry().genTlbEntry(memRdata, Mux(level===3.U, 2.U, level), req.vpn)))
resp(i).bits.pf := Mux(level===3.U || notFound, true.B, Mux(tlbHit, false.B, Mux(state===state_wait_ready, latch.pf, memPte.isPf())))
// TODO: the pf must not be correct, check it
}
/*
* refill
*/
assert(!memRespFire || state===state_wait_resp)
when (memRespFire && !memPte.isPf()) {
when (level===0.U && !memPte.isLeaf) {
val refillIdx = LFSR64()(log2Up(PtwL1EntrySize)-1,0) // TODO: may be LRU
ptwl1(refillIdx).refill(l1addr, memRdata)
l1v := l1v | UIntToOH(refillIdx)
}
when (level===1.U && !memPte.isLeaf) {
val l2addrStore = RegEnable(l2addr, memReqFire && state===state_req && level===1.U)
val refillIdx = getVpnn(req.vpn, 1)(log2Up(PtwL2EntrySize)-1, 0)
ptwl2.write(refillIdx, new PtwEntry(tagLen2).genPtwEntry(l2addrStore, memRdata))
l2v := l2v | UIntToOH(refillIdx)
l2g := l2g | Mux(memPte.perm.g, UIntToOH(refillIdx), 0.U)
}
when (memPte.isLeaf()) {
val refillIdx = getVpnn(req.vpn, 0)(log2Up(TlbL2EntrySize)-1, 0)
tlbl2.write(refillIdx, new TlbEntry().genTlbEntry(memRdata, level, req.vpn))
tlbv := tlbv | UIntToOH(refillIdx)
tlbg := tlbg | Mux(memPte.perm.g, UIntToOH(refillIdx), 0.U)
}
}
/* sfence
* for ram is syncReadMem, so could not flush conditionally
* l3 may be conflict with l2tlb??, may be we could combine l2-tlb with l3-ptw
*/
when (sfence.valid) { // TODO: flush optionally
when (sfence.bits.rs1/*va*/) {
when (sfence.bits.rs2) {
// all va && all asid
tlbv := 0.U
tlbg := 0.U
l1v := 0.U
l2v := 0.U
l2g := 0.U
} .otherwise {
// all va && specific asid except global
tlbv := tlbv & tlbg
l1v := l1v & l1g
l2v := l2v & l2g
}
} .otherwise {
when (sfence.bits.rs2) {
// specific leaf of addr && all asid
tlbv := tlbv & ~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen))
tlbg := tlbg & ~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen))
} .otherwise {
// specific leaf of addr && specific asid
tlbv := tlbv & (~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen)) | tlbg)
}
}
}
if (!env.FPGAPlatform) {
ExcitingUtils.addSource(validOneCycle, "perfCntPtwReqCnt", Perf)
ExcitingUtils.addSource(valid, "perfCntPtwCycleCnt", Perf)
ExcitingUtils.addSource(valid && tlbHit && state===state_req && level===0.U, "perfCntPtwL2TlbHit", Perf)
}
assert(level=/=3.U)
def PrintFlag(en: Bool, flag: Bool, nameEnable: String, nameDisable: String): Unit = {
when(flag) {
XSDebug(false, en, nameEnable)
}.otherwise {
XSDebug(false, en, nameDisable)
}
}
XSDebug(validOneCycle, "**New Ptw Req from ")
PrintFlag(validOneCycle, arbChosen===0.U, "DTLB**:", "ITLB**:")
XSDebug(false, validOneCycle, p"(v:${validOneCycle} r:${arb.io.out.ready}) vpn:0x${Hexadecimal(req.vpn)}\n")
XSDebug(resp(arbChosen).fire(), "**Ptw Resp to ")
PrintFlag(resp(arbChosen).fire(), arbChosen===0.U, "DTLB**:\n", "ITLB**\n")
XSDebug(resp(arbChosen).fire(), p"(v:${resp(arbChosen).valid} r:${resp(arbChosen).ready}) entry:${resp(arbChosen).bits.entry} pf:${resp(arbChosen).bits.pf}\n")
XSDebug(sfence.valid, p"Sfence: sfence instr here ${sfence.bits}\n")
XSDebug(valid, p"CSR: ${csr}\n")
XSDebug(valid, p"vpn2:0x${Hexadecimal(getVpnn(req.vpn, 2))} vpn1:0x${Hexadecimal(getVpnn(req.vpn, 1))} vpn0:0x${Hexadecimal(getVpnn(req.vpn, 0))}\n")
XSDebug(valid, p"state:${state} level:${level} tlbHit:${tlbHit} l1addr:0x${Hexadecimal(l1addr)} l1Hit:${l1Hit} l2addr:0x${Hexadecimal(l2addr)} l2Hit:${l2Hit} l3addr:0x${Hexadecimal(l3addr)} memReq(v:${mem.a.valid} r:${mem.a.ready})\n")
XSDebug(memRespFire, p"mem req fire addr:0x${Hexadecimal(memAddr)}\n")
XSDebug(memRespFire, p"mem resp fire rdata:0x${Hexadecimal(mem.d.bits.data)} Pte:${memPte}\n")
}
\ No newline at end of file
......@@ -11,10 +11,8 @@ class StoreMissEntry extends DCacheModule
val io = IO(new Bundle {
val id = Input(UInt())
val req_pri_val = Input(Bool())
val req_pri_rdy = Output(Bool())
val req = Input(new DCacheLineReq )
val replay = DecoupledIO(new DCacheLineReq )
val lsu = Flipped(new DCacheStoreIO)
val replay = new DCacheStoreIO
val miss_req = DecoupledIO(new MissReq)
val miss_resp = Flipped(ValidIO(new MissResp))
......@@ -24,23 +22,25 @@ class StoreMissEntry extends DCacheModule
val tag = Output(Valid(UInt()))
})
val s_invalid :: s_miss_req :: s_miss_resp :: s_drain_rpq :: s_replay_resp :: s_miss_finish :: Nil = Enum(6)
val s_invalid :: s_replay_req :: s_replay_resp :: s_resp :: s_miss_req :: s_miss_resp :: s_miss_finish :: Nil = Enum(7)
val state = RegInit(s_invalid)
val req = Reg(new DCacheLineReq )
val resp = Reg(new DCacheResp)
val req_idx = get_idx(req.addr)
val req_tag = get_tag(req.addr)
val req_block_addr = get_block_addr(req.addr)
val reg_miss_resp = Reg(new MissResp)
// assign default values to output signals
io.req_pri_rdy := state === s_invalid
when (io.req_pri_val && io.req_pri_rdy) {
assert(req.cmd === M_XWR)
}
io.lsu.req.ready := state === s_invalid
io.lsu.resp.valid := false.B
io.lsu.resp.bits := DontCare
io.replay.valid := false.B
io.replay.bits := DontCare
io.replay.req.valid := false.B
io.replay.req.bits := DontCare
io.replay.resp.ready := false.B
io.miss_req.valid := false.B
io.miss_req.bits := DontCare
......@@ -57,9 +57,43 @@ class StoreMissEntry extends DCacheModule
// --------------------------------------------
// s_invalid: receive requests
when (state === s_invalid) {
when (io.req_pri_val && io.req_pri_rdy) {
req := io.req
state := s_miss_req
when (io.lsu.req.fire()) {
assert(io.lsu.req.bits.cmd === M_XWR)
assert(!io.lsu.req.bits.meta.replay)
req := io.lsu.req.bits
state := s_replay_req
}
}
// --------------------------------------------
// replay
when (state === s_replay_req) {
io.replay.req.valid := true.B
io.replay.req.bits := req
when (io.replay.req.fire()) {
state := s_replay_resp
}
}
when (state === s_replay_resp) {
io.replay.resp.ready := true.B
when (io.replay.resp.fire()) {
when (io.replay.resp.bits.miss) {
// replayed reqs should not miss
assert(!req.meta.replay)
when (!req.meta.replay) {
state := s_miss_req
}
} .otherwise {
resp := io.replay.resp.bits
when (!req.meta.replay) {
state := s_resp
} .otherwise {
state := s_miss_finish
}
}
assert(!io.replay.resp.bits.nack)
}
}
......@@ -77,34 +111,10 @@ class StoreMissEntry extends DCacheModule
when (state === s_miss_resp) {
when (io.miss_resp.fire()) {
reg_miss_resp := io.miss_resp.bits
state := s_drain_rpq
}
}
// --------------------------------------------
// replay
val storePipelineLatency = 2
val replay_resp_ctr = Reg(UInt(log2Up(storePipelineLatency).W))
when (state === s_drain_rpq) {
io.replay.valid := true.B
io.replay.bits := req
io.replay.bits.meta.replay := true.B
when (io.replay.fire()) {
replay_resp_ctr := 0.U
state := s_replay_resp
}
}
//
// we must wait for response here,
// if we do'not wait for response here,
// this entry may be freed before it's response comes back
//
when (state === s_replay_resp) {
replay_resp_ctr := replay_resp_ctr + 1.U
when (replay_resp_ctr === (storePipelineLatency - 1).U) {
state := s_miss_finish
reg_miss_resp := io.miss_resp.bits
// mark req as replayed req
req.meta.replay := true.B
state := s_replay_req
}
}
......@@ -113,6 +123,16 @@ class StoreMissEntry extends DCacheModule
io.miss_finish.bits.client_id := io.id
io.miss_finish.bits.entry_id := reg_miss_resp.entry_id
when (io.miss_finish.fire()) {
state := s_resp
}
}
// --------------------------------------------
when (state === s_resp) {
io.lsu.resp.valid := true.B
io.lsu.resp.bits := resp
when (io.lsu.resp.fire()) {
state := s_invalid
}
}
......@@ -130,9 +150,10 @@ class StoreMissQueue extends DCacheModule
val miss_finish = DecoupledIO(new MissFinish)
})
val miss_req_arb = Module(new Arbiter(new MissReq, cfg.nStoreMissEntries))
val miss_finish_arb = Module(new Arbiter(new MissFinish, cfg.nStoreMissEntries))
val replay_arb = Module(new Arbiter(new DCacheLineReq , cfg.nStoreMissEntries))
val miss_req_arb = Module(new Arbiter(new MissReq, cfg.nStoreMissEntries))
val miss_finish_arb = Module(new Arbiter(new MissFinish, cfg.nStoreMissEntries))
val replay_arb = Module(new Arbiter(new DCacheLineReq, cfg.nStoreMissEntries))
val resp_arb = Module(new Arbiter(new DCacheResp, cfg.nStoreMissEntries))
val idx_matches = Wire(Vec(cfg.nLoadMissEntries, Bool()))
val tag_matches = Wire(Vec(cfg.nLoadMissEntries, Bool()))
......@@ -150,38 +171,58 @@ class StoreMissQueue extends DCacheModule
// if the same block is being handled dcache
// assert(!(req.valid && tag_match))
io.replay.resp.ready := false.B
val entry_id_MSB = reqIdWidth - 1
val entry_id_LSB = reqIdWidth - storeMissQueueEntryIdWidth
val entries = (0 until cfg.nStoreMissEntries) map { i =>
val entry = Module(new StoreMissEntry)
entry.io.id := i.U(log2Up(cfg.nStoreMissEntries).W)
entry.io.id := i.U(storeMissQueueEntryIdWidth.W)
idx_matches(i) := entry.io.idx.valid && entry.io.idx.bits === get_idx(req.bits.addr)
tag_matches(i) := entry.io.tag.valid && entry.io.tag.bits === get_tag(req.bits.addr)
// entry req
entry.io.req_pri_val := (i.U === entry_alloc_idx) && pri_val
// lsu req and resp
val entry_lsu = entry.io.lsu
entry_lsu.req.valid := (i.U === entry_alloc_idx) && pri_val
when (i.U === entry_alloc_idx) {
pri_rdy := entry.io.req_pri_rdy
pri_rdy := entry_lsu.req.ready
}
entry_lsu.req.bits := req.bits
resp_arb.io.in(i) <> entry_lsu.resp
// replay req and resp
val entry_replay = entry.io.replay
replay_arb.io.in(i) <> entry_replay.req
replay_arb.io.in(i).bits.meta.id <> Cat(entry.io.id,
entry_replay.req.bits.meta.id(entry_id_LSB - 1, 0))
val resp_entry_id = io.replay.resp.bits.meta.id(entry_id_MSB, entry_id_LSB)
entry_replay.resp.valid := (i.U === resp_entry_id) && io.replay.resp.valid
entry_replay.resp.bits := io.replay.resp.bits
entry_replay.resp.bits.meta.id := Cat(0.U(storeMissQueueEntryIdWidth.W),
io.replay.resp.bits.meta.id(entry_id_LSB - 1, 0))
when (entry_replay.resp.valid) {
io.replay.resp.ready := entry_replay.resp.ready
}
entry.io.req := req.bits
replay_arb.io.in(i) <> entry.io.replay
miss_req_arb.io.in(i) <> entry.io.miss_req
miss_req_arb.io.in(i) <> entry.io.miss_req
entry.io.miss_resp.valid := (i.U === io.miss_resp.bits.client_id) && io.miss_resp.valid
entry.io.miss_resp.bits := io.miss_resp.bits
miss_finish_arb.io.in(i) <> entry.io.miss_finish
entry
}
entry_alloc_idx := PriorityEncoder(entries.map(m=>m.io.req_pri_rdy))
entry_alloc_idx := PriorityEncoder(entries.map(m=>m.io.lsu.req.ready))
// whenever index matches, do not let it in
req.ready := pri_rdy && !idx_match
io.lsu.resp <> resp_arb.io.out
io.replay.req <> replay_arb.io.out
io.lsu.resp <> io.replay.resp
io.miss_req <> miss_req_arb.io.out
io.miss_finish <> miss_finish_arb.io.out
......
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, TlbCmd, MemoryOpConstants}
class LoadToLsroqIO extends XSBundle {
val loadIn = ValidIO(new LsPipelineBundle)
......@@ -19,7 +19,7 @@ class LoadUnit extends XSModule {
val redirect = Flipped(ValidIO(new Redirect))
val tlbFeedback = ValidIO(new TlbFeedback)
val dcache = new DCacheLoadIO
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO()
val sbuffer = new LoadForwardQueryIO
val lsroq = new LoadToLsroqIO
})
......@@ -50,6 +50,10 @@ class LoadUnit extends XSModule {
// send req to dtlb
io.dtlb.req.valid := l2_out.valid
io.dtlb.req.bits.vaddr := l2_out.bits.vaddr
io.dtlb.req.bits.cmd := TlbCmd.read
io.dtlb.req.bits.roqIdx := l2_out.bits.uop.roqIdx
io.dtlb.req.bits.debug.pc := l2_out.bits.uop.cf.pc
io.dtlb.req.bits.debug.lsroqIdx := l2_out.bits.uop.lsroqIdx
l2_dtlb_hit := io.dtlb.resp.valid && !io.dtlb.resp.bits.miss
l2_dtlb_miss := io.dtlb.resp.valid && io.dtlb.resp.bits.miss
......@@ -103,6 +107,8 @@ class LoadUnit extends XSModule {
XSDebug(l2_out.fire(), "load req: pc 0x%x addr 0x%x -> 0x%x op %b\n",
l2_out.bits.uop.cf.pc, l2_out.bits.vaddr, l2_out.bits.paddr, l2_out.bits.uop.ctrl.fuOpType)
XSDebug(io.dcache.req.valid, p"dcache req(${io.dcache.req.valid} ${io.dcache.req.ready}): pc:0x${Hexadecimal(io.dcache.req.bits.meta.uop.cf.pc)} roqIdx:${io.dcache.req.bits.meta.uop.roqIdx} lsroqIdx:${io.dcache.req.bits.meta.uop.lsroqIdx} addr:0x${Hexadecimal(io.dcache.req.bits.addr)} vaddr:0x${Hexadecimal(io.dcache.req.bits.meta.vaddr)} paddr:0x${Hexadecimal(io.dcache.req.bits.meta.paddr)} mmio:${io.dcache.req.bits.meta.mmio} tlb_miss:${io.dcache.req.bits.meta.tlb_miss} mask:${io.dcache.req.bits.meta.mask}\n")
//-------------------------------------------------------
// LD Pipeline Stage 3
// Compare tag, use addr to query DCache Data
......@@ -153,6 +159,7 @@ class LoadUnit extends XSModule {
l4_out.bits.mmio := io.dcache.resp.bits.meta.mmio
l4_out.bits.mask := io.dcache.resp.bits.meta.mask
l4_out.bits.miss := io.dcache.resp.bits.miss
XSDebug(io.dcache.resp.fire(), p"DcacheResp(l4): data:0x${Hexadecimal(io.dcache.resp.bits.data)} paddr:0x${Hexadecimal(io.dcache.resp.bits.meta.paddr)} pc:0x${Hexadecimal(io.dcache.resp.bits.meta.uop.cf.pc)} roqIdx:${io.dcache.resp.bits.meta.uop.roqIdx} lsroqIdx:${io.dcache.resp.bits.meta.uop.lsroqIdx} miss:${io.dcache.resp.bits.miss}\n")
} .otherwise {
l4_out.bits := l4_bundle
}
......@@ -189,13 +196,13 @@ class LoadUnit extends XSModule {
PipelineConnect(l4_out, l5_in, io.ldout.fire() || (l5_in.bits.miss || l5_in.bits.mmio) && l5_in.valid, false.B)
XSDebug(l4_valid, "l4: pc 0x%x addr 0x%x -> 0x%x op %b data 0x%x mask %x forwardData: 0x%x forwardMask: %x dcache %b mmio %b\n",
l4_out.bits.uop.cf.pc, l4_out.bits.vaddr, l4_out.bits.paddr,
XSDebug(l4_valid, "l4: out.valid:%d pc 0x%x addr 0x%x -> 0x%x op %b data 0x%x mask %x forwardData: 0x%x forwardMask: %x dcache %b mmio %b miss:%d\n",
l4_out.valid, l4_out.bits.uop.cf.pc, l4_out.bits.vaddr, l4_out.bits.paddr,
l4_out.bits.uop.ctrl.fuOpType, l4_out.bits.data, l4_out.bits.mask,
l4_out.bits.forwardData.asUInt, l4_out.bits.forwardMask.asUInt, l4_dcache, l4_out.bits.mmio)
l4_out.bits.forwardData.asUInt, l4_out.bits.forwardMask.asUInt, l4_dcache, l4_out.bits.mmio, l4_out.bits.miss)
XSDebug(l5_in.valid, "L5: pc 0x%x addr 0x%x -> 0x%x op %b data 0x%x mask %x forwardData: 0x%x forwardMask: %x\n",
l5_in.bits.uop.cf.pc, l5_in.bits.vaddr, l5_in.bits.paddr,
XSDebug(l5_in.valid, "L5(%d %d): pc 0x%x addr 0x%x -> 0x%x op %b data 0x%x mask %x forwardData: 0x%x forwardMask: %x\n",
l5_in.valid, l5_in.ready, l5_in.bits.uop.cf.pc, l5_in.bits.vaddr, l5_in.bits.paddr,
l5_in.bits.uop.ctrl.fuOpType , l5_in.bits.data, l5_in.bits.mask,
l5_in.bits.forwardData.asUInt, l5_in.bits.forwardMask.asUInt)
......@@ -205,7 +212,7 @@ class LoadUnit extends XSModule {
XSDebug(l4_valid, "l4: lsroq forwardData: 0x%x forwardMask: %x\n",
io.lsroq.forward.forwardData.asUInt, io.lsroq.forward.forwardMask.asUInt)
XSDebug(io.redirect.valid, p"Redirect: excp:${io.redirect.bits.isException} misp:${io.redirect.bits.isMisPred} replay:${io.redirect.bits.isReplay} pc:0x${Hexadecimal(io.redirect.bits.pc)} target:0x${Hexadecimal(io.redirect.bits.target)} brTag:${io.redirect.bits.brTag} l2:${io.ldin.bits.uop.needFlush(io.redirect)} l3:${l3_uop.needFlush(io.redirect)} l4:${l4_out.bits.uop.needFlush(io.redirect)}\n")
//-------------------------------------------------------
// LD Pipeline Stage 5
// Do data ecc check, merge result and write back to LS ROQ
......
......@@ -5,7 +5,7 @@ import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, MemoryOpConstants}
class LsRoqEntry extends XSBundle {
val paddr = UInt(PAddrBits.W)
......@@ -13,11 +13,7 @@ class LsRoqEntry extends XSBundle {
val mask = UInt(8.W)
val data = UInt(XLEN.W)
val exception = UInt(8.W)
// val miss = Bool()
val mmio = Bool()
// val store = Bool()
// val bwdMask = Vec(8, Bool()) // UInt(8.W)
// val bwdData = Vec(8, UInt(8.W))
val fwdMask = Vec(8, Bool())
val fwdData = Vec(8, UInt(8.W))
}
......@@ -56,14 +52,20 @@ class Lsroq extends XSModule {
val ringBufferTailExtended = RegInit(0.U(LsroqIdxWidth.W))
val ringBufferHead = ringBufferHeadExtended(InnerLsroqIdxWidth - 1, 0)
val ringBufferTail = ringBufferTailExtended(InnerLsroqIdxWidth - 1, 0)
val ringBufferEmpty = ringBufferHead === ringBufferTail && ringBufferHeadExtended(InnerLsroqIdxWidth) === ringBufferTailExtended(InnerLsroqIdxWidth)
val ringBufferFull = ringBufferHead === ringBufferTail && ringBufferHeadExtended(InnerLsroqIdxWidth) =/= ringBufferTailExtended(InnerLsroqIdxWidth)
val ringBufferSameFlag = ringBufferHeadExtended(InnerLsroqIdxWidth) === ringBufferTailExtended(InnerLsroqIdxWidth)
val ringBufferEmpty = ringBufferHead === ringBufferTail && ringBufferSameFlag
val ringBufferFull = ringBufferHead === ringBufferTail && !ringBufferSameFlag
val ringBufferAllowin = !ringBufferFull
val storeCommit = (0 until CommitWidth).map(i => io.commits(i).valid && !io.commits(i).bits.isWalk && io.commits(i).bits.uop.ctrl.commitType === CommitType.STORE)
val loadCommit = (0 until CommitWidth).map(i => io.commits(i).valid && !io.commits(i).bits.isWalk && io.commits(i).bits.uop.ctrl.commitType === CommitType.LOAD)
val mcommitIdx = (0 until CommitWidth).map(i => io.commits(i).bits.uop.lsroqIdx(InnerLsroqIdxWidth-1,0))
val tailMask = (((1.U((LsroqSize + 1).W)) << ringBufferTail).asUInt - 1.U)(LsroqSize - 1, 0)
val headMask = (((1.U((LsroqSize + 1).W)) << ringBufferHead).asUInt - 1.U)(LsroqSize - 1, 0)
val enqDeqMask1 = tailMask ^ headMask
val enqDeqMask = Mux(ringBufferSameFlag, enqDeqMask1, ~enqDeqMask1)
// TODO: misc arbitor
// Enqueue at dispatch
......@@ -174,7 +176,7 @@ class Lsroq extends XSModule {
val missRefillSelVec = VecInit(
(0 until LsroqSize).map(i => allocated(i) && miss(i))
)
val missRefillSel = PriorityEncoder(missRefillSelVec.asUInt)
val missRefillSel = getFirstOne(missRefillSelVec, tailMask)
io.dcache.req.valid := missRefillSelVec.asUInt.orR
io.dcache.req.bits.cmd := MemoryOpConstants.M_XRD
io.dcache.req.bits.addr := data(missRefillSel).paddr
......@@ -201,39 +203,13 @@ class Lsroq extends XSModule {
}
when(io.dcache.req.fire()){
XSDebug("miss req: pc %x addr %x\n", uop(missRefillSel).cf.pc, io.dcache.req.bits.addr)
XSDebug("miss req: pc:0x%x roqIdx:%d lsroqIdx:%d (p)addr:0x%x vaddr:0x%x\n", io.dcache.req.bits.meta.uop.cf.pc, io.dcache.req.bits.meta.uop.roqIdx, io.dcache.req.bits.meta.uop.lsroqIdx, io.dcache.req.bits.addr, io.dcache.req.bits.meta.vaddr)
}
when(io.dcache.resp.fire()){
XSDebug("miss resp: addr %x data %x\n", io.dcache.resp.bits.meta.paddr, io.dcache.resp.bits.data)
XSDebug("miss resp: pc:0x%x roqIdx:%d lsroqIdx:%d (p)addr:0x%x data %x\n", io.dcache.resp.bits.meta.uop.cf.pc, io.dcache.resp.bits.meta.uop.roqIdx, io.dcache.resp.bits.meta.uop.lsroqIdx, io.dcache.resp.bits.meta.paddr, io.dcache.resp.bits.data)
}
// get load result from refill resp
// Refill a line in 1 cycle
// def refillDataSel(data: UInt, offset: UInt): UInt = {
// Mux1H((0 until 8).map(p => (data(5, 3) === p.U, data(64 * (p + 1) - 1, 64 * p))))
// }
// def mergeRefillData(refill: UInt, fwd: UInt, fwdMask: UInt): UInt = {
// val res = Wire(Vec(8, UInt(8.W)))
// (0 until 8).foreach(i => {
// res(i) := Mux(fwdMask(i), fwd(8 * (i + 1) - 1, 8 * i), refill(8 * (i + 1) - 1, 8 * i))
// })
// res.asUInt
// }
// (0 until LsroqSize).map(i => {
// val addrMatch = data(i).paddr(PAddrBits - 1, 6) === io.refill.bits.meta.paddr
// when(allocated(i) && listening(i) && addrMatch && io.dcache.resp.fire()) {
// // TODO: merge data
// // val refillData = refillDataSel(io.refill.bits.data, data(i).paddr(5, 0))
// // data(i).data := mergeRefillData(refillData, data(i).data, data(i).mask)
// data(i).data := refillDataSel(io.refill.bits.data, data(i).paddr(5, 0)) // TODO: forward refill data
// valid(i) := true.B
// listening(i) := false.B
// }
// })
// Refill 64 bit in a cycle
// Refill data comes back from io.dcache.resp
def mergeRefillData(refill: UInt, fwd: UInt, fwdMask: UInt): UInt = {
......@@ -310,18 +286,18 @@ class Lsroq extends XSModule {
})
// writeback up to 2 store insts to CDB
// just randomly pick 2 stores, write them back to cdb
// choose the first two valid store requests from deqPtr
val storeWbSelVec = VecInit((0 until LsroqSize).map(i => {
allocated(i) && valid(i) && !writebacked(i) && store(i)
})).asUInt()
}))
val storeWbSel = Wire(Vec(StorePipelineWidth, UInt(log2Up(LsroqSize).W)))
val storeWbValid = Wire(Vec(StorePipelineWidth, Bool()))
val sselvec0 = PriorityEncoderOH(storeWbSelVec)
val sselvec1 = PriorityEncoderOH(storeWbSelVec & (~sselvec0).asUInt)
storeWbSel(0) := OHToUInt(sselvec0)
storeWbSel(1) := OHToUInt(sselvec1)
storeWbValid(0) := sselvec0.orR
storeWbValid(1) := sselvec1.orR
storeWbSel(0) := getFirstOne(storeWbSelVec, tailMask)
val firstSelMask = UIntToOH(storeWbSel(0))
val secondWbSelVec = VecInit((0 until LsroqSize).map(i => storeWbSelVec(i) && !firstSelMask(i)))
storeWbSel(1) := getFirstOne(secondWbSelVec, tailMask)
storeWbValid(0) := Cat(storeWbSelVec).orR
storeWbValid(1) := Cat(secondWbSelVec).orR
(0 until StorePipelineWidth).map(i => {
io.stout(i).bits.uop := uop(storeWbSel(i))
......@@ -339,21 +315,12 @@ class Lsroq extends XSModule {
// remove retired insts from lsroq, add retired store to sbuffer
// move tailPtr
// FIXME: opt size using OH -> Mask
val dequeueMask = Wire(Vec(LsroqSize * 2, Bool()))
(0 until LsroqSize * 2).foreach(i => {
val ptr = i.U(InnerLsroqIdxWidth - 1, 0)
if (i == 0) {
dequeueMask(i) := ringBufferTail === i.U && !ringBufferEmpty && !allocated(ptr) // beginning of dequeuemask
} else {
dequeueMask(i) := (
dequeueMask(i - 1) && !allocated(ptr) && ringBufferHead =/= i.U(InnerLsroqIdxWidth - 1, 0) ||
ringBufferTail === i.U && !ringBufferEmpty && !allocated(ptr) // beginning of dequeuemask
// TODO: opt timing
)
}
})
ringBufferTailExtended := ringBufferTailExtended + PopCount(dequeueMask.asUInt)
// allocatedMask: dequeuePtr can go to the next 1-bit
val allocatedMask = VecInit((0 until LsroqSize).map(i => allocated(i) || !enqDeqMask(i)))
// find the first one from deqPtr (ringBufferTail)
val nextTail1 = getFirstOneWithFlag(allocatedMask, tailMask, ringBufferTailExtended(InnerLsroqIdxWidth))
val nextTail = Mux(Cat(allocatedMask).orR, nextTail1, ringBufferHeadExtended)
ringBufferTailExtended := nextTail
// send commited store inst to sbuffer
// select up to 2 writebacked store insts
......@@ -421,113 +388,75 @@ class Lsroq extends XSModule {
})
// load forward query
// check over all lsroq entries and forward data from the first matched store
(0 until LoadPipelineWidth).map(i => {
io.forward(i).forwardMask := 0.U(8.W).asBools
io.forward(i).forwardData := DontCare
// Just for functional simulation
// forward
val needForward1 = WireInit(VecInit((0 until LsroqSize).map(j => {
io.forward(i).lsroqIdx(InnerLsroqIdxWidth - 1, 0) > j.U &&
(
ringBufferTail <= j.U ||
ringBufferTailExtended(InnerLsroqIdxWidth) =/= io.forward(i).lsroqIdx(InnerLsroqIdxWidth)
)
})))
val needForward2 = WireInit(VecInit((0 until LsroqSize).map(j => {
ringBufferTail <= j.U &&
ringBufferTailExtended(InnerLsroqIdxWidth) =/= io.forward(i).lsroqIdx(InnerLsroqIdxWidth)
})))
// Compare ringBufferTail (deqPtr) and forward.lsroqIdx, we have two cases:
// (1) if they have the same flag, we need to check range(tail, lsroqIdx)
// (2) if they have different flags, we need to check range(tail, lsroqSize) and range(0, lsroqIdx)
// Forward1: Mux(same_flag, range(tail, lsroqIdx), range(tail, lsroqSize))
// Forward2: Mux(same_flag, 0.U, range(0, lsroqIdx) )
// i.e. forward1 is the target entries with the same flag bits and forward2 otherwise
val forwardMask1 = WireInit(VecInit(Seq.fill(8)(false.B)))
val forwardData1 = WireInit(VecInit(Seq.fill(8)(0.U(8.W))))
val forwardMask2 = WireInit(VecInit(Seq.fill(8)(false.B)))
val forwardData2 = WireInit(VecInit(Seq.fill(8)(0.U(8.W))))
// forward lookup vec2
(0 until LsroqSize).map(j => {
when(
needForward2(j) &&
valid(j) && allocated(j) && store(j) &&
io.forward(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3)
) {
(0 until 8).map(k => {
when(data(j).mask(k)) {
forwardMask2(k) := true.B
forwardData2(k) := data(j).data(8 * (k + 1) - 1, 8 * k)
XSDebug("forwarding " + k + "th byte %x from ptr %d pc %x\n",
data(j).data(8 * (k + 1) - 1, 8 * k), j.U, uop(j).cf.pc
)
}
})
}
})
// forward lookup vec1
(0 until LsroqSize).map(j => {
when(
needForward1(j) &&
valid(j) && allocated(j) && store(j) &&
io.forward(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3)
) {
(0 until 8).map(k => {
when(data(j).mask(k)) {
val differentFlag = ringBufferTailExtended(InnerLsroqIdxWidth) =/= io.forward(i).lsroqIdx(InnerLsroqIdxWidth)
val forwardMask = ((1.U((LsroqSize + 1).W)) << io.forward(i).lsroqIdx(InnerLsroqIdxWidth - 1, 0)).asUInt - 1.U
val needForward1 = Mux(differentFlag, ~tailMask, tailMask ^ forwardMask)
val needForward2 = Mux(differentFlag, forwardMask, 0.U(LsroqSize.W))
// entry with larger index should have higher priority since it's data is younger
for (j <- 0 until LsroqSize) {
val needCheck = valid(j) && allocated(j) && store(j) &&
io.forward(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3)
(0 until XLEN / 8).foreach(k => {
when (needCheck && data(j).mask(k)) {
when (needForward1(j)) {
forwardMask1(k) := true.B
forwardData1(k) := data(j).data(8 * (k + 1) - 1, 8 * k)
XSDebug("forwarding " + k + "th byte %x from ptr %d pc %x, idx %d pc %x\n",
data(j).data(8 * (k + 1) - 1, 8 * k), j.U, uop(j).cf.pc, io.forward(i).lsroqIdx, uop(io.forward(i).lsroqIdx(InnerLsroqIdxWidth - 1, 0)).cf.pc
)
}
})
}
})
when (needForward2(j)) {
forwardMask2(k) := true.B
forwardData2(k) := data(j).data(8 * (k + 1) - 1, 8 * k)
}
XSDebug(needForward1(j) || needForward2(j),
p"forwarding $k-th byte ${Hexadecimal(data(j).data(8 * (k + 1) - 1, 8 * k))} " +
p"from ptr $j pc ${Hexadecimal(uop(j).cf.pc)}\n")
}
})
}
// merge forward lookup results
(0 until 8).map(k => {
// forward2 is younger than forward1 and should have higher priority
(0 until XLEN / 8).map(k => {
io.forward(i).forwardMask(k) := forwardMask1(k) || forwardMask2(k)
io.forward(i).forwardData(k) := Mux(forwardMask1(k), forwardData1(k), forwardData2(k))
io.forward(i).forwardData(k) := Mux(forwardMask2(k), forwardData2(k), forwardData1(k))
})
// (1 until LsroqSize).map(j => {
// val ptr = io.forward(i).lsroqIdx - j.U
// when(
// lsroqIdxOlderThan(ptr, io.forward(i).lsroqIdx) &&
// valid(ptr) && allocated(ptr) && store(ptr) &&
// io.forward(i).paddr(PAddrBits-1, 3) === data(ptr).paddr(PAddrBits-1, 3)
// ){
// (0 until 8).map(k => {
// // when(data(ptr).mask(k) && io.forward(i).mask(k)){
// when(data(ptr).mask(k)){
// io.forward(i).forwardMask(k) := true.B
// io.forward(i).forwardData(k) := data(ptr).data(8*(k+1)-1, 8*k)
// XSDebug("forwarding "+k+"th byte %x from ptr %d pc %x\n",
// io.forward(i).forwardData(k), ptr, uop(ptr).cf.pc
// )
// }
// })
// }
// })
// backward
// (0 until 8).map(k => {
// when(data(io.forward(i).lsroqIdx).bwdMask(k)) {
// io.forward(i).forwardMask(k) := true.B
// io.forward(i).forwardData(k) := data(io.forward(i).lsroqIdx).bwdData(k)
// XSDebug("backwarding " + k + "th byte %x, idx %d pc %x\n",
// io.forward(i).forwardData(k), io.forward(i).lsroqIdx(InnerLsroqIdxWidth - 1, 0), uop(io.forward(i).lsroqIdx).cf.pc
// )
// }
// })
})
// rollback check
val rollback = Wire(Vec(StorePipelineWidth, Valid(new Redirect)))
def getFirstOne(mask: Vec[Bool], start: UInt) = {
def getFirstOne(mask: Vec[Bool], startMask: UInt) = {
val length = mask.length
val lowMask = (1.U((length + 1).W) << start).asUInt() - 1.U
val highBits = (0 until length).map(i => mask(i) & ~lowMask(i))
val highBits = (0 until length).map(i => mask(i) & ~startMask(i))
val highBitsUint = Cat(highBits.reverse)
PriorityEncoder(Mux(highBitsUint.orR(), highBitsUint, mask.asUInt))
}
def getFirstOneWithFlag(mask: Vec[Bool], startMask: UInt, startFlag: UInt) = {
val length = mask.length
val highBits = (0 until length).map(i => mask(i) & ~startMask(i))
val highBitsUint = Cat(highBits.reverse)
val changeDirection = !highBitsUint.orR()
val index = PriorityEncoder(Mux(!changeDirection, highBitsUint, mask.asUInt))
Cat(startFlag ^ changeDirection, index)
}
def getOldestInTwo(valid: Seq[Bool], uop: Seq[MicroOp]) = {
assert(valid.length == uop.length)
assert(valid.length == 2)
......@@ -562,7 +491,10 @@ class Lsroq extends XSModule {
when(io.storeIn(i).valid) {
val startIndex = io.storeIn(i).bits.uop.lsroqIdx(InnerLsroqIdxWidth - 1, 0)
val toEnqPtrMask = rangeMask(io.storeIn(i).bits.uop.lsroqIdx, ringBufferHeadExtended)
val lsroqIdxMask = ((1.U((LsroqSize + 1).W) << startIndex).asUInt - 1.U)(LsroqSize - 1, 0)
val xorMask = lsroqIdxMask ^ headMask
val sameFlag = io.storeIn(i).bits.uop.lsroqIdx(InnerLsroqIdxWidth) === ringBufferHeadExtended(InnerLsroqIdxWidth)
val toEnqPtrMask = Mux(sameFlag, xorMask, ~xorMask)
val lsroqViolationVec = VecInit((0 until LsroqSize).map(j => {
val addrMatch = allocated(j) &&
io.storeIn(i).bits.paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3)
......@@ -572,7 +504,7 @@ class Lsroq extends XSModule {
Cat(violationVec).orR() && entryNeedCheck
}))
val lsroqViolation = lsroqViolationVec.asUInt().orR()
val lsroqViolationIndex = getFirstOne(lsroqViolationVec, startIndex)
val lsroqViolationIndex = getFirstOne(lsroqViolationVec, lsroqIdxMask)
val lsroqViolationUop = uop(lsroqViolationIndex)
XSDebug(lsroqViolation, p"${Binary(Cat(lsroqViolationVec))}, $startIndex, $lsroqViolationIndex\n")
......@@ -649,7 +581,9 @@ class Lsroq extends XSModule {
// setup misc mem access req
// mask / paddr / data can be get from lsroq.data
val commitType = io.commits(0).bits.uop.ctrl.commitType
io.uncache.req.valid := pending(ringBufferTail) && allocated(ringBufferTail) &&
(commitType === CommitType.STORE || commitType === CommitType.LOAD) &&
io.commits(0).bits.uop.lsroqIdx === ringBufferTailExtended &&
!io.commits(0).bits.isWalk
......@@ -681,7 +615,13 @@ class Lsroq extends XSModule {
}
when(io.uncache.req.fire()){
XSDebug("uncache req: pc %x addr %x data %x op %x mask %x\n", uop(missRefillSel).cf.pc, io.dcache.req.bits.addr, io.uncache.req.bits.data, io.uncache.req.bits.cmd, io.uncache.req.bits.mask)
XSDebug("uncache req: pc %x addr %x data %x op %x mask %x\n",
uop(ringBufferTail).cf.pc,
io.uncache.req.bits.addr,
io.uncache.req.bits.data,
io.uncache.req.bits.cmd,
io.uncache.req.bits.mask
)
}
when(io.uncache.resp.fire()){
......
......@@ -118,17 +118,19 @@ class Memend extends XSModule {
val miscToDcache = new DCacheLoadIO
val sbufferToDcache = new DCacheStoreIO
val uncache = new DCacheLoadIO
val ptw = new TlbPtwIO
})
val loadUnits = (0 until exuParameters.LduCnt).map(_ => Module(new LoadUnit))
val storeUnits = (0 until exuParameters.StuCnt).map(_ => Module(new StoreUnit))
val miscUnit = Module(new MiscUnit)
// val mshq = Module(new MSHQ)
val dtlb = Module(new Dtlb) //TODO: move dtlb out
val lsroq = Module(new Lsroq)
val sbuffer = Module(new FakeSbuffer)
dtlb.io := DontCare
val dtlb = Module(new TLB(Width = DTLBWidth, isDtlb = true))
val lsroq = Module(new Lsroq)
val sbuffer = Module(new Sbuffer)
// if you wants to stress test dcache store, use FakeSbuffer
// val sbuffer = Module(new FakeSbuffer)
val loadUnitToDcacheVec = Wire(Vec(exuParameters.LduCnt, new DCacheLoadIO))
......@@ -147,6 +149,8 @@ class Memend extends XSModule {
io.sbufferToDcache <> sbufferToDcache
io.uncache <> lsroqToUncache
io.ptw <> dtlb.io.ptw
// LoadUnit
for (i <- 0 until exuParameters.LduCnt) {
loadUnits(i).io.ldin <> io.backend.ldin(i)
......@@ -154,7 +158,7 @@ class Memend extends XSModule {
loadUnits(i).io.redirect <> io.backend.redirect
loadUnits(i).io.tlbFeedback <> io.backend.tlbFeedback(i)
loadUnits(i).io.dcache <> loadUnitToDcacheVec(i)
loadUnits(i).io.dtlb <> dtlb.io.lsu(i)
loadUnits(i).io.dtlb <> dtlb.io.requestor(i)
loadUnits(i).io.sbuffer <> sbuffer.io.forward(i)
lsroq.io.loadIn(i) <> loadUnits(i).io.lsroq.loadIn
......@@ -167,7 +171,7 @@ class Memend extends XSModule {
storeUnits(i).io.stin <> io.backend.stin(i)
storeUnits(i).io.redirect <> io.backend.redirect
storeUnits(i).io.tlbFeedback <> io.backend.tlbFeedback(exuParameters.LduCnt + i)
storeUnits(i).io.dtlb <> dtlb.io.lsu(exuParameters.LduCnt + i)
storeUnits(i).io.dtlb <> dtlb.io.requestor(exuParameters.LduCnt + i) // FIXME
storeUnits(i).io.lsroq <> lsroq.io.storeIn(i)
}
......@@ -193,7 +197,7 @@ class Memend extends XSModule {
miscUnit.io.in.valid := io.backend.ldin(0).valid && io.backend.ldin(0).bits.uop.ctrl.fuType === FuType.mou ||
io.backend.ldin(1).valid && io.backend.ldin(1).bits.uop.ctrl.fuType === FuType.mou
when(miscUnit.io.dtlb.req.valid){
dtlb.io.lsu(0) <> miscUnit.io.dtlb
dtlb.io.requestor(0) <> miscUnit.io.dtlb // TODO: check it later
}
miscUnit.io.dcache <> miscUnitToDcache
......
......@@ -4,14 +4,14 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, TlbCmd, MemoryOpConstants}
class MiscUnit extends XSModule with MemoryOpConstants{
val io = IO(new Bundle() {
val in = Flipped(Decoupled(new ExuInput))
val out = Decoupled(new ExuOutput)
val dcache = new DCacheLoadIO
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO
})
//-------------------------------------------------------
......@@ -23,7 +23,7 @@ class MiscUnit extends XSModule with MemoryOpConstants{
switch (state) {
is (s_tlb) {
when(io.in.valid && io.dtlb.resp.valid){
when(io.in.valid && io.dtlb.resp.valid && !io.dtlb.resp.bits.miss){
state := s_cache_req
}
}
......@@ -42,8 +42,13 @@ class MiscUnit extends XSModule with MemoryOpConstants{
// TLB
// send req to dtlb
// keep firing until tlb hit
io.dtlb.req.valid := io.in.valid && state === s_tlb
io.dtlb.req.valid := io.in.valid && state === s_tlb
io.dtlb.req.bits.vaddr := io.in.bits.src1
io.dtlb.req.bits.roqIdx := io.in.bits.uop.roqIdx
io.dtlb.req.bits.cmd := Mux(io.in.bits.uop.ctrl.fuOpType === LSUOpType.lr, TlbCmd.read, TlbCmd.write)
io.dtlb.req.bits.debug.pc := io.in.bits.uop.cf.pc
io.dtlb.req.bits.debug.lsroqIdx := io.in.bits.uop.lsroqIdx
// TODO: add excp logic of dtlb.resp.bits.excp.pf
// record paddr
val paddr = RegEnable(io.dtlb.resp.bits.paddr, io.in.fire())
......
......@@ -62,6 +62,9 @@ class Sbuffer extends XSModule with HasSBufferConst {
def getTag(pa: UInt): UInt =
pa(PAddrBits - 1, PAddrBits - tagWidth)
def getAddr(tag: UInt): UInt =
Cat(tag, 0.U((PAddrBits - tagWidth).W))
def getByteOffset(pa: UInt): UInt =
Cat(pa(offsetWidth - 1, log2Up(8)), Fill(3, 0.U))
......@@ -90,11 +93,15 @@ class Sbuffer extends XSModule with HasSBufferConst {
// 0. compare with former requests
for (formerIdx <- 0 until storeIdx) {
// i: former request
when (getTag(io.in(storeIdx).bits.addr) === updateInfo(formerIdx).newTag &&
(updateInfo(formerIdx).isUpdated || updateInfo(formerIdx).isInserted) && io.in(storeIdx).valid) {
when ((getTag(io.in(storeIdx).bits.addr) === updateInfo(formerIdx).newTag) &&
(updateInfo(formerIdx).isUpdated || updateInfo(formerIdx).isInserted) && io.in(storeIdx).valid && io.in(formerIdx).valid) {
updateInfo(storeIdx).isForward := true.B
updateInfo(formerIdx).isIgnored := true.B
updateInfo(storeIdx).idx := updateInfo(formerIdx).idx
XSDebug("req#%d writes same line with req#%d\n", storeIdx.U, formerIdx.U)
updateInfo(storeIdx).isInserted := updateInfo(formerIdx).isInserted
updateInfo(storeIdx).isUpdated := updateInfo(formerIdx).isUpdated
updateInfo(storeIdx).newTag := updateInfo(formerIdx).newTag
......@@ -188,18 +195,21 @@ class Sbuffer extends XSModule with HasSBufferConst {
XSInfo(updateInfo(storeIdx).isUpdated && updateInfo(storeIdx).isInserted, "Error: one line is both updated and inserted!\n")
io.in(storeIdx).ready := updateInfo(storeIdx).isUpdated || updateInfo(storeIdx).isInserted || updateInfo(storeIdx).isForward
if (storeIdx > 0)
io.in(storeIdx).ready := io.in(storeIdx - 1).ready && (updateInfo(storeIdx).isUpdated || updateInfo(storeIdx).isInserted)
else
io.in(storeIdx).ready := updateInfo(storeIdx).isUpdated || updateInfo(storeIdx).isInserted
when(io.in(storeIdx).fire()){
when(updateInfo(storeIdx).isIgnored) {
XSInfo("Ignore line#%d\n", storeIdx.U)
XSInfo("Ignore req#%d with paddr %x, mask %x, data %x\n", storeIdx.U, io.in(storeIdx).bits.addr, io.in(storeIdx).bits.mask, io.in(storeIdx).bits.data)
// Update or Forward
// Update
// ----------------------------------------
} .elsewhen(updateInfo(storeIdx).isUpdated || updateInfo(storeIdx).isForward) {
} .elsewhen(updateInfo(storeIdx).isUpdated) {
// clear lruCnt
// cache(updateInfo(storeIdx).idx).lruCnt := 0.U
lru.access(updateInfo(storeIdx).idx)
......@@ -213,7 +223,7 @@ class Sbuffer extends XSModule with HasSBufferConst {
int := updateInfo(storeIdx).newMask(i)
}
XSInfo("Update line#%d with tag %x, mask: %x, data: %x\n", updateInfo(storeIdx).idx, cache(updateInfo(storeIdx).idx).tag,
XSInfo("Update line#%d with tag %x, mask %x, data %x\n", updateInfo(storeIdx).idx, cache(updateInfo(storeIdx).idx).tag,
io.in(storeIdx).bits.mask, io.in(storeIdx).bits.data)
......@@ -248,37 +258,45 @@ class Sbuffer extends XSModule with HasSBufferConst {
//--------------------------------------------------------------------------------------------------------------------
val waitingCacheLine: SBufferCacheLine = RegInit(0.U.asTypeOf(new SBufferCacheLine))
val validCnt: UInt = Wire(UInt(4.W))
val validCnt: UInt = Wire(UInt((sBufferIndexWidth + 1).W))
validCnt := PopCount((0 until StoreBufferSize).map(i => cache(i).valid))
XSInfo("[ %d ] lines valid this cycle\n", validCnt)
val oldestLineIdx: UInt = Wire(UInt(sBufferIndexWidth.W))
oldestLineIdx := lru.way
XSInfo("Least recently used #[ %d ] line\n", validCnt)
XSInfo("Least recently used #[ %d ] line\n", oldestLineIdx)
val dcacheData = Wire(UInt(io.dcache.req.bits.data.getWidth.W))
val dcacheMask = Wire(UInt(io.dcache.req.bits.mask.getWidth.W))
dcacheData := DontCare
dcacheMask := DontCare
io.dcache.req.valid := false.B //needWriteToCache
io.dcache.req.bits.addr := DontCare
io.dcache.req.bits.data := DontCare
io.dcache.req.bits.mask := DontCare
io.dcache.req.bits.cmd := DontCare // NOT USED
io.dcache.req.bits.data := dcacheData
io.dcache.req.bits.mask := dcacheMask
io.dcache.req.bits.cmd := MemoryOpConstants.M_XWR
io.dcache.req.bits.meta := DontCare // NOT USED
io.dcache.resp.ready := waitingCacheLine.valid
when (validCnt + 2.U >= StoreBufferSize.U && !waitingCacheLine.valid) {
when (validCnt === StoreBufferSize.U && !waitingCacheLine.valid) {
// assert valid and send data + mask + addr(ends with 000b) to d-cache
io.dcache.req.bits.addr := Cat(cache(oldestLineIdx).tag, 0.U(3.W))
io.dcache.req.bits.addr := getAddr(cache(oldestLineIdx).tag)
when (!busy(oldestLineIdx, StorePipelineWidth)) {
io.dcache.req.bits.data := cache(oldestLineIdx).data.asUInt()
io.dcache.req.bits.mask := cache(oldestLineIdx).mask.asUInt()
dcacheData := cache(oldestLineIdx).data.asUInt()
dcacheMask := cache(oldestLineIdx).mask.asUInt()
XSDebug("[New D-Cache Req] idx: %d, addr: %x, mask: %x, data: %x\n", oldestLineIdx, io.dcache.req.bits.addr, waitingCacheLine.mask.asUInt(), waitingCacheLine.data.asUInt())
} .otherwise {
XSDebug("[Pending Write Back] tag: %x, mask: %x, data: %x\n", waitingCacheLine.tag, waitingCacheLine.mask.asUInt(), waitingCacheLine.data.asUInt())
}
for (i <- 0 until StorePipelineWidth) {
when (updateInfo(i).idx === oldestLineIdx && updateInfo(i).isUpdated && io.in(i).valid) {
io.dcache.req.bits.data := updateInfo(i).newData.asUInt()
io.dcache.req.bits.mask := updateInfo(i).newMask.asUInt()
dcacheData := updateInfo(i).newData.asUInt()
dcacheMask := updateInfo(i).newMask.asUInt()
}
}
......@@ -287,16 +305,20 @@ class Sbuffer extends XSModule with HasSBufferConst {
when(io.dcache.req.fire()){
// save current req
waitingCacheLine.valid := true.B
waitingCacheLine := cache(oldestLineIdx)
waitingCacheLine.data := dcacheData.asTypeOf(Vec(cacheMaskWidth, UInt(8.W)))
waitingCacheLine.mask := dcacheMask.asTypeOf(Vec(cacheMaskWidth, Bool()))
XSError(!cache(oldestLineIdx).valid, "!cache(oldestLineIdx).valid\n")
// waitingCacheLine.valid := true.B
cache(oldestLineIdx).valid := false.B
XSInfo("send req to dcache %x\n", oldestLineIdx)
}
when(io.dcache.resp.fire()) {
waitingCacheLine.valid := false.B
lru.miss
XSInfo("recv resp from dcache. wb tag %x\n", waitingCacheLine.tag)
XSInfo("recv resp from dcache. wb tag %x mask %x data %x\n", waitingCacheLine.tag, waitingCacheLine.mask.asUInt(), waitingCacheLine.data.asUInt())
}
......@@ -306,29 +328,37 @@ class Sbuffer extends XSModule with HasSBufferConst {
io.forward(loadIdx).forwardMask := VecInit(List.fill(instMaskWidth)(false.B))
io.forward(loadIdx).forwardData := DontCare
when(getTag(io.forward(loadIdx).paddr) === waitingCacheLine.tag) {
(0 until XLEN / 8).map(i => {
io.forward(loadIdx).forwardData(i) := waitingCacheLine.data(i.U + getByteOffset(io.forward(loadIdx).paddr))
io.forward(loadIdx).forwardMask(i) := waitingCacheLine.mask(i.U + getByteOffset(io.forward(loadIdx).paddr))
when(getTag(io.forward(loadIdx).paddr) === waitingCacheLine.tag && waitingCacheLine.valid) {
(0 until XLEN / 8).foreach(i => {
when (waitingCacheLine.mask(i.U + getByteOffset(io.forward(loadIdx).paddr)) && io.forward(loadIdx).mask(i)) {
io.forward(loadIdx).forwardData(i) := waitingCacheLine.data(i.U + getByteOffset(io.forward(loadIdx).paddr))
io.forward(loadIdx).forwardMask(i) := true.B
}
})
} .otherwise {
(0 until StoreBufferSize).foreach(sBufIdx => {
when(getTag(io.forward(loadIdx).paddr) === cache(sBufIdx).tag) {
// send data with mask in this line
// this mask is not 'mask for cache line' and we need to check low bits of paddr
// to get certain part of one line
// P.S. data in io.in will be manipulated by lsroq
(0 until XLEN / 8).map(i => {
}
// data in StoreBuffer should have higer priority than waitingCacheLine
for (sBufIdx <- 0 until StoreBufferSize) {
when(getTag(io.forward(loadIdx).paddr) === cache(sBufIdx).tag && cache(sBufIdx).valid) {
// send data with mask in this line
// this mask is not 'mask for cache line' and we need to check low bits of paddr
// to get certain part of one line
// P.S. data in io.in will be manipulated by lsroq
(0 until XLEN / 8).foreach(i => {
when (cache(sBufIdx).mask(i.U + getByteOffset(io.forward(loadIdx).paddr)) && io.forward(loadIdx).mask(i)) {
io.forward(loadIdx).forwardData(i) := cache(sBufIdx).data(i.U + getByteOffset(io.forward(loadIdx).paddr))
io.forward(loadIdx).forwardMask(i) := cache(sBufIdx).mask(i.U + getByteOffset(io.forward(loadIdx).paddr))
})
io.forward(loadIdx).forwardMask(i) := true.B
}
})
XSDebug("[Forwarding] tag: %x data: %x mask: %x\n", io.forward(loadIdx).paddr, io.forward(loadIdx).forwardData.asUInt(),
when (io.forward(loadIdx).valid) {
XSDebug("[ForwardReq] paddr: %x mask: %x pc: %x\n", io.forward(loadIdx).paddr, io.forward(loadIdx).mask, io.forward(loadIdx).pc)
XSDebug("[Forwarding] forward-data: %x forward-mask: %x\n", io.forward(loadIdx).forwardData.asUInt(),
io.forward(loadIdx).forwardMask.asUInt())
}
})
}
}
})
// additional logs
......@@ -341,9 +371,8 @@ class Sbuffer extends XSModule with HasSBufferConst {
XSDebug(line.valid, "[#%d line] Tag: %x, data: %x, mask: %x\n", i.U, line.tag, line.data.asUInt(), line.mask.asUInt())
}}
}
// Fake Store buffer for XiangShan Out of Order LSU
// NutShell DCache Interface
class FakeSbuffer extends XSModule {
val io = IO(new Bundle() {
val in = Vec(StorePipelineWidth, Flipped(Decoupled(new DCacheWordReq)))
......
......@@ -4,14 +4,14 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.DtlbToLsuIO
import xiangshan.cache.{TlbRequestIO, TlbCmd}
class StoreUnit extends XSModule {
val io = IO(new Bundle() {
val stin = Flipped(Decoupled(new ExuInput))
val redirect = Flipped(ValidIO(new Redirect))
val tlbFeedback = ValidIO(new TlbFeedback)
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO()
val lsroq = ValidIO(new LsPipelineBundle)
})
......@@ -55,6 +55,10 @@ class StoreUnit extends XSModule {
io.dtlb.req.bits.vaddr := saddr
io.dtlb.req.valid := io.stin.valid
io.dtlb.req.bits.cmd := TlbCmd.write
io.dtlb.req.bits.roqIdx := io.stin.bits.uop.roqIdx
io.dtlb.req.bits.debug.pc := io.stin.bits.uop.cf.pc
io.dtlb.req.bits.debug.lsroqIdx := io.stin.bits.uop.lsroqIdx
s2_out.bits := DontCare
s2_out.bits.vaddr := saddr
......
......@@ -27,16 +27,36 @@ void addpageSv39() {
#define PTEADDR(i) (0x88000000 - (PAGESIZE * PTENUM) + (PAGESIZE * i)) //0x88000000 - 0x100*64
#define PTEMMIONUM 128
#define PDEMMIONUM 1
#define PTEDEVNUM 128
#define PDEDEVNUM 1
uint64_t pdde[ENTRYNUM];
uint64_t pde[ENTRYNUM];
uint64_t pte[PTENUM][ENTRYNUM];
//special addr for mmio 0x40000000 - 0x4fffffff
// special addr for mmio 0x40000000 - 0x4fffffff
uint64_t pdemmio[ENTRYNUM];
uint64_t ptemmio[PTEMMIONUM][ENTRYNUM];
pdde[1] = (((PDDEADDR-PAGESIZE*1) & 0xfffff000) >> 2) | 0x1;
// special addr for internal devices 0x30000000-0x3fffffff
uint64_t pdedev[ENTRYNUM];
uint64_t ptedev[PTEDEVNUM][ENTRYNUM];
// dev: 0x30000000-0x3fffffff
pdde[0] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)) & 0xfffff000) >> 2) | 0x1;
for (int i = 0; i < PTEDEVNUM; i++) {
pdedev[ENTRYNUM-PTEDEVNUM+i] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM-i)) & 0xfffff000) >> 2) | 0x1;
}
for(int outidx = 0; outidx < PTEDEVNUM; outidx++) {
for(int inidx = 0; inidx < ENTRYNUM; inidx++) {
ptedev[outidx][inidx] = (((0x30000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000) >> 2) | 0xf;
}
}
// mmio: 0x40000000 - 0x4fffffff
pdde[1] = (((PDDEADDR-PAGESIZE*PDEMMIONUM) & 0xfffff000) >> 2) | 0x1;
for(int i = 0; i < PTEMMIONUM; i++) {
pdemmio[i] = (((PDDEADDR-PAGESIZE*(PTEMMIONUM+PDEMMIONUM-i)) & 0xfffff000) >> 2) | 0x1;
......@@ -63,6 +83,8 @@ void addpageSv39() {
}
}
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM)),ptedev,PAGESIZE*PTEDEVNUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)),pdedev,PAGESIZE*PDEDEVNUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM)),ptemmio, PAGESIZE*PTEMMIONUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM)), pdemmio, PAGESIZE*PDEMMIONUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM)), pdde, PAGESIZE*PDDENUM);
......
......@@ -19,7 +19,7 @@ class AluTest extends FlatSpec
with HasPartialDecoupledDriver
{
it should "do simple test corrcetly" in {
test(new AluExeUnit){c =>
test(new AluExeUnit(false)){c =>
c.io.in.initSource().setSourceClock(c.clock)
c.io.out.initSink().setSinkClock(c.clock)
......@@ -32,7 +32,7 @@ class AluTest extends FlatSpec
}
it should "do random add correctly" in {
test(new AluExeUnit){c =>
test(new AluExeUnit(false)){c =>
c.io.in.initSource().setSourceClock(c.clock)
c.io.out.initSink().setSinkClock(c.clock)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册