Skip to content

Commit

Permalink
ICache document
Browse files Browse the repository at this point in the history
  • Loading branch information
midnighter95 committed Jun 27, 2022
1 parent a612389 commit d5f5694
Showing 1 changed file with 73 additions and 36 deletions.
109 changes: 73 additions & 36 deletions src/main/scala/rocket/ICache.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p)
class ICache(val icacheParams: ICacheParams, val staticIdForMetadataUseOnly: Int)(implicit p: Parameters) extends LazyModule {
lazy val module = new ICacheModule(this)

/** Diplomatic hardid bundle used for ITIM. */
/** Diplomatic hartid bundle used for ITIM. */
val hartIdSinkNodeOpt = icacheParams.itimAddr.map(_ => BundleBridgeSink[UInt]())
/** @todo base address offset for ITIM? */
val mmioAddressPrefixSinkNodeOpt = icacheParams.itimAddr.map(_ => BundleBridgeSink[UInt]())
Expand All @@ -103,7 +103,7 @@ class ICache(val icacheParams: ICacheParams, val staticIdForMetadataUseOnly: Int
*
* source Id range:
* 0: use [[TLEdgeOut.Get]] to get instruction.
* 1: use [[TLEdgeOut.Hint]] to hint next level memory device fetching next page, if configured [[icacheParams.prefetch]].
* 1: use [[TLEdgeOut.Hint]] to hint next level memory device fetching next cache line, if configured [[icacheParams.prefetch]].
*
* @todo why if no [[useVM]], will have AMBAProtField in requestFields?
*/
Expand Down Expand Up @@ -198,6 +198,7 @@ class ICacheBundle(val outer: ICache) extends CoreBundle()(outer.p) {

/** should I$ prefetch next line on a miss?
* TODO: doc this after BPU.
* send a hint to the next level cache
*/
val s2_prefetch = Bool(INPUT)

Expand Down Expand Up @@ -226,6 +227,10 @@ class ICacheBundle(val outer: ICache) extends CoreBundle()(outer.p) {

/** Rocket virtually-indexed physically-tagged (VIPT) L1 Instruction Cache module,
* which also can be used as an ITIM(Instruction Tightly Integrated Memory).
* Note: Page size = 4KB thus paddr[11:0] = vaddr[11:0]
* considering sets = 64, cachelineBytes =64
* use vaddr[11:6] to access tag_array
* use vaddr[11:2] to access data_array
* If ITIM is configured:
* set: if address to access is not to be configured to ITIM yet,
* a memory accessing to ITIM address range will modify `scratchpadMax`,
Expand All @@ -236,26 +241,27 @@ class ICacheBundle(val outer: ICache) extends CoreBundle()(outer.p) {
*
* Pipeline:
* Stage 0: access `tag_array` and `data_array` with `vaddr`.
* Stage 1: get data and tag.
* TODO if hit in stage 0:
* TODO tag comparison with paddr or variation of PT(mix of `vaddr` and `paddr`)
* TODO if miss in stage 0:
* Stage 2: data way select + ecc dec
* Stage 1: get data(index:vaddr[11:2]) and tag(index:vaddr[11:6]),
* compare tag and paddr when the entry is valid
* if hit : s1_hit = 1, respond to CPU in stage 2
* tag comparison with paddr or variation of PT(mix of `vaddr` and `paddr`)
* if miss : start refilling in stage 2
*
* Stage 2: respond to CPU
*
* `tag_array` read with vaddr at Stage 0,
* write with `index(vaddr, paddr)`.
* `data_array` read with vaddr truncating TileLink beat count at Stage 0.
* write with `index(vaddr, paddr)` truncating TileLink beat count.
*
*
* Stage 1: Tag ECC
* Stage 2: Data ECC
* `tag_array` read starts at Stage 0 with vaddr[11:6]
* write with `index(vaddr, paddr)`
* `data_array` read starts at Stage 0 with vaddr[11:2]
* write with `index(vaddr, paddr)` truncating TileLink beat count
* ECC:
* Stage 1: Tag ECC decoding
* Stage 2: Data ECC decoding
*
* ITIM:
* │ tag │ set │offset│
* │way│
* There is always last way reserve to I$
* if `way` == 11 (last way), deallocate
* if `way` == b11 (last way), deallocate
* if write to ITIM all I$ will be invalidate
*/
class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
Expand Down Expand Up @@ -290,10 +296,11 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
val io_mmio_address_prefix = outer.mmioAddressPrefixSinkNodeOpt.map(_.bundle)
/** register indicates wheather ITIM is enabled. */
val scratchpadOn = RegInit(false.B)
/** a cut point to SRAM, indicates which SRAM will be used as SRAM or Cache. */
/** a cut point to SRAM, indicates which SRAM will be used as SRAM or Cache.
* todo: (yyq) if enable ITIM, the ITIM size is fixed to (way = 11)?*/
val scratchpadMax = tl_in.map(tl => Reg(UInt(width = log2Ceil(nSets * (nWays - 1)))))
/** line is a minimal granularity accessing to SRAM, check if a line is in the scratchpad or not.
* Accessing from [[tl_in]]: convert address to line with `untagBits+log2Ceil(nWays)-1, blockOffBits`(slices from address)
* Accessing from [[tl_in]]: convert address to line with `untagBits+log2Ceil(nWays)-1, blockOffBits`(slices of address)
* {{{
* │ tag │ set │offset│
* ├way┘ → indicate way location
Expand All @@ -314,7 +321,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
/** check an address in the scratchpad address range. */
def addrMaybeInScratchpad(addr: UInt) = scratchpadBase.map(base => addr >= base && addr < base + outer.size).getOrElse(false.B)

/** check property this address exists in scratchpad.
/** check property this address(paddr) exists in scratchpad.
* @todo seems duplicated in `addrMaybeInScratchpad(addr)` between `lineInScratchpad(addr(untagBits+log2Ceil(nWays)-1, blockOffBits))`?
*/
def addrInScratchpad(addr: UInt) = addrMaybeInScratchpad(addr) && lineInScratchpad(addr(untagBits+log2Ceil(nWays)-1, blockOffBits))
Expand All @@ -328,18 +335,19 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
*/
def scratchpadWay(addr: UInt) = addr.extract(untagBits+log2Ceil(nWays)-1, untagBits)

/** can this way being used by scratchpad?
* at least the last way should be reserved to cache.
/** check if the selected way is legal.
* note: the last way should be reserved to ICache.
*/
def scratchpadWayValid(way: UInt) = way < nWays - 1

/** return the cacheline which will be used as scratchpad for accessing address?
/** return the cacheline which will be used as scratchpad for accessing address
* {{{
* │ tag │ set │offset│
* ├way┘ → indicate way location
* │ line │
* }}}
* @param addr address to be found.
* applied to slave_addr
*/
def scratchpadLine(addr: UInt) = addr(untagBits+log2Ceil(nWays)-1, blockOffBits)

Expand All @@ -357,7 +365,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
/** virtual address from CPU in stage 0. */
val s0_vaddr = io.req.bits.addr

/** valid signal for CPU accessing cache in stage 1.*/
/** valid signal for stage 1, drived by s0_valid.*/
val s1_valid = Reg(init=Bool(false))
/** virtual address from CPU in stage 1. */
val s1_vaddr = RegEnable(s0_vaddr, s0_valid)
Expand Down Expand Up @@ -387,7 +395,9 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
val invalidated = Reg(Bool())
/** status register to indicate there is a outstanding refill. */
val refill_valid = RegInit(false.B)
/** register to indicate [[tl_out]] is performing a hint. */
/** register to indicate [[tl_out]] is performing a hint.
* prefetch happens after refilling
* */
val send_hint = RegInit(false.B)
/** indicate [[tl_out]] is performing a refill. */
val refill_fire = tl_out.a.fire() && !send_hint
Expand Down Expand Up @@ -438,7 +448,11 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
v
}

// init tag SRAM, indexed with virtual memory, content with `eccError ## tag` after ECC.
/** init tag SRAM, indexed with virtual memory(vaddr[11:6]),
* size = nSets = 64
* 4-way,
* content with `eccError ## tag[19:0]` after ECC
* */
val tag_array = DescribedSRAM(
name = "tag_array",
desc = "ICache Tag Array",
Expand All @@ -457,9 +471,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
val refillError = tl_out.d.bits.corrupt || (refill_cnt > 0 && accruedRefillError)
when (refill_done) {
// For AccessAckData, denied => corrupt
/** data write to [[tag_array]]. */
/** data written to [[tag_array]].
* ECC encoded `refillError ## refill_tag`*/
val enc_tag = tECC.encode(Cat(refillError, refill_tag))
// write tag array with ECC encoded `refillError ## refill_tag`
// write tag array with refill_idx and the way to be replaced
tag_array.write(refill_idx, Vec.fill(nWays)(enc_tag), Seq.tabulate(nWays)(repl_way === _))

ccover(refillError, "D_CORRUPT", "I$ D-channel corrupt")
Expand Down Expand Up @@ -489,7 +504,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
invalidated := Bool(true)
}

/** wire indicate that tag is correctable or uncorrectable.
/** wire indicates that tag is correctable or uncorrectable.
* will trigger CPU to replay and I$ invalidating, if correctable.
*/
val s1_tag_disparity = Wire(Vec(nWays, Bool()))
Expand All @@ -515,6 +530,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
*/
val s1s3_slaveData = Reg(UInt(width = wordBits))

/** Goals in stage 1
* 1: define cache hit or miss
* 2: error check
* */
for (i <- 0 until nWays) {
/** set index from CPU request. */
val s1_idx = index(s1_vaddr, io.s1_paddr)
Expand Down Expand Up @@ -567,7 +586,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
* └─set──┴─offset─┘
* └────row───┘
*
* TODO: timing issue here MusOH(data_arrays.read)
*/
val data_arrays = Seq.tabulate(tl_out.d.bits.data.getWidth / wordBits) {
i =>
Expand All @@ -578,19 +596,34 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
data = Vec(nWays, UInt(width = dECC.width(wordBits)))
)
}

/** init data SRAM, indexed with virtual memory(vaddr[11:2]),
* vaddr[11:3]->row,
* vaddr[2]->bank=i,
* Cache line size = refillCycels(8) * bank(2) * datasize(4 bytes) = 64 bytes
* 4-way,
* data width = 32
* read:
* read happens in stage 0
* write:
* It takes 8 beats to refill 16 instruction in each refilling cycle.
* Data_array receives data[63:0](2 instructions) at once,they will be allocated in deferent bank according to vaddr[2]
* */
for ((data_array , i) <- data_arrays zipWithIndex) {
/** Is this address access in this bank? */
/** bank match (vaddr[2]) */
def wordMatch(addr: UInt) = addr.extract(log2Ceil(tl_out.d.bits.data.getWidth/8)-1, log2Ceil(wordBits/8)) === i
/** return row correspond to a address. */
/** calculate row (vaddr[11:3]).
* row means the index for data_array
* vaddr[11:6]=row[8:3]
* vaddr[5:3]=row[2:0]
*/
def row(addr: UInt) = addr(untagBits-1, blockOffBits-log2Ceil(refillCycles))
/** CPU or ITIM read match this bank. */
val s0_ren = (s0_valid && wordMatch(s0_vaddr)) || (s0_slaveValid && wordMatch(s0_slaveAddr))
/** refill from [[tl_out]] or ITIM write. */
val wen = (refill_one_beat && !invalidated) || (s3_slaveValid && wordMatch(s1s3_slaveAddr))
/** index to access [[data_array]]. */
val mem_idx =
// I$ refill.
// I$ refill. refill_idx[2:0]is the beats
Mux(refill_one_beat, (refill_idx << log2Ceil(refillCycles)) | refill_cnt,
// ITIM write.
Mux(s3_slaveValid, row(s1s3_slaveAddr),
Expand All @@ -599,7 +632,9 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// CPU read.
row(s0_vaddr))))
when (wen) {
//wr_data
val data = Mux(s3_slaveValid, s1s3_slaveData, tl_out.d.bits.data(wordBits*(i+1)-1, wordBits*i))
//the way to be written
val way = Mux(s3_slaveValid, scratchpadWay(s1s3_slaveAddr), repl_way)
data_array.write(mem_idx, Vec.fill(nWays)(dECC.encode(data)), (0 until nWays).map(way === _))
}
Expand Down Expand Up @@ -714,6 +749,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
when (edge_in.get.hasData(a)) {
// access data in 0 -> way - 2 allocate and enable, access data in way - 1(last way), deallocate.
val enable = scratchpadWayValid(scratchpadWay(a.address))
//The address isn't in range,
when (!lineInScratchpad(scratchpadLine(a.address))) {
scratchpadMax.get := scratchpadLine(a.address)
invalidate := true
Expand All @@ -738,7 +774,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
&& s2_valid && s2_data_decoded.error && !s2_tag_disparity) {
// handle correctable errors on CPU accesses to the scratchpad.
// if there is an in-flight slave-port access to the scratchpad,
// report the a miss but don't correct the error (as there is
// report the miss but don't correct the error (as there is
// a structural hazard on s1s3_slaveData/s1s3_slaveAddress).
s3_slaveValid := true
s1s3_slaveData := s2_data_decoded.corrected
Expand Down Expand Up @@ -798,8 +834,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)

// prefetch when not access cross a page.
if (cacheParams.prefetch) {
/** [[crosses_page]] the last address of this current page is requested to refill.
* [[next_block]] next address to be accessed.
/** [[crosses_page]] indicate if there is a crosses page access
* [[next_block]] : the address to be prefetched.
*/
val (crosses_page, next_block) = Split(refill_paddr(pgIdxBits-1, blockOffBits) +& 1, pgIdxBits-blockOffBits)

Expand Down Expand Up @@ -882,6 +918,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
* }}}
*
* else use paddr directly.
* Note: if [[untagBits]] > [[pgIdxBits]], there will be a alias issue which the current ICache cannot handle .
*/
def index(vaddr: UInt, paddr: UInt) = {
/** [[paddr]] as LSB to be used for VIPT. */
Expand Down

0 comments on commit d5f5694

Please sign in to comment.