[Cache] ICache fix LRU
This commit is contained in:
parent
d76e825756
commit
c85c69e804
@ -50,6 +50,7 @@ module ICache (
|
|||||||
|
|
||||||
wire [`IC_TAG_LENGTH-1:0] tagOut1[4];
|
wire [`IC_TAG_LENGTH-1:0] tagOut1[4];
|
||||||
wire [`IC_DATA_LENGTH-1:0] dataOut1[4];
|
wire [`IC_DATA_LENGTH-1:0] dataOut1[4];
|
||||||
|
wire [3:0] tagV1;
|
||||||
|
|
||||||
wire hit1; // Cache hit or not
|
wire hit1; // Cache hit or not
|
||||||
wire [3:0] hitWay1; // Cache Line hit or not
|
wire [3:0] hitWay1; // Cache Line hit or not
|
||||||
@ -66,6 +67,7 @@ module ICache (
|
|||||||
|
|
||||||
wire hit2;
|
wire hit2;
|
||||||
wire [3:0] hitWay2;
|
wire [3:0] hitWay2;
|
||||||
|
wire [3:0] tagV2;
|
||||||
|
|
||||||
typedef enum logic [1:0] {
|
typedef enum logic [1:0] {
|
||||||
Idle,
|
Idle,
|
||||||
@ -81,6 +83,7 @@ module ICache (
|
|||||||
wire [5:0] addr3;
|
wire [5:0] addr3;
|
||||||
wire [`IC_TAG_LENGTH-2:0] tag3;
|
wire [`IC_TAG_LENGTH-2:0] tag3;
|
||||||
wire [1:0] victim3;
|
wire [1:0] victim3;
|
||||||
|
wire [3:0] tagV3;
|
||||||
wire [3:0] wen3;
|
wire [3:0] wen3;
|
||||||
|
|
||||||
|
|
||||||
@ -103,10 +106,11 @@ module ICache (
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
mux2 #(6) ctrl0_mux (
|
mux3 #(6) ctrl0_mux (
|
||||||
sram.addr[9:4],
|
sram.addr[9:4],
|
||||||
|
PC1[9:4],
|
||||||
wAddr4,
|
wAddr4,
|
||||||
ctrl0,
|
{ctrl0, ~sram.addr_ok}, // TODO: 这里可能有问题,需要详细测试
|
||||||
cacheAddress0
|
cacheAddress0
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -135,7 +139,7 @@ module ICache (
|
|||||||
// =========== Lookup ===========
|
// =========== Lookup ===========
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
// TODO: 确保cacheMiss时tagOut1和dataOut1不变
|
// 确保cacheMiss时tagOut1和dataOut1不变 -> L106 mux3解决?
|
||||||
assign tagOut1[0] = TagRAM0.rdata;
|
assign tagOut1[0] = TagRAM0.rdata;
|
||||||
assign tagOut1[1] = TagRAM1.rdata;
|
assign tagOut1[1] = TagRAM1.rdata;
|
||||||
assign tagOut1[2] = TagRAM2.rdata;
|
assign tagOut1[2] = TagRAM2.rdata;
|
||||||
@ -146,14 +150,19 @@ module ICache (
|
|||||||
assign dataOut1[2] = DataRAM2.rdata;
|
assign dataOut1[2] = DataRAM2.rdata;
|
||||||
assign dataOut1[3] = DataRAM3.rdata;
|
assign dataOut1[3] = DataRAM3.rdata;
|
||||||
|
|
||||||
|
assign tagV1[0] = tagOut1[0][0];
|
||||||
|
assign tagV1[1] = tagOut1[1][0];
|
||||||
|
assign tagV1[2] = tagOut1[2][0];
|
||||||
|
assign tagV1[3] = tagOut1[3][0];
|
||||||
|
|
||||||
// Hit Check
|
// Hit Check
|
||||||
assign tag1 = PC1[31:10];
|
assign tag1 = PC1[31:10];
|
||||||
|
assign addr1 = PC1[9:4];
|
||||||
|
|
||||||
assign hitWay1[0] = tagOut1[0][0] & tagOut1[0][`IC_TAG_LENGTH-1:1] == tag1;
|
assign hitWay1[0] = tagV1[0] & tagOut1[0][`IC_TAG_LENGTH-1:1] == tag1;
|
||||||
assign hitWay1[1] = tagOut1[1][0] & tagOut1[1][`IC_TAG_LENGTH-1:1] == tag1;
|
assign hitWay1[1] = tagV1[1] & tagOut1[1][`IC_TAG_LENGTH-1:1] == tag1;
|
||||||
assign hitWay1[2] = tagOut1[2][0] & tagOut1[2][`IC_TAG_LENGTH-1:1] == tag1;
|
assign hitWay1[2] = tagV1[2] & tagOut1[2][`IC_TAG_LENGTH-1:1] == tag1;
|
||||||
assign hitWay1[3] = tagOut1[3][0] & tagOut1[3][`IC_TAG_LENGTH-1:1] == tag1;
|
assign hitWay1[3] = tagV1[3] & tagOut1[3][`IC_TAG_LENGTH-1:1] == tag1;
|
||||||
assign hit1 = hitWay1[0] | hitWay1[1] | hitWay1[2] | hitWay1[3];
|
assign hit1 = hitWay1[0] | hitWay1[1] | hitWay1[2] | hitWay1[3];
|
||||||
|
|
||||||
assign cacheLine1 = (hitWay1[0] ? dataOut1[0] : `IC_DATA_LENGTH'b0) |
|
assign cacheLine1 = (hitWay1[0] ? dataOut1[0] : `IC_DATA_LENGTH'b0) |
|
||||||
@ -221,12 +230,12 @@ module ICache (
|
|||||||
// ==== Pipeline Register 2 =====
|
// ==== Pipeline Register 2 =====
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
ffenr #(37) pipelineReg2 (
|
ffenr #(41) pipelineReg2 (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.rst(rst | AXIBlocker == Done),
|
.rst(rst | AXIBlocker == Done),
|
||||||
.en (AXIBlocker == Idle), // TODO: 这里需要重新设计一下: AXI是否流水
|
.en (AXIBlocker == Idle), // TODO: 这里需要重新设计一下: AXI是否流水
|
||||||
.d ({PC1, hitWay1, cacheMiss}),
|
.d ({PC1, hitWay1, cacheMiss, tagV1}),
|
||||||
.q ({PC2, hitWay2, req2}) // TODO: Req2的逻辑可能有误
|
.q ({PC2, hitWay2, req2, tagV2})
|
||||||
);
|
);
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
@ -268,19 +277,23 @@ module ICache (
|
|||||||
// ==== Pipeline Register 3 =====
|
// ==== Pipeline Register 3 =====
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
ffenr #(`IC_DATA_LENGTH + 1 + 6 + 22) pipelineReg3 (
|
ffenr #(`IC_DATA_LENGTH + 1 + 6 + 22 + 4) pipelineReg3 (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.rst(rst),
|
.rst(rst),
|
||||||
.en (1'b1),
|
.en (1'b1),
|
||||||
.d ({ICacheLine, ICacheLineOK, PC2[9:4], PC2[31:10]}),
|
.d ({ICacheLine, ICacheLineOK, PC2[9:4], PC2[31:10], tagV2}),
|
||||||
.q ({ICacheLine3, ICacheLineOK3, addr3, tag3})
|
.q ({ICacheLine3, ICacheLineOK3, addr3, tag3, tagV3})
|
||||||
);
|
);
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
// ========== Replace ===========
|
// ========== Replace ===========
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
assign victim3 = LRU[addr3][0] == 0 ? 2'b00 :
|
assign victim3 = tagV3[0] == 0 ? 2'b00 :
|
||||||
|
tagV3[1] == 0 ? 2'b01 :
|
||||||
|
tagV3[2] == 0 ? 2'b10 :
|
||||||
|
tagV3[3] == 0 ? 2'b11 :
|
||||||
|
LRU[addr3][0] == 0 ? 2'b00 :
|
||||||
LRU[addr3][1] == 0 ? 2'b01 :
|
LRU[addr3][1] == 0 ? 2'b01 :
|
||||||
LRU[addr3][2] == 0 ? 2'b10 :
|
LRU[addr3][2] == 0 ? 2'b10 :
|
||||||
LRU[addr3][3] == 0 ? 2'b11 :
|
LRU[addr3][3] == 0 ? 2'b11 :
|
||||||
@ -290,6 +303,13 @@ module ICache (
|
|||||||
assign wen3[2] = (victim3 == 2) & ICacheLineOK3;
|
assign wen3[2] = (victim3 == 2) & ICacheLineOK3;
|
||||||
assign wen3[3] = (victim3 == 3) & ICacheLineOK3;
|
assign wen3[3] = (victim3 == 3) & ICacheLineOK3;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (wen3 != 0) begin
|
||||||
|
$display("Victim Found: wen3=0x%b, addr3=0x%8h, tagV3=0x%b, LRU=0x%b", wen3, addr3, tagV3,
|
||||||
|
LRU[addr3]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
// ==== Pipeline Register 4 =====
|
// ==== Pipeline Register 4 =====
|
||||||
// ==============================
|
// ==============================
|
||||||
|
2
src/testbench/icache/.gitignore
vendored
2
src/testbench/icache/.gitignore
vendored
@ -1,3 +1 @@
|
|||||||
obj_dir
|
|
||||||
logs
|
|
||||||
coe
|
coe
|
@ -1,13 +0,0 @@
|
|||||||
verilator -I/home/paul/loongson/MIPS/src/AXI/ \
|
|
||||||
-I/home/paul/loongson/MIPS/src/Cache/ \
|
|
||||||
-I/home/paul/loongson/MIPS/src/Core/ \
|
|
||||||
-I/home/paul/loongson/MIPS/src/CP0/ \
|
|
||||||
-I/home/paul/loongson/MIPS/src/include/ \
|
|
||||||
-I/home/paul/loongson/MIPS/src/testbench/happy/ \
|
|
||||||
+1800-2017ext+sv \
|
|
||||||
--cc --trace --exe --build \
|
|
||||||
sim_main.cpp testbench.sv
|
|
||||||
|
|
||||||
./obj_dir/Vtestbench +trace
|
|
||||||
|
|
||||||
gtkwave ./logs/vlt_dump.vcd
|
|
@ -1,90 +0,0 @@
|
|||||||
#include <memory>
|
|
||||||
#include "Vtestbench.h"
|
|
||||||
#include "verilated.h"
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **env)
|
|
||||||
{
|
|
||||||
// Create logs/ directory in case we have traces to put under it
|
|
||||||
Verilated::mkdir("logs");
|
|
||||||
|
|
||||||
// Construct a VerilatedContext to hold simulation time, etc.
|
|
||||||
// Multiple modules (made later below with Vtop) may share the same
|
|
||||||
// context to share time, or modules may have different contexts if
|
|
||||||
// they should be independent from each other.
|
|
||||||
|
|
||||||
// Using unique_ptr is similar to
|
|
||||||
// "VerilatedContext* contextp = new VerilatedContext" then deleting at end.
|
|
||||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
|
||||||
|
|
||||||
// Set debug level, 0 is off, 9 is highest presently used
|
|
||||||
// May be overridden by commandArgs argument parsing
|
|
||||||
contextp->debug(0);
|
|
||||||
|
|
||||||
// Randomization reset policy
|
|
||||||
// May be overridden by commandArgs argument parsing
|
|
||||||
contextp->randReset(2);
|
|
||||||
|
|
||||||
// Verilator must compute traced signals
|
|
||||||
contextp->traceEverOn(true);
|
|
||||||
|
|
||||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
|
||||||
// This needs to be called before you create any model
|
|
||||||
contextp->commandArgs(argc, argv);
|
|
||||||
|
|
||||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v".
|
|
||||||
// Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at end.
|
|
||||||
// "TOP" will be the hierarchical name of the module.
|
|
||||||
const std::unique_ptr<Vtestbench> top{new Vtestbench{contextp.get(), "TESTBENCH"}};
|
|
||||||
|
|
||||||
// Set Vtop's input signals
|
|
||||||
top->clk = 0;
|
|
||||||
top->rst = 0;
|
|
||||||
|
|
||||||
// Simulate until $finish
|
|
||||||
while (!contextp->gotFinish())
|
|
||||||
{
|
|
||||||
// Historical note, before Verilator 4.200 Verilated::gotFinish()
|
|
||||||
// was used above in place of contextp->gotFinish().
|
|
||||||
// Most of the contextp-> calls can use Verilated:: calls instead;
|
|
||||||
// the Verilated:: versions simply assume there's a single context
|
|
||||||
// being used (per thread). It's faster and clearer to use the
|
|
||||||
// newer contextp-> versions.
|
|
||||||
|
|
||||||
contextp->timeInc(1); // 1 timeprecision period passes...
|
|
||||||
// Historical note, before Verilator 4.200 a sc_time_stamp()
|
|
||||||
// function was required instead of using timeInc. Once timeInc()
|
|
||||||
// is called (with non-zero), the Verilated libraries assume the
|
|
||||||
// new API, and sc_time_stamp() will no longer work.
|
|
||||||
|
|
||||||
// Toggle a fast (time/2 period) clock
|
|
||||||
top->clk = !top->clk;
|
|
||||||
|
|
||||||
// Evaluate model
|
|
||||||
// (If you have multiple models being simulated in the same
|
|
||||||
// timestep then instead of eval(), call eval_step() on each, then
|
|
||||||
// eval_end_step() on each. See the manual.)
|
|
||||||
top->eval();
|
|
||||||
|
|
||||||
// Read outputs
|
|
||||||
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rst=%x -> "
|
|
||||||
"req=%x "
|
|
||||||
"addr=%" VL_PRI64 "x "
|
|
||||||
"addr_ok=%x data_ok=%x "
|
|
||||||
"rdata0=%" VL_PRI64 "x "
|
|
||||||
"rdata1=%" VL_PRI64 "x "
|
|
||||||
"\n",
|
|
||||||
contextp->time(), top->clk, top->rst,
|
|
||||||
top->req,
|
|
||||||
top->addr,
|
|
||||||
top->addr_ok, top->data_ok,
|
|
||||||
top->rdata0,
|
|
||||||
top->rdata1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final model cleanup
|
|
||||||
top->final();
|
|
||||||
|
|
||||||
// Return good completion status
|
|
||||||
// Don't use exit() or destructor won't get called
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -114,7 +114,7 @@ module test ();
|
|||||||
assign rready = fake_axi.AXIReadAddr.rready;
|
assign rready = fake_axi.AXIReadAddr.rready;
|
||||||
|
|
||||||
integer counter = 0;
|
integer counter = 0;
|
||||||
reg [31:0] addr;
|
reg [11:0] addr;
|
||||||
enum logic [1:0] {
|
enum logic [1:0] {
|
||||||
IDLE,
|
IDLE,
|
||||||
REQ,
|
REQ,
|
||||||
@ -135,8 +135,8 @@ module test ();
|
|||||||
nextStatus = REQ;
|
nextStatus = REQ;
|
||||||
end else begin
|
end else begin
|
||||||
fake_sram.req = 1'b1;
|
fake_sram.req = 1'b1;
|
||||||
//fake_sram.addr = addr;
|
fake_sram.addr = {18'b0, addr, 2'b0};
|
||||||
fake_sram.addr = addrt[addrx];
|
//fake_sram.addr = addrt[addrx];
|
||||||
nextStatus = REQ;
|
nextStatus = REQ;
|
||||||
end
|
end
|
||||||
end else nextStatus = IDLE;
|
end else nextStatus = IDLE;
|
||||||
@ -148,8 +148,12 @@ module test ();
|
|||||||
end
|
end
|
||||||
if (fake_sram.data_ok) begin
|
if (fake_sram.data_ok) begin
|
||||||
nextStatus = IDLE;
|
nextStatus = IDLE;
|
||||||
//addr = addr + 8;
|
if(fake_sram.rdata0 != (addr&'hFFE) && fake_sram.rdata1 != (addr&'hFFE) + 1)begin
|
||||||
addrx = addrx + 1;
|
$display("ERROR OCCURED! addr=0x%8h, rdata0=0x%8h, rdata1=0x%8h",
|
||||||
|
((addr-1)<<2), fake_sram.rdata0, fake_sram.rdata1);
|
||||||
|
end
|
||||||
|
addr = addr + 1;
|
||||||
|
//addrx = addrx + 1;
|
||||||
end else nextStatus = REQ;
|
end else nextStatus = REQ;
|
||||||
end else nextStatus = IDLE;
|
end else nextStatus = IDLE;
|
||||||
end
|
end
|
||||||
@ -190,7 +194,7 @@ module test ();
|
|||||||
$dumpvars();
|
$dumpvars();
|
||||||
|
|
||||||
status = IDLE;
|
status = IDLE;
|
||||||
addr = 20;
|
addr = 0;
|
||||||
|
|
||||||
addrx = 0;
|
addrx = 0;
|
||||||
addrt[0] = 48;
|
addrt[0] = 48;
|
@ -1,45 +0,0 @@
|
|||||||
`include "ICache.svh"
|
|
||||||
`include "sram.svh"
|
|
||||||
|
|
||||||
module testbench (
|
|
||||||
input clk,
|
|
||||||
input rst,
|
|
||||||
output req,
|
|
||||||
output word_t addr,
|
|
||||||
output addr_ok,
|
|
||||||
output data_ok,
|
|
||||||
output word_t rdata0,
|
|
||||||
output word_t rdata1
|
|
||||||
);
|
|
||||||
|
|
||||||
sramro_i fake_sram ();
|
|
||||||
ICache ic (
|
|
||||||
.clk (clk),
|
|
||||||
.rst (rst),
|
|
||||||
.sram(fake_sram.slave)
|
|
||||||
);
|
|
||||||
|
|
||||||
assign req = fake_sram.req;
|
|
||||||
assign addr = fake_sram.addr;
|
|
||||||
assign addr_ok = fake_sram.addr_ok;
|
|
||||||
assign data_ok = fake_sram.data_ok;
|
|
||||||
assign rdata0 = fake_sram.rdata0;
|
|
||||||
assign rdata1 = fake_sram.rdata1;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
$dumpfile("logs/vlt_dump.vcd");
|
|
||||||
$dumpvars();
|
|
||||||
fake_sram.req = 1;
|
|
||||||
fake_sram.addr = 32'b0100000;
|
|
||||||
end
|
|
||||||
|
|
||||||
integer counter = 0;
|
|
||||||
always_ff @(posedge clk) begin
|
|
||||||
if (fake_sram.data_ok) fake_sram.addr = fake_sram.addr + 1;
|
|
||||||
if (clk == 1'b1) begin
|
|
||||||
counter = counter + 1;
|
|
||||||
if (counter >= 16) $finish;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
Loading…
Reference in New Issue
Block a user