Skip to content

Commit

Permalink
bug fix and reorganization
Browse files Browse the repository at this point in the history
  • Loading branch information
midnighter95 committed Jul 1, 2022
1 parent d5f5694 commit 48d2b85
Showing 1 changed file with 39 additions and 60 deletions.
99 changes: 39 additions & 60 deletions src/main/scala/rocket/ICache.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ import chisel3.util.random.LFSR
case class ICacheParams(
nSets: Int = 64,
nWays: Int = 4,
// @todo none-used parameter for ICache.
// unused parameter for ICache.
rowBits: Int = 128,
// @todo none-used parameter for ICache.
// unused parameter for ICache.
nTLBSets: Int = 1,
// @todo none-used parameter for ICache.
// unused parameter for ICache.
nTLBWays: Int = 32,
// @todo none-used parameter for ICache.
// unused parameter for ICache.
nTLBBasePageSectors: Int = 4,
// @todo none-used parameter for ICache.
// unused parameter for ICache.
nTLBSuperpages: Int = 4,
// @todo none-used parameter.
// unused parameter for ICache.
cacheIdBits: Int = 0,
tagECC: Option[String] = None,
dataECC: Option[String] = None,
Expand Down Expand Up @@ -74,10 +74,32 @@ class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p)
}

/** [[ICache]] is a set associated cache I$(Instruction Cache) of Rocket.
* Keywords: Set-associated
* 3 stage pipeline
* Virtually-Indexed Physically-Tagged (VIPT)
* Parallel access to tag and data SRAM
* Random replacement algorithm
* Optional Features:
* Prefetch
* ECC
* Instruction Tightly Integrated Memory(ITIM)
*
* 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
*
* ITIM:
* It can have an optional dynamic configurable ITIM sharing SRAM with I$ by configuring [[icacheParams.itimAddr]].
* if PutFullData/PutPartialData to the ITIM address, it will dynamically allocate base address to the address of this accessing from SRAM.
* if access to last way of ITIM, it set will change back to I$.
*
* * 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`,
* from ITIM base to `scratchpadMax` will be used as ITIM.
* unset: @todo
*
* There will always be one way(the last way) used for I$, which cannot be allocated to ITIM.
*
* @param icacheParams parameter to this I$.
Expand Down Expand Up @@ -195,6 +217,9 @@ class ICacheBundle(val outer: ICache) extends CoreBundle()(outer.p) {
* TODO: doc this after main pipeline.
*/
val s2_kill = Bool(INPUT)
/**should L2 cache line on a miss?
*/
val s2_cacheable = Bool(INPUT)

/** should I$ prefetch next line on a miss?
* TODO: doc this after BPU.
Expand Down Expand Up @@ -226,41 +251,20 @@ 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`,
* from ITIM base to `scratchpadMax` will be used as ITIM.
* unset: @todo
*
* It hides TLB access latency(Stage 0 -> Stage 1)
*
* Pipeline:
* Stage 0: access `tag_array` and `data_array` with `vaddr`.
* 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 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` == b11 (last way), deallocate
* if write to ITIM all I$ will be invalidate
*/
Expand All @@ -281,9 +285,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
*/
val (tl_in, edge_in) = outer.slaveNode.in.headOption.unzip

/** tag ecc. */
val tECC = cacheParams.tagCode
/** data ecc. */
val dECC = cacheParams.dataCode

require(isPow2(nSets) && isPow2(nWays))
Expand Down Expand Up @@ -347,7 +349,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
* │ line │
* }}}
* @param addr address to be found.
* applied to slave_addr
* applied to slave_addr
*/
def scratchpadLine(addr: UInt) = addr(untagBits+log2Ceil(nWays)-1, blockOffBits)

Expand Down Expand Up @@ -396,7 +398,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
/** status register to indicate there is a outstanding refill. */
val refill_valid = RegInit(false.B)
/** register to indicate [[tl_out]] is performing a hint.
* prefetch happens after refilling
* prefetch only happens after refilling
* */
val send_hint = RegInit(false.B)
/** indicate [[tl_out]] is performing a refill. */
Expand All @@ -412,13 +414,9 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
* miss under miss won't trigger another burst.
*/
val s2_request_refill = s2_miss && RegNext(s1_can_request_refill)
/** physical address to refill. */
val refill_paddr = RegEnable(io.s1_paddr, s1_valid && s1_can_request_refill)
/** virtual address to refill. */
val refill_vaddr = RegEnable(s1_vaddr, s1_valid && s1_can_request_refill)
/** tag of address to refill. */
val refill_tag = refill_paddr >> pgUntagBits
/** index of address to refill. */
val refill_idx = index(refill_vaddr, refill_paddr)
/** AccessAckData, is refilling I$, it will block request form CPU. */
val refill_one_beat = tl_out.d.fire() && edge_out.hasData(tl_out.d.bits)
Expand Down Expand Up @@ -449,9 +447,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
}

/** init tag SRAM, indexed with virtual memory(vaddr[11:6]),
* size = nSets = 64
* 4-way,
* content with `eccError ## tag[19:0]` after ECC
* content with `refillError ## tag[19:0]` after ECC
* */
val tag_array = DescribedSRAM(
name = "tag_array",
Expand All @@ -474,7 +470,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
/** data written to [[tag_array]].
* ECC encoded `refillError ## refill_tag`*/
val enc_tag = tECC.encode(Cat(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 @@ -530,14 +525,8 @@ 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)
/** tag from CPU paddr request. */
val s1_tag = io.s1_paddr >> pgUntagBits
/** this way is used by scratchpad.
* [[tag_array]] corrupted.
Expand All @@ -553,22 +542,17 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// @todo Accessing ITIM correspond address will be able to read cacheline?
// is this desired behavior?
addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i)
/** new valid block after scratchpad accessing. */
val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid
/** ECC decoded result form [[tag_rdata]]. */
val enc_tag = tECC.decode(tag_rdata(i))
/** [[tl_error]] ECC error bit.
* [[tag]] of [[tag_array]] access.
*/
val (tl_error, tag) = Split(enc_tag.uncorrected, tagBits)

/** way [[i]] access is matched to CPU access from [[io]]. */
val tagMatch = s1_vb && tag === s1_tag
/** tag error happens. */
s1_tag_disparity(i) := s1_vb && enc_tag.error
// if tag matched but ecc checking failed, this access will trigger [[Causes.fetch_access]] exception.
/** if tag matched but ecc checking failed, this access will trigger [[Causes.fetch_access]] exception.*/
s1_tl_error(i) := tagMatch && tl_error.asBool
// hit index [[i]] of [[tag_array]].
s1_tag_hit(i) := tagMatch || scratchpadHit
}
assert(!(s1_valid || s1_slaveValid) || PopCount(s1_tag_hit zip s1_tag_disparity map { case (h, d) => h && !d }) <= 1)
Expand Down Expand Up @@ -741,7 +725,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// (de)allocate ITIM
when (s0_slaveValid) {
val a = tl.a.bits
// S1
// address
s1s3_slaveAddr := tl.a.bits.address
// store Put/PutP data
s1s3_slaveData := tl.a.bits.data
Expand Down Expand Up @@ -785,7 +769,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// pull up [[respValid]] when [[s2_slaveValid]] until [[tl.d.fire()]]
respValid := s2_slaveValid || (respValid && !tl.d.ready)
// if [[s2_full_word_write]] will overwrite data, and [[s2_data_decoded.uncorrectable]] can be ignored.
// TODO: I thought respError is for Get?
val respError = RegEnable(s2_scratchpad_hit && s2_data_decoded.uncorrectable && !s1s2_full_word_write, s2_slaveValid)
when (s2_slaveValid) {
// need stage 3 if Put or correct decoding.
Expand Down Expand Up @@ -813,7 +796,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// @todo why directly `edge_in.get.AccessAck(s1_a, s1s3_slaveData, denied = Bool(false), corrupt = respError)`
tl.d.bits.data := s1s3_slaveData

// Tie off unused channels
tl.b.valid := false
tl.c.ready := true
tl.e.ready := true
Expand All @@ -825,7 +807,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
}
}

// refill
tl_out.a.valid := s2_request_refill
tl_out.a.bits := edge_out.Get(
fromSource = UInt(0),
Expand All @@ -839,7 +820,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
*/
val (crosses_page, next_block) = Split(refill_paddr(pgIdxBits-1, blockOffBits) +& 1, pgIdxBits-blockOffBits)

// assign to [[send_hint]] and [[hint_outstanding]]
when (tl_out.a.fire()) {
send_hint := !hint_outstanding && io.s2_prefetch && !crosses_page
when (send_hint) {
Expand Down Expand Up @@ -902,7 +882,6 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
s1_valid || s2_valid || refill_valid || send_hint || hint_outstanding // I$

/** index to access [[data_arrays]] and [[tag_array]].
* @todo why not VA directly?
* @note
* if [[untagBits]] > [[pgIdxBits]] in
* {{{
Expand All @@ -918,7 +897,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 .
* Note: if [[untagBits]] > [[pgIdxBits]], there will be a alias issue which isn't addressend by the icache yet.
*/
def index(vaddr: UInt, paddr: UInt) = {
/** [[paddr]] as LSB to be used for VIPT. */
Expand Down

0 comments on commit 48d2b85

Please sign in to comment.