Skip to content

Commit

Permalink
mem: add CSR based l1 cache instructions (OpenXiangShan#1116)
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustusWillisWang authored Oct 21, 2021
1 parent 45f497a commit e19f796
Show file tree
Hide file tree
Showing 11 changed files with 514 additions and 34 deletions.
21 changes: 21 additions & 0 deletions src/main/scala/xiangshan/Bundle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,29 @@ class CustomCSRCtrlIO(implicit p: Parameters) extends XSBundle {
}

class DistributedCSRIO(implicit p: Parameters) extends XSBundle {
// CSR has been writen by csr inst, copies of csr should be updated
val w = ValidIO(new Bundle {
val addr = Output(UInt(12.W))
val data = Output(UInt(XLEN.W))
})
}

class DistributedCSRUpdateReq(implicit p: Parameters) extends XSBundle {
// Request csr to be updated
//
// Note that this request will ONLY update CSR Module it self,
// copies of csr will NOT be updated, use it with care!
//
// For each cycle, no more than 1 DistributedCSRUpdateReq is valid
val w = ValidIO(new Bundle {
val addr = Output(UInt(12.W))
val data = Output(UInt(XLEN.W))
})
def apply(valid: Bool, addr: UInt, data: UInt, src_description: String) = {
when(valid){
w.bits.addr := addr
w.bits.data := data
}
println("Distributed CSR update req registered for " + src_description)
}
}
2 changes: 2 additions & 0 deletions src/main/scala/xiangshan/XSCore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer)
csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0)
csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0)

csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO

fenceio.sfence <> memBlock.io.sfence
fenceio.sbuffer <> memBlock.io.fenceToSbuffer

Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/xiangshan/backend/MemBlock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
val rob = Flipped(new RobLsqIO) // rob to lsq
}
val csrCtrl = Flipped(new CustomCSRCtrlIO)
val csrUpdate = new DistributedCSRUpdateReq
val error = new L1CacheErrorInfo
val memInfo = new Bundle {
val sqFull = Output(Bool())
Expand All @@ -95,6 +96,8 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
val dcache = outer.dcache.module
val uncache = outer.uncache.module

dcache.io.csr.distribute_csr <> io.csrCtrl.distribute_csr
io.csrUpdate <> dcache.io.csr.update
io.error <> RegNext(RegNext(dcache.io.error))

val loadUnits = Seq.fill(exuParameters.LduCnt)(Module(new LoadUnit))
Expand Down
19 changes: 18 additions & 1 deletion src/main/scala/xiangshan/backend/fu/CSR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ class CSRFileIO(implicit p: Parameters) extends XSBundle {
val debugMode = Output(Bool())
// Custom microarchiture ctrl signal
val customCtrl = Output(new CustomCSRCtrlIO)
val distributedUpdate = Flipped(new DistributedCSRUpdateReq)
// to Fence to disable sfence
val disableSfence = Output(Bool())
// distributed csr w
Expand Down Expand Up @@ -676,10 +677,13 @@ class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMP
// perfCntMapping += MaskedRegMap(MhpmeventStart + i, perfEvents(i))
// }

val cacheopRegs = CacheInstrucion.CacheInsRegisterList.map{case (name, attribute) => {
name -> RegInit(0.U(attribute("width").toInt.W))
}}
val cacheopMapping = CacheInstrucion.CacheInsRegisterList.map{case (name, attribute) => {
MaskedRegMap(
Scachebase + attribute("offset").toInt,
RegInit(0.U(attribute("width").toInt.W))
cacheopRegs(name)
)
}}

Expand Down Expand Up @@ -1017,6 +1021,19 @@ class CSR(implicit p: Parameters) extends FunctionUnit with HasCSRConst with PMP

XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc)

// Distributed CSR update req
//
// For now we use it to implement customized cache op

when(csrio.distributedUpdate.w.valid){
// cacheopRegs can be distributed updated
CacheInstrucion.CacheInsRegisterList.map{case (name, attribute) => {
when((Scachebase + attribute("offset").toInt).U === csrio.distributedUpdate.w.bits.addr){
cacheopRegs(name) := csrio.distributedUpdate.w.bits.data
}
}}
}

def readWithScala(addr: Int): UInt = mapping(addr)._1

val difftestIntrNO = Mux(raiseIntr, causeNO, 0.U)
Expand Down
208 changes: 181 additions & 27 deletions src/main/scala/xiangshan/cache/CacheInstruction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import xiangshan._
import xiangshan.frontend._
import utils._
import chipsalliance.rocketchip.config.Parameters
import xiangshan.backend.fu.util.HasCSRConst

object CacheOpMap{
def apply(opcode: String, optype: String, name: String ): Map[String, String] = {
Expand All @@ -31,6 +32,8 @@ trait CacheControlConst{
def maxDataRowSupport = 8
}

abstract class CacheCtrlModule(implicit p: Parameters) extends XSModule with HasCSRConst with CacheControlConst

object CacheInstrucion{
def CacheOperation = List(
CacheOpMap("b00000", "CHECK", "READ_TAG_ECC"),
Expand All @@ -45,45 +48,64 @@ object CacheInstrucion{
)

def CacheInsRegisterList = Map(
/** offset width authority name */
CacheRegMap("0", "64", "RW", "CACHE_LEVEL"),
CacheRegMap("1", "64", "RW", "CACHE_WAY"),
CacheRegMap("2", "64", "RW", "CACHE_IDX"),
CacheRegMap("3", "64", "RW", "CACHE_TAG_ECC"),
CacheRegMap("4", "64", "RW", "CACHE_TAG_BITS"),
CacheRegMap("5", "64", "RW", "CACHE_TAG_LOW"),
CacheRegMap("6", "64", "RW", "CACHE_TAG_HIGH"),
CacheRegMap("7", "64", "R", "CACHE_ECC_WIDTH"),
CacheRegMap("8", "64", "RW", "CACHE_ECC_NUM"),
CacheRegMap("9", "64", "RW", "CACHE_DATA_ECC"),
CacheRegMap("10", "64", "RW", "CACHE_DATA_0"),
CacheRegMap("11", "64", "RW", "CACHE_DATA_1"),
CacheRegMap("12", "64", "RW", "CACHE_DATA_2"),
CacheRegMap("13", "64", "RW", "CACHE_DATA_3"),
CacheRegMap("14", "64", "RW", "CACHE_DATA_4"),
CacheRegMap("15", "64", "RW", "CACHE_DATA_5"),
CacheRegMap("16", "64", "RW", "CACHE_DATA_6"),
CacheRegMap("17", "64", "RW", "CACHE_DATA_7"),
CacheRegMap("18", "64", "R", "OP_FINISH") ,
CacheRegMap("19", "64", "RW", "CACHE_OP")
// offset width authority name
CacheRegMap("0", "64", "RW", "CACHE_OP"),
CacheRegMap("1", "64", "RW", "OP_FINISH"),
CacheRegMap("2", "64", "RW", "CACHE_LEVEL"),
CacheRegMap("3", "64", "RW", "CACHE_WAY"),
CacheRegMap("4", "64", "RW", "CACHE_IDX"),
CacheRegMap("5", "64", "RW", "CACHE_BANK_NUM"),
CacheRegMap("6", "64", "RW", "CACHE_TAG_ECC"),
CacheRegMap("7", "64", "RW", "CACHE_TAG_BITS"), // TODO
CacheRegMap("8", "64", "RW", "CACHE_TAG_LOW"),
CacheRegMap("9", "64", "RW", "CACHE_TAG_HIGH"), // not used in 64 bit arch
CacheRegMap("10", "64", "RW", "CACHE_ECC_WIDTH"), // TODO
CacheRegMap("11", "64", "RW", "CACHE_DATA_ECC"),
CacheRegMap("12", "64", "RW", "CACHE_DATA_0"),
CacheRegMap("13", "64", "RW", "CACHE_DATA_1"),
CacheRegMap("14", "64", "RW", "CACHE_DATA_2"),
CacheRegMap("15", "64", "RW", "CACHE_DATA_3"),
CacheRegMap("16", "64", "RW", "CACHE_DATA_4"),
CacheRegMap("17", "64", "RW", "CACHE_DATA_5"),
CacheRegMap("18", "64", "RW", "CACHE_DATA_6"),
CacheRegMap("19", "64", "RW", "CACHE_DATA_7"),
)

// Usage:
// val cacheopMapping = CacheInstrucion.CacheInsRegisterList.map{case (name, attribute) => {
// doSthWith(name, attribute("offset"), attribute("width"))
// }}

def COP_CHECK = 0.U
def COP_LOAD = 1.U
def COP_STORE = 2.U
def COP_FLUSH = 3.U

def COP_ID_ICACHE = 0
def COP_ID_DCACHE = 1

def COP_RESULT_CODE_IDLE = 0.U
def COP_RESULT_CODE_OK = 1.U
def COP_RESULT_CODE_ERROR = 2.U

def isReadTagECC(opcode: UInt) = opcode === "b00000".U
def isReadDataECC(opcode: UInt) = opcode === "b00001".U
def isReadTag(opcode: UInt) = opcode === "b00010".U
def isReadData(opcode: UInt) = opcode === "b00011".U
def isWriteTagECC(opcode: UInt) = opcode === "b00101".U
def isWriteTagECC(opcode: UInt) = opcode === "b00100".U
def isWriteDataECC(opcode: UInt) = opcode === "b00101".U
def isWriteTag(opcode: UInt) = opcode === "b00110".U
def isWriteData(opcode: UInt) = opcode === "b00111".U
def isFlush(opcode: UInt) = opcode === "b01000".U

def isReadOp(opcode: UInt) = isReadTagECC(opcode) ||
isReadDataECC(opcode) ||
isReadTag(opcode) ||
isReadData(opcode)
}

class CacheCtrlReqInfo(implicit p: Parameters) extends XSBundle with CacheControlConst {
val level = UInt(XLEN.W) // op target id
val wayNum = UInt(XLEN.W)
val index = UInt(XLEN.W)
val opCode = UInt(XLEN.W)
Expand All @@ -92,7 +114,7 @@ class CacheCtrlReqInfo(implicit p: Parameters) extends XSBundle with CacheContro
val write_tag_ecc = UInt(XLEN.W)
val write_data_vec = Vec(maxDataRowSupport, UInt(XLEN.W))
val write_data_ecc = UInt(XLEN.W)
val ecc_num = UInt(XLEN.W)
val bank_num = UInt(XLEN.W)
}

class CacheCtrlRespInfo(implicit p: Parameters) extends XSBundle with HasICacheParameters with CacheControlConst{
Expand All @@ -101,10 +123,142 @@ class CacheCtrlRespInfo(implicit p: Parameters) extends XSBundle with HasICacheP
val read_tag_ecc = UInt(XLEN.W)
val read_data_vec = Vec(maxDataRowSupport, UInt(XLEN.W))
val read_data_ecc = UInt(XLEN.W)
val ecc_num = UInt(XLEN.W)
val bank_num = UInt(XLEN.W)
}

class L1CacheToCsrIO(implicit p: Parameters) extends DCacheBundle {
val distribute_csr = Flipped(new DistributedCSRIO)
val update = new DistributedCSRUpdateReq
}

class DCacheInnerOpIO(implicit p: Parameters) extends DCacheBundle {
val req = Valid(new CacheCtrlReqInfo)
val resp = Flipped(Valid(new CacheCtrlRespInfo))
}

class CSRCacheOpDecoder(decoder_name: String, id: Int)(implicit p: Parameters) extends CacheCtrlModule {
val io = IO(new Bundle {
val csr = new L1CacheToCsrIO
val cache = new DCacheInnerOpIO
})

// CSRCacheOpDecoder state
val w_csr_op_req = RegInit(true.B) // waiting for csr "CACHE_OP" being write
val w_cache_op_resp = RegInit(false.B) // waiting for dcache to finish dcache op
val s_csr_op_resp_data = RegInit(false.B) // ready to write data readed from cache back to csr
val s_csr_op_resp_finish = RegInit(false.B) // ready to write "OP_FINISH" csr
// val cache_op_resp_timer = RegInit(0.U(4.W))
val data_transfer_finished = WireInit(false.B)
val data_transfer_cnt = RegInit(0.U(log2Up(maxDataRowSupport).W))

// Translate CSR write to cache op
val translated_cache_req = Reg(new CacheCtrlReqInfo)
println("Cache op decoder (" + decoder_name + "):")
println(" Id " + id)
// CacheInsRegisterList.map{case (name, attribute) => {
// println(" Register CSR mirror " + name)
// }}

def cacheop_csr_is_being_write(csr_name: String): Bool = {
io.csr.distribute_csr.w.bits.addr === (CacheInstrucion.CacheInsRegisterList(csr_name)("offset").toInt + Scachebase).U &&
io.csr.distribute_csr.w.valid
}

def update_cache_req_when_write(csr_name: String, req_field: Data) = {
when(
cacheop_csr_is_being_write(csr_name)
){
req_field := io.csr.distribute_csr.w.bits.data
assert(w_csr_op_req)
}
}

update_cache_req_when_write("CACHE_OP", translated_cache_req.opCode)
update_cache_req_when_write("CACHE_LEVEL", translated_cache_req.level)
update_cache_req_when_write("CACHE_WAY", translated_cache_req.wayNum)
update_cache_req_when_write("CACHE_IDX", translated_cache_req.index)
update_cache_req_when_write("CACHE_BANK_NUM", translated_cache_req.bank_num)
update_cache_req_when_write("CACHE_TAG_HIGH", translated_cache_req.write_tag_high)
update_cache_req_when_write("CACHE_TAG_LOW", translated_cache_req.write_tag_low)
update_cache_req_when_write("CACHE_DATA_ECC", translated_cache_req.write_tag_ecc)
update_cache_req_when_write("CACHE_DATA_0", translated_cache_req.write_data_vec(0))
update_cache_req_when_write("CACHE_DATA_1", translated_cache_req.write_data_vec(1))
update_cache_req_when_write("CACHE_DATA_2", translated_cache_req.write_data_vec(2))
update_cache_req_when_write("CACHE_DATA_3", translated_cache_req.write_data_vec(3))
update_cache_req_when_write("CACHE_DATA_4", translated_cache_req.write_data_vec(4))
update_cache_req_when_write("CACHE_DATA_5", translated_cache_req.write_data_vec(5))
update_cache_req_when_write("CACHE_DATA_6", translated_cache_req.write_data_vec(6))
update_cache_req_when_write("CACHE_DATA_7", translated_cache_req.write_data_vec(7))
update_cache_req_when_write("CACHE_DATA_ECC", translated_cache_req.write_data_ecc)

// class CSRCacheInsIO(implicit p: Parameters) extends XSModule{
// // TODO: extend pmp cfg interface
// }
val cache_op_start = WireInit(cacheop_csr_is_being_write("CACHE_OP") && id.U === translated_cache_req.level)
when(cache_op_start) {
w_csr_op_req := false.B
}

// Send cache op to cache
io.cache.req.valid := RegNext(cache_op_start)
io.cache.req.bits := translated_cache_req
when(io.cache.req.fire()){
w_cache_op_resp := true.B
}

// Receive cache op resp from cache
val raw_cache_resp = Reg(new CacheCtrlRespInfo)
when(io.cache.resp.fire()){
w_cache_op_resp := false.B
raw_cache_resp := io.cache.resp.bits
when(CacheInstrucion.isReadOp(translated_cache_req.opCode)){
s_csr_op_resp_data := true.B
s_csr_op_resp_finish := false.B
assert(data_transfer_cnt === 0.U)
}.otherwise{
s_csr_op_resp_data := false.B
s_csr_op_resp_finish := true.B
}
}

// Translate cache op resp to CSR write, send it back to CSR
when(io.csr.update.w.fire() && s_csr_op_resp_data && data_transfer_finished){
s_csr_op_resp_data := false.B
s_csr_op_resp_finish := true.B
}
when(io.csr.update.w.fire() && s_csr_op_resp_finish){
s_csr_op_resp_finish := false.B
w_csr_op_req := true.B
}

io.csr.update.w.valid := s_csr_op_resp_data || s_csr_op_resp_finish
io.csr.update.w.bits := DontCare

val isReadTagECC = WireInit(CacheInstrucion.isReadTagECC(translated_cache_req.opCode))
val isReadDataECC = WireInit(CacheInstrucion.isReadDataECC(translated_cache_req.opCode))
val isReadTag = WireInit(CacheInstrucion.isReadTag(translated_cache_req.opCode))
val isReadData = WireInit(CacheInstrucion.isReadData(translated_cache_req.opCode))

when(s_csr_op_resp_data){
io.csr.update.w.bits.addr := Mux1H(List(
isReadTagECC -> (CacheInstrucion.CacheInsRegisterList("CACHE_TAG_ECC")("offset").toInt + Scachebase).U,
isReadDataECC -> (CacheInstrucion.CacheInsRegisterList("CACHE_BANK_NUM")("offset").toInt + Scachebase).U,
isReadTag -> ((CacheInstrucion.CacheInsRegisterList("CACHE_TAG_LOW")("offset").toInt + Scachebase).U + data_transfer_cnt),
isReadData -> ((CacheInstrucion.CacheInsRegisterList("CACHE_DATA_0")("offset").toInt + Scachebase).U + data_transfer_cnt),
))
io.csr.update.w.bits.data := Mux1H(List(
isReadTagECC -> raw_cache_resp.read_tag_ecc,
isReadDataECC -> raw_cache_resp.read_tag_ecc,
isReadTag -> raw_cache_resp.read_tag_low,
isReadData -> raw_cache_resp.read_data_vec(data_transfer_cnt),
))
data_transfer_finished := Mux(isReadData(translated_cache_req.opCode),
data_transfer_cnt === (maxDataRowSupport-1).U,
true.B
)
data_transfer_cnt := data_transfer_cnt + 1.U
}

when(s_csr_op_resp_finish){
io.csr.update.w.bits.addr := (CacheInstrucion.CacheInsRegisterList("OP_FINISH")("offset").toInt + Scachebase).U
io.csr.update.w.bits.data := CacheInstrucion.COP_RESULT_CODE_OK
data_transfer_cnt := 0.U
}
}
Loading

0 comments on commit e19f796

Please sign in to comment.