refactor CACHE inst on D-CACHE

This commit is contained in:
Paul Pan 2021-09-05 23:59:23 +08:00
parent f8d7b7b0c6
commit 9df689ed7a
5 changed files with 199 additions and 57 deletions

View File

@ -1462,8 +1462,10 @@
LI(t2, data1); \
LI(t3, data2); \
/* prepare -> hit writeback invalidate */ \
sw t2, offset(t0); \
sw t2, offset(t1); \
cache 21, offset(t1); \
lw a0, offset(t0); \
bne t2, a0, inst_error; \
lw a0, offset(t1); \
bne t2, a0, inst_error; \
nop; \
@ -1472,12 +1474,16 @@
cache 17, offset(t1); \
lw a0, offset(t0); \
bne a0, t2, inst_error; \
lw a0, offset(t1); \
bne a0, t2, inst_error; \
nop; \
/* test hit writeback invalidate */ \
sw t3, offset(t1); \
cache 21, offset(t1); \
lw a0, offset(t0); \
bne a0, t3, inst_error; \
lw a0, offset(t1); \
bne a0, t3, inst_error; \
nop; \
/* test multiple*/ \
addi a1, t1, 4; \

View File

@ -8,6 +8,9 @@ LEAF(n98_cache_dcache_test)
li s2, 0x0
###test inst
## CACHE 17 D-Cache Hit Invalid
## CACHE 21 D-Cache Hit Writeback Invalid
TEST_CACHE_DCACHE_HIT(0xa00d0000, 0x800d0000, 0, 0xA5A5A5A5, 0x12345678)
TEST_CACHE_DCACHE_HIT(0xa00d0004, 0x800d0004, 0, 0xABCDEFAB, 0xF0F0F0F0)
TEST_CACHE_DCACHE_HIT(0xa00d0008, 0x800d0008, 4, 0x87654321, 0xAABBCCDD)
@ -125,7 +128,80 @@ TEST_CACHE_DCACHE_HIT(0xa00d0028, 0x800d0028, 4, 0xF0F0F0F0, 0xABCDEFAB)
nop
/* TEST D-CACHE Index OP */
## CACHE 1 D-Cache Index Writeback Invalid
## CACHE 9 D-Cache Index Store Tag
.n98_c1_prepare:
li a0, 0x12345678
li v0, 0x800d0000
li v1, 0x800d0200
.n98_c1_loop:
beq v0, v1, .n98_c1_check
sw a0, 0(v0)
sw a0, 4(v0)
sw a0, 8(v0)
sw a0, 12(v0)
addi a1, v0, 0
GET_DCACHE_INDEX
cache 0, 0(v0)
addi v0, a1, 16
j .n98_c1_loop
.n98_c1_check:
li v0, 0xa00d0000
li v1, 0xa00d0200
.n98_c1_check_loop:
beq v0, v1, .n98_c1_check2
lw a1, 0(v0)
bne a0, a1, inst_error
addi v0, v0, 4
j .n98_c1_check_loop
.n98_c1_check2:
li v0, 0x800d0000
li v1, 0x800d0200
.n98_c1_check2_loop:
beq v0, v1, .n98_c9_prepare
lw a1, 0(v0)
bne a0, a1, inst_error
addi v0, v0, 4
j .n98_c1_check2_loop
.n98_c9_prepare:
li v0, 0x800d0000
li v1, 0x800d0200
.n98_c9_loop:
beq v0, v1, .n98_c9_check
sw zero, 0(v0)
sw zero, 4(v0)
sw zero, 8(v0)
sw zero, 12(v0)
addi a1, v0, 0
GET_DCACHE_INDEX
cache 9, 0(v0)
addi v0, a1, 16
j .n98_c9_loop
.n98_c9_check:
li v0, 0xa00d0000
li v1, 0xa00d0200
.n98_c9_check_loop:
beq v0, v1, .n98_c9_check2
lw a1, 0(v0)
bne a0, a1, inst_error
addi v0, v0, 4
j .n98_c9_check_loop
.n98_c9_check2:
li v0, 0x800d0000
li v1, 0x800d0200
.n98_c9_check2_loop:
beq v0, v1, .n98_done
lw a1, 0(v0)
bne a0, a1, inst_error
addi v0, v0, 4
j .n98_c9_check2_loop
.n98_done:
nop
###detect exception
bne s2, zero, inst_error

View File

@ -24,22 +24,22 @@ module DCache (
// ==============================
// Four way assoc bram controller:
DCTagRAM_t TagRAM0, TagRAM1, TagRAM2, TagRAM3;
DCTagRAM_t TagRAM0, TagRAM1, TagRAM2, TagRAM3;
DCDataRAM_t DataRAM0, DataRAM1, DataRAM2, DataRAM3;
logic [3:0] LRU[128];
logic [3:0] nextLRU;
logic [3:0] nowLRU;
DCTag_t tagOut[4];
DCData_t dataOut[4];
DCTag_t tagOut[4];
DCData_t dataOut[4];
logic [3:0] tagV;
DCIndexL_t index1;
logic hit;
logic hit;
logic [3:0] hitWay;
DCData_t cacheLine;
DCData_t cacheLine;
logic [3:0] victim;
logic [3:0] wen;
@ -56,18 +56,8 @@ module DCache (
// ======== Flip-Flop ========
// ===========================
ffen #(`DC_TAGL-`DC_INDEXL) index_ff (
clk,
port.index,
port.req,
index1
);
ffen #(4) wen_ff (
clk,
wen,
en2,
wen2
);
ffen #(`DC_TAGL-`DC_INDEXL) index_ff (clk, port.index, port.req, index1);
ffen #(4) wen_ff (clk, wen, en2, wen2);
// ===============================
// ======== State Machine ========
@ -97,7 +87,7 @@ module DCache (
nextState = IDLE;
end
end else begin
if (hit) begin
if (hit & ~port.clearWb | port.clear & port.clearIdx) begin
if (port.wvalid) begin
bwe1 = 1'b1;
nextState = IDLE;
@ -161,20 +151,21 @@ module DCache (
// ==============================
// Choose Victim
assign victim = port.clear ? hitWay
: tagV[0] == 0 ? 4'b0001
: tagV[1] == 0 ? 4'b0010
: tagV[2] == 0 ? 4'b0100
: tagV[3] == 0 ? 4'b1000
assign victim = port.clearWb ? hitWay
: tagV[0] == 0 ? 4'b0001
: tagV[1] == 0 ? 4'b0010
: tagV[2] == 0 ? 4'b0100
: tagV[3] == 0 ? 4'b1000
: nowLRU[0] == 0 & ~tagOut[0].dirty ? 4'b0001
: nowLRU[1] == 0 & ~tagOut[1].dirty ? 4'b0010
: nowLRU[2] == 0 & ~tagOut[2].dirty ? 4'b0100
: nowLRU[3] == 0 & ~tagOut[3].dirty ? 4'b1000
: nowLRU[0] == 0 ? 4'b0001
: nowLRU[1] == 0 ? 4'b0010
: nowLRU[2] == 0 ? 4'b0100
: nowLRU[0] == 0 ? 4'b0001
: nowLRU[1] == 0 ? 4'b0010
: nowLRU[2] == 0 ? 4'b0100
: 4'b1000;
assign wen = hit ? hitWay : victim;
assign wen = port.clear & port.clearIdx ? 4'b1111
: hit ? hitWay : victim;
assign port.dirt_valid = (state == LOOKUP)
& |{tagV & {tagOut[3].dirty, tagOut[2].dirty, tagOut[1].dirty, tagOut[0].dirty} & victim};

View File

@ -60,12 +60,12 @@ module MMU (
I_CACHE, I_CACHE_REFILL
} istate_t;
typedef enum bit [2:0] {
typedef enum bit [3:0] {
DR_IDLE,
DR_WA,
DR_WD1, DR_WD2, DR_WD3, DR_WD4,
DR_REFILL,
DR_CACHE
DR_ICACHE, DR_CACHE, DR_CACHE_REFILL, DR_CACHE_CLEAR, DR_CACHE_REQ
} drstate_t;
typedef enum bit [2:0] {
@ -296,6 +296,9 @@ module MMU (
word_t ddAddr1;
logic [127:0] ddData1;
// D-Cache Clear
logic dClrValid, dClrRv, dClrReq;
// ============================
// ======== dFlip-Flop ========
// ============================
@ -329,14 +332,34 @@ module MMU (
drNextState = drState;
data.data_ok = 0;
rdata_axi.req = 0;
dc.clear = 0;
dc.clearIdx = 0;
dc.clearWb = 0;
dClrValid = 0;
dClrRv = 0;
dClrReq = 0;
case (drState)
DR_IDLE: begin
if (diReq) drNextState = DR_CACHE;
else if (~dValid1) dEn = 1;
if (diReq) drNextState = DR_ICACHE;
else if (dReq1 & cacheOp1[2] & dCached1) begin
if (cacheOp2[0]) begin
// Do not write back
// dc.valid = dc.wvalid = 1;
dClrValid = 1;
dc.clear = 1;
dc.clearIdx = cacheOp2[1];
drNextState = DR_CACHE_REFILL;
end else begin
// WriteBack
dc.clearWb = 1;
drNextState = DR_CACHE;
dEn2 = 1;
end
end else if (~dValid1) dEn = 1;
else begin
dEn2 = 1;
if (data.wr) data.data_ok = 1;
if (data.wr & (~dCached1 | dc.hit | cacheOp1[2])) drNextState = DR_REFILL;
if (data.wr & (~dCached1 | dc.hit)) drNextState = DR_REFILL;
else if (dCached1 & dc.hit) begin
dEn = 1;
data.data_ok = 1;
@ -386,7 +409,7 @@ module MMU (
drNextState = DR_IDLE;
end
end
DR_CACHE: begin
DR_ICACHE: begin
/*
* I-CACHE
* iState == I_CACHE_REFILL
@ -397,6 +420,38 @@ module MMU (
drNextState = DR_IDLE;
end
end
DR_CACHE: begin
// WriteBack
// Clear By Index or Address
// D-Cache: state == REPLACE
if (wdata_ok) begin
if (cacheOp2[1]) begin
drNextState = DR_CACHE_CLEAR;
end else begin
dClrRv = 1;
dc.clear = 1;
drNextState = DR_CACHE_REFILL;
end
// drNextState = DR_CACHE_CLEAR;
end
end
DR_CACHE_REFILL: begin
// avoid deadlock
dEn = 1;
drNextState = DR_IDLE;
data.data_ok = 1;
end
DR_CACHE_CLEAR: begin
// deal with timing loop
dClrRv = 1;
dc.clear = 1;
drNextState = DR_CACHE_REQ;
end
DR_CACHE_REQ: begin
// deal with timing loop
dClrReq = 1; // use dClrReq to start a new D-Cache req
drNextState = DR_IDLE;
end
endcase
end
@ -409,16 +464,30 @@ module MMU (
* Cache
* TLB D-Cache 访
* dc.req I-Cache Cache 0
* drState DR_REFILL DW_STATE
* dwState dwaState CACHE
* dAddressError TLBModified Address TLBRefill TLBInvalid
* dc.clear
* Index WriteBack Hit WriteBack(s) + Index Invalid
*/
/*
D-Cache:
IDLE <- dc.req + dc.index
LOOKUP <- dc.tag1: Lookup模式下需要传入正确的tag1
dc.valid: 1
dc.wvalid: 1
dc.clear: Hit Invalid and Index Invalid
dc.clearIdx: Hit Invalid or Index Invalid
dc.clearWb:
-> dc.dirt_valid
dc.dirt_addr
dc.dirt_data
REPLACE <- dc.rvalid
dc.clear: same cycle as dc.rvalid
*/
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);
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);
assign dTLBRefill = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dHit1;
assign dTLBInvalid = drState == DR_IDLE & dcReq1 & (cacheOp1 == CNOP | ~cacheOp1[1]) & ~dMValid1;
@ -464,12 +533,12 @@ module MMU (
);
// do not request when handling CACHE instruction on I-Cache
assign dc.req = dEn & (cacheOp[2] | ~|cacheOp[1:0]);
assign dc.valid = dValid1 & (dCached1 & (~cacheOp1[2] | dc.hit) | cacheOp1[1]);
assign dc.index = dVA[`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];
assign dc.rvalid = rdata_axi.rvalid & rdata_axi.data_ok;
assign dc.req = dClrReq | dEn & (cacheOp[2] | ~|cacheOp[1:0]);
assign dc.valid = dClrValid | dValid1 & dCached1;
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];
assign dc.rvalid = dClrRv | rdata_axi.rvalid & rdata_axi.data_ok;
mux4 #(128) dc_rdata_mux (
{rdata_axi.rdata, drD3, drD2, drD1},
{drD3, drD2, drD1, rdata_axi.rdata},
@ -508,7 +577,7 @@ module MMU (
if (dEn2 & (~dCached1 & data.wr
| dCached1 & dc.dirt_valid
& (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback Invalid 直接写回
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况
)) begin
if (dCached1) begin
wdata_axi.wdata = dc.dirt_data[31:0];
@ -583,7 +652,7 @@ module MMU (
if (~wdata_axi.data_ok) dwNextState = DW_WB;
else begin
// fixme: AXI3 wait WA
if (drState == DR_REFILL) dwNextState = DW_IDLE;
if (drState == DR_REFILL | drState == DR_CACHE_REFILL) dwNextState = DW_IDLE;
else dwNextState = DW_WAITR;
end
end
@ -592,12 +661,12 @@ module MMU (
// TODO: goto IDLE on failure
if (wdata_axi.data_ok) begin
// fixme: AXI3 wait WA
if (drState == DR_REFILL) dwNextState = DW_IDLE;
if (drState == DR_REFILL | drState == DR_CACHE_REFILL) dwNextState = DW_IDLE;
else dwNextState = DW_WAITR;
end
end
DW_WAITR: begin
if (drState == DR_REFILL) dwNextState = DW_IDLE;
if (drState == DR_REFILL | drState == DR_CACHE_REFILL) dwNextState = DW_IDLE;
end
endcase
end
@ -621,8 +690,8 @@ module MMU (
if (dEn2 & (~dCached1 & data.wr
| dCached1 & dc.dirt_valid
& (~cacheOp1[2] | ~cacheOp1[0]) // WriteOnly 不允许写回
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0])) // Writeback Invalid 直接写回
) begin
& (~dc.hit | cacheOp1[2] & ~cacheOp1[0]) // Writeback 或一般情况
)) begin
wdata_axi.req = 1'b1;
if (~wdata_axi.addr_ok) dwaNextState = DWA_WA;
end
@ -658,11 +727,9 @@ module MMU (
assign wdata_axi.addr = (dEn2 ? dCached1 : dCached2) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2;
assign wdata_axi.len = (dEn2 ? dCached1 : dCached2) ? 4'b0011 : 4'b0000;
assign wdata_axi.size = (dEn2 ? dCached1 : dCached2) ? 3'b010 : {1'b0, dSize1};
assign dc.wvalid = dEn2 ? data.wr : dwr1;
assign dc.wvalid = dClrValid | 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

@ -50,20 +50,22 @@ interface DCache_i;
DCData_t dirt_data;
DCData_t row;
logic clear;
logic clearIdx;
logic clearWb;
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 clear
input clear, clearIdx, clearWb
);
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 clear
output clear, clearIdx, clearWb
);
endinterface //DCache_i