From a5192eb4d8829cf69992030a78d7ece77c3eacda Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Wed, 22 Sep 2021 22:29:52 +0800 Subject: [PATCH 1/5] update README.md --- README.md | 54 ++++++------------------------------------------------ 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index f25e48e..4290b0f 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,13 @@ Our awesome `MIPS` CPU written in `SystemVerilog` for Loongson Cup ``` . +├── model <-- IP行为模型 ├── resources <-- 资源包 ├── src <-- CPU设计代码 │ ├── AXI <-- AXI总线交互 │ ├── Cache <-- Cache │ ├── Core <-- CPU核心 +│ ├── Gadgets <-- 小部件 │ ├── CP0 <-- CP0协处理器 │ ├── include <-- 头文件 │ ├── IP <-- 用到的IP @@ -26,53 +28,10 @@ Our awesome `MIPS` CPU written in `SystemVerilog` for Loongson Cup - [ ] 浮点运算单元 - [ ] ~~做一个真的`FPU`~~ :x: - [ ] 浮点运算指令报`Coprocessor Unusable`,同时`CP0`中新增`Cause.CE` :clock3: -- [ ] 新增指令 - -| Status | Instruction | Type | Tier | Comment | -| :----------------: | :-------------------------------: | :------: | :--: | :-------------------------------------- | -| :heavy_check_mark: | `I-Cache Index Invalid` | `SYS` | 2 | | -| :heavy_check_mark: | `I-Cache Hit Invalid` | `SYS` | 2 | | -| :heavy_check_mark: | `D-Cache Index Writeback Invalid` | `SYS` | 2 | :cry: | -| :heavy_check_mark: | `D-Cache Index Store Tag` | `SYS` | 2 | | -| :heavy_check_mark: | `D-Cache Hit Invalid` | `SYS` | 2 | | -| :heavy_check_mark: | `D-Cache Hit Writeback Invalid` | `SYS` | 2 | | -| :heavy_check_mark: | `PREF` | `SYS` | 1 | Treat as `NOP` | -| :heavy_check_mark: | `SYNC` | `SYS` | 1 | Treat as `NOP` (We're strongly ordered) | -| :clock3: | `WAIT` | `SYS` | 2 | | -| :heavy_check_mark: | `TEQ` | `SYS` | 2 | | -| :heavy_check_mark: | `TEQI` | `SYS` | 2 | | -| :heavy_check_mark: | `TGE` | `SYS` | 2 | | -| :heavy_check_mark: | `TGEI` | `SYS` | 2 | | -| :heavy_check_mark: | `TGEIU` | `SYS` | 2 | | -| :heavy_check_mark: | `TGEU` | `SYS` | 2 | | -| :heavy_check_mark: | `TLT` | `SYS` | 2 | | -| :heavy_check_mark: | `TLTI` | `SYS` | 2 | | -| :heavy_check_mark: | `TLTIU` | `SYS` | 2 | | -| :heavy_check_mark: | `TLTU` | `SYS` | 2 | | -| :heavy_check_mark: | `TNE` | `SYS` | 2 | | -| :heavy_check_mark: | `TNEI` | `SYS` | 2 | | -| :clock3: | `CLO` | `ARITH` | 2 | `RT == RD` | -| :clock3: | `CLZ` | `ARITH` | 2 | `RT == RD` | -| :heavy_check_mark: | `MADD` | `ARITH` | 2 | `M`阶段加一个流水级 | -| :heavy_check_mark: | `MADDU` | `ARITH` | 2 | `M`阶段加一个流水级 | -| :heavy_check_mark: | `MSUB` | `ARITH` | 2 | `M`阶段加一个流水级 | -| :heavy_check_mark: | `MSUBU` | `ARITH` | 2 | `M`阶段加一个流水级 | -| :heavy_check_mark: | `MOVN` | `ARITH` | 2 | | -| :heavy_check_mark: | `MOVZ` | `ARITH` | 2 | | -| :x: | `LL` | `MEM` | 3 | 修改内核去除相关指令 | -| :heavy_check_mark: | `LWL` | `MEM` | 1 | | -| :heavy_check_mark: | `LWR` | `MEM` | 1 | | -| :x: | `SC` | `MEM` | 3 | 修改内核去除相关指令 | -| :heavy_check_mark: | `SWL` | `MEM` | 1 | | -| :heavy_check_mark: | `SWR` | `MEM` | 1 | | -| :x: | `BEQL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BGEZALL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BGEZL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BGTZL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BLEZL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BLTZALL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BLTZL` | `BRANCH` | 3 | 修改编译指令 | -| :x: | `BNEL` | `BRANCH` | 3 | 修改编译指令 | +- [x] 新增指令 +- [ ] `Cache`指令修正 + - [ ] 完善 Test Cases + - [ ] 重新阻止流水线结构 (`TLB`转换) ## `Cache`指令 @@ -113,4 +72,3 @@ Hit Writeback Invalid : VA -> Lookup -> Hit? -> (Write Back) -> Write Zero | 1 | 1 | 1 | | | `I-Cache(0) or D-Cache(1)` | `Lookup(0) or Index(1)` | `WriteBack(0) or WriteOnly(1)` | | -`Todo`: 涉及`I-Cache`的`CACHE`指令需要清空流水线 From 4facc2dd10952320a66aec6ca0d0fa3eb2290c15 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Fri, 24 Sep 2021 20:45:55 +0800 Subject: [PATCH 2/5] enhanced test cases --- README.md | 2 +- .../2021/soft/func/inst/n98_cache_dcache.S | 81 ++++++++++ .../2021/soft/func/inst/n99_cache_icache.S | 146 ++++++++++++++++-- resources/2021/soft/func/start.S | 39 ++--- 4 files changed, 237 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 4290b0f..8182e82 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Our awesome `MIPS` CPU written in `SystemVerilog` for Loongson Cup - [ ] 浮点运算指令报`Coprocessor Unusable`,同时`CP0`中新增`Cause.CE` :clock3: - [x] 新增指令 - [ ] `Cache`指令修正 - - [ ] 完善 Test Cases + - [x] 完善 Test Cases - [ ] 重新阻止流水线结构 (`TLB`转换) ## `Cache`指令 diff --git a/resources/2021/soft/func/inst/n98_cache_dcache.S b/resources/2021/soft/func/inst/n98_cache_dcache.S index 63bfc1f..2cfb3c4 100644 --- a/resources/2021/soft/func/inst/n98_cache_dcache.S +++ b/resources/2021/soft/func/inst/n98_cache_dcache.S @@ -222,6 +222,87 @@ TEST_CACHE_DCACHE_HIT(0xa00d0028, 0x800d0028, 4, 0xF0F0F0F0, 0xABCDEFAB) .n98_done: nop +## CACHE 1 D-Cache Index Writeback Invalid + +## Enforced test on writeback whole line + + li t0, 0xa00d0000 + li t1, 0xa00d0800 + li t2, 0xa00d1000 + li t3, 0xa00d1800 + + li v0, 0xa00d000c +.n98_en_rst: + beq t0, v0, .n98_en_w_bgn + nop + sw zero, 0(t0) + sw zero, 0(t1) + sw zero, 0(t2) + sw zero, 0(t3) + addi t0, t0, 4 + addi t1, t1, 4 + addi t2, t2, 4 + addi t3, t3, 4 + j .n98_en_rst + nop + +.n98_en_w_bgn: + li t0, 0x800d0000 + li t1, 0x800d0800 + li t2, 0x800d1000 + li t3, 0x800d1800 + + li v0, 0x800d000c + li a0, 0xa5a50000 +.n98_en_w: + beq t0, v0, .n98_en_chk_bgn + nop + sw a0, 0(t0) + sw a0, 0(t1) + sw a0, 0(t2) + sw a0, 0(t3) + addi t0, t0, 4 + addi t1, t1, 4 + addi t2, t2, 4 + addi t3, t3, 4 + addi a0, a0, 1 + j .n98_en_w + nop + +.n98_en_chk_bgn: + li t0, 0xa00d0000 + li t1, 0xa00d0800 + li t2, 0xa00d1000 + li t3, 0xa00d1800 + li v0, 0xa00d000c + li a0, 0xa5a50000 + + cache 1, 0(zero) +.n98_en_chk: + beq t0, v0, .n98_en_end + nop + lw a1, 0(t0) + bne a0, a1, inst_error + nop + lw a1, 0(t1) + bne a0, a1, inst_error + nop + lw a1, 0(t2) + bne a0, a1, inst_error + nop + lw a1, 0(t3) + bne a0, a1, inst_error + nop + addi t0, t0, 4 + addi t1, t1, 4 + addi t2, t2, 4 + addi t3, t3, 4 + addi a0, a0, 1 + j .n98_en_chk + nop +.n98_en_end: + nop + ###detect exception bne s2, zero, inst_error nop diff --git a/resources/2021/soft/func/inst/n99_cache_icache.S b/resources/2021/soft/func/inst/n99_cache_icache.S index 7830a72..4a49017 100644 --- a/resources/2021/soft/func/inst/n99_cache_icache.S +++ b/resources/2021/soft/func/inst/n99_cache_icache.S @@ -29,8 +29,8 @@ LEAF(n99_cache_icache_test) cache 16, 0(v0) # I-Cache Hit Invalid # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_1 nop @@ -65,8 +65,8 @@ LEAF(n99_cache_icache_test) .n99_2_check: # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_2 nop @@ -101,8 +101,8 @@ LEAF(n99_cache_icache_test) .n99_3_check: # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_3 nop @@ -129,8 +129,8 @@ LEAF(n99_cache_icache_test) cache 0, 0(v0) # I-Cache Hit Invalid # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_4 nop @@ -157,8 +157,8 @@ LEAF(n99_cache_icache_test) cache 8, 0(v0) # I-Cache Index Store Tag # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_5 nop @@ -261,8 +261,8 @@ LEAF(n99_cache_icache_test) .n99_con_loop_end: # TODO: clear Datapath on CACHE # using enough nop to stop prefetch - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop - nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop + nop;nop;nop;nop;nop;nop; + nop;nop;nop;nop;nop;nop; j .n99_con nop @@ -304,6 +304,128 @@ LEAF(n99_cache_icache_test) 148 00000000 nop */ +/* + Enhanced test: + 1. fill 800d0000, 800D0800, 800D1000, 800D1800 with instructions + 2. jump to 800d0000, 800D0800, 800D1000, 800D1800 and execute + 3. return back to here and check registers + 4. modify 800d0000, 800D0800, 800D1000, 800D1800 + 5. same as 2 3 + + 20050000 addi $a1, $zero, 0 + 03e00008 jr $ra + 20a5000[] addi $a1, $a1, [case] + +*/ +.n99_en_bgn: + move a0, ra + + li t0, 0x800d0000 + li t1, 0x800d0800 + li t2, 0x800d1000 + li t3, 0x800d1800 + + li a1, 0x20050000 + li a2, 0x03e00008 + li a3, 0x20a50000 + +.n98_en_step1: + sw a1, 0(t0) + sw a1, 0(t1) + sw a1, 0(t2) + sw a1, 0(t3) + + sw a2, 4(t0) + sw a2, 4(t1) + sw a2, 4(t2) + sw a2, 4(t3) + + sw a3, 8(t0) + addi a3, a3, 1 + sw a3, 8(t1) + addi a3, a3, 1 + sw a3, 8(t2) + addi a3, a3, 1 + sw a3, 8(t3) + addi a3, a3, 1 + + cache 1, 0(zero) + cache 0, 0(zero) + +.n98_en_step23: + li a1, 0 + li a2, 0 + jalr t0 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 1 + jalr t1 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 2 + jalr t2 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 3 + jalr t3 + nop + bne a1, a2, inst_error + nop + +.n98_en_step4: + sw a3, 8(t0) + addi a3, a3, 1 + sw a3, 8(t1) + addi a3, a3, 1 + sw a3, 8(t2) + addi a3, a3, 1 + sw a3, 8(t3) + addi a3, a3, 1 + + cache 1, 0(zero) + cache 0, 0(zero) + +.n98_en_step5: + li a1, 0 + li a2, 4 + jalr t0 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 5 + jalr t1 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 6 + jalr t2 + nop + bne a1, a2, inst_error + nop + + li a1, 0 + li a2, 7 + jalr t3 + nop + bne a1, a2, inst_error + nop + +.n98_en_rst: + move ra, a0 + ###detect exception bne s2, zero, inst_error nop diff --git a/resources/2021/soft/func/start.S b/resources/2021/soft/func/start.S index 5f71e3d..3c0e5ab 100644 --- a/resources/2021/soft/func/start.S +++ b/resources/2021/soft/func/start.S @@ -320,6 +320,27 @@ inst_test: jr t9 #kseg0 -> kseg1 nop ##### kseg0_kseg1: + + jal n98_cache_dcache_test + nop + jal wait_1s + nop + + la t1, n99_kseg1_kseg0 + li t2, 0x20000000 + subu t9, t1, t2 + jr t9 + nop +n99_kseg1_kseg0: + jal n99_cache_icache_test + nop + jal wait_1s + nop + la t9, n99_kseg0_kseg1 + jr t9 + nop +n99_kseg0_kseg1: + jal n2_addu_test #addu nop jal wait_1s @@ -704,25 +725,7 @@ kseg0_kseg1: nop jal wait_1s nop - jal n98_cache_dcache_test - nop - jal wait_1s - nop - la t1, n99_kseg1_kseg0 - li t2, 0x20000000 - subu t9, t1, t2 - jr t9 - nop -n99_kseg1_kseg0: - jal n99_cache_icache_test - nop - jal wait_1s - nop - la t9, n99_kseg0_kseg1 - jr t9 - nop -n99_kseg0_kseg1: jal n100_movz_movn_test nop From c4942661dc75b3ad2696f6e505ad9b0e10e26fa5 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Mon, 27 Sep 2021 16:58:22 +0800 Subject: [PATCH 3/5] refactor cache inst on I-Cache --- .vscode/settings.json | 6 ++- src/MMU/MMU.sv | 97 ++++++++++++++++++++++++++++++------------- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9834788..7630cf2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -63,5 +63,9 @@ "typeinfo": "cpp", "iomanip": "cpp" }, - "editor.defaultFormatter": "bmpenuelas.systemverilog-formatter-vscode" + "editor.defaultFormatter": "bmpenuelas.systemverilog-formatter-vscode", + "verilog.linting.linter": "verilator", + "verilog.linting.verilator.useWSL": true, + "verilog.linting.verilator.arguments": "-x-assign 0 -Wall --assert -Wno-UNOPT -Wno-UNOPTFLAT -Wno-BLKSEQ -DSIMULATION_PC -I./src/AXI/ -I./src/Cache/ -I./src/Core/ -I./src/CP0/ -I./src/Gadgets/ -I./src/include/ -I./src/IP/ -I./src/MMU/ -I./src/Core/Gadgets/ -I./src/IP/DCData_bram/ -I./src/IP/DCTag_bram/ -I./src/IP/div_signed/ -I./src/IP/div_unsigned/ -I./src/IP/ICData_bram/ -I./src/IP/ICTag_bram/ -I./src/IP/mul_signed/ -I./src/IP/mul_unsigned/ ./model/DCData_bram.v ./model/DCTag_bram.v ./model/div_signed.v ./model/div_unsigned.v ./model/ICData_bram.v ./model/ICTag_bram.v ./model/mul_signed.sv ./model/mul_unsigned.sv ./src/mycpu_top.sv ./src/AXI/AXIRead_i.sv ./src/AXI/AXI.sv ./src/AXI/AXIWrite_i.sv ./src/Cache/DCache_i.sv ./src/Cache/DCache.sv ./src/Cache/ICache_i.sv ./src/Cache/ICache.sv ./src/Core/ALU.sv ./src/Core/Controller.sv ./src/Core/Datapath.sv ./src/Core/Queue.sv ./src/Core/RF.sv ./src/CP0/CP0.sv ./src/Gadgets/extender.sv ./src/Gadgets/ffenrc.sv ./src/Gadgets/ffenr.sv ./src/Gadgets/ffen.sv ./src/Gadgets/mux2.sv ./src/Gadgets/mux3.sv ./src/Gadgets/mux4.sv ./src/Gadgets/mux5.sv ./src/Gadgets/mux6.sv ./src/Gadgets/myBuffer0.sv ./src/Gadgets/myBuffer.sv ./src/Gadgets/onehot_bin16.sv ./src/Gadgets/onehot_bin32.sv ./src/Gadgets/onehot_bin4.sv ./src/Gadgets/onehot_bin8.sv ./src/Gadgets/prio_mux4.sv ./src/Gadgets/prio_mux5.sv ./src/MMU/MMU.sv ./src/MMU/sram_i.sv ./src/MMU/SRAM_RO_AXI_i.sv ./src/MMU/sramro_i.sv ./src/MMU/SRAM_W_AXI_i.sv ./src/MMU/TLB_Lookup.sv ./src/MMU/TLB.sv -top mycpu_top", + "files.trimTrailingWhitespace": true } diff --git a/src/MMU/MMU.sv b/src/MMU/MMU.sv index 0a5d088..363aad0 100644 --- a/src/MMU/MMU.sv +++ b/src/MMU/MMU.sv @@ -56,7 +56,7 @@ module MMU ( I_WA, I_WD1, I_WD2, I_WD3, I_WD4, I_WD5, I_WD6, I_WD7, I_WD8, I_REFILL, - I_CACHE, I_CACHE_REFILL + I_CACHE, I_CACHE_DISPATCH, I_CACHE_REFILL } istate_t; typedef enum bit [3:0] { @@ -79,6 +79,16 @@ module MMU ( DWA_WA } dwastate_t; + // ========================== + // ======== CacheVar ======== + // ========================== + + logic icReq; // whether there is a i-cache request + logic icvReq; // whether the i-cache req is valid (I_CACHE_DISPATCH) + + CacheOp_t cacheOp1; // cacheOp piped for a cycle + word_t dVA1; + // ====================== // ======== iVar ======== // ====================== @@ -96,10 +106,6 @@ module MMU ( word_t iD1, iD2, iD3, iD4, iD5, iD6, iD7; - logic diReq; - CacheOp_t cacheOp1; - word_t dVA1, diPA; - // ================================ // ======== iState Machine ======== // ================================ @@ -122,7 +128,14 @@ module MMU ( ic.clearIdx = 0; case (iState) I_IDLE: begin - if (diReq & ~iValid1) begin + if (icReq & ~iReq1) begin + /* + * Try to strip TLB-related logic from the critical path + * When there is a cache request, if the instruction queue + * has been filled, directly handle the request to avoid + * deadlock , or else the request will be handled when + * current request is finished at I-REFILL or I-WD2 + */ iNextState = I_CACHE; end else if (~iValid1) iEn = 1; else begin @@ -151,7 +164,8 @@ module MMU ( if (inst_axi.rvalid) begin inst.data_ok = 1; if (iCached2) iNextState = I_WD3; - else if (diReq) iNextState = I_CACHE; + // make sure icReq is handled + else if (icReq) iNextState = I_CACHE; else begin iEn = 1; iNextState = I_IDLE; @@ -177,29 +191,43 @@ module MMU ( if (inst_axi.rvalid) iNextState = I_REFILL; end I_REFILL: begin - if (diReq) iNextState = I_CACHE; + // make sure icReq is handled + if (icReq) iNextState = I_CACHE; else begin iEn = 1; iNextState = I_IDLE; end end I_CACHE: begin - /* - * I-Cache Cache指令实现备注: - * 在进入 I_CACHE 状态时需确保 iEn == 0 - * 跳出 I_CACHE 状态时 iEn = 0 - * 注意处理 Exceptions - * TLB 转换请求在 iNextState == I_CACHE时发送 - * I-Cache 查询请求在 iNextState == I_CACHE时发送 - * 在 I_CACHE 状态下屏蔽 iAddressError 且只有在 Address 类型请求下允许 TLBRefill 和 TLBInvalid - * I_CACHE 状态下向 I_CACHE 发送 clear 信号 - * drState 状态机同步 + /* For "I-Cache Hit Invalid": + * send TLB translation request here to reduce logic on critical path + * For "I-Cache Index Invalid" or "I-Cache Index Store Tag": + * I-Cache's request is send here too to sync with Hit Invalid + * + * Critical Signals: + * 1. ic.req = 1'b1 + * 2. iVA = dVA1 (use a dedicated var?) */ - if (~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1])) ic.clear = 1; + iNextState = I_CACHE_DISPATCH; + end + I_CACHE_DISPATCH: begin + /* + * State: + * 1. I-Cache state == LOOKUP + * 2. TLB iCached1 iHit1 iValid1 ... is valid + * + * Critical Signals: + * 1. ic.req = 1'b0 + * 2. ic.tag1 -> iEn2 -> iPA1 + * 3. ic.clear & ic.clearIdx + */ + + if (icvReq) ic.clear = 1; + ic.clearIdx = cacheOp1[1]; - iEn = 0; - iEn2 = 1; + iEn2 = 1; // use iPA1 as tag + iNextState = I_CACHE_REFILL; end I_CACHE_REFILL: begin @@ -230,7 +258,9 @@ module MMU ( // ========== iFunction ========== // =============================== - assign iVA = (iNextState == I_CACHE | iState == I_CACHE) ? dVA1 : inst.addr; + // On I_CACHE: sending cache request + // On I_CACHE_DISPATCH: using the same addr to clear + assign iVA = (iState == I_CACHE | iState == I_CACHE_DISPATCH) ? dVA1 : inst.addr; assign iValid1 = iReq1 & iHit1 & iMValid1 & (in_kernel | iUser1); assign inst.addr_ok = iEn; @@ -245,7 +275,7 @@ module MMU ( ); // I-Cache req on inst query or cache instruction - assign ic.req = iEn & iState != I_CACHE | iNextState == I_CACHE; + assign ic.req = iEn | iState == I_CACHE; assign ic.valid = iValid1 & iCached1; assign ic.index = iVA[`IC_TAGL-1:`IC_INDEXL]; assign ic.tag1 = iEn2 ? iPA1[31:`IC_TAGL] : iPA2[31:`IC_TAGL]; @@ -264,8 +294,8 @@ module MMU ( assign inst_axi.len = (iEn2 ? iCached1 : iCached2) ? 4'b0111 : 4'b0001; assign inst_axi.size = 3'b010; - assign iTLBRefill = (iState == I_IDLE & iReq1 | iState == I_CACHE & ~cacheOp1[1]) & ~iHit1; - assign iTLBInvalid = (iState == I_IDLE & iReq1 | iState == I_CACHE & ~cacheOp1[1]) & ~iMValid1; + assign iTLBRefill = (iState == I_IDLE & iReq1 | iState == I_CACHE_DISPATCH & ~cacheOp1[1]) & ~iHit1; + assign iTLBInvalid = (iState == I_IDLE & iReq1 | iState == I_CACHE_DISPATCH & ~cacheOp1[1]) & ~iMValid1; assign iAddressError = (iState == I_IDLE) & iReq1 & ~in_kernel & ~iUser1; // ====================== @@ -307,13 +337,11 @@ module MMU ( ffenr #(1) dvalid_ff (clk, rst, data.req, dEn, dReq1); ffen #(2) dsize_ff (clk, data.size, dEn, dSize1); - ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); ffen #(32) dPA_ff (clk, dPA1, dEn2, dPA2); ffen #(1) dCached_ff (clk, dCached1, dEn2, dCached2); ffen #(1) dwr_ff (clk, data.wr, dEn2, dwr1); ffen #(4) dwstrb_ff (clk, data.wstrb, dEn2, dWstrb1); ffen #(32) dwdata_ff (clk, data.wdata, dEn2, dWdata1); - ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); ffen #(1) dDirtValid_ff (clk, dc.dirt_valid, dEn2, dDirtValid); ffenr #(1) dCCached_ff (clk, dCClear | rst, 1'b1, dCEn, dCCached); @@ -348,7 +376,7 @@ module MMU ( dClrReq = 0; case (drState) DR_IDLE: begin - if (diReq) drNextState = DR_ICACHE; + if (icReq) drNextState = DR_ICACHE; else if (dReq1 & cacheOp1[2] & (dCached1 | dCCached | cacheOp1[1])) begin if (cacheOp1[0]) begin // 不需要写回的情况 @@ -474,7 +502,6 @@ module MMU ( // ================================ assign dVA = data.addr; - assign diReq = dReq1 & ~cacheOp1[2] & |cacheOp1[1:0]; assign dcReq1 = dReq1 & (cacheOp1 == CNOP | cacheOp1[2]); // exclude I-Cache clear assign dValid1 = dReq1 & dHit1 & dMValid1 & (~data.wr | dDirty1) & (in_kernel | dUser1); @@ -722,6 +749,18 @@ module MMU ( assign dc.wdata = dEn2 ? data.wdata : dWdata1; assign dc.wstrb = dEn2 ? data.wstrb : dWstrb1; + // =============================== + // ========== CacheInst ========== + // =============================== + + ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); + ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); + + + assign icReq = dReq1 & ~cacheOp1[2] & |cacheOp1[1:0]; + assign icvReq = ~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1]); + + // ============================== // ========== VA -> PA ========== // ============================== From fa0f195d17bab7c8df69d0f48b0627f0b96465d0 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Thu, 30 Sep 2021 22:45:28 +0800 Subject: [PATCH 4/5] refactor DCache --- src/Cache/DCache.sv | 7 +- src/MMU/MMU.sv | 189 ++++++++++++++++++++++++++------------------ 2 files changed, 116 insertions(+), 80 deletions(-) diff --git a/src/Cache/DCache.sv b/src/Cache/DCache.sv index ca28e62..e890264 100644 --- a/src/Cache/DCache.sv +++ b/src/Cache/DCache.sv @@ -36,7 +36,7 @@ module DCache ( DCIndexL_t index1; - logic hit; + logic hit, hit2; logic [3:0] hitWay; DCData_t cacheLine; @@ -140,14 +140,15 @@ module DCache ( assign hitWay[2] = tagV[2] & tagOut[2].tag == port.tag1; assign hitWay[3] = tagV[3] & tagOut[3].tag == port.tag1; // 在 clearWb状态下确保命中 - assign hit = |{hitWay} | port.clear & port.clearWb; + assign hit = |{hitWay} | port.clear & port.clearWb; + assign hit2 = |{hitWay}; assign cacheLine = (hitWay[0] ? dataOut[0] : `DC_DATA_LENGTH'b0) | (hitWay[1] ? dataOut[1] : `DC_DATA_LENGTH'b0) | (hitWay[2] ? dataOut[2] : `DC_DATA_LENGTH'b0) | (hitWay[3] ? dataOut[3] : `DC_DATA_LENGTH'b0); - assign port.hit = hit; + assign port.hit = hit2; assign port.row = cacheLine; // ============================== diff --git a/src/MMU/MMU.sv b/src/MMU/MMU.sv index 363aad0..cd4251b 100644 --- a/src/MMU/MMU.sv +++ b/src/MMU/MMU.sv @@ -56,7 +56,7 @@ module MMU ( I_WA, I_WD1, I_WD2, I_WD3, I_WD4, I_WD5, I_WD6, I_WD7, I_WD8, I_REFILL, - I_CACHE, I_CACHE_DISPATCH, I_CACHE_REFILL + I_CACHE_PREPARE, I_CACHE_DISPATCH, I_CACHE_REFILL } istate_t; typedef enum bit [3:0] { @@ -64,7 +64,7 @@ module MMU ( DR_WA, DR_WD1, DR_WD2, DR_WD3, DR_WD4, DR_REFILL, - DR_ICACHE, DR_CACHE, DR_CACHE_REFILL, DR_CACHE_REQ + DR_ICACHE, DR_CACHE_PREPARE, DR_CACHE_DISPATCH, DR_CACHE_REFILL, DR_CACHE_REQ } drstate_t; typedef enum bit [2:0] { @@ -83,12 +83,23 @@ module MMU ( // ======== CacheVar ======== // ========================== - logic icReq; // whether there is a i-cache request - logic icvReq; // whether the i-cache req is valid (I_CACHE_DISPATCH) + logic icReq; // whether there is an i-cache request + logic icReqV; // whether i-cache req is valid (I_CACHE_DISPATCH) CacheOp_t cacheOp1; // cacheOp piped for a cycle - word_t dVA1; + word_t dVA1; // data.addr + logic dcReq; // whether there is a d-cache request + logic dClrRv; // dc.rvalid + logic dClrReq; // dc.req + logic dClrInv; // make dc.valid false + logic dDirtValid; // whether it is still dirty + + logic dcReqV; // whether d-cache req is valid + logic dcCEn; // dCached1 en + logic dCClear; // clear dcCached1 + logic dcCached1; // dCached1 pipe + logic dc2nd; // dcache cache write // ====================== // ======== iVar ======== // ====================== @@ -136,7 +147,7 @@ module MMU ( * deadlock , or else the request will be handled when * current request is finished at I-REFILL or I-WD2 */ - iNextState = I_CACHE; + iNextState = I_CACHE_PREPARE; end else if (~iValid1) iEn = 1; else begin iEn2 = 1; @@ -165,7 +176,7 @@ module MMU ( inst.data_ok = 1; if (iCached2) iNextState = I_WD3; // make sure icReq is handled - else if (icReq) iNextState = I_CACHE; + else if (icReq) iNextState = I_CACHE_PREPARE; else begin iEn = 1; iNextState = I_IDLE; @@ -192,13 +203,13 @@ module MMU ( end I_REFILL: begin // make sure icReq is handled - if (icReq) iNextState = I_CACHE; + if (icReq) iNextState = I_CACHE_PREPARE; else begin iEn = 1; iNextState = I_IDLE; end end - I_CACHE: begin + I_CACHE_PREPARE: begin /* For "I-Cache Hit Invalid": * send TLB translation request here to reduce logic on critical path * For "I-Cache Index Invalid" or "I-Cache Index Store Tag": @@ -223,7 +234,7 @@ module MMU ( * 3. ic.clear & ic.clearIdx */ - if (icvReq) ic.clear = 1; + if (icReqV) ic.clear = 1; ic.clearIdx = cacheOp1[1]; iEn2 = 1; // use iPA1 as tag @@ -258,9 +269,9 @@ module MMU ( // ========== iFunction ========== // =============================== - // On I_CACHE: sending cache request + // On I_CACHE_PREPARE: sending cache request // On I_CACHE_DISPATCH: using the same addr to clear - assign iVA = (iState == I_CACHE | iState == I_CACHE_DISPATCH) ? dVA1 : inst.addr; + assign iVA = (iState == I_CACHE_PREPARE | iState == I_CACHE_DISPATCH) ? dVA1 : inst.addr; assign iValid1 = iReq1 & iHit1 & iMValid1 & (in_kernel | iUser1); assign inst.addr_ok = iEn; @@ -275,7 +286,7 @@ module MMU ( ); // I-Cache req on inst query or cache instruction - assign ic.req = iEn | iState == I_CACHE; + assign ic.req = iEn | iState == I_CACHE_PREPARE; assign ic.valid = iValid1 & iCached1; assign ic.index = iVA[`IC_TAGL-1:`IC_INDEXL]; assign ic.tag1 = iEn2 ? iPA1[31:`IC_TAGL] : iPA2[31:`IC_TAGL]; @@ -305,7 +316,7 @@ module MMU ( word_t dVA; logic dEn; - logic dReq1, dcReq1; + logic dReq1; logic dHit1; logic dCached1, dCached2; logic dDirty1; @@ -326,11 +337,6 @@ module MMU ( word_t ddAddr1; logic [127:0] ddData1; - // D-Cache Clear - logic dClrRv, dClrReq; - logic dDirtValid; - logic dCEn, dCClear, dCCached; - // ============================ // ======== dFlip-Flop ======== // ============================ @@ -343,9 +349,6 @@ module MMU ( ffen #(4) dwstrb_ff (clk, data.wstrb, dEn2, dWstrb1); ffen #(32) dwdata_ff (clk, data.wdata, dEn2, dWdata1); - ffen #(1) dDirtValid_ff (clk, dc.dirt_valid, dEn2, dDirtValid); - ffenr #(1) dCCached_ff (clk, dCClear | rst, 1'b1, dCEn, dCCached); - // ================================= // ======== drState Machine ======== // ================================= @@ -361,44 +364,37 @@ module MMU ( always_comb begin dEn = 0; dEn2 = 0; - dCEn = 0; - dCClear = 0; + drNextState = drState; data.data_ok = 0; rdata_axi.req = 0; + // D-Cache 清除功能 (与 req 一起发送) - dc.clear = 0; + dc.clear = 0; // dc.valid = ... (dc.clear | ...) ... dc.clearIdx = 0; dc.clearWb = 0; + // 直接发送 dc.rvalid dClrRv = 0; // 直接发送 dc.req dClrReq = 0; + // 清除 dc.valid + dClrInv = 0; + // 记录 dCached1 + dcCEn = 0; + // 清除 dcCached1 + dCClear = 0; + // CACHE 指令二阶段 + dc2nd = 0; + case (drState) DR_IDLE: begin if (icReq) drNextState = DR_ICACHE; - else if (dReq1 & cacheOp1[2] & (dCached1 | dCCached | cacheOp1[1])) begin - if (cacheOp1[0]) begin - // 不需要写回的情况 - // D-Cache 状态机处于 Lookup 阶段 - dc.clear = 1; // 发送清除 - dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 - drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 - end else begin - // 需要写回 - // 此时 D-Cache 状态机处于 Lookup 状态 - // 可能是: 1. CACHE 请求第一次发送 - // 2. Index Writeback 清除一路后返回 - dc.clear = 1; // 发送清除 - dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 - dc.clearWb = 1; // 需要写回的清除 - drNextState = DR_CACHE; // 进入 DR_CACHE 等候写入完成 - dEn2 = 1; // 二阶段 - dCEn = 1; // 缓存 dCached1 - end - end else if (dReq1 & cacheOp1[2]) begin - // avoid deadlock when address is uncached - drNextState = DR_CACHE_REFILL; + else if (dcReq & ~dTLBRefill & ~dTLBInvalid) begin + dcCEn = 1'b1; // Store dCached1 + dEn2 = 1'b1; // Store dPA1 + dClrInv = 1'b1; // clear dc.valid + drNextState = DR_CACHE_REQ; end else if (~dValid1) dEn = 1; else begin dEn2 = 1; @@ -464,22 +460,49 @@ module MMU ( drNextState = DR_IDLE; end end - DR_CACHE: begin + DR_CACHE_PREPARE: begin + if (~dcReqV) begin + /* + * Jump back when + * 1. Request is invalid + * 2. finished + */ + dc.clear = 1; // Let D-Cache state machine went back to IDLE + drNextState = DR_CACHE_REFILL; + end else if (dcCached1 | cacheOp1[1]) begin + if (cacheOp1[0]) begin + // 不需要写回的情况 + // D-Cache 状态机处于 Lookup 阶段 + dc.clear = 1; // 发送清除 + dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 + drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 + end else begin + // 需要写回 + // 此时 D-Cache 状态机处于 Lookup 状态 + // 可能是: 1. CACHE 请求第一次发送 + // 2. Index Writeback 清除一路后返回 + dc.clear = 1; // 发送清除 + dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 + dc.clearWb = 1; // 需要写回的清除 + drNextState = DR_CACHE_DISPATCH; // 进入 DR_CACHE_DISPATCH 等候写入完成 + dc2nd = 1; // 二阶段 + end + end + end + DR_CACHE_DISPATCH: begin // WriteBack // D-Cache: state == REPLACE if (wdata_ok) begin - dClrRv = 1; // 直接发送 dc.rvalid 通知可写 + dClrRv = 1; // 直接发送 dc.rvalid 通知可写 // Why cann't I send dc.clear HERE ??? // dc.clear = 1; if (cacheOp1[1]) begin // Clear by Index - if (dDirtValid) - drNextState = DR_CACHE_REQ; // 重新进入准备其它路的清除 - else - drNextState = DR_CACHE_REFILL; // 清除完了 + if (dDirtValid) drNextState = DR_CACHE_REQ; // 重新进入准备其它路的清除 + else drNextState = DR_CACHE_REFILL; // 清除完了 end else begin // Clear by Address - drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 + drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 end end end @@ -490,8 +513,9 @@ module MMU ( data.data_ok = 1; end DR_CACHE_REQ: begin + // From DR_IDLE or DR_CACHE_DISPATCH dClrReq = 1; - drNextState = DR_IDLE; + drNextState = DR_CACHE_PREPARE; end default: begin drNextState = DR_IDLE; end endcase @@ -502,11 +526,10 @@ module MMU ( // ================================ assign dVA = data.addr; - assign dcReq1 = dReq1 & (cacheOp1 == CNOP | cacheOp1[2]); // exclude I-Cache clear assign dValid1 = dReq1 & dHit1 & dMValid1 & (~data.wr | dDirty1) & (in_kernel | dUser1); - assign dTLBRefill = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dHit1; - assign dTLBInvalid = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dMValid1; + assign dTLBRefill = drState == DR_IDLE & dReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dHit1; + assign dTLBInvalid = drState == DR_IDLE & dReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dMValid1; assign dTLBModified = drState == DR_IDLE & dReq1 & cacheOp1 == CNOP & data.wr & ~dDirty1; assign dAddressError = drState == DR_IDLE & dReq1 & cacheOp1 == CNOP & ~in_kernel & ~dUser1; @@ -550,7 +573,7 @@ module MMU ( // do not request when handling CACHE instruction on I-Cache assign dc.req = dClrReq | dEn & (cacheOp[2] | ~|cacheOp[1:0]); - assign dc.valid = dValid1 & dCached1 | dc.clear; + assign dc.valid = ~dClrInv & (dValid1 & dCached1 | dc.clear); assign dc.index = dEn ? dVA[`DC_TAGL-1:`DC_INDEXL] : dVA1[`DC_TAGL-1:`DC_INDEXL]; assign dc.tag1 = dEn2 ? dPA1[31:`DC_TAGL] : dPA2[31:`DC_TAGL]; assign dc.sel1 = dEn2 ? dPA1[3:2] : dPA2[3:2]; @@ -590,12 +613,13 @@ module MMU ( case (dwState) DW_IDLE: begin - if (dEn2 & (~(dCached1 | dCEn) & data.wr - | (dCached1 | dCEn) & dc.dirt_valid - & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 - & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 + if ( (dEn2 & ~dcReq | dc2nd) + & (~(dCached1 | dcCached1) ? data.wr + : dc.dirt_valid + & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 + & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 )) begin - if (dCached1 | dCEn) begin + if (dCached1 | dcCached1) begin wdata_axi.wdata = dc.dirt_data[31:0]; wdata_axi.wstrb = 4'b1111; wdata_axi.wvalid = 1'b1; @@ -608,7 +632,7 @@ module MMU ( if (~wdata_axi.wready) dwNextState = DW_WD1; else begin - if (dCached1 | dCEn) dwNextState = DW_WD2; + if (dCached1 | dcCached1) dwNextState = DW_WD2; else begin if (~wdata_axi.data_ok) dwNextState = DW_WB; else begin @@ -621,7 +645,7 @@ module MMU ( end end DW_WD1: begin - if (dCached2 | dCCached) begin + if (dCached2 | dcCached1) begin wdata_axi.wdata = ddData1[31:0]; wdata_axi.wstrb = 4'b1111; wdata_axi.wvalid = 1'b1; @@ -633,7 +657,7 @@ module MMU ( end if (wdata_axi.wready) begin - if (dCached2 | dCCached) dwNextState = DW_WD2; + if (dCached2 | dcCached1) dwNextState = DW_WD2; else begin if (~wdata_axi.data_ok) dwNextState = DW_WB; else begin @@ -704,10 +728,11 @@ module MMU ( case (dwaState) DWA_IDLE: begin - if (dEn2 & (~(dCached1 | dCEn) & data.wr - | (dCached1 | dCEn) & dc.dirt_valid - & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 - & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 + if ( (dEn2 & ~dcReq | dc2nd) + & (~(dCached1 | dcCached1) ? data.wr + : dc.dirt_valid + & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 + & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 )) begin wdata_axi.req = 1'b1; if (~wdata_axi.addr_ok) dwaNextState = DWA_WA; @@ -742,9 +767,9 @@ module MMU ( // ========== dwFunction ========== // ================================ - assign wdata_axi.addr = ((dEn2 ? dCached1 : dCached2) | dCEn) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2; - assign wdata_axi.len = ((dEn2 ? dCached1 : dCached2) | dCEn) ? 4'b0011 : 4'b0000; - assign wdata_axi.size = ((dEn2 ? dCached1 : dCached2) | dCEn) ? 3'b010 : {1'b0, dSize1}; + assign wdata_axi.addr = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2; + assign wdata_axi.len = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? 4'b0011 : 4'b0000; + assign wdata_axi.size = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? 3'b010 : {1'b0, dSize1}; assign dc.wvalid = dEn2 ? data.wr : dwr1; assign dc.wdata = dEn2 ? data.wdata : dWdata1; assign dc.wstrb = dEn2 ? data.wstrb : dWstrb1; @@ -753,13 +778,23 @@ module MMU ( // ========== CacheInst ========== // =============================== - ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); - ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); + ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); + ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); + ffen #(1) dDirtValid_ff (clk, dc.dirt_valid, dc.clear, dDirtValid); + ffenr #(1) dcCached1_ff ( + .clk(clk), + .rst(rst | dCClear), + .d(dCached1 | &cacheOp1[2:1]), + .en(dcCEn), + .q(dcCached1) + ); assign icReq = dReq1 & ~cacheOp1[2] & |cacheOp1[1:0]; - assign icvReq = ~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1]); + assign icReqV = ~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1]); + assign dcReq = dReq1 & cacheOp1[2]; + assign dcReqV = ~dTLBRefill & ~dTLBInvalid & (dcCached1 & dc.hit | cacheOp1[1]); // ============================== // ========== VA -> PA ========== From 24613eeadec3f2938c4d249bb187306f91275b3f Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Thu, 30 Sep 2021 22:45:28 +0800 Subject: [PATCH 5/5] Revert "refactor DCache" This reverts commit fa0f195d17bab7c8df69d0f48b0627f0b96465d0. --- src/Cache/DCache.sv | 7 +- src/MMU/MMU.sv | 189 ++++++++++++++++++-------------------------- 2 files changed, 80 insertions(+), 116 deletions(-) diff --git a/src/Cache/DCache.sv b/src/Cache/DCache.sv index e890264..ca28e62 100644 --- a/src/Cache/DCache.sv +++ b/src/Cache/DCache.sv @@ -36,7 +36,7 @@ module DCache ( DCIndexL_t index1; - logic hit, hit2; + logic hit; logic [3:0] hitWay; DCData_t cacheLine; @@ -140,15 +140,14 @@ module DCache ( assign hitWay[2] = tagV[2] & tagOut[2].tag == port.tag1; assign hitWay[3] = tagV[3] & tagOut[3].tag == port.tag1; // 在 clearWb状态下确保命中 - assign hit = |{hitWay} | port.clear & port.clearWb; - assign hit2 = |{hitWay}; + assign hit = |{hitWay} | port.clear & port.clearWb; assign cacheLine = (hitWay[0] ? dataOut[0] : `DC_DATA_LENGTH'b0) | (hitWay[1] ? dataOut[1] : `DC_DATA_LENGTH'b0) | (hitWay[2] ? dataOut[2] : `DC_DATA_LENGTH'b0) | (hitWay[3] ? dataOut[3] : `DC_DATA_LENGTH'b0); - assign port.hit = hit2; + assign port.hit = hit; assign port.row = cacheLine; // ============================== diff --git a/src/MMU/MMU.sv b/src/MMU/MMU.sv index cd4251b..363aad0 100644 --- a/src/MMU/MMU.sv +++ b/src/MMU/MMU.sv @@ -56,7 +56,7 @@ module MMU ( I_WA, I_WD1, I_WD2, I_WD3, I_WD4, I_WD5, I_WD6, I_WD7, I_WD8, I_REFILL, - I_CACHE_PREPARE, I_CACHE_DISPATCH, I_CACHE_REFILL + I_CACHE, I_CACHE_DISPATCH, I_CACHE_REFILL } istate_t; typedef enum bit [3:0] { @@ -64,7 +64,7 @@ module MMU ( DR_WA, DR_WD1, DR_WD2, DR_WD3, DR_WD4, DR_REFILL, - DR_ICACHE, DR_CACHE_PREPARE, DR_CACHE_DISPATCH, DR_CACHE_REFILL, DR_CACHE_REQ + DR_ICACHE, DR_CACHE, DR_CACHE_REFILL, DR_CACHE_REQ } drstate_t; typedef enum bit [2:0] { @@ -83,23 +83,12 @@ module MMU ( // ======== CacheVar ======== // ========================== - logic icReq; // whether there is an i-cache request - logic icReqV; // whether i-cache req is valid (I_CACHE_DISPATCH) + logic icReq; // whether there is a i-cache request + logic icvReq; // whether the i-cache req is valid (I_CACHE_DISPATCH) CacheOp_t cacheOp1; // cacheOp piped for a cycle - word_t dVA1; // data.addr + word_t dVA1; - logic dcReq; // whether there is a d-cache request - logic dClrRv; // dc.rvalid - logic dClrReq; // dc.req - logic dClrInv; // make dc.valid false - logic dDirtValid; // whether it is still dirty - - logic dcReqV; // whether d-cache req is valid - logic dcCEn; // dCached1 en - logic dCClear; // clear dcCached1 - logic dcCached1; // dCached1 pipe - logic dc2nd; // dcache cache write // ====================== // ======== iVar ======== // ====================== @@ -147,7 +136,7 @@ module MMU ( * deadlock , or else the request will be handled when * current request is finished at I-REFILL or I-WD2 */ - iNextState = I_CACHE_PREPARE; + iNextState = I_CACHE; end else if (~iValid1) iEn = 1; else begin iEn2 = 1; @@ -176,7 +165,7 @@ module MMU ( inst.data_ok = 1; if (iCached2) iNextState = I_WD3; // make sure icReq is handled - else if (icReq) iNextState = I_CACHE_PREPARE; + else if (icReq) iNextState = I_CACHE; else begin iEn = 1; iNextState = I_IDLE; @@ -203,13 +192,13 @@ module MMU ( end I_REFILL: begin // make sure icReq is handled - if (icReq) iNextState = I_CACHE_PREPARE; + if (icReq) iNextState = I_CACHE; else begin iEn = 1; iNextState = I_IDLE; end end - I_CACHE_PREPARE: begin + I_CACHE: begin /* For "I-Cache Hit Invalid": * send TLB translation request here to reduce logic on critical path * For "I-Cache Index Invalid" or "I-Cache Index Store Tag": @@ -234,7 +223,7 @@ module MMU ( * 3. ic.clear & ic.clearIdx */ - if (icReqV) ic.clear = 1; + if (icvReq) ic.clear = 1; ic.clearIdx = cacheOp1[1]; iEn2 = 1; // use iPA1 as tag @@ -269,9 +258,9 @@ module MMU ( // ========== iFunction ========== // =============================== - // On I_CACHE_PREPARE: sending cache request + // On I_CACHE: sending cache request // On I_CACHE_DISPATCH: using the same addr to clear - assign iVA = (iState == I_CACHE_PREPARE | iState == I_CACHE_DISPATCH) ? dVA1 : inst.addr; + assign iVA = (iState == I_CACHE | iState == I_CACHE_DISPATCH) ? dVA1 : inst.addr; assign iValid1 = iReq1 & iHit1 & iMValid1 & (in_kernel | iUser1); assign inst.addr_ok = iEn; @@ -286,7 +275,7 @@ module MMU ( ); // I-Cache req on inst query or cache instruction - assign ic.req = iEn | iState == I_CACHE_PREPARE; + assign ic.req = iEn | iState == I_CACHE; assign ic.valid = iValid1 & iCached1; assign ic.index = iVA[`IC_TAGL-1:`IC_INDEXL]; assign ic.tag1 = iEn2 ? iPA1[31:`IC_TAGL] : iPA2[31:`IC_TAGL]; @@ -316,7 +305,7 @@ module MMU ( word_t dVA; logic dEn; - logic dReq1; + logic dReq1, dcReq1; logic dHit1; logic dCached1, dCached2; logic dDirty1; @@ -337,6 +326,11 @@ module MMU ( word_t ddAddr1; logic [127:0] ddData1; + // D-Cache Clear + logic dClrRv, dClrReq; + logic dDirtValid; + logic dCEn, dCClear, dCCached; + // ============================ // ======== dFlip-Flop ======== // ============================ @@ -349,6 +343,9 @@ module MMU ( ffen #(4) dwstrb_ff (clk, data.wstrb, dEn2, dWstrb1); ffen #(32) dwdata_ff (clk, data.wdata, dEn2, dWdata1); + ffen #(1) dDirtValid_ff (clk, dc.dirt_valid, dEn2, dDirtValid); + ffenr #(1) dCCached_ff (clk, dCClear | rst, 1'b1, dCEn, dCCached); + // ================================= // ======== drState Machine ======== // ================================= @@ -364,37 +361,44 @@ module MMU ( always_comb begin dEn = 0; dEn2 = 0; - + dCEn = 0; + dCClear = 0; drNextState = drState; data.data_ok = 0; rdata_axi.req = 0; - // D-Cache 清除功能 (与 req 一起发送) - dc.clear = 0; // dc.valid = ... (dc.clear | ...) ... + dc.clear = 0; dc.clearIdx = 0; dc.clearWb = 0; - // 直接发送 dc.rvalid dClrRv = 0; // 直接发送 dc.req dClrReq = 0; - // 清除 dc.valid - dClrInv = 0; - // 记录 dCached1 - dcCEn = 0; - // 清除 dcCached1 - dCClear = 0; - // CACHE 指令二阶段 - dc2nd = 0; - case (drState) DR_IDLE: begin if (icReq) drNextState = DR_ICACHE; - else if (dcReq & ~dTLBRefill & ~dTLBInvalid) begin - dcCEn = 1'b1; // Store dCached1 - dEn2 = 1'b1; // Store dPA1 - dClrInv = 1'b1; // clear dc.valid - drNextState = DR_CACHE_REQ; + else if (dReq1 & cacheOp1[2] & (dCached1 | dCCached | cacheOp1[1])) begin + if (cacheOp1[0]) begin + // 不需要写回的情况 + // D-Cache 状态机处于 Lookup 阶段 + dc.clear = 1; // 发送清除 + dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 + drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 + end else begin + // 需要写回 + // 此时 D-Cache 状态机处于 Lookup 状态 + // 可能是: 1. CACHE 请求第一次发送 + // 2. Index Writeback 清除一路后返回 + dc.clear = 1; // 发送清除 + dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 + dc.clearWb = 1; // 需要写回的清除 + drNextState = DR_CACHE; // 进入 DR_CACHE 等候写入完成 + dEn2 = 1; // 二阶段 + dCEn = 1; // 缓存 dCached1 + end + end else if (dReq1 & cacheOp1[2]) begin + // avoid deadlock when address is uncached + drNextState = DR_CACHE_REFILL; end else if (~dValid1) dEn = 1; else begin dEn2 = 1; @@ -460,49 +464,22 @@ module MMU ( drNextState = DR_IDLE; end end - DR_CACHE_PREPARE: begin - if (~dcReqV) begin - /* - * Jump back when - * 1. Request is invalid - * 2. finished - */ - dc.clear = 1; // Let D-Cache state machine went back to IDLE - drNextState = DR_CACHE_REFILL; - end else if (dcCached1 | cacheOp1[1]) begin - if (cacheOp1[0]) begin - // 不需要写回的情况 - // D-Cache 状态机处于 Lookup 阶段 - dc.clear = 1; // 发送清除 - dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 - drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 - end else begin - // 需要写回 - // 此时 D-Cache 状态机处于 Lookup 状态 - // 可能是: 1. CACHE 请求第一次发送 - // 2. Index Writeback 清除一路后返回 - dc.clear = 1; // 发送清除 - dc.clearIdx = cacheOp1[1]; // 清除时清除整行或者命中对象 - dc.clearWb = 1; // 需要写回的清除 - drNextState = DR_CACHE_DISPATCH; // 进入 DR_CACHE_DISPATCH 等候写入完成 - dc2nd = 1; // 二阶段 - end - end - end - DR_CACHE_DISPATCH: begin + DR_CACHE: begin // WriteBack // D-Cache: state == REPLACE if (wdata_ok) begin - dClrRv = 1; // 直接发送 dc.rvalid 通知可写 + dClrRv = 1; // 直接发送 dc.rvalid 通知可写 // Why cann't I send dc.clear HERE ??? // dc.clear = 1; if (cacheOp1[1]) begin // Clear by Index - if (dDirtValid) drNextState = DR_CACHE_REQ; // 重新进入准备其它路的清除 - else drNextState = DR_CACHE_REFILL; // 清除完了 + if (dDirtValid) + drNextState = DR_CACHE_REQ; // 重新进入准备其它路的清除 + else + drNextState = DR_CACHE_REFILL; // 清除完了 end else begin // Clear by Address - drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 + drNextState = DR_CACHE_REFILL; // 进入 REFILL 等候写入完成 end end end @@ -513,9 +490,8 @@ module MMU ( data.data_ok = 1; end DR_CACHE_REQ: begin - // From DR_IDLE or DR_CACHE_DISPATCH dClrReq = 1; - drNextState = DR_CACHE_PREPARE; + drNextState = DR_IDLE; end default: begin drNextState = DR_IDLE; end endcase @@ -526,10 +502,11 @@ module MMU ( // ================================ assign dVA = data.addr; + assign dcReq1 = dReq1 & (cacheOp1 == CNOP | cacheOp1[2]); // exclude I-Cache clear assign dValid1 = dReq1 & dHit1 & dMValid1 & (~data.wr | dDirty1) & (in_kernel | dUser1); - assign dTLBRefill = drState == DR_IDLE & dReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dHit1; - assign dTLBInvalid = drState == DR_IDLE & dReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dMValid1; + assign dTLBRefill = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dHit1; + assign dTLBInvalid = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dMValid1; assign dTLBModified = drState == DR_IDLE & dReq1 & cacheOp1 == CNOP & data.wr & ~dDirty1; assign dAddressError = drState == DR_IDLE & dReq1 & cacheOp1 == CNOP & ~in_kernel & ~dUser1; @@ -573,7 +550,7 @@ module MMU ( // do not request when handling CACHE instruction on I-Cache assign dc.req = dClrReq | dEn & (cacheOp[2] | ~|cacheOp[1:0]); - assign dc.valid = ~dClrInv & (dValid1 & dCached1 | dc.clear); + assign dc.valid = dValid1 & dCached1 | dc.clear; assign dc.index = dEn ? dVA[`DC_TAGL-1:`DC_INDEXL] : dVA1[`DC_TAGL-1:`DC_INDEXL]; assign dc.tag1 = dEn2 ? dPA1[31:`DC_TAGL] : dPA2[31:`DC_TAGL]; assign dc.sel1 = dEn2 ? dPA1[3:2] : dPA2[3:2]; @@ -613,13 +590,12 @@ module MMU ( case (dwState) DW_IDLE: begin - if ( (dEn2 & ~dcReq | dc2nd) - & (~(dCached1 | dcCached1) ? data.wr - : dc.dirt_valid - & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 - & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 + if (dEn2 & (~(dCached1 | dCEn) & data.wr + | (dCached1 | dCEn) & dc.dirt_valid + & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 + & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 )) begin - if (dCached1 | dcCached1) begin + if (dCached1 | dCEn) begin wdata_axi.wdata = dc.dirt_data[31:0]; wdata_axi.wstrb = 4'b1111; wdata_axi.wvalid = 1'b1; @@ -632,7 +608,7 @@ module MMU ( if (~wdata_axi.wready) dwNextState = DW_WD1; else begin - if (dCached1 | dcCached1) dwNextState = DW_WD2; + if (dCached1 | dCEn) dwNextState = DW_WD2; else begin if (~wdata_axi.data_ok) dwNextState = DW_WB; else begin @@ -645,7 +621,7 @@ module MMU ( end end DW_WD1: begin - if (dCached2 | dcCached1) begin + if (dCached2 | dCCached) begin wdata_axi.wdata = ddData1[31:0]; wdata_axi.wstrb = 4'b1111; wdata_axi.wvalid = 1'b1; @@ -657,7 +633,7 @@ module MMU ( end if (wdata_axi.wready) begin - if (dCached2 | dcCached1) dwNextState = DW_WD2; + if (dCached2 | dCCached) dwNextState = DW_WD2; else begin if (~wdata_axi.data_ok) dwNextState = DW_WB; else begin @@ -728,11 +704,10 @@ module MMU ( case (dwaState) DWA_IDLE: begin - if ( (dEn2 & ~dcReq | dc2nd) - & (~(dCached1 | dcCached1) ? data.wr - : dc.dirt_valid - & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 - & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 + if (dEn2 & (~(dCached1 | dCEn) & data.wr + | (dCached1 | dCEn) & dc.dirt_valid + & (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回 + & (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况 )) begin wdata_axi.req = 1'b1; if (~wdata_axi.addr_ok) dwaNextState = DWA_WA; @@ -767,9 +742,9 @@ module MMU ( // ========== dwFunction ========== // ================================ - assign wdata_axi.addr = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2; - assign wdata_axi.len = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? 4'b0011 : 4'b0000; - assign wdata_axi.size = ((dEn2 ? dCached1 : dCached2) | dcCached1) ? 3'b010 : {1'b0, dSize1}; + assign wdata_axi.addr = ((dEn2 ? dCached1 : dCached2) | dCEn) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2; + assign wdata_axi.len = ((dEn2 ? dCached1 : dCached2) | dCEn) ? 4'b0011 : 4'b0000; + assign wdata_axi.size = ((dEn2 ? dCached1 : dCached2) | dCEn) ? 3'b010 : {1'b0, dSize1}; assign dc.wvalid = dEn2 ? data.wr : dwr1; assign dc.wdata = dEn2 ? data.wdata : dWdata1; assign dc.wstrb = dEn2 ? data.wstrb : dWstrb1; @@ -778,23 +753,13 @@ module MMU ( // ========== CacheInst ========== // =============================== - ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); - ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); - ffen #(1) dDirtValid_ff (clk, dc.dirt_valid, dc.clear, dDirtValid); + ffen #(3) cache_op_ff (clk, cacheOp[2:0], dEn, cacheOp1[2:0]); + ffen #(32) dVA1_ff (clk, data.addr, dEn, dVA1); - ffenr #(1) dcCached1_ff ( - .clk(clk), - .rst(rst | dCClear), - .d(dCached1 | &cacheOp1[2:1]), - .en(dcCEn), - .q(dcCached1) - ); assign icReq = dReq1 & ~cacheOp1[2] & |cacheOp1[1:0]; - assign icReqV = ~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1]); + assign icvReq = ~iTLBRefill & ~iTLBInvalid & (iCached1 & ic.hit | cacheOp1[1]); - assign dcReq = dReq1 & cacheOp1[2]; - assign dcReqV = ~dTLBRefill & ~dTLBInvalid & (dcCached1 & dc.hit | cacheOp1[1]); // ============================== // ========== VA -> PA ==========