try add D-Cache's CACHE inst

This commit is contained in:
Paul Pan 2021-09-01 23:12:58 +08:00
parent 53c0c018bb
commit 3dffdae575
No known key found for this signature in database
GPG Key ID: DA97C6DCB84DEC68
11 changed files with 184 additions and 153 deletions

132
README.md
View File

@ -28,46 +28,94 @@ Our awesome `MIPS` CPU written in `SystemVerilog` for Loongson Cup
- [ ] 浮点运算指令报`Coprocessor Unusable`,同时`CP0`中新增`Cause.CE` :clock3:
- [ ] 新增指令
| Status | Instruction | Type | Tier | Comment |
| :----------------: | :---------: | :------: | :--: | :-------------------------------------- |
| :hourglass: | `Cache` | `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 | |
| :clock3: | `TEQ` | `SYS` | 2 | |
| :clock3: | `TEQI` | `SYS` | 2 | |
| :clock3: | `TGE` | `SYS` | 2 | |
| :clock3: | `TGEI` | `SYS` | 2 | |
| :clock3: | `TGEIU` | `SYS` | 2 | |
| :clock3: | `TGEU` | `SYS` | 2 | |
| :clock3: | `TLT` | `SYS` | 2 | |
| :clock3: | `TLTI` | `SYS` | 2 | |
| :clock3: | `TLTIU` | `SYS` | 2 | |
| :clock3: | `TLTU` | `SYS` | 2 | |
| :clock3: | `TNE` | `SYS` | 2 | |
| :clock3: | `TNEI` | `SYS` | 2 | |
| :clock3: | `CLO` | `ARITH` | 2 | `RT == RD` |
| :clock3: | `CLZ` | `ARITH` | 2 | `RT == RD` |
| :hourglass: | `MADD` | `ARITH` | 2 | `M`阶段加一个流水级 |
| :hourglass: | `MADDU` | `ARITH` | 2 | `M`阶段加一个流水级 |
| :hourglass: | `MSUB` | `ARITH` | 2 | `M`阶段加一个流水级 |
| :hourglass: | `MSUBU` | `ARITH` | 2 | `M`阶段加一个流水级 |
| :hourglass: | `MOVN` | `ARITH` | 2 | `D`阶段阻塞 |
| :hourglass: | `MOVZ` | `ARITH` | 2 | `D`阶段阻塞 |
| :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 | |
| :clock3: | `MOVF` | `FP` | 3 | |
| :clock3: | `MOVT` | `FP` | 3 | |
| :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 | 修改编译指令 |
| Status | Instruction | Type | Tier | Comment |
| :----------------: | :-------------------------------: | :------: | :--: | :-------------------------------------- |
| :hourglass: | `I-Cache Index Invalid` | `SYS` | 2 | |
| :hourglass: | `I-Cache Hit Invalid` | `SYS` | 2 | |
| :hourglass: | `D-Cache Index Writeback Invalid` | `SYS` | 2 | |
| :hourglass: | `D-Cache Index Store Tag` | `SYS` | 2 | |
| :hourglass: | `D-Cache Hit Invalid` | `SYS` | 2 | |
| :hourglass: | `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 | |
| :clock3: | `TEQ` | `SYS` | 2 | |
| :clock3: | `TEQI` | `SYS` | 2 | |
| :clock3: | `TGE` | `SYS` | 2 | |
| :clock3: | `TGEI` | `SYS` | 2 | |
| :clock3: | `TGEIU` | `SYS` | 2 | |
| :clock3: | `TGEU` | `SYS` | 2 | |
| :clock3: | `TLT` | `SYS` | 2 | |
| :clock3: | `TLTI` | `SYS` | 2 | |
| :clock3: | `TLTIU` | `SYS` | 2 | |
| :clock3: | `TLTU` | `SYS` | 2 | |
| :clock3: | `TNE` | `SYS` | 2 | |
| :clock3: | `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`阶段加一个流水级 |
| :hourglass: | `MOVN` | `ARITH` | 2 | `D`阶段阻塞 |
| :hourglass: | `MOVZ` | `ARITH` | 2 | `D`阶段阻塞 |
| :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 | |
| :clock3: | `MOVF` | `FP` | 3 | |
| :clock3: | `MOVT` | `FP` | 3 | |
| :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 | 修改编译指令 |
## `Cache`指令
预计实现以下`7`条操作
```verilog
32'b101111?????00000???????????????? // I-Cache Index Invalid
32'b101111?????01000???????????????? // I-Cache Index Store Tag
32'b101111?????10000???????????????? // I-Cache Hit Invalid
32'b101111?????00001???????????????? // D-Cache Index Writeback Invalid
32'b101111?????01001???????????????? // D-Cache Index Store Tag
32'b101111?????10001???????????????? // D-Cache Hit Invalid
32'b101111?????10101???????????????? // D-Cache Hit Writeback Invalid
```
其中,`Index Store Tag`中使用到了`TagLo`和`TagHi`寄存器。考虑到地址最多`32`位,故不实现`TagHi`寄存器(恒`0`);同时,由于`TagLo`和`TagHi`寄存器定义与具体处理器实现相关,在应用上用于将`Cache`的`Tag`清零(可以魔改内核),故也不实现`TagLo`寄存器(恒`0`)。所以`Index Store Tag`指令在实现上变为不写回的`Index Invalid`
对于上述操作,具体实现:
```
Cache -> VIPT
Index Invalid : VA -> Index -> (Write Back) -> Write Zero
Index Store Tag : VA -> Index -> Write Zero
Hit Invalid : VA -> Lookup -> Hit? -> Write Zero
Hit Writeback Invalid : VA -> Lookup -> Hit? -> (Write Back) -> Write Zero
```
控制信号:
| `CacheOp[2]` | `CacheOp[1]` | `CacheOp[0]` | Name |
| :------------------------: | :---------------------: | :----------------------------: | :---: |
| 0 | 0 | 0 | `NOP` |
| 0 | 0 | 1 | |
| 0 | 1 | ? | |
| 1 | 0 | 0 | |
| 1 | 0 | 1 | |
| 1 | 1 | 0 | |
| 1 | 1 | 1 | |
| `I-Cache(0) or D-Cache(1)` | `Lookup(0) or Index(1)` | `WriteBack(0) or WriteOnly(1)` | |
备注:
1. `Cache`指令当成写请求
2.

View File

@ -45,7 +45,6 @@ module CP0 (
& |{rf_cp0.Cause.IP & rf_cp0.Status.IM,
rf_cp0.Cause.TI & rf_cp0.Status.IM[7]};
assign rf_cp0.TagLo.zero = 9'b0;
assign rf_cp0.Config.M = 1'b1;
assign rf_cp0.Config.zero = 15'b0;
assign rf_cp0.Config.BE = 1'b0;
@ -88,9 +87,6 @@ module CP0 (
always_ff @(posedge clk)
if (rst) begin
rf_cp0.TagLo.Tag = 21'b0;
rf_cp0.TagLo.D = 1'b0;
rf_cp0.TagLo.V = 1'b0;
rf_cp0.Config.K0 = 3'b011;
rf_cp0.EPC = 32'h0;
rf_cp0.Cause.BD = 1'b0;
@ -135,11 +131,7 @@ module CP0 (
// 31: rf_cp0.DESAVE = wdata;
// 30: rf_cp0.ErrorEPC = wdata;
// 29: rf_cp0.TagHi = wdata;
28: begin
rf_cp0.TagLo.Tag = wdata[22:2];
rf_cp0.TagLo.D = wdata[1];
rf_cp0.TagLo.V = wdata[0];
end
// 28: rf_cp0.TagLo = wdata;
// 27: rf_cp0.CacheErr = wdata;
// 26: rf_cp0.Errctl = wdata;
// 25: rf_cp0.PerfCnt = wdata;
@ -257,7 +249,7 @@ module CP0 (
// 31: rdata = rf_cp0.DESAVE;
// 30: rdata = rf_cp0.ErrorEPC;
// 29: rdata = rf_cp0.TagHi;
28: rdata = rf_cp0.TagLo;
// 28: rdata = rf_cp0.TagLo;
// 27: rdata = rf_cp0.CacheErr;
// 26: rdata = rf_cp0.Errctl;
// 25: rdata = rf_cp0.PerfCnt;

View File

@ -240,10 +240,10 @@ module DCache (
assign DataRAM2.wen = (bwe1 & wen[2]) | (bwe2 & wen2[2]);
assign DataRAM3.wen = (bwe1 & wen[3]) | (bwe2 & wen2[3]);
// 写数据
assign TagRAM0.wdata = {port.tag1, port.wvalid, 1'b1};
assign TagRAM1.wdata = {port.tag1, port.wvalid, 1'b1};
assign TagRAM2.wdata = {port.tag1, port.wvalid, 1'b1};
assign TagRAM3.wdata = {port.tag1, port.wvalid, 1'b1};
assign TagRAM0.wdata = port.clear ? `DC_TAG_LENGTH'b0 : {port.tag1, port.wvalid, 1'b1};
assign TagRAM1.wdata = port.clear ? `DC_TAG_LENGTH'b0 : {port.tag1, port.wvalid, 1'b1};
assign TagRAM2.wdata = port.clear ? `DC_TAG_LENGTH'b0 : {port.tag1, port.wvalid, 1'b1};
assign TagRAM3.wdata = port.clear ? `DC_TAG_LENGTH'b0 : {port.tag1, port.wvalid, 1'b1};
assign DataRAM0.wdata = state == LOOKUP ? wdata1[0] : wdata2[0];
assign DataRAM1.wdata = state == LOOKUP ? wdata1[1] : wdata2[1];

View File

@ -90,14 +90,14 @@ module instr_valid (
32'b101010??????????????????????????: valid = 1'b1; // SWL
32'b101011??????????????????????????: valid = 1'b1; // SW
32'b101110??????????????????????????: valid = 1'b1; // SWR
32'b101111?????00000????????????????: valid = 1'b1; // I-Cache Index Invalid
32'b101111?????01000????????????????: valid = 1'b1; // I-Cache Index Store Tag
32'b101111?????10000????????????????: valid = 1'b1; // I-Cache Hit Invalid
32'b101111?????00001????????????????: valid = 1'b1; // D-Cache Index Writeback Invalid
32'b101111?????01001????????????????: valid = 1'b1; // D-Cache Index Store Tag
32'b101111?????10001????????????????: valid = 1'b1; // D-Cache Hit Invalid
32'b101111?????10101????????????????: valid = 1'b1; // D-Cache Hit Writeback Invalid
32'b110011??????????????????????????: valid = 1'b1; // PREF (NOP)
// 32'b101111?????00000????????????????: valid = 1'b1; // I-Cache Index Invalid
// 32'b101111?????01000????????????????: valid = 1'b1; // I-Cache Index Store Tag
// 32'b101111?????10000????????????????: valid = 1'b1; // I-Cache Hit Invalid
// 32'b101111?????00001????????????????: valid = 1'b1; // D-Cache Index Writeback Invalid
// 32'b101111?????01001????????????????: valid = 1'b1; // D-Cache Index Store Tag
// 32'b101111?????10001????????????????: valid = 1'b1; // D-Cache Hit Invalid
// 32'b101111?????10101????????????????: valid = 1'b1; // D-Cache Hit Writeback Invalid
default: valid = 1'b0;
endcase
endmodule

View File

@ -12,8 +12,9 @@ module MMU (
ICache_i.mmu ic,
DCache_i.mmu dc,
sramro_i.slave inst,
sram_i.slave data,
sramro_i.slave inst,
sram_i.slave data,
input CacheOp_t cacheOp,
SRAM_RO_AXI_i.master inst_axi,
SRAM_RO_AXI_i.master rdata_axi,
@ -309,6 +310,8 @@ module MMU (
logic dUser1;
word_t dPA1, dPA2;
logic [1:0] dSize1;
CacheOp_t cacheOp1, cacheOp2;
logic dEn2;
logic dwr1;
@ -325,49 +328,15 @@ module MMU (
// ======== dFlip-Flop ========
// ============================
ffenr #(1) dvalid_ff (
clk,
rst,
data.req,
dEn,
dReq1
);
ffen #(2) dsize_ff (
clk,
data.size,
dEn,
dSize1
);
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
);
ffenr #(1) dvalid_ff (clk, rst, data.req, dEn, dReq1);
ffen #(2) dsize_ff (clk, data.size, dEn, dSize1);
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, dEn, cacheOp1);
ffen #(3) cache_op2_ff (clk, cacheOp1, dEn2, cacheOp2);
// =================================
// ======== drState Machine ========
@ -393,7 +362,7 @@ module MMU (
else begin
dEn2 = 1;
if (data.wr) data.data_ok = 1;
if (data.wr & (~dCached1 | dc.hit)) drNextState = DR_REFILL;
if (data.wr & (~dCached1 | dc.hit | cacheOp1[2])) drNextState = DR_REFILL;
else if (dCached1 & dc.hit) begin
dEn = 1;
data.data_ok = 1;
@ -453,10 +422,10 @@ module MMU (
assign dVA = data.addr;
assign dValid1 = dReq1 & dHit1 & dMValid1 & (~data.wr | dDirty1) & (in_kernel | dUser1);
assign dTLBRefill = (drState == DR_IDLE) & dReq1 & ~dHit1;
assign dTLBInvalid = (drState == DR_IDLE) & dReq1 & ~dMValid1;
assign dTLBModified = (drState == DR_IDLE) & dReq1 & data.wr & ~dDirty1;
assign dAddressError = (drState == DR_IDLE) & dReq1 & ~in_kernel & ~dUser1;
assign dTLBRefill = (drState == DR_IDLE) & dReq1 & ~cacheOp1[1] & ~dHit1;
assign dTLBInvalid = (drState == DR_IDLE) & dReq1 & ~cacheOp1[1] & ~dMValid1;
assign dTLBModified = (drState == DR_IDLE) & dReq1 & ~cacheOp1[1] & data.wr & ~dDirty1;
assign dAddressError = (drState == DR_IDLE) & dReq1 & ~cacheOp1[1] & ~in_kernel & ~dUser1;
// =============================
// ======== drFlip-Flop ========
@ -537,7 +506,11 @@ module MMU (
case (dwState)
DW_IDLE: begin
if (dEn2 & (~dCached1 & data.wr | dCached1 & ~dc.hit & dc.dirt_valid)) begin
if (dEn2 & (~dCached1 & data.wr
| dCached1 & dc.dirt_valid
& (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback Invalid 直接写回
)) begin
if (dCached1) begin
wdata_axi.wdata = dc.dirt_data[31:0];
wdata_axi.wstrb = 4'b1111;
@ -646,7 +619,11 @@ module MMU (
case (dwaState)
DWA_IDLE: begin
if (dEn2 & (~dCached1 & data.wr | dCached1 & ~dc.hit & dc.dirt_valid)) begin
if (dEn2 & (~dCached1 & data.wr
| dCached1 & dc.dirt_valid
& (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0])) // Writeback Invalid 直接写回
) begin
wdata_axi.req = 1'b1;
if (~wdata_axi.addr_ok) dwaNextState = DWA_WA;
end
@ -685,6 +662,8 @@ module MMU (
assign dc.wvalid = dEn2 ? data.wr : dwr1;
assign dc.wdata = dEn2 ? data.wdata : dWdata1;
assign dc.wstrb = dEn2 ? data.wstrb : dWstrb1;
assign dc.clear = dEn2 ? cacheOp1[2] & dCached1 & (dc.hit | cacheOp1[1])
: cacheOp2[2] & dCached2;
// ==============================
// ========== VA -> PA ==========

View File

@ -79,6 +79,8 @@ module mycpu_top (
sramro_i inst ();
sram_i data ();
CacheOp_t cache_op;
logic C0_int;
logic [4:0] C0_addr;
@ -135,6 +137,7 @@ module mycpu_top (
.dc (dcache.mmu),
.inst (inst.slave),
.data (data.slave),
.cacheOp (cache_op),
.inst_axi (inst_axi.master),
.rdata_axi (rdata_axi.master),
.wdata_axi (wdata_axi.master),

View File

@ -2,7 +2,6 @@
`define CP0_SVH
`include "defines.svh"
`include "Cache.svh"
`include "TLB.svh"
typedef enum bit [4:0] {
@ -94,8 +93,8 @@ typedef struct packed {
// ==== sel0 ====
// word_t DESAVE,
// ErrorEPC,
// word_t TagHi;
TagLo_t TagLo;
// TagHi
word_t TagLo;
// CacheErr,
// Errctl,
// PerfCnt,
@ -109,7 +108,7 @@ typedef struct packed {
// LLAddr
// ;
CP0_REGS_CONFIG_t Config;
word_t PRId;
word_t PRId;
word_t EPC;
CP0_REGS_CAUSE_t Cause;
CP0_REGS_STATUS_t Status;

View File

@ -1,11 +0,0 @@
`ifndef CACHE_SVH
`define CACHE_SVH
typedef struct packed {
logic [ 8:0] zero;
logic [20:0] Tag;
logic D;
logic V;
} TagLo_t;
`endif

View File

@ -49,18 +49,21 @@ interface DCache_i;
word_t dirt_addr;
DCData_t dirt_data;
DCData_t row;
logic clear;
modport cache(
input req, valid,
input index, tag1, sel1,
input rvalid, rdata, wvalid, wdata, wstrb,
output hit, dirt_valid, dirt_addr, dirt_data, row
input req, valid,
input index, tag1, sel1,
input rvalid, rdata, wvalid, wdata, wstrb,
output hit, dirt_valid, dirt_addr, dirt_data, row,
input clear
);
modport mmu(
output req, valid,
output index, tag1, sel1,
output rvalid, rdata, wvalid, wdata, wstrb,
input hit, dirt_valid, dirt_addr, dirt_data, row
output req, valid,
output index, tag1, sel1,
output rvalid, rdata, wvalid, wdata, wstrb,
input hit, dirt_valid, dirt_addr, dirt_data, row,
output clear
);
endinterface //DCache_i

View File

@ -41,15 +41,22 @@ interface ICache_i;
ICData_t row;
logic rvalid;
ICData_t rdata;
logic clear;
modport cache(input req, valid,
input index, tag1,
output hit, row,
input rvalid, rdata);
modport mmu(output req, valid,
output index, tag1,
input hit, row,
output rvalid, rdata);
modport cache(
input req, valid,
input index, tag1,
output hit, row,
input rvalid, rdata,
input clear
);
modport mmu(
output req, valid,
output index, tag1,
input hit, row,
output rvalid, rdata,
output clear
);
endinterface //ICache_i
`endif

View File

@ -83,6 +83,16 @@ typedef enum logic [1:0] {
URIGHT = 2'b10
} ALR_t;
typedef enum logic [2:0] {
CNOP = 3'b000,
IC_L = 3'b001, // I-Cache Lookup
IC_I = 3'b011, // I-Cache Index
DC_LB = 3'b100, // D-Cache Lookup writeBack
DC_LO = 3'b101, // D-Cache Lookup writeOnly
DC_IB = 3'b110, // D-Cache Index writeBack
DC_IO = 3'b111 // D-Cache Index writeOnly
} CacheOp_t;
typedef struct packed {
SA_t SA;
SB_t SB;
@ -101,15 +111,16 @@ typedef struct packed {
} MCtrl0_t;
typedef struct packed {
logic MR; // critical
logic MWR; // critical
logic MR; // critical
logic MWR; // critical
logic MX;
ALR_t ALR; // critical
ALR_t ALR; // critical
logic [1:0] SZ;
logic TLBWI; // critical
logic TLBWR; // critical
logic TLBR; // critical
logic TLBP; // critical
logic TLBWI; // critical
logic TLBWR; // critical
logic TLBR; // critical
logic TLBP; // critical
CacheOp_t CACHE_OP; // critical
} MCtrl1_t;
typedef struct packed {