- Init submodules
make init
- Generate DCache SystemVerilog
make dcache
- Test
make test
Version1 Feature List:
- Highly configurable & loosely coupled
- Nonblocking
- 2 cycle load to use & cache hit lat 1 cycle
- PIPT (latency + 1cycle)
- Single Load/store pipe
- Access Bandwidth 8/16/32/64 bytes (matrix ld/st 不经过 L1)
- Replacement policy: PLRU
- Prefetcher: Stream + Stride
- [V/M] Support L1 bypassing
- ⽀持多 load/store pipe: 1 load pipe & 1 store pipe --> multiple load pipe & multiple store pipe
- Prefetcher: Plus SMS+BOP (BOP move to L2 later)
- Replacement Policy: RRIP
- ECC
- 可以转换 AXI/TileLink Bus
- 开机启动时⽀持 Uncacheable 模式
Pipeline stages:
- t0: 虚拟地址翻译成物理地址
- t1/s0: 获得地址翻译结果,根据物理地址读取 data array 和 meta array
- s1: 获得 data array 和 meta array 结果,判断 hit/miss。hit 则组织数据,返回结果;miss 则 allocate mshr
- s2: 组织 AMOALU 要 store 的数据
- s3: 写 data array 和 meta array
- s4: data array 和 meta array 写⼊完成
- MSHR -> Pipeline Load/Write Miss(Refill Queue -> Replay Reg -> Write Cache) + Hit But Need Write Permission
- IOMSHR -> Bypass(Refill Queue -> LSU) + MMIO(Uncacheable) + AMO(TileLink Atomic)
- Storage
- Data array
- Meta array (include tag & coherence meta)
- MSHR/IOMSHR: Handling Cache Miss (FSM)
- Refill Queue
- Writeback Queue
- Probe Queue
- Prefetcher
- Replacer
地址翻译之后发给 cache
| 信号 | ⽅向 | 源 | ⽬的 | 信号组名 | 位宽 | 描述 |
|---|---|---|---|---|---|---|
| clock | input | 1 | 时钟信号 | |||
| reset | input | 1 | 异步复位信号 | |||
| io_req_valid | input | Core/Vector | Cache | req | 1 | |
| io_req_ready | output | cache | Core/Vector | req | 1 | |
| io_req_bits_source | input | Core/Vector | Cache | req | srcWidth | req 来源; scalar int(0)/scalar fp(1)/vector(2)/matrix(3) |
| io_req_bits_dest | input | Core/Vector | Cache | req | destWidth | 对于 scalar 来说,是寄存器地址,对于 vector 来说,是 vlsu queue index |
| io_req_bits_cmd | input | Core/Vector | Cache | req | M_SZ | 访存操作类型,如 READ/WRITE/PARTIAL WRITE/AMO |
| io_req_bits_paddr | input | Core/Vector | Cache | req | paddrWidth | 物理地址 |
| io_req_bits_size | input | Core/Vector | Cache | req | log2Up(log2Up(dataBytes)) | 数据⼤⼩ |
| io_req_bits_signed | input | Core/Vector | Cache | req | 1 | 是否做符号位扩展 |
| io_req_bits_wdata | input | Core/Vector | Cache | req | max(VLEN, XLEN) | 写操作的数据 |
| io_req_bits_wmask | input | Core/Vector | Cache | req | max(VLEN/8, XLEN/8) | 写操作的 mask |
| io_req_bits_nAlloc | input | Core/Vector | Cache | req | 1 | 不需要 cache 分配 entry |
| io_req_bits_isRefill | input | Core/Vector | Cache | req | 1 | 是否是 refill 请求 (for test) |
| io_req_bits_refillCoh | input | Core/Vector | Cache | req | cohWidt h |
refill 指定的 coherence state (for test) |
| io_resp_valid | outpu t |
Cache | Core/Vector | resp | 1 | |
| io_resp_bits_s ource |
outpu t |
Cache | Core/Vector | resp | srcWidth | req 来源 |
| io_resp_dest | outpu t |
Cache | Core/Vector | resp | destWidt h |
对于 scalar 来说,是寄存器地址,对于 vector 来说,是 vlsu queue index |
| io_resp_bits_s ize |
outpu t |
Cache | Core | resp | log2Up(l og2Up(d ataBytes) ) |
数据⼤⼩(FP 需要) |
| io_resp_status | outpu t |
Cache | Core/Vector | resp | respStat usWidth |
resp 状态,包含 hit/miss/replay(重发当 handle 之后返回结果) 前指令)/refill(miss hit(0), miss(1), replay(2), refill(3) |
| io_resp_bits_h asData |
Outp ut |
Cache | Core/Vector | resp | 1 | 是否携带数据 |
| io_resp_bits_d ata |
outpu t |
Cache | Core/Vector | resp | max(VLE N, XLEN) |
load 数据 |
| Cache | Core | resp | 1 | |||
| io_nextCycleW b |
outpu t |
下⼀个周期 cache 要写回 scalar 数据,占 ⽤ wb 阶段,因此不能处理 s0 阶段的请求 |
||||
| io_fenceRdy | Outp ut |
Cache | Core | resp | 1 | cache 中所有请求都已经结束 fence 等待完成,可以执⾏后续指令 |
| io_s0_kill | Input | Core | Cache | 1 | 流⽔线控制信号;kill 掉 s0 阶段的操作 | |
| io_s1_kill | Input | Core | Cache | 1 | 流⽔线控制信号;kill 掉 s1 阶段的操作 |
s0 阶段,接收 cache req 请求
s1 阶段,cache hit,返回结果
s0 阶段,接收 cache req 请求
s1 阶段,cache miss, 返回 resp
之后 cache 进入 mshr 状态机,
数据回来之后,
如果是 scalar cache miss: 在将数据发送给 scalar pipe 之前一个周期,要先发送一个 nextCycleWb, 通知 pipeline 下一个周期 cache 要写回; 一个周期之后,返回 cache 结果
如果非 scalar, 则不需要提前一周期发 nextCycleWb

s0 阶段,接收 cache req 请求
s1 阶段,cache hit,返回响应
s0 阶段,接收 cache req 请求
s1 阶段,cache miss,返回响应
当作已经完成请求,不需要再做回复 s0 阶段,接收 cache req 请求
如果遇到了 mshr 满或者地址冲突的情况,
在 s1 阶段,返回 replay, 表⽰要重新执⾏这条指令,同时会把 cache ready 信号拉低,防⽌乱序访存
- req1 和 req2 为对相同地址的 load 指令,都发生了 cache miss
- req3 发生了 cache hit
- req4 在 s1 阶段返回结果要 replay, 同时 req1/req2 要返回结果,因此发送了 nextCycleWb
- 发送完 nextCycleWb 之后,req1 和 req2 开始 refill
- 在 nextCycleWb 拉高的时间段,不能处理 s0 阶段的请求;在 nextCycleWb 拉低之后,处理下一个请求,因为 req4 需要 replay, 所以下一个请求重发 req4
- req4 发生 cache miss

| Operations | Explain | Encoding | Constraints |
| Normal (support) | |||
| M_XRD | Int load | 00000 | - 支持符号位扩展 - 支持 mmio - 支持 bypass |
| M_XWR | Int store | 00001 | - 不支持符号位扩展 - 支持 mmio - 支持 bypass |
| M_PWR | Partial masked store | 10001 | - 不支持符号位扩展 - 不支持 mmio - 支持 bypass - size 必须为 6 (64Byte) |
| Prefetch (Support) | |||
| M_PFR | Prefetch with intent to read | 00010 | - 不支持符号位扩展 - 不支持 mmio - 不支持 bypass - 不返回结果 - 不保证指令完成(例如 s1 MSHR 满了,prefetch 请求不会 replay,而是被丢弃) |
| M_PFW | Prefetch with intent to write | 00011 | - 不支持符号位扩展 - 不支持 mmio - 不支持 bypass - 不返回结果 - 不保证指令完成(例如 s1 MSHR 满了,prefetch 请求不会 replay,而是被丢弃) |
| CMO (Not Support) | |||
| M_FLUSH | Write back dirty data and cede R/W permissions | 10000 | |
| M_PRODUCE | Write back dirty data and cede W permission | 10010 | |
| M_CLEAN | Write back dirty data and retain R/W permissions | 10011 | |
| M_FLUSH_ALL | Flush all lines | 00101 | |
| AMO (Support) | |||
| M_XLR | Load reserved | 00110 | - 总是做符号位扩展 - 不支持 mmio - 不支持 bypass - Size 为 2 或者 3 (word/double word) |
| M_XSC | Store conditional | 00111 | - 不支持符号位扩展 - 不支持 mmio - 不支持 bypass - Size 为 2 或者 3 (word/double word) |
| M_XA_SWAP | 00100 | - 总是做符号位扩展 - 支持 mmio - 支持 bypass - Size 为 2 或者 3 (word/double word) |
|
| M_XA_ADD | 01000 | ||
| M_XA_XOR | 01001 | ||
| M_XA_OR | 01010 | ||
| M_XA_AND | 01011 | ||
| M_XA_MIN | 01100 | ||
| M_XA_MAX | 01101 | ||
| M_XA_MINU | 01110 | ||
| M_XA_MAXU | 01111 | ||
| FENCE (To be discussed) | |||
| M_SFENCE | 10100 | ||
| M_HFENCEV | 10101 | ||
| M_HFENCEG | 10110 | ||
| M_WOK | 10111 | ||
| M_HLVX | 10000 |
| rowBits | SRAM row bits (固定为 64) |
|---|---|
| numBanks | bank 数量 |
| numWays | 组关联数量 |
| numSets | set 数量 |
- SRAM ⼀般单⼝,单⼝ SRAM 的⾯积功耗更⼩,⽽且带来的性能损失⾮常⼩; 双⼝的主要是⾯积⽐较⼤,如果将来总容量很⼤的话,那么 floorplan 上⽐较难处理,时序也就难于上去了。
- SRAM ⼀般做成⽅形的结构,⽐如 64*64, ⻓形结构像 1024*8 是不好的
负责 DCache 数据 data 的存储与读写, 每个 bank 有⼀个读⼝和⼀个写⼝
假设 32Kb cache; SRAM row = 64 bits; 4 个 bank; 4 way 组关联 => ⼀共有 128 个 Sets 也就是说:
- numBanks b = 4
- numSets s = 128
- rowBits r = 64
- SRAM entries = numSets * (cache line size / (numBanks * rowBits)) = 128 * (512 / (4 * 64)) = 256
| 信号 | 方向 | 源 | 目的 | 信号组名 | 位宽 | 描述 |
|---|---|---|---|---|---|---|
| clock | input | |||||
| reset | input | |||||
| rvalid | input | Main pipe | Data Array | read_req | 1 | |
| rready | output | Data Array | Main pipe | read_req | 1 | |
| rsetIdx | input | Main pipe | Data Array | read_req | log2Up(nSets) | |
| rbankIdx | input | Main pipe | Data Array | read_req | log2Up(nBanks) | |
| rwayEn | input | Main pipe | Data Array | read_req | nWays | |
| resp | output | Data Array | Main Pipe | read_resp | nWays _ (nBanks _ rowBits) | |
| wvalid | input | Main pipe | Data Array | write_req | 1 | |
| wready | output | Data Array | Main pipe | write_req | 1 | |
| wsetIdx | input | Main pipe | Data Array | write_req | log2Up(nSets) | |
| wbankIdx | input | Main pipe | Data Array | write_req | log2Up(nBanks) | |
| wwayEn | input | Main pipe | Data Array | write_req | nWays | Pop count = 1 |
| wdata | input | Main pipe | Data Array | write_req | nBanks * rowBits | |
| wmask | input | Main pipe | Data Array | write_req | nBanks * rowWords | |
假设 32Kb cache; SRAM row = 64 bits; 4 个 bank; 4 way 组关联 => ⼀共有 128 个 Sets
负责 DCache tag 与 coherence meta 的存储与读写
| 信号 | 方向 | 源 | 目的 | 信号组名 | 位宽 | 描述 |
|---|---|---|---|---|---|---|
| clock | input | |||||
| reset | input | |||||
| rvalid | input | Main pipe | Meta Array | read_req | 1 | |
| rready | output | Meta Array | Main pipe | read_req | 1 | |
| rsetIdx | input | Main pipe | Meta Array | read_req | log2Up(nSets) | |
| rwayEn | input | Main pipe | Meta Array | read_req | nWays | |
| resp | output | Meta Array | Main Pipe | read_resp | nWays * metaBits | |
| wvalid | input | Main pipe | Meta Array | write_req | 1 | |
| wready | output | Meta Array | Main pipe | write_req | 1 | |
| wsetIdx | input | Main pipe | Meta Array | write_req | log2Up(nSets) | |
| wwayEn | input | Main pipe | Meta Array | write_req | nWays | Pop count = 1 |
| wdata | input | Main pipe | Meta Array | write_req | metaBits | |
- s0:
- ⽤物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 从 metaArray 读的 meta 结果和后续 forward 过来的 meta 结果中选出最新的 meta,判断 way
$w$ hit - 从 data array 以及 store-to-load forwarding 的数据中选出最新的 way
$w$ 的 data - 通过 loadGen 组织好数据(size & signed),返回 resp
- 更新 replacer (way
$w$ 是最近被访问的)
- 从 metaArray 读的 meta 结果和后续 forward 过来的 meta 结果中选出最新的 meta,判断 way
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 根据最新的 meta 结果,判定为 cache miss;
- 分配 mshr entry, 开始将 req 写入 mshr entry
- 返回 resp
- s2 进⼊ mshr 状态机: - Refill: 向 L2 请求数据,写⼊ Refill buffer - Refill 完成: - MSHR 发送 replace req 进⼊ main pipeline, 读出被替换的数据,如果是 dirty 的则写⼊ wb queue; s1 请求 replacer 获得 victim way; 然后将 refill 数据覆盖原来的 victim way; 更新 replacer (具体过程⻅ replace)

- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 从 metaArray 读的 meta 结果和后续 forward 过来的 meta 结果中选出最新的 meta,判断 way
$w$ hit ; - 从 data array 以及 store-to-load forwarding 的数据中选出最新的 way
$w$ 的 data - 返回 resp
- 通过 storeGen 组织好要写入的数据(size & signed),与之前读出来的 way
$w$ 数据合并到一起 - 更新 replacer (way
$w$ 是最近被访问的)
- 从 metaArray 读的 meta 结果和后续 forward 过来的 meta 结果中选出最新的 meta,判断 way
- s2:传递 meta/data 更新数据
- s3:
- 将数据写⼊ data array
- 更新 meta 中的 coherence state
• s4: meta/data array 写⼊完成
- s0:
- ⽤物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 根据最新的 meta 结果,判定为数据存在但没有权限的 cache miss;
- 通过 storeGen 组织好要写⼊的数据(size & signed),与之前读出来的 way
$w$ 数据合并到⼀起 - 分配 mshr entry, 开始将 req 写⼊ mshr entry
- s2
- pipeline 中进⾏ meta 传递, 并且将 store 数据传⼊ mshr
- s2 进⼊ mshr 状态机:
- Refill: 向 L2 请求数据,写⼊ Refill buffer
- Refill 完成:
- 请求 replacer 分配 victim way
- 合并 store 的数据到 refill 数据
- MSHR 发送 replace req 进⼊ main pipeline, 读出被替换的数据,如果是 dirty 的则写⼊ wb queue; 然后将 refill 数据覆盖原来的 victim way
- s3: 将对应的 meta 清空 (防⽌后续 load 请求发⽣ cache hit)
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,数据不存在;判定为没有数据的 cache miss
- 分配 mshr entry, 开始将 req 写入 mshr entry
- s2 进入 mshr 状态机:
- Refill: 向 L2 请求数据,写入 Refill buffer
- Refill 完成: - 合并 store 的数据到 refill 数据
- MSHR 发送 replace req 进入 main pipeline, 请求 replacer 分配 victim way, 读出被替换的数据,如果是 dirty 的则写入 wb queue; 然后将 refill 数据覆盖原来的 victim way
整体过程见 load cache miss
如果保证 ordering
aq/rl 的⽀持
- ⾹⼭对于 lr/sc 的特殊⽀持
RISC-V spec 定义了 constrained LR/SC loops (参⻅ Volume I: RISC-V Unprivileged ISA: 8.3 Eventual Success of Store-Conditional Instructions). 受到 Rocket 的启发, ⾹⼭提供了类似的机制来处理 constrained LR/SC loops.
在 lr 指令执⾏之后, 处理器会依次进⼊以下三种状态:
- 阻塞对当前核当前 cacheline 的所有 probe 请求并阻塞后续 lr 的执⾏, 持续⼀段时间 (lrscCycles - LRSCBackOff cycles)
- 持续阻塞后续 lr 的执⾏, 但允许对这⼀ cacheline 的 probe 请求执⾏, 持续⼀段时间 (LRSCBackOff cycles)
- 恢复到正常状态
对于⾹⼭(南湖), 在 lrscCycles - LRSCBackOff 周期内, constrained LR/SC loop (最多 16 条指令) ⼀定能执⾏完. 在这段时间内, 对 LR 所设置的 reservation set 中地址的 probe 操作将会被阻塞. 当前 hart 能不被打扰的执⾏⼀个成功的 SC. 随后的 LRSCBackOff 周期内后续的 lr 不会执⾏, 来防⽌两个核同时执⾏ lr, 结果两者都不能接受 probe 请求, 两者都拿不到权限从⽽卡死的情况. 加⼊这个退避阶段后, 来⾃其他核的 probe 请求可以取得 cacheline 的权限.
RISC-V 对 LR 和 SC 之间的指令是有限制的,⼀个是 LR 和 SC 之间最⼤只能包含 16 个指令, 另外这些指令只能使⽤基础整数指令集(指令集 "I",不包含内存访问指令,跳转指令, fence 和 system 指令)。如果违反了这些限制,LR/SC 指令的效果是不受约束的
lr/sc 指令,锁定的地址是 8-byte 对⻬的
- lrscCycles: 80 (worst case is 14 mispredicted branches + slop)
- lrscBackoff: 3 (disallow LRSC reacquisition briefly)
根据这两个参数,lr/sc 分成了三个阶段:
- Lrsc stage1: 阻塞对当前核当前 cacheline 的所有 probe 请求并阻塞后续 lr 的执行, 持续一段时间 (lrscCycles - LRSCBackOff cycles)
- Lrsc stage2: 持续阻塞后续 lr 的执行, 但允许对这一 cacheline 的 probe 请求执行, 持续一段时间 (LRSCBackOff cycles)
- Lrsc stage3: 恢复到正常状态
- lr 指令进入 pipeline
- s0
- 请求进入 cache
- 读取 tag 和 data
- s1
- tag check and way muxing。找到 match 的 way
- 判定 cache hit, 返回 cache resp
- 在 s1 阶段,如果是 lr 指令,则将 lrsc_count 置为 lrscCycles, 记录请求的地址,进入 lrsc stage 1
- s0
- 等待 sc 指令的到来:每个 cycle, lrsc_count-1
- sc 指令进入 pipeline
- s0 同上
- s1
- 判定 cache hit
- 如果是 sc 指令,判定
- 请求进入 cache
- 读取 tag 和 data
- 判定 cache hit
- s1
- tag check and way muxing。找到 match 的 way
- 判定 cache hit, 返回 cache resp
- 在 s1 阶段,如果是 lr 指令,则将 lrsc_count 置为 lrscCycles , 记录请求的地址, 进入 lrsc stage 1
- 等待 sc 指令的到来:每个 cycle, lrsc_count-1;
- sc 指令进入 pipeline
- s0 同上
- s1
- 判定 cache hit
- 如果是 sc 指令,判定
- lrsc_count- LRSCBackOff > 0
- Address match
- 如果是 sc 指令,判定
- Reset lrsc_count
- 判定 cache hit
如果 lr 发生了 cache miss, 则分配 mshr, refill 数据/replace 完成之后,lr 指令重发进行 redo
sc success 和 fail resp 的 hasData 都为 true, success data = 0, fail data = 1
resp status cpu 侧不关心,现在 sc hit 还是返回 hit(hit 不代表 success), sc miss 返回 miss
- s0:
- ⽤物理地址同时请求 data array 和 meta array
- 获得 s1/s2 forward 的 meta 和 data
- s1:
- 获得 tag 结果,判断 way w hit
- 获得 n 路 data array 结果,选出 way w 的 data
- 通过 LoadGen 组织好数据,返回 resp
- 更新 replacer
- s2: 通过 AMOALU 计算写⼊ cache 的数据
- s3:
- 将数据写⼊ data array
- 更新 meta 中的 coherence state
- s4: meta/data array 写⼊完成
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,判定为 miss
- 分配 IOMSHR, 开始将 req 写入 IOMSHR
- s2 进入 iomshr 状态机:
- IOMSHR 通过 tilelink 发起 atomics 操作,获取数据并向下层 cache 写入
- refill 完成,返回结果,不再写入 cache
- 由于 L2 没有处理 AMO 请求的能力,需要在 L1 的 MSHR 中处理 Data/Permission Miss 的 AMO 请求,涉及的一些关键点如下:
- 为了保证 Permission Miss 的 AMO 请求可以被正确处理,在 MSHR 中添加了存储 AMO 数据的 Array(64b * 8),当出现 Data/Permission Miss 时将 Core 发来的原始数据存入其中,且 Permission Miss 时会将 CacheLine 中的原数据也给入 MSHR
- 在 MSHR 中,AMO 请求不可以和任何同地址的 Store 请求合并,如果出现则需要持续 Replay 流水线直至 Refill 完成
- 同地址有前序的一条/多条 Store Req 时,AMO 需要 Replay
- MSHR Entry 有 AMO 指令,后续的 Store/AMO 需要 Replay
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 根据最新的 meta 结果,判定为数据存在但没有权限的 cache miss
- 分配 mshr entry, 开始将 req 写入 mshr entry
- s2:
- pipeline 中进行 meta 传递, 并且将原数据(512b)和新数据(64b)传入 mshr
- s2 进入 mshr 状态机:
- Refill: 向 L2 请求数据
- L2 返回权限之后
- MSHR 中的 amoalu 计算写回 cache 的数据
- MSHR 发送 replace req 进入 main pipeline 进行 replace
- s3: 将对应的 meta 清空(防止后续 load 请求发生 cache hit)
- s0:
- ⽤物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,数据不存在;判定为没有数据的 cache miss
- 分配 mshr entry, 开始将 req 写⼊ mshr entry
- s2 进⼊ mshr 状态机:
- pipeline 中进⾏ meta 传递, 并且将新数据(64b)传⼊ mshr
- Refill: 向 L2 请求数据,写⼊ Refill buffer
- Refill 完成:
- Refill: 向 L2 请求数据
- L2 返回数据之后
- MSHR 中的 amoalu 计算写回 cache 的数据
- MSHR 发送 replace req 进⼊ main pipeline 进⾏ replace
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,判定 probe 地址不存在
- 将 probe 请求相关的信息发送给 writebackUnit
- s2:
- WritebakUnit 通过 tilelink 向 L2 发送 probe ack
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,判定 probe 地址存在,并且 clean
- probe 请求相关的信息发送给 writebackUnit(后续 writeback unit 通过 tilelink 向 L2 发送 ProbeAck)
- s2: pipeline 传递信息
- s3:
- 清除对应的 meta array / data array 数据
- s0:
- 用物理地址同时请求 data array 和 meta array
- 获得 s1/s2/s3 forward 的 meta 和 data
- s1:
- 获得 tag 结果,判定 probe 地址存在,并且 clean
- probe 请求相关的信息发送给 writebackUnit(后续 writeback unit 通过 tilelink 向 L2 发送 ProbeAckData)
- s2: pipeline 传递信息
- s3:
- 清除对应的 meta array / data array 数据
- s0:
- 用 set index 同时请求 data array 和 meta array
- s1:
- 请求 replacer 获得 victim way
- 获得 victim way 的 meta 结果, 选出 data
- 如果要 replace, 并且 replace way 处于 dirty 状态,则将其数据写入 wb queue
- 更新 replacer
- 通知 MSHR 当前 replace 过程已经完成
- s2: 传递 meta/data 更新的数据
- s3: meta/data array 写⼊
- s4: meta/data array 写⼊完成
对于 Prefetch 请求,不保证能够进行处理,有如下注意点:
- Prefetch 指令不会返回 resp
- Prefetch 指令,cache hit 的条件是 tag match, 不检查 permission
- Cache miss 则 allocate mshr, allocate 不成功则直接丢弃,不需要 replay
- Probe Req
- Replace Req
- Core Req
- Choice 1: Cache Refill 的时候 allocate victim way [we choose]
- Pros: don't need to lock
- Cons: need to read cacheline (to writeback) again when refill
- Choice 2: Cache Miss 的时候 allocate
- Pros: only need to read cacheline once
- Cons: need lock cache line
Cache miss 的时候选择数据进⾏替换
MSHR 在 Refill 完成后,请求 replacer 获得 victim way
⻅ Rocket
- SetAssocLRU
- SetAssocPLRU
⻅ 5.6 Replace
总体设计:
Feature:
-
MSHR 可以 merge 多条访存指令, 此过程中:
- TL-A 发出 Acquire 之前的指令可以合并,合并过程中保留指令顺序用于 replay,合并后会对发出的权限进行直接修改,取最高权限;注意点:连续的 Store 请求可以直接合并为一个请求,但是在出现 [Store -> Load -> Store] 时第二个 Store 不可以被合并入 MSHR(因为每个 MSHR Entry 只能存储一个 512 的 Store Data),此时会要求 Cache Pipeline 进行 Replay
- TL-A 发出 Acquire 之后但是开始 Replay 之前的指令如果想要合并入 MSHR,需要查看
-
- 没有出现 [Store -> Load -> Store] 的请求组合
-
- 如果 Acquire 之前只有 Load 指令(则发出了对 B 权限的请求),则后续的 Store 请求因为权限不够不能合并入 MSHR,需要进行 Replay 直到拥有 B 权限的 Cacheline Refill
-
-
开始 Refill ReplayReg / Replay / Refill Cache 过程中出现的同地址 miss 需要被 replay 直到写回 cache
-
IOMSHR 发出的请求不涉及 Cache Coherence 的问题,每个 Entry 只处理单个指令,不存在 merge 的功能
-
MSHR 和 IOMSHR 包含在 MSHR Wrapper 这个顶层模块中,二者会对每个进入顶层模块的请求的地址进行匹配查询,此时可能会出现以下几种情况:
| Req Inst Dest | Addr Hit Region | Final Dest | Behaviour |
| MSHR | IOMSHR | MSHR | Replay |
| IOMSHR AMO | MSHR | IOMSHR | Replay |
| IOMSHR MMIO | MSHR | IOMSHR | Error (MMIO Addr Can't Acquire MSHR) |
| IOMSHR Bypass | MSHR | MSHR | Merge to MSHR |
- First Col: the destination of the current req (secondary req)
- Second Col: which module holds the current req addr (where primary req saved in)
- Third Col: where the req will be finally putted into
Feature:
- MSHR Table / Replay Table / IOMSHR Table Coupling
- Replay On [Refill Buffer → Replay Reg]
- Priority: Probe > Replay > Allocate
- Don't allow send Read(Get S) and receive Write miss Req: Block and Replay on Cache Pipeline
- Only allow Read -> Write -> Read, subsequent Write requests can be received
About Replace:
MSHR 在 refill 完成之后:
- 请求 replacer 选择 victim way
- 构建 replace_req 进入 main pipeline (replace_req 进入 main pipe 之后,不允许对该 victim way 的访问请求进入 pipeline)
- s0 读取 victim way 信息,接收 store-to-load forwarding 数据
- s1 读取完成,将 dirty 数据写入 wb buffer
- s2 读取 replay reg, 开始覆盖 victim way
- s3 覆盖完成
mode_idle:空闲的 MSHR Entrymode_req_enqueue:将本条 MSHR 的 ID 放入到 mshr_req_queue 中,到 Queue 发送到本 ID 的请求时向 MSHR 发送唤醒请求,向 L2 发送的数据从 MSHR 内部直接发送;(为了解决:原 Miss 为 load,在等待发射时后续有 Miss 的 Write 指令进入,需要提高本次请求的权限,此情况下直接将 Current Permission 设置为 M)mode_resp_wait:等待总线的数据回传到 Refill Queue 中,等待数据返回后进入mode_replay状态,将 Refill Queue 中的数据读入 Replay Reg 对其进行 Replaymode_replay:当本 MSHR 条目为 Refill Queue 中第一条可用的数据,将其放入 Replay Reg,并使用 MSHR 中存储的 Replay Inst 对 Replay Reg 中存储的 Cache Line 进行 Replay;转换到本状态后向 WriteBack Queue 发送写回 Enable 以及 Tagmode_refill:write back 和 replay 都已经完成,从 replay reg 中对 cache line 进行 refill
Notice:
- 为了减少正常流水线上 Dcache 读写过程中需要查询的 DRAM/Regfile 数量,Refill Buffer, Replay Reg 中的 Tag 及数据都不可被查询
| 信号 | 源 | 目的 | Sub Bundle | 位宽 | 描述 |
| clock | 1 | 时钟信号 | |||
| reset | 1 | 异步复位信号(0 使能) | |||
| Cache Pipeline | |||||
| io_pipelineReq_valid | Cache pipeline | MSHR | 1 | S1 出现 Miss 时请求 MSHR 分配 Entry | |
| io_pipelineReq_tag | PTAG_WIDTH | 出现 miss 的物理地址 tag | |||
| io_pipelineReq_rw_type | meta | 1 | write(1)/read(0) | ||
| io_pipelineReq_regIDX | destWidth | 对于 scalar 来说,是寄存器地址,对于 vector 来说,是 vlsu queue index | |||
| io_pipelineReq_typ | log2Up(log2Up(dataBytes)) | 操作的数据的大小 | |||
| io_pipelineReq_signed | 1 | ||||
| io_pipelineReq_addrIdx | PIDX_WIDTH | 物理地址的 index | |||
| io_pipelineReq_mask | VLEN/8 | 以 byte 为最小宽度的 mask | |||
| io_pipelineReq_data | VLEN | 数据总长度(512) | |||
| io_pipelineReq_ready | MSHR | Cache pipeline | 1 | MSHR 是否有空闲单元/是否存在冲突/是否有上位请求 | |
| io_toL2Req_valid | MSHR | TileLink | 1 | ||
| io_toL2Req_priv | 1 | 请求的权限 write(1)/read(0) | |||
| io_toL2Req_tag | PTAG_WIDTH | 请求的物理地址 | |||
| io_toL2Req_ready | TileLink | MSHR | 1 | tilelink 允许发送请求 | |
| io_fromRefill_valid | Refill Queue | MSHR | 1 | Refill queue 中存在可用的数据 | |
| io_fromRefill_tag | PTAG_WIDTH | ||||
| io_fromRefill_data | VLEN | ||||
| io_fromRefill_ready | MSHR | Refill Queue | 1 | ||
| io_fromProbe_valid | Probe Unit | MSHR | 1 | ||
| io_fromProbe_tag | PTAG_WIDTH | ||||
| io_fromProbe_probeReady | MSHR | Probe Unit | 1 | MSHR 中存在与 Probe 请求相同 tag 的 entry | |
| io_toPipeline_valid | MSHR | Cache pipeline | 1 | MSHR Replay Read 命令后向 cache pipeline 发起写回请求 | |
| io_toPipeline_regIdx | destWidth | ||||
| io_toPipeline_regData | VLEN | ||||
| io_toPipeline_ready | Cache pipeline | MSHR | 1 | ||
| io_toReplace_valid | MSHR | Pipe s0 | 1 | 向 S0 发出的 replace 请求信号 | |
| io_toReplace_priv | 读回的 miss 的 cacheline 的权限 | ||||
| io_toReplace_tag | PTAG_WIDTH | ||||
| io_toReplace_data | VLEN | 在 S2 阶段发出的 replay reg 中的数据 | |||
| io_toReplace_ready | Pipe s0 | MSHR | 1 | S0 接收 replace 请求完成 | |
| io_replaceFinish | Pipe s2 | MSHR | 1 | S2 在当前周期完成接收 replay reg 中的数据 |
For Processing MMIO / Read Bypass MSHR / AMO
通过 TileLink 的 Atomic 指令直接实现
通过 IOMSHR 向总线发起请求,并将 Read 的请求进⾏ Replay
设计中的 Bypass 指 LSU 需要但 Miss 的数据不会先写入 DCache 再写入 LSU:
LSU Read:
- Hit:直接从 DCache 中读出并写入 LSU
- Miss:由 IOMSHR 记录缺失信息,当需要的数据返回时直接从 Refill Queue 写入 LSU(IOMSHR 不需要对 Cache 有写请求)
LSU Write:
- 直接从 LSU 写入 DCache,不存在 Bypass
(数据存在的话,cache hit 或者 cache miss 通过原来 mshr 通道去发送;数据不存在,通过 IOMSHR 的 get/put 发送请求)
- AMO 范围内的访问直接使⽤ LogicalData / ArithmeticData 两种请求
- MMIO 范围内的访问直接使⽤ put / get
- Bypass 范围内的请求,load 直接使⽤ get,store 请求需要查看对应的请求命令是否为 M_PWR,如果是 partial store 则使⽤ PutPartialData,否则使⽤ put
mode_idle: 初始状态mode_amo_req: 使⽤ TileLink 的原⼦接⼝发送,收到 grant 后转回初始状态mode_wb: 需要 Bypass Cache 的数据如果 hit 且 Dirty,则需要 Write Backmode_inv_line: invalidate hit 的 Cache Linemode_req_enqueue: 将需要向下发送的数据/地址 Enqueuemode_resp_wait: 等待返回相应mode_replay: 如果 MMIO 请求为 Read,则对其进⾏ Replaymoe_fill_LSU: 如果为 Bypass 请求,则从 Refill Queue 中直接写⼊ LSU
WritebackQueue 接收 Cache 替换块以及组织对 probe 请求的响应,返回给 L2
- 对于 probe 请求,给 L2 发送 probeAck[C]
- 对于 release,给 L2 发送 Release[C], 并且等待 L2 返回 ReleaseAck[D]
- MSHR 在发送 pending Grant 时,不能发送相同地址的 Release; 也就是说 miss 的地址不能出现在 WBU 中 (=> miss check)
- 对于相同地址的 writeback 请求,需要保序或者合并 (=>FIFO Queue)
| 信号 | 方向 | 源 | 目的 | 信号组名 | 位宽 | 描述 |
| clock | input | 1 | 时钟信号 | |||
| reset | input | 1 | 异步复位信号 | |||
| io_req_ready | output | WBU | Pipeline | WritebackReq | 1 | |
| io_req_valid | input | Pipeline | WBU | 1 | ||
| io_req_lineAddr | input | Pipeline | WBU | lineAddrWidth | 写回的 line addr | |
| io_req_perm | input | Pipeline | WBU | TODO | permission | |
| io_req_hasData | input | Pipeline | WBU | 1 | 是否携带数据 | |
| io_req_data | input | Pipeline | WBU | dataWidth | 要写回的数据 | |
| io_req_voluntary | input | Pipeline | WBU | 1 | release 是 voluntary; probe 则不是 voluntary | |
| io_missCheck_valid | Input | Pipeline | WBU | Miss | 1 | 查找 miss 的 addr 是否在 WBU 中存在,如果存在返回 block |
| io_missCheck_lineAddr | Input | Pipeline | WBU | lineAddrWidth | ||
| io_missCheck_blockMiss | Output | WBU | Pipeline | 1 | ||
| io_release_X | Tilelink C 通道;发送 release/ProbeAck[Data] | |||||
| io_grant_X | Tilelink D 通道;接收 ReleaseAck |
- enqPtr: wb req 进⼊时加 1
- deqPtr: wbFinish 时加 1(ProbeAck 发送出去/Release 收到 ReleaseAck)
- s_invalid: 复位状态,该 Entry 为空项
- s_release_req: 正在发送 Release 或者 ProbeAck 请求
- s_release_resp: 等待 ReleaseAck 请求
- s_invalid
- 条件:接收到 wbReq
- 动作:存储 req 到寄存器
- 下一个状态:s_release_req
- s_release_req
- 动作:组织当前 beat 的数据和 tilelink message, 发送
- 下一个状态
- 所有 beats 发送完成且为 probe:s_invalid
- 所有 beats 发送完成且为 release:s_release_resp
- beats 未发送完成: s_release_req
- s_release_resp
- 下一个状态:
- 接收到 releaseAck:s_invalid
- 未接收到 releaseAck:s_release_resp
- 下一个状态:
WBU 的地址有两个来源:
- Probe
- Replace
限制: MSHR 在发送 pending Grant 时,不能发送相同地址的 Release 也就是说 miss 的地址不能出现在 WBU 中
当 Writeback queue full 的时候,不能再接收来⾃ probe queue 以及 mshr replace 的数据:
- probequeue 收到 s1 阶段 wb 不 ready 的信号,会重发当前的 probe 请求
- mshr 同理
probeQueue 接收下层或者别的 core 的 cache 发送来的 coherence requests,向 cache main pipeline 发送请求
| 信号 | 方向 | 源 | 目的 | 信号组名 | 位宽 | 描述 |
| clock | input | 1 | 时钟信号 | |||
| reset | input | 1 | 异步复位信号 | |||
| io_memProbe_X | Input | ProbeUnit | 与 L2 交互的 B 通道 | |||
| io_mainPipeReq_X | Output | Main Pipe | 将 probe 请求发送给 main pipeline | |||
| io_probeResp | Input | Main Pipe | ProbeUnit | pipeline 返回给的 probe 请求的处理情况,有 invalid/finish/replay 集中情况 | ||
| io_lrscAddr_valid | Input | 1 | constrained LR/SC loop 执行期间,对 LR 所设置的地址块的 probe 操作需要被阻塞 | |||
| io_lrscAddr_bits | Input | |||||
| io_probeCheck_valid | Ouput | 1 | ||||
| io_probeCheck_lineAddr | Output | lineAddrWidth | ||||
| io_probeCheck_block | Input | 1 | ||||
| io_wbReq_X |
- s_invalid: 复位状态,该 Entry 为空项
- s_check_mshr: 检查 mshr 是否有相同地址请求
- s_wait_mshr: 等待 Mshr 完成
- s_pipe_req: 可以向 pipeline 发出 probe 请求。发出条件为 MSHR 以及 Pipeline 中没有对该地址的请求,lrsc 也不处于 lrsc stage1
- s_wb_req: probe 请求进⼊ writebackQueue
- s_wait_resp: 等待 pipeline 响应
Probe 指令在进⼊ DCache 后,会先请求 MSHR,查看其中是否存在相同的地址,然后进⾏后续的操作,MSHR 中相同地址的请求及其状态会影响 Probe 的后续执⾏。访问 MSHR 后放回的信号有以下两个:
| 信号 | ⽅向 | 源 | ⽬的 | 信号组名 | 位宽 | 描述 |
|---|---|---|---|---|---|---|
| hit | output | 1 | MSHR 中存在与 Probe 地址相同的 Entry | |||
| pass | output | 1 | MSHR/Reill Queue 中对应 Entry 的状态允许放⾏ Probe 指令进⼊ Cache Pipeline |
| Probe MSHR State | Encode | Description |
|---|---|---|
| miss | 00 | Not hit in MSHR |
| hitGo | 01 | Hit in MSHR, but can complete immediately (No need to acquire meta & data Array) |
| hitBlockN | 10 | Hit in MSHR, may need to be blocked, depend on refill queue |
| hitBlockB | 10 | Hit in MSHR, need to be blocked |
根据 MSHR 和 Reill Queue 中的数据判断是否可以放⾏ Probe 请求(以下判断条件⾄少满⾜ hit=1):
| Data In RefillQ | Data Not In RefillQ | |
|---|---|---|
| BtoT | !pass && State -> NtoT | pass |
| NtoB | !pass | pass |
| NtoT | !pass | pass |
MSHR:
Feature: 当出现冲突时直接阻塞 Probe 直到数据写回 meta & data Array,然后允许 Probe 进入流水线执行;后续可以改成将 Probe 信息融合到 MSHR Entry 中,让 Probe 可以乱序执行
- BtoT:
- toN Probe & (两个核同时请求 T 权限)后拿到权限: MSHR 中存在 Entry 但是 Refill Queue 中没有 -> NtoT(Probe 先于 Replay 执行),Probe 直接执行完成(ProbeAck)
- toN Probe & (两个核同时请求 T 权限)先拿到权限: MSHR 中存在 Entry 且 Refill Queue 中存在,Refill Queue 数据被前面阻塞,阻塞 toN(Replay 先于 Probe 执行),replay & refill 执行完成后允许 Probe 进入流水线执行(ProbeAckData)
- toB Probe: 阻塞直到 replay & refill 完成,允许 Probe 进入流水线执行(ProbeAckData)
- NtoB:
- toN Probe & (另外一个 Master 同时请求 T 权限)后拿到权限: Probe 直接完成(ProbeAck)
- toN Probe & (另外一个 Master 同时请求 T 权限)先拿到权限: MSHR 中存在 Entry 且 Refill Queue 中存在,Refill Queue 数据被前面阻塞,阻塞 toN(Replay 先于 Probe 执行),replay & refill 执行完成后允许 Probe 进入流水线执行(ProbeAck)(可以直接将 Probe 标记为完成,不让数据写回 meta & data Array,后续再改)
- toB Probe: Probe 直接完成(ProbeAck)
- NtoT:
- toN Probe & (两个核同时请求 T 权限)后拿到权限: MSHR 中存在 Entry 但是 Refill Queue 中没有(Probe 先于 Replay 执行),Probe 直接执行完成(ProbeAck)
- toN Probe & (两个核同时请求 T 权限)先拿到权限: MSHR 中存在 Entry 且 Refill Queue 中存在,Refill Queue 数据被前面阻塞,阻塞 toN(Replay 先于 Probe 执行),replay & refill 执行完成后允许 Probe 进入流水线执行(ProbeAckData)
- toB Probe: 阻塞直到 replay & refill 完成,允许 Probe 进入流水线执行(ProbeAckData)
| MSHR 权限升级 | Probe 权限降级 | 两核竞争权限时先拿到还是后拿到 | MSHR 和 RefillQueue 的情况 | 处理过程 |
|---|---|---|---|---|
| B->T | -> N | 先 | MSHR 中存在 Entry Refill Queue 中存在 Entry |
[Replay -> Probe] 阻塞 Probe MSHR replay & refill 执行完成后允许 Probe 进入流水线执行 |
| 后 | MSHR 中存在 Entry Refill Queue 中没有 Entry |
[Probe -> Replay] Probe 请求直接通过 Writeback Queue 发送 ProbeAck BtoN MSHR 请求权限变为 N->T |
||
| -> B / -> T | 先 | MSHR 中存在 Entry Refill Queue 中存在 Entry |
[Replay -> Probe] 阻塞 Probe MSHR replay & refill 执行完成后允许 Probe 进入流水线执行 |
|
| 后 | MSHR 中存在 Entry Refill Queue 中没有 Entry |
[Probe -> Replay] Probe 请求直接通过 Writeback Queue 发送 ProbeAck BtoB |
||
| N->B | -> N / -> B / -> T | 先 | MSHR 中存在 Entry Refill Queue 中存在 Entry |
[Replay -> Probe] 阻塞 Probe MSHR replay & refill 执行完成后允许 Probe 进入流水线执行 |
| 后 | MSHR 中存在 Entry Refill Queue 中没有 Entry |
[Probe -> Replay] Probe 请求直接通过 Writeback Queue 发送 ProbeAck NtoN |
||
| N->T | -> N / -> B / -> T | 先 | MSHR 中存在 Entry Refill Queue 中存在 Entry |
[Replay -> Probe] 阻塞 Probe MSHR replay & refill 执行完成后允许 Probe 进入流水线执行 |
| 后 | MSHR 中存在 Entry Refill Queue 中没有 Entry |
[Probe -> Replay] Probe 请求直接通过 Writeback Queue 发送 ProbeAck NtoN |
LR/SC 指令执⾏过程分成 3 个阶段:
- Lrsc stage1: 阻塞对当前核当前 cacheline 的所有 probe 请求并阻塞后续 lr 的执⾏, 持续⼀段时间 (lrscCycles - LRSCBackOff cycles)
- Lrsc stage2: 持续阻塞后续 lr 的执⾏, 但允许对这⼀ cacheline 的 probe 请求执⾏, 持续⼀段时间 (LRSCBackOff cycles)
在 Lrsc stage1 的时候,需要阻塞 probe 请求
Feature:
- Acquire Perm ⽐ Acquire Data 的请求占⽤ Refill Queue 接⼝的优先级更⾼,因此可能出现后接收到 TL-D Grant 的地址先 Refill MSHR 的情况
- Load A hit -> Load B hit
- Load A miss
- A 未 refill: B 成为 secondary miss, merge 到 A 的 mshr
- A replayreg 拿到数据准备 replay/refill: B 需要在 s1 阶段返回 replay
- A refill 写⼊ cache 完成: Load B hit
- Load A hit
- A 权限>Branch, Store B hit
- A 权限<=Branch, Store B miss, 处理过程⻅ 6.2.2
- Load A miss
- A 向 L2 的 acquire 请求未发出: B 成为 secondary miss, merge 到 A 的 mshr, 发出更⾼权限的请求
- A 向 L2 的 acquire 请求已发出: B 在 s1 阶段返回 replay
- A refill 写⼊ cache: Store B miss
Version 1:
- A 向 L2 的 acquire 请求已发出: B merge 进 mshr, A refill 的数据回来后,同时做两件事
- a. 发送 acquire B 对应权限的请求
- b. 对于 A 及其之后,B 之前的 load 指令,返回结果
- Store A hit -> Load B hit
- Store A 数据/权限缺失 miss
- A refill 未完成: B merge 进 mshr
- A repaly/refill 过程中: B 在 s1 阶段返回 replay
- A refill 写⼊ cache: Load B hit
补充: Store A -> Load B -> Store A
在 miss 的情况下第三条 storeA ⼀定在 s1 阶段返回 replay
- Store A hit -> Store B hit
- Store A miss
- A refill 未完成: B merge 进 mshr
- A repaly/refill 过程中: B 在 s1 阶段返回 replay
- A refill 写⼊ cache: Store B hit
store 将数据和 meta bypass 给 Replace 请求, 写⼊ wb buffer
Ldst A 拿到 replace bypass 的信息, 判定 Ldst A miss
Note: 可以把 A replace 的数据 bypass 给 ldst A
LdstB 在 s1 阶段返回 replay 重发
Version1: MSHR 在 replace 过程中, 仍然允许在 replace 之前进⼊ pipeline 的对 B 的请求 merge 进来, 并且进⾏ replay
Load 从 replay reg 中读取数据
Store 将数据 merge 进 replay reg
⽽ replace 在 s2 才会读 replay reg, 可以保证所有 replace 之前的 store 指令的结果都已经 Merge 进来
B Refill 的数据 bypass 给 ldst B
同 12.1.1
- PFR A hit -> Load B hit
- PFR A miss
- A 未 refill: B 成为 secondary miss, merge 到 A 的 mshr
- A replayreg 拿到数据准备 replay/refill: B 需要在 s1 阶段返回 replay
- A refill 写⼊ cache 完成: Load B hit
同 12.1.2
- PFR A hit
- A 权限>Branch, Store B hit
- A 权限<=Branch, Store B miss, 处理过程⻅ 6.2.2
- PFR A miss
- A 向 L2 的 acquire 请求未发出: B 成为 secondary miss, merge 到 A 的 mshr, 发出更⾼权限的请求
- A 向 L2 的 acquire 请求已发出: B 在 s1 阶段返回 replay
- A refill 写⼊ cache: Store B miss
同 12.1.3
- PFW A hit -> Load/Store B hit
- PFW A miss
- A refill 未完成: B merge 进 mshr
- A repaly/refill 过程中: B 在 s1 阶段返回 replay
- A refill 写⼊ cache: Load/Store B hit
- Load A hit -> PFR B hit 更新 replacer
- Load A miss
- A refill 未完成: PFR B 被丢弃
- A repaly/refill 过程中: PFR B 被丢弃
- A refill 写⼊ cache: PFR B hit 更新 replacer
- Load A hit
- 如果 A 权限是 Branch, PFW B 虽然权限不够,但被视作 hit, 不更改 A 权限到 Tunk, 更新 replacer
- 如果 A 权限>=Trunk, PFW B hit, 更新 replacer
- Load A miss
- A refill 未完成: PFW B 被丢弃
- A repaly/refill 过程中: PFW B 被丢弃
- A refill 写⼊ cache: PFW B 虽然权限不够,但被视作 hit, 不更改 A 权限到 Tunk, 更新 replacer
- Store A hit -> PFR/PFW B hit 更新 replacer
- Store A miss
- A refill 未完成: PFR/PFW B 被丢弃
- A repaly/refill 过程中: PFR/PFW B 被丢弃
- A refill 写⼊ cache: PFR/PFW B hit 更新 replacer
- PFR/PFW A hit -> PFR/PFW B hit 更新 replacer
- PFR/PFW A miss
- refill 未完成: PFR/PFW B 被丢弃
- A repaly/refill 过程中: PFR/PFW B 被丢弃
- A refill 写⼊ cache: PFR/PFW B hit 更新 replacer
- PFR/PFW A hit -> PFR/PFW B hit 更新 replacer
- PFR/PFW A miss
- refill 未完成: PFR/PFW B 被丢弃
- A repaly/refill 过程中: PFR/PFW B 被丢弃
- A refill 写⼊ cache: PFR/PFW B hit 更新 replacer
MMIO Load/Store/AMO B replay 直到 MMIO Load/Store/AMO A 完成并且 deallocate
MMIO 操作不会和 MSHR 有关联
- A 数据已经存在于 cache 或者 MSHR 中, 参照普通的 Load/Store A -> Load/Store B
- A 数据不存在于 cache 和 MSHR
- Bypass Load/Store A miss, 进⼊ IOMSHR
- Load/Store B 需要 replay 直到 Bypass Load/Store A 完成并且从 IOMSHR deallocate
Bypass Load/Store B 和普通 Load/Store B ⾛⼀样的流程
AMO B replay 直到 Bypass Load/Store A 完成并且 deallocate
然后进⼊ AMO 流程
- A 处于 invalid 状态
- Load A allocate ⼀个新的 MSHR entry, AMO B 直接合并进⼊同⼀个 entry
- A 处于 Branch 状态
- AMO B 权限不⾜, allocate ⼀个新的 MSHR entry 进⾏处理
- A 处于 Trunk 或者 Dirty 状态
- AMO B 发⽣ cache hit, 返回结果, 写⼊ cache
- A 处于 invalid / Branch 状态
- Store A allocate ⼀个新的 MSHR entry, AMO B replay 直到 Store A 在 MSHR 中完成并写回 cache
- A 处于 Trunk 或者 Dirty 状态
- AMO B 发⽣ cache hit, 返回结果, 写⼊ cache
AMO A 进⼊ MSHR
AMO/Load/Store B replay 直到 AMO A 完成并且 IOMSHR deallocate
然后进⼊ AMO/Load/Store 流程
- Load A hit
- A 权限>Branch, LR B hit
- A 权限<=Branch, LR B miss, 分配 mshr entry 进⾏处理, 同时 LR replay
- Load A miss
- A 向 L2 的 acquire 请求未发出: LR B merge 到 A 的 mshr, 发出更⾼权限的请求, LR B replay
- A 向 L2 的 acquire 请求已发出: LR B replay
- A refill 写⼊ cache: LR B miss, 分配 mshr entry 进⾏处理, 同时 LR replay
- Store A hit -> LR B hit
- Store A miss
- A refill 未完成: LR B replay
- A repaly/refill 过程中: LR B replay
- A refill 写⼊ cache: LR B hit
只考虑 lr hit 的情况, 因为 lr miss 要 replay ⼀直到 hit
- s1 阶段 lrscCounter > 3
- Load/Store 仍然按照流程返回 hit/miss, lrscCounter 置为 3, 进⼊退避阶段
- s1 阶段 lrscCounter < 3
- Load/Store 仍然按照流程返回 hit/miss
- s1 阶段 lrscCounter > 3
- LR B replay, lrscCounter 置为 3, 进⼊退避阶段
- s1 阶段 lrscCounter < 3
- LR B replay, lrscCounter 保持原有的递减
- s1 阶段 lrscCounter > 3
- Sc hit -> success
- s1 阶段 lrscCounter < 3
- Sc fail
| CMD | Initial Data State | Hit or miss | Transactions | Final Data State |
|---|---|---|---|---|
ReadM_XRDM_PFRM_HLVX |
Nothing | miss | Nothing -> [A] Send AcquireBlock -> [D] Receive GrantData -> [E] Send GrantAck -> Branch |
Branch |
| Branch | hit | Branch | ||
| Trunk | hit | Trunk | ||
| Dirty | hit | Dirty | ||
WriteM_XWRM_PWRM_XSCM_XA_SWAPM_XA_ADDM_XA_XORM_XA_ORM_XA_ANDM_XA_MINM_XA_MAXM_XA_MINUM_XA_MAXU |
Nothing | miss | Nothing -> [A] Send AcquireBlock -> [D] Receive GrantData -> [E] Send GrantAck -> Dirty |
Dirty |
| Branch | miss | Branch -> [A] Send AcquireBlock -> [D] Receive Grant -> [E] Send GrantAck -> Dirty |
Dirty | |
| Trunk | hit | Trunk -> Inside Cache Upgrade Perm -> Dirty |
Dirty | |
| Dirty | hit | Dirty | ||
Write intentionM_XLRM_PFW |
Nothing | miss | Nothing -> [A] Send AcquireBlock -> [D] Receive GrantData -> [E] Send GrantAck -> Trunk |
Trunk |
| Branch | miss | Branch -> [A] Send AcquireBlock -> [D] Receive Grant -> [E] Send GrantAck -> Trunk |
Trunk | |
| Trunk | hit | Trunk | ||
| Dirty | hit | Dirty | ||
Flush (Include Replace)M_FLUSH_ALLM_FLUSH |
Nothing | Nothing | ||
| Branch | Branch -> [C] Send Release -> [D] Receive ReleaseAck -> Nothing |
Nothing | ||
| Trunk | Trunk -> [C] Send Release -> [D] Receive ReleaseAck -> Nothing |
Nothing | ||
| Dirty | Dirty -> [C] ReleaseData -> [D] Receive ReleaseAck -> Nothing |
Nothing | ||
Produce = toBM_PRODUCE |
Nothing | Nothing | ||
| Branch | Branch | |||
| Trunk | Trunk -> [C] Release -> [D] ReleaseAck -> Branch |
Branch | ||
| Dirty | Dirty -> [C] ReleaseData -> [D] ReleaseAck -> Branch |
Branch | ||
CleanM_CLEAN |
Nothing | Nothing | ||
| Branch | Branch | |||
| Trunk | Trunk | |||
| Dirty | Dirty -> [C] ReleaseData -> [D] ReleaseAck -> Trunk |
Trunk | ||
| ProbeBlock (toN) | Nothing | Nothing -> [C] ProbeAck -> Nothing |
Nothing | |
| Branch | Branch -> [C] ProbeAck -> Nothing |
Nothing | ||
| Trunk | Trunk -> [C] ProbeAck -> Nothing |
Nothing | ||
| Dirty | Dirty -> [C] ProbeAckData -> Nothing |
Nothing | ||
| ProbeBlock (toB) | Nothing | Nothing -> [C] ProbeAck -> Nothing |
Nothing | |
| Branch | Branch -> [C] ProbeAck -> Branch |
Branch | ||
| Trunk | Trunk -> [C] ProbeAck -> Branch |
Branch | ||
| Dirty | Dirty -> [C] ProbeAckData -> Branch |
Branch | ||
| ProbeBlock (toT) | Nothing | Nothing -> [C] ProbeAck -> Nothing |
Nothing | |
| Branch | Branch -> [C] ProbeAck -> Branch |
Branch | ||
| Trunk | Trunk -> [C] ProbeAck -> Trunk |
Branch | ||
| Dirty | Dirty -> [C] ProbeAckData -> Trunk |
Branch |

































