Line 57... |
Line 57... |
|
|
// Status
|
// Status
|
output miss_o /*verilator public*/,
|
output miss_o /*verilator public*/,
|
output busy_o /*verilator public*/,
|
output busy_o /*verilator public*/,
|
|
|
// Memory interface (slave)
|
// Memory interface
|
output reg [31:0] mem_addr_o /*verilator public*/,
|
output reg [31:0] wbm_addr_o /*verilator public*/,
|
input [31:0] mem_data_i /*verilator public*/,
|
input [31:0] wbm_dat_i /*verilator public*/,
|
output reg mem_burst_o /*verilator public*/,
|
output reg [2:0] wbm_cti_o /*verilator public*/,
|
output reg mem_rd_o /*verilator public*/,
|
output reg wbm_cyc_o /*verilator public*/,
|
input mem_accept_i/*verilator public*/,
|
output reg wbm_stb_o /*verilator public*/,
|
input mem_ack_i/*verilator public*/
|
input wbm_stall_i/*verilator public*/,
|
|
input wbm_ack_i/*verilator public*/
|
);
|
);
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Params
|
// Params
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
Line 98... |
Line 99... |
// (5-bits)
|
// (5-bits)
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Registers / Wires
|
// Registers / Wires
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
|
|
// Tag read / write data
|
wire [CACHE_TAG_WIDTH-1:0] tag_data_out;
|
wire [CACHE_TAG_WIDTH-1:0] tag_data_out;
|
reg [CACHE_TAG_WIDTH-1:0] tag_data_in;
|
reg [CACHE_TAG_WIDTH-1:0] tag_data_in;
|
reg tag_wr;
|
reg tag_wr;
|
|
|
|
// Tag address
|
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry;
|
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry;
|
wire [CACHE_DWIDTH-1:0] cache_address_rd;
|
|
|
|
|
// Data memory read / write
|
|
wire [CACHE_DWIDTH-1:0] cache_address_rd;
|
reg [CACHE_DWIDTH-1:0] cache_address_wr;
|
reg [CACHE_DWIDTH-1:0] cache_address_wr;
|
reg [31:0] cache_data_w;
|
reg [31:0] cache_data_in;
|
reg cache_wr;
|
reg cache_wr;
|
|
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] fetch_word;
|
// Word currently being fetched within a line
|
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_fetch_word;
|
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_resp_idx;
|
|
|
|
// Current / Miss PC
|
reg [31:0] last_pc;
|
reg [31:0] last_pc;
|
reg [31:0] miss_pc;
|
reg [31:0] miss_pc;
|
|
|
reg initial_fetch;
|
// Flush state
|
reg flush_req;
|
reg flush_req;
|
|
|
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr;
|
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr;
|
reg flush_wr;
|
reg flush_wr;
|
|
|
|
// Other state
|
|
reg initial_fetch;
|
reg read_while_busy;
|
reg read_while_busy;
|
|
|
// Current state
|
// Current state
|
parameter STATE_CHECK = 0;
|
parameter STATE_CHECK = 0;
|
parameter STATE_FETCH = 1;
|
parameter STATE_FETCH = 1;
|
parameter STATE_WAIT = 2;
|
parameter STATE_WAIT = 2;
|
parameter STATE_WAIT2 = 3;
|
parameter STATE_WAIT2 = 3;
|
parameter STATE_FLUSH = 4;
|
parameter STATE_FLUSH = 4;
|
reg [3:0] state;
|
reg [3:0] state;
|
|
|
assign tag_entry = (state != STATE_CHECK) ? miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
|
// Tag address from input PC or flopped version of it
|
|
assign tag_entry = (state != STATE_CHECK) ?
|
|
miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] :
|
|
pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
|
|
|
|
// Cache read address
|
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2];
|
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2];
|
|
|
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || (last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0;
|
// Cache miss output if requested PC is not in the tag memory
|
|
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] ||
|
|
(last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0;
|
|
|
|
// Cache output valid
|
assign valid_o = !miss_o && !busy_o;
|
assign valid_o = !miss_o && !busy_o;
|
|
|
|
// Stall the CPU if cache state machine is not idle!
|
|
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1;
|
|
|
|
// Final word to fetch from memory
|
|
wire mem_fetch_final_word = (mem_fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}});
|
|
|
|
// Flushing: Last line to flush
|
|
wire flush_final_line = (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}});
|
|
|
|
// Is this a cache miss?
|
|
wire cache_miss = (miss_o && // Tag lookup failed
|
|
!initial_fetch && // NOT initial fetch after reset
|
|
!rd_i && // NOT new read request cycle
|
|
!read_while_busy && // NOT pending read whilst busy
|
|
!flush_req && // NOT flush request
|
|
!invalidate_i);
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Control logic
|
// Next State Logic
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word;
|
reg [3:0] next_state_r;
|
|
always @ *
|
|
begin
|
|
next_state_r = state;
|
|
|
|
case (state)
|
|
|
|
//-----------------------------------------
|
|
// CHECK - check cache for hit or miss
|
|
//-----------------------------------------
|
|
STATE_CHECK :
|
|
begin
|
|
// Cache flush request pending?
|
|
if (flush_req || invalidate_i)
|
|
next_state_r = STATE_FLUSH;
|
|
// Cache miss (& new read request not pending)
|
|
else if (cache_miss)
|
|
next_state_r = STATE_FETCH;
|
|
// Cache hit (or new read request)
|
|
else
|
|
next_state_r = STATE_CHECK;
|
|
end
|
|
//-----------------------------------------
|
|
// FETCH - Fetch row from memory
|
|
//-----------------------------------------
|
|
STATE_FETCH :
|
|
begin
|
|
// Line fetch complete?
|
|
if (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}} && wbm_ack_i)
|
|
next_state_r = STATE_WAIT;
|
|
end
|
|
//-----------------------------------------
|
|
// FLUSH - Invalidate tag memory
|
|
//-----------------------------------------
|
|
STATE_FLUSH :
|
|
begin
|
|
if (flush_final_line)
|
|
next_state_r = STATE_FETCH;
|
|
else
|
|
next_state_r = STATE_FLUSH;
|
|
end
|
|
//-----------------------------------------
|
|
// WAIT - Wait cycle
|
|
//-----------------------------------------
|
|
STATE_WAIT :
|
|
// Allow extra wait state to handle write & read collision
|
|
next_state_r = STATE_WAIT2;
|
|
//-----------------------------------------
|
|
// WAIT2 - Wait cycle
|
|
//-----------------------------------------
|
|
STATE_WAIT2 :
|
|
next_state_r = STATE_CHECK;
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
|
|
// Update state
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
state <= STATE_CHECK;
|
|
else
|
|
state <= next_state_r;
|
|
end
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
// Check for cache misses
|
|
//-----------------------------------------------------------------
|
always @ (posedge rst_i or posedge clk_i )
|
always @ (posedge rst_i or posedge clk_i )
|
begin
|
begin
|
if (rst_i == 1'b1)
|
if (rst_i == 1'b1)
|
begin
|
begin
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
mem_addr_o <= 32'h00000000;
|
|
mem_rd_o <= 1'b0;
|
|
mem_burst_o <= 1'b0;
|
|
tag_wr <= 1'b0;
|
|
cache_address_wr<= {CACHE_DWIDTH{1'b0}};
|
|
cache_data_w <= 32'h00000000;
|
|
cache_wr <= 1'b0;
|
|
miss_pc <= BOOT_VECTOR + `VECTOR_RESET;
|
miss_pc <= BOOT_VECTOR + `VECTOR_RESET;
|
last_pc <= 32'h00000000;
|
last_pc <= 32'h00000000;
|
state <= STATE_CHECK;
|
|
initial_fetch <= 1'b1;
|
initial_fetch <= 1'b1;
|
read_while_busy <= 1'b0;
|
read_while_busy <= 1'b0;
|
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b0}};
|
|
flush_wr <= 1'b0;
|
|
flush_req <= 1'b0;
|
|
end
|
end
|
else
|
else
|
begin
|
begin
|
|
|
if (mem_accept_i)
|
|
mem_rd_o <= 1'b0;
|
|
tag_wr <= 1'b0;
|
|
cache_wr <= 1'b0;
|
|
initial_fetch <= 1'b0;
|
initial_fetch <= 1'b0;
|
flush_wr <= 1'b0;
|
|
last_pc <= pc_i;
|
last_pc <= pc_i;
|
|
|
// Latch invalidate request even if can't be actioned now...
|
|
if (invalidate_i)
|
|
flush_req <= 1'b1;
|
|
|
|
// New request whilst cache busy?
|
// New request whilst cache busy?
|
if (rd_i)
|
if (rd_i)
|
read_while_busy <= 1'b1;
|
read_while_busy <= 1'b1;
|
|
|
case (state)
|
case (state)
|
Line 190... |
Line 269... |
//-----------------------------------------
|
//-----------------------------------------
|
// CHECK - check cache for hit or miss
|
// CHECK - check cache for hit or miss
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_CHECK :
|
STATE_CHECK :
|
begin
|
begin
|
// Cache flush request pending?
|
|
if (flush_req || invalidate_i)
|
|
begin
|
|
flush_req <= 1'b0;
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}};
|
|
flush_wr <= 1'b1;
|
|
state <= STATE_FLUSH;
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
|
$display("Fetch: Cache flush request");
|
|
`endif
|
|
end
|
|
// Cache miss (& new read request not pending)
|
// Cache miss (& new read request not pending)
|
else if ((miss_o && !initial_fetch) && !rd_i && !read_while_busy)
|
if (cache_miss)
|
begin
|
begin
|
read_while_busy <= 1'b0;
|
read_while_busy <= 1'b0;
|
|
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i);
|
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i);
|
`endif
|
`endif
|
|
|
// Start fetch from memory
|
|
mem_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
|
mem_rd_o <= 1'b1;
|
|
mem_burst_o <= 1'b1;
|
|
state <= STATE_FETCH;
|
|
|
|
// Update tag memory with this line's details
|
|
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
|
tag_wr <= 1'b1;
|
|
end
|
end
|
// Cache hit (or new read request)
|
// Cache hit (or new read request)
|
else
|
else
|
begin
|
begin
|
`ifdef CONF_CORE_DEBUG
|
`ifdef CONF_CORE_DEBUG
|
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i);
|
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i);
|
if (read_while_busy)
|
if (read_while_busy)
|
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i);
|
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i);
|
`endif
|
`endif
|
|
|
// Store fetch PC
|
// Store fetch PC
|
miss_pc <= pc_i;
|
miss_pc <= pc_i;
|
state <= STATE_CHECK;
|
|
read_while_busy <= 1'b0;
|
read_while_busy <= 1'b0;
|
end
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// FETCH - Fetch row from memory
|
// FLUSH - Invalidate tag memory
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_FETCH :
|
STATE_FLUSH :
|
begin
|
|
// Data ready from memory?
|
|
if (mem_ack_i)
|
|
begin
|
begin
|
// Write data into cache
|
// Last line, clear pending reads whilst busy
|
cache_address_wr<= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], fetch_word};
|
if (flush_final_line)
|
cache_data_w <= mem_data_i;
|
read_while_busy <= 1'b0;
|
cache_wr <= 1'b1;
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
// Line fetch complete?
|
//-----------------------------------------------------------------
|
if (fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}})
|
// Cache Tag Write
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
begin
|
begin
|
state <= STATE_WAIT;
|
tag_data_in <= {CACHE_TAG_WIDTH{1'b0}};
|
|
tag_wr <= 1'b0;
|
end
|
end
|
// Fetch next word for line
|
|
else
|
else
|
begin
|
begin
|
v_line_word = fetch_word + 1'b1;
|
tag_wr <= 1'b0;
|
fetch_word <= v_line_word;
|
|
|
|
mem_addr_o <= {mem_addr_o[31:CACHE_LINE_SIZE_WIDTH], v_line_word, 2'b00};
|
case (state)
|
mem_rd_o <= 1'b1;
|
|
|
|
if (fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1))
|
//-----------------------------------------
|
|
// CHECK - check cache for hit or miss
|
|
//-----------------------------------------
|
|
STATE_CHECK :
|
begin
|
begin
|
mem_burst_o <= 1'b0;
|
// Cache miss (& new read request not pending)
|
end
|
if (cache_miss)
|
end
|
begin
|
|
// Update tag memory with this line's details
|
|
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
|
tag_wr <= 1'b1;
|
end
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// FLUSH - Invalidate tag memory
|
// FLUSH - Invalidate tag memory
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_FLUSH :
|
STATE_FLUSH :
|
begin
|
begin
|
if (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}})
|
if (flush_final_line)
|
begin
|
begin
|
// Fetch current PC line again
|
|
mem_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
|
mem_rd_o <= 1'b1;
|
|
mem_burst_o <= 1'b1;
|
|
state <= STATE_FETCH;
|
|
|
|
// Update tag memory with this line's details
|
// Update tag memory with this line's details
|
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
tag_wr <= 1'b1;
|
tag_wr <= 1'b1;
|
|
end
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
// Start of line
|
//-----------------------------------------------------------------
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
// Cache Data Write
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
cache_address_wr<= {CACHE_DWIDTH{1'b0}};
|
|
cache_data_in <= 32'h00000000;
|
|
cache_wr <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
cache_wr <= 1'b0;
|
|
|
// Clear pending reads whilst busy
|
// FETCH - Fetch row from memory
|
read_while_busy <= 1'b0;
|
if (state == STATE_FETCH)
|
|
begin
|
|
// Data ready from memory?
|
|
if (wbm_ack_i)
|
|
begin
|
|
// Write data into cache
|
|
cache_address_wr <= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], mem_resp_idx};
|
|
cache_data_in <= wbm_dat_i;
|
|
cache_wr <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
//-----------------------------------------------------------------
|
|
// Flush Logic
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b0}};
|
|
flush_wr <= 1'b0;
|
|
flush_req <= 1'b0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
|
flush_wr <= 1'b0;
|
|
|
|
// Latch invalidate request even if can't be actioned now...
|
|
if (invalidate_i)
|
|
flush_req <= 1'b1;
|
|
|
|
case (state)
|
|
|
|
//-----------------------------------------
|
|
// CHECK - check cache for hit or miss
|
|
//-----------------------------------------
|
|
STATE_CHECK :
|
|
begin
|
|
// Cache flush request pending?
|
|
if (flush_req || invalidate_i)
|
|
begin
|
|
flush_req <= 1'b0;
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}};
|
|
flush_wr <= 1'b1;
|
|
|
|
`ifdef CONF_CORE_DEBUG
|
|
$display("Fetch: Cache flush request");
|
|
`endif
|
|
end
|
|
end
|
|
//-----------------------------------------
|
|
// FLUSH - Invalidate tag memory
|
|
//-----------------------------------------
|
|
STATE_FLUSH :
|
|
begin
|
|
if (~flush_final_line)
|
|
begin
|
flush_addr <= flush_addr - 1;
|
flush_addr <= flush_addr - 1;
|
flush_wr <= 1'b1;
|
flush_wr <= 1'b1;
|
state <= STATE_FLUSH;
|
|
end
|
end
|
end
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
//-----------------------------------------------------------------
|
|
// External Mem Access
|
|
//-----------------------------------------------------------------
|
|
|
|
// Next fetch address
|
|
wire [CACHE_LINE_SIZE_WIDTH-3:0] mem_next_word = mem_fetch_word + 1;
|
|
|
|
// Last word to fetch
|
|
wire mem_resp_idx_word = (mem_fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1));
|
|
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
begin
|
|
wbm_addr_o <= 32'h00000000;
|
|
wbm_cti_o <= 3'b0;
|
|
wbm_stb_o <= 1'b0;
|
|
|
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
end
|
|
else
|
|
begin
|
|
if (~wbm_stall_i)
|
|
wbm_stb_o <= 1'b0;
|
|
|
|
case (state)
|
|
|
//-----------------------------------------
|
//-----------------------------------------
|
// WAIT - Wait cycle
|
// CHECK - check cache for hit or miss
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WAIT :
|
STATE_CHECK :
|
begin
|
begin
|
// Allow extra wait state to handle write & read collision
|
// Cache miss (& new read request not pending)
|
state <= STATE_WAIT2;
|
if (cache_miss)
|
|
begin
|
|
// Start fetch from memory
|
|
wbm_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
|
|
|
// Incrementing linear burst
|
|
wbm_cti_o <= 3'b010;
|
|
|
|
// Start of cycle
|
|
wbm_stb_o <= 1'b1;
|
|
|
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
end
|
end
|
end
|
//-----------------------------------------
|
//-----------------------------------------
|
// WAIT2 - Wait cycle
|
// FETCH - Fetch row from memory
|
//-----------------------------------------
|
//-----------------------------------------
|
STATE_WAIT2 :
|
STATE_FETCH :
|
begin
|
begin
|
`ifdef CONF_CORE_DEBUG
|
// Command accepted
|
$display("Fetch: Filled line containing PC=%x", miss_pc);
|
if (~wbm_stall_i)
|
`endif
|
begin
|
state <= STATE_CHECK;
|
// Fetch next word for line
|
|
if (!mem_fetch_final_word)
|
|
begin
|
|
wbm_addr_o <= {wbm_addr_o[31:CACHE_LINE_SIZE_WIDTH], mem_next_word, 2'b00};
|
|
|
|
// Final word to read?
|
|
if (mem_resp_idx_word)
|
|
wbm_cti_o <= 3'b111;
|
|
|
|
mem_fetch_word <= mem_next_word;
|
|
|
|
// Still fetching...
|
|
wbm_stb_o <= 1'b1;
|
end
|
end
|
|
end
|
|
end
|
|
//-----------------------------------------
|
|
// FLUSH - Invalidate tag memory
|
|
//-----------------------------------------
|
|
STATE_FLUSH :
|
|
begin
|
|
// Fetch current PC line again
|
|
if (flush_final_line)
|
|
begin
|
|
wbm_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
|
|
|
// Incrementing linear burst
|
|
wbm_cti_o <= 3'b010;
|
|
|
|
// Start of cycle
|
|
wbm_stb_o <= 1'b1;
|
|
|
|
// Start of line
|
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
end
|
|
end
|
default:
|
default:
|
;
|
;
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
// Stall the CPU if cache state machine is not idle!
|
//-----------------------------------------------------------------
|
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1;
|
// CYC_O
|
|
//-----------------------------------------------------------------
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
wbm_cyc_o <= 1'b0;
|
|
else
|
|
begin
|
|
case (state)
|
|
|
|
//-----------------------------------------
|
|
// CHECK - check cache for hit or miss
|
|
//-----------------------------------------
|
|
STATE_CHECK :
|
|
begin
|
|
// Cache miss (& new read request not pending)
|
|
if (cache_miss)
|
|
wbm_cyc_o <= 1'b1;
|
|
end
|
|
//-----------------------------------------
|
|
// FLUSH - Invalidate tag memory
|
|
//-----------------------------------------
|
|
STATE_FLUSH :
|
|
begin
|
|
// Fetch current PC line again
|
|
if (flush_final_line)
|
|
wbm_cyc_o <= 1'b1;
|
|
end
|
|
//-----------------------------------------
|
|
// FETCH - Fetch row from memory
|
|
//-----------------------------------------
|
|
STATE_FETCH :
|
|
begin
|
|
// Last response?
|
|
if (wbm_ack_i && (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}}))
|
|
wbm_cyc_o <= 1'b0;
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Instantiation
|
// Memory response counter
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
|
always @ (posedge rst_i or posedge clk_i )
|
|
begin
|
|
if (rst_i == 1'b1)
|
|
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
else
|
|
begin
|
|
case (state)
|
|
|
|
//-----------------------------------------
|
|
// CHECK - check cache for hit or miss
|
|
//-----------------------------------------
|
|
STATE_CHECK :
|
|
begin
|
|
// Cache miss (& new read request not pending)
|
|
if (cache_miss)
|
|
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
end
|
|
//-----------------------------------------
|
|
// FLUSH - Invalidate tag memory
|
|
//-----------------------------------------
|
|
STATE_FLUSH :
|
|
begin
|
|
// Fetch current PC line again
|
|
if (flush_final_line)
|
|
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
|
end
|
|
//-----------------------------------------
|
|
// FETCH - Fetch row from memory
|
|
//-----------------------------------------
|
|
STATE_FETCH :
|
|
begin
|
|
// Response
|
|
if (wbm_ack_i)
|
|
mem_resp_idx <= mem_resp_idx + 1;
|
|
end
|
|
default:
|
|
;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
//-----------------------------------------------------------------
|
// Tag memory
|
// Tag memory
|
|
//-----------------------------------------------------------------
|
altor32_ram_dp
|
altor32_ram_dp
|
#(
|
#(
|
.WIDTH(CACHE_TAG_WIDTH),
|
.WIDTH(CACHE_TAG_WIDTH),
|
.SIZE(CACHE_LINE_ADDR_WIDTH)
|
.SIZE(CACHE_LINE_ADDR_WIDTH)
|
)
|
)
|
u1_tag_mem
|
u1_tag_mem
|
(
|
(
|
|
// Tag read/write port
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.adat_o(tag_data_out),
|
.adat_o(tag_data_out),
|
.adat_i(tag_data_in),
|
.adat_i(tag_data_in),
|
.aadr_i(tag_entry),
|
.aadr_i(tag_entry),
|
.awr_i(tag_wr),
|
.awr_i(tag_wr),
|
|
|
|
// Tag invalidate port
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(flush_addr),
|
.badr_i(flush_addr),
|
.bdat_o(/*open*/),
|
.bdat_o(/*open*/),
|
.bdat_i({CACHE_TAG_WIDTH{1'b0}}),
|
.bdat_i({CACHE_TAG_WIDTH{1'b0}}),
|
.bwr_i(flush_wr)
|
.bwr_i(flush_wr)
|
);
|
);
|
|
|
|
//-----------------------------------------------------------------
|
// Data memory
|
// Data memory
|
|
//-----------------------------------------------------------------
|
altor32_ram_dp
|
altor32_ram_dp
|
#(
|
#(
|
.WIDTH(32),
|
.WIDTH(32),
|
.SIZE(CACHE_DWIDTH)
|
.SIZE(CACHE_DWIDTH)
|
)
|
)
|
u2_data_mem
|
u2_data_mem
|
(
|
(
|
|
// Data read port
|
.aclk_i(clk_i),
|
.aclk_i(clk_i),
|
.aadr_i(cache_address_rd),
|
.aadr_i(cache_address_rd),
|
.adat_o(instruction_o),
|
.adat_o(instruction_o),
|
.adat_i(32'h00),
|
.adat_i(32'h00),
|
.awr_i(1'b0),
|
.awr_i(1'b0),
|
|
|
|
// Data write port
|
.bclk_i(clk_i),
|
.bclk_i(clk_i),
|
.badr_i(cache_address_wr),
|
.badr_i(cache_address_wr),
|
.bdat_o(/*open*/),
|
.bdat_o(/*open*/),
|
.bdat_i(cache_data_w),
|
.bdat_i(cache_data_in),
|
.bwr_i(cache_wr)
|
.bwr_i(cache_wr)
|
);
|
);
|
|
|
endmodule
|
endmodule
|
|
|