blob: 4a14c5e14b9c4c2d8371655a8c02e92d94f19faf [file] [log] [blame]
// SPDX-FileCopyrightText: 2020 Efabless Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
`default_nettype none
/*
*-------------------------------------------------------------
*
* user_proj_example
*
* This is an example of a (trivially simple) user project,
* showing how the user project can connect to the logic
* analyzer, the wishbone bus, and the I/O pads.
*
* This project generates an integer count, which is output
* on the user area GPIO pads (digital output only). The
* wishbone connection allows the project to be controlled
* (start and stop) from the management SoC program.
*
* See the testbenches in directory "mprj_counter" for the
* example programs that drive this user project. The three
* testbenches are "io_ports", "la_test1", and "la_test2".
*
*-------------------------------------------------------------
*/
module user_proj_example #(
parameter BITS = 32
)(
`ifdef USE_POWER_PINS
inout vccd1, // User area 1 1.8V supply
inout vssd1, // User area 1 digital ground
`endif
// Wishbone Slave ports (WB MI A)
input wb_clk_i,
input wb_rst_i,
input wbs_stb_i,
input wbs_cyc_i,
input wbs_we_i,
input [3:0] wbs_sel_i,
input [31:0] wbs_dat_i,
input [31:0] wbs_adr_i,
output wbs_ack_o,
output [31:0] wbs_dat_o,
// Logic Analyzer Signals
input [127:0] la_data_in,
output [127:0] la_data_out,
input [127:0] la_oenb,
// IOs
input [`MPRJ_IO_PADS-1:0] io_in,
output [`MPRJ_IO_PADS-1:0] io_out,
output [`MPRJ_IO_PADS-1:0] io_oeb,
// IRQ
output [2:0] irq
);
wire clk;
wire rst;
wire [`MPRJ_IO_PADS-1:0] io_in;
wire [`MPRJ_IO_PADS-1:0] io_out;
wire [`MPRJ_IO_PADS-1:0] io_oeb;
wire [31:0] rdata;
wire [31:0] wdata;
wire [BITS-1:0] count;
wire valid;
wire [3:0] wstrb;
wire [31:0] la_write;
// WB MI A
assign valid = wbs_cyc_i && wbs_stb_i;
assign wstrb = wbs_sel_i & {4{wbs_we_i}};
assign wbs_dat_o = rdata;
assign wdata = wbs_dat_i;
// IO
assign io_out = count;
assign io_oeb = {(`MPRJ_IO_PADS-1){rst}};
// IRQ
assign irq = 3'b000; // Unused
// LA
assign la_data_out = {{(127-BITS){1'b0}}, count};
// Assuming LA probes [63:32] are for controlling the count register
assign la_write = ~la_oenb[63:32] & ~{BITS{valid}};
// Assuming LA probes [65:64] are for controlling the count clk & reset
assign clk = (~la_oenb[64]) ? la_data_in[64]: wb_clk_i;
assign rst = (~la_oenb[65]) ? la_data_in[65]: wb_rst_i;
counter #(
.BITS(BITS)
) counter(
.clk(clk),
.reset(la_data_in[0]),
.trace_ready(la_data_in[1]),
.mem_addr(la_data_in[33:2]),
.L1_hit_count(la_data_out[9:0]),
.L2_hit_count4(la_data_out[19:10]),
.L2_hit_count8(la_data_out[29:20]),
.L2_hit_count16(la_data_out[39:30]),
.L2_ss1_count4(la_data_out[49:40]),
.L2_ss1_count8(la_data_out[59:50]),
.L2_ss1_count16(la_data_out[69:60]),
.L2_ss2_count4(la_data_out[79:70]),
.L2_ss2_count8(la_data_out[89:80]),
.L2_ss2_count16(la_data_out[99:90])
);
endmodule
module main(clk,reset,trace_ready,mem_addr,L1_hit_count,L2_hit_count4,L2_hit_count8,L2_hit_count16,L2_ss1_count4,L2_ss1_count8,L2_ss1_count16,L2_ss2_count4,L2_ss2_count8,L2_ss2_count16);
parameter L1_way = 4;
parameter L1_block_size_byte = 16;
parameter L1_cache_size_byte = 1*1024;
parameter L2_way = 16;
parameter L2_block_size_byte = 16;
parameter L2_set_size = 64;
parameter L1_block_offset_index = $rtoi($ln(L1_block_size_byte)/$ln(2));
parameter L1_set = L1_cache_size_byte/(L1_block_size_byte*L1_way);
parameter L1_set_index = $rtoi($ln(L1_set)/$ln(2));
parameter L1_way_width = $rtoi($ln(L1_way)/$ln(2));
parameter L2_block_offset_index = $rtoi($ln(L2_block_size_byte)/$ln(2));
parameter L2_set_index = $rtoi($ln(L2_set_size)/$ln(2));
parameter L2_way_width = $rtoi($ln(L2_way)/$ln(2));
input clk,trace_ready,reset;
input [31:0] mem_addr;
output [19:0] L1_hit_count,L2_hit_count4,L2_hit_count8,L2_hit_count16,L2_ss1_count4,L2_ss1_count8,L2_ss1_count16,L2_ss2_count4,L2_ss2_count8,L2_ss2_count16;
wire updated;
// variables to divide address in tag, index and offset for L1 cache
wire [31-L1_set_index-L1_block_offset_index:0] L1_tag;
wire [L1_set_index-1:0] L1_index;
wire [L1_block_offset_index-1:0] L1_block_offset;
// variables to divide address in tag, index and offset for L2 cache
wire [31-L2_set_index-L2_block_offset_index:0] L2_tag;
wire [L2_set_index-1:0] L2_index;
wire [L2_block_offset_index-1:0] L2_block_offset;
//L1 cache
wire L1_done,L1_found_in_cache,L1_updated;
//L2 cache
wire L2_done,L2_found_in_cache,L2_updated ;
wire [L2_way_width:0] L2_hit_way;
//Subset cache1
wire ss1_found_in_cache,ss1_updated;
wire [L2_way_width:0] ss1_hit_way;
//Subset cache2
wire ss2_found_in_cache,ss2_updated;
wire [L2_way_width:0] ss2_hit_way;
wire [L2_set_index-2:0] ss1_index;
//prefetcher
wire prefetch_hit,prefetch_done;
assign L1_block_offset = mem_addr[L1_block_offset_index-1:0];
assign L1_index = mem_addr[L1_set_index+L1_block_offset_index-1:L1_block_offset_index];
assign L1_tag = mem_addr[31:L1_set_index+L1_block_offset_index];
assign L2_block_offset = mem_addr[L2_block_offset_index-1:0];
assign L2_index = mem_addr[L2_set_index+L2_block_offset_index-1:L2_block_offset_index];
assign L2_tag = mem_addr[31:L2_set_index+L2_block_offset_index];
assign ss1_index = L2_index[L2_set_index-2:0];
assign updated = !prefetch_hit&&ss1_updated ? 1'b1 : L1_updated&&(prefetch_hit||L1_found_in_cache) ? 1'b1 : 1'b0;
L1_cache #(.way(L1_way),.block_size_byte(L1_block_size_byte),.cache_size_byte(L1_cache_size_byte)) i1 (clk,reset,L1_tag,L1_index,L1_block_offset,trace_ready,prefetch_hit,L2_found_in_cache,L1_hit_count,L1_found_in_cache,L1_updated,L1_done,prefetch_done);
L2_cache #(.way(L2_way),.block_size_byte(L2_block_size_byte),.set_size(L2_set_size)) i2 (clk,reset,L2_tag,L2_index,L2_block_offset,(prefetch_done && !prefetch_hit),L2_hit_count4,L2_hit_count8,L2_hit_count16,L2_found_in_cache,L2_hit_way,L2_done,L2_updated);
L2_cache_subset #(.way(L2_way),.block_size_byte(L2_block_size_byte),.set_size(L2_set_size/2)) i3 (clk,reset,L2_index,L2_updated,L2_found_in_cache,L2_hit_way,ss1_found_in_cache,L2_ss1_count4,L2_ss1_count8,L2_ss1_count16,ss1_hit_way,ss1_updated);
L2_cache_subset #(.way(L2_way),.block_size_byte(L2_block_size_byte),.set_size(L2_set_size/4)) i4 (clk,reset,ss1_index,ss1_updated,ss1_found_in_cache,ss1_hit_way,ss2_found_in_cache,L2_ss2_count4,L2_ss2_count8,L2_ss2_count16,ss2_hit_way,ss2_updated);
prefetcher #(.way(L1_way),.block_size_byte(L1_block_size_byte),.cache_size_byte(L1_cache_size_byte)) i5(clk,mem_addr,(L1_done && !L1_found_in_cache),prefetch_hit);
endmodule
module L1_cache(clk,reset,tag,index,block_offset,find_start,prefetch_hit,L2_cache_hit,cache_hit_count,found_in_cache,updated,done_L1,done_prefetch);
parameter way = 4;
parameter block_size_byte = 16;
parameter cache_size_byte = 32*1024;
parameter block_offset_index = $rtoi($ln(block_size_byte)/$ln(2));
parameter set = cache_size_byte/(block_size_byte*way);
parameter set_index = $rtoi($ln(set)/$ln(2));
parameter way_width = $rtoi($ln(way)/$ln(2));
parameter cache_line_width = 32-set_index-block_offset_index+1;
input clk,find_start,L2_cache_hit,prefetch_hit,reset;
input [31-set_index-block_offset_index:0] tag;
input [set_index-1:0] index;
input [block_offset_index-1:0] block_offset;
output reg found_in_cache;
output reg [19:0] cache_hit_count;
output reg updated,done_L1,done_prefetch;
reg [1:0]find_state;
reg [1:0]flag;
reg bi_flag;
reg [way_width:0] way_index;
reg [way_width-1:0] hit_way;
reg [cache_line_width-1:0] cache [0:set-1][0:way-1];
reg [cache_line_width-1:0] temp_content;
reg [cache_line_width-1:0] temp_content1 [0:way-1];
integer i,j;
initial
begin
found_in_cache = 0;
cache_hit_count = 0;
find_state = 0;
flag = 0;
bi_flag = 0;
updated = 0;
done_prefetch = 0;
for (i=0;i<set;i=i+1)
for (j=0;j<way;j=j+1)
cache[i][j] = 0;
end
always @ (posedge clk)
begin
if (reset)
begin
found_in_cache = 0;
cache_hit_count = 0;
//cache_miss_count = 0;
find_state = 0;
flag = 0;
bi_flag = 0;
updated = 0;
done_prefetch = 0;
for (i=0;i<set;i=i+1)
for (j=0;j<way;j=j+1)
cache[i][j] = 0;
end
else
begin
case (find_state)
2'b00: begin
found_in_cache = 1'b0;
if(find_start)
begin
find_state = 2'b01;
done_L1 = 1'b0;
end
end
2'b01: begin
if (done_L1 && !found_in_cache)
begin
find_state = 2'b10;
done_L1 = 1'b0;
end
else if (done_L1 && found_in_cache)
begin
find_state = 2'b11;
done_L1 = 1'b0;
end
else
begin
for (way_index=0;way_index<way;way_index=way_index+1'b1)
begin
if(cache[index][way_index][cache_line_width-1]) // valid bit
begin
if(cache[index][way_index][cache_line_width-2:0]==tag) // tag comparison
begin
found_in_cache = 1'b1;
hit_way = way_index;
temp_content = cache[index][way_index];
cache_hit_count = cache_hit_count + 1'b1;
done_L1 = 1'b1;
end
end
end
if (way_index==way&&!found_in_cache)
begin
//cache_miss_count = cache_miss_count + 1'b1;
found_in_cache = 1'b0;
done_L1 = 1'b1;
end
end
end
2'b10: begin
if(done_prefetch)
begin
find_state= 2'b11;
done_prefetch = 1'b0;
flag = 1'b0;
end
else
begin
if(!flag)
flag = 1'b1;
else
begin
if(prefetch_hit&flag)
begin
flag = 1'b0;
cache_hit_count = cache_hit_count + 1'b1;
end
//else
//cache_miss_count = cache_miss_count + 1'b1;
done_prefetch = 1'b1;
end
end
end
2'b11: begin
if(updated)
begin
find_state = 2'b00;
updated = 1'b0;
end
else
begin
if(found_in_cache) // hit
begin
if(hit_way != 0)
begin
cache[index][hit_way] = cache[index][hit_way-1];
hit_way = hit_way - 1;
end
else
begin
cache[index][0] = temp_content;
updated = 1'b1;
end
end
else // miss
begin
for(way_index=way-2;way_index>0;way_index=way_index-1)
cache[index][way_index+1] = cache[index][way_index];
cache[index][1] = cache[index][0];
cache[index][0] = {1'b1,tag};
updated = 1'b1;
end
end
end
endcase
end
end
endmodule
module L2_cache(clk,reset,tag,index,block_offset,find_start,cache_hit_count4,cache_hit_count8,cache_hit_count16,found_in_cache,hit_way,done,updated);
parameter way = 16;
parameter block_size_byte = 16;
parameter set_size = 64;
parameter block_offset_index = $rtoi($ln(block_size_byte)/$ln(2));
parameter set_index = $rtoi($ln(set_size)/$ln(2));
parameter way_width = $rtoi($ln(way)/$ln(2));
parameter cache_line_width = 32-set_index-block_offset_index+1;
input clk,find_start,reset;
input [31-set_index-block_offset_index:0] tag;
input [set_index-1:0] index;
input [block_offset_index-1:0] block_offset;
output reg found_in_cache;
// this needs to get parameterized based on number of max associativity
output reg [19:0] cache_hit_count4;
output reg [19:0] cache_hit_count8;
output reg [19:0] cache_hit_count16;
output reg [way_width:0] hit_way;
output reg updated,done;
reg [1:0]find_state;
reg [way_width:0] way_index;
reg [cache_line_width-1:0] cache [0:set_size-1][0:way-1];
reg [cache_line_width-1:0] temp_content;
//reg [19:0] hit_count [way-1:0];
integer i,j;
initial
begin
found_in_cache = 0;
cache_hit_count4 = 0;
cache_hit_count8 = 0;
cache_hit_count16 = 0;
find_state = 0;
updated = 0;
for (i=0;i<set_size;i=i+1)
for (j=0;j<way;j=j+1)
cache[i][j] = 0;
end
always @ (posedge clk)
begin
if (reset)
begin
found_in_cache = 0;
cache_hit_count4 = 0;
cache_hit_count8 = 0;
cache_hit_count16 = 0;
find_state = 0;
updated = 0;
for (i=0;i<set_size;i=i+1)
for (j=0;j<way;j=j+1)
cache[i][j] = 0;
end
else
begin
case (find_state)
2'b00: begin
found_in_cache = 1'b0;
if(find_start)
begin
find_state = 2'b01;
done = 1'b0;
end
end
// Find cache state (to check if particular memory address data is present in cache or not)
2'b01: begin
if (done)
begin
find_state = 2'b10;
end
else
begin
for (way_index=0;way_index<way;way_index=way_index+1'b1)
begin
if(cache[index][way_index][cache_line_width-1]) // valid bit
begin
if(cache[index][way_index][cache_line_width-2:0]==tag) // tag comparison
begin
found_in_cache = 1'b1;
hit_way = way_index;
temp_content = cache[index][way_index];
end
end
end
if (found_in_cache)
begin
if (hit_way>=0 && hit_way<4)
begin
cache_hit_count4 = cache_hit_count4 + 1;
cache_hit_count8 = cache_hit_count8 + 1;
cache_hit_count16 = cache_hit_count16 + 1;
end
else if (hit_way>=4 && hit_way<8)
begin
cache_hit_count8 = cache_hit_count8 + 1;
cache_hit_count16 = cache_hit_count16 + 1;
end
else if (hit_way>=8 && hit_way<16)
begin
cache_hit_count16 = cache_hit_count16 + 1;
end
done = 1'b1;
way_index = hit_way;
end
else
begin
hit_way = way;
done = 1'b1;
end
end
end
// Updation of cache according LRU shift register policy
2'b10: begin
if(updated)
begin
find_state = 2'b00;
updated = 1'b0;
end
else
begin
if(found_in_cache) // hit
begin
if(way_index != 0)
begin
cache[index][way_index] = cache[index][way_index-1];
way_index = way_index - 1;
end
else
begin
cache[index][0] = temp_content;
updated = 1'b1;
end
end
else // miss
begin
for(way_index=way-2;way_index>0;way_index=way_index-1)
cache[index][way_index+1] = cache[index][way_index];
cache[index][1] = cache[index][0];
cache[index][0] = {1'b1,tag};
updated = 1'b1;
end
end
end
endcase
end
end
endmodule
module L2_cache_subset(clk,reset,msb_index,find_start,L2_found_in_cache,hit_way,found_in_cache,cache_hit_count4,cache_hit_count8,cache_hit_count16,hit_source,updated);
parameter way = 16;
parameter block_size_byte = 16;
parameter set_size = 512;
parameter set_index = $rtoi($ln(set_size)/$ln(2));
parameter way_width = $rtoi($ln(way)/$ln(2));
input clk,find_start,reset,L2_found_in_cache;
input [way_width:0] hit_way;
input [set_index:0] msb_index;
output reg found_in_cache;
// this needs to get parameterized based on number of max associativity
output reg [19:0] cache_hit_count4;
output reg [19:0] cache_hit_count8;
output reg [19:0] cache_hit_count16;
output reg updated;
output reg [way_width:0] hit_source;
reg msb_indexbit,msb_update,mask_update;
reg [set_index-1:0] index;
reg [way_width:0] way_index;
reg mask0 [0:set_size-1][0:way-1];
reg mask1 [0:set_size-1][0:way-1];
reg [1:0] source [0:set_size-1][0:way-1];
reg [1:0] temp_data;
reg temp_source;
reg [way_width:0] count;
//reg [19:0] hit_count [way-1:0];
reg [1:0]find_state;
reg done;
integer i,j;
initial
begin
found_in_cache = 0;
cache_hit_count4 = 0;
cache_hit_count8 = 0;
cache_hit_count16 = 0;
//cache_miss_count = 0;
find_state = 0;
temp_data = 0;
msb_update = 0;
mask_update = 0;
for (i=0;i<set_size;i=i+1)
begin
for (j=0;j<way;j=j+1)
begin
source[i][j] = 0;
mask0[i][j] = 0;
mask1[i][j] = 0;
end
end
end
always @ (posedge clk)
begin
if (reset)
begin
found_in_cache = 0;
cache_hit_count4 = 0;
cache_hit_count8 = 0;
cache_hit_count16 = 0;
find_state = 0;
temp_data = 0;
for (i=0;i<set_size;i=i+1)
begin
for (j=0;j<way;j=j+1)
begin
source[i][j] = 0;
mask0[i][j] = 0;
mask1[i][j] = 0;
end
end
end
else
begin
case (find_state)
2'b00: begin
if(find_start)
begin
found_in_cache = 1'b0;
find_state = 2'b01;
done = 1'b0;
end
end
2'b01: begin
if (done)
begin
find_state = 2'b10;
count = 0;
end
else
begin
// to check if there is hit in cache
msb_indexbit = msb_index[set_index];
index[set_index-1:0] = msb_index[set_index-1:0];
if (L2_found_in_cache)
begin
if (msb_indexbit)
begin
if(mask1[index][hit_way])
begin
temp_source = 1'b1;
found_in_cache = 1'b1;
end
end
else if (!msb_indexbit)
begin
if(mask0[index][hit_way]) // mask0[0][16]
begin
temp_source = 1'b0;
found_in_cache = 1'b1;
end
end
if (found_in_cache)
begin
way_index = 0;
if(temp_source)
begin
for(way_index=0;way_index<way;way_index=way_index+1)
begin
if(source[index][way_index]==2'b11&&count<hit_way+1)
count = count + 1;
if(count==hit_way+1)
begin
temp_data = source[index][way_index];
hit_source = way_index;
count = count + 1;
end
end
end
else if (!temp_source)
begin
for(way_index=0;way_index<way;way_index=way_index+1)
begin
if(source[index][way_index]==2'b10&&count<hit_way+1)
count = count + 1;
if(count==hit_way+1)
begin
temp_data = source[index][way_index];
hit_source = way_index;
count = count + 1;
end
end
end
if (hit_source>=0 && hit_source<4)
begin
cache_hit_count4 = cache_hit_count4 + 1;
cache_hit_count8 = cache_hit_count8 + 1;
cache_hit_count16 = cache_hit_count16 + 1;
end
else if (hit_source>=4 && hit_source<8)
begin
cache_hit_count8 = cache_hit_count8 + 1;
cache_hit_count16 = cache_hit_count16 + 1;
end
else if (hit_source>=8 && hit_source<16)
begin
cache_hit_count16 = cache_hit_count16 + 1;
end
way_index = hit_source;
done = 1'b1;
end
else
begin
hit_source = way;
done = 1'b1;
end
end
else
begin
hit_source = way;
done = 1'b1;
end
end
end
2'b10: begin
if(updated)
begin
find_state = 2'b00;
updated = 1'b0;
count = 0;
end
else
begin
if(found_in_cache)
begin
if(msb_indexbit && !msb_update && !mask_update)
begin
if(way_index != 0)
begin
mask1[index][way_index] = mask1[index][way_index-1];
way_index = way_index - 1;
end
else
begin
mask1[index][0] = 1'b1;
msb_update = 1'b1;
end
end
else if (!msb_indexbit && !msb_update && !mask_update)
begin
if(way_index != 0)
begin
mask0[index][way_index] = mask0[index][way_index-1];
way_index = way_index - 1;
end
else
begin
mask0[index][0] = 1'b1;
msb_update = 1'b1;
end
end
if (msb_update && !mask_update)
begin
for(way_index=0;way_index<way;way_index=way_index+1)
begin
if(mask0[index][way_index])
count = count + 1;
if(mask1[index][way_index])
count = count + 1;
end
// if count>way then we have to change one of mask from 1 to 0 based on LRU
if(count>way)
begin
if(source[index][way-1] == 2'b11)
begin
way_index = way-1;
while(way_index>0 && !mask1[index][way_index])
way_index = way_index - 1;
mask1[index][way_index] = 1'b0;
end
else if (source[index][way-1] == 2'b10)
begin
way_index = way-1;
while(way_index>0 && !mask0[index][way_index])
way_index = way_index - 1;
mask0[index][way_index] = 1'b0;
end
end
mask_update = 1'b1;
way_index = hit_source;
msb_update = 1'b0;
end
if(mask_update)
begin
if(way_index != 0)
begin
source[index][way_index] = source[index][way_index-1];
way_index = way_index - 1;
end
else
begin
mask_update = 1'b0;
source[index][0] = temp_data;
updated = 1'b1;
end
end
end
else // cache miss
begin
// update mask register
if(msb_indexbit)
begin
for(way_index=way-2;way_index>0;way_index=way_index-1)
mask1[index][way_index+1] = mask1[index][way_index];
mask1[index][1] = mask1[index][0];
mask1[index][0] = 1'b1;
end
else
begin
for(way_index=way-2;way_index>0;way_index=way_index-1)
mask0[index][way_index+1] = mask0[index][way_index];
mask0[index][1] = mask0[index][0];
mask0[index][0] = 1'b1;
end
// after updating the mask registers check count of 1's in both mask 0 and 1
for(way_index=0;way_index<way;way_index=way_index+1)
begin
if(mask0[index][way_index])
count = count + 1;
if(mask1[index][way_index])
count = count + 1;
end
// if count>way then we have to change one of mask from 1 to 0 based on LRU
if(count>way)
begin
if(source[index][way-1] == 2'b11)
begin
way_index = way-1;
while(way_index>0 && !mask1[index][way_index])
way_index = way_index - 1;
mask1[index][way_index] = 1'b0;
end
else if (source[index][way-1] == 2'b10)
begin
way_index = way-1;
while(way_index>0 && !mask0[index][way_index])
way_index = way_index - 1;
mask0[index][way_index] = 1'b0;
end
end
// update source register
for(way_index=way-2;way_index>0;way_index=way_index-1)
source[index][way_index+1] = source[index][way_index];
source[index][1] = source[index][0];
source[index][0] = {1'b1,msb_indexbit};
updated = 1'b1;
end
end
end
endcase
end
end
endmodule
module prefetcher (clk,address,cache_miss,prefetch_hit);
parameter way = 4;
parameter block_size_byte = 16;
parameter cache_size_byte = 1024;
parameter block_offset_index = $rtoi($ln(block_size_byte)/$ln(2)); //2
parameter set = cache_size_byte/(block_size_byte*way);
parameter set_index = $rtoi($ln(set)/$ln(2));
parameter prefetch_width = 32-block_offset_index + 1; // without data (tag+index+valid)
input clk,cache_miss;
input [31:0]address;
output reg prefetch_hit;
wire [31-set_index-block_offset_index:0] tag; // 23 bits..22:0
wire [set_index-1:0] index; //7 bits...6:0
wire [block_offset_index-1:0] block_offset; //2 bits...1:0
wire [set_index-1:0]temp_index;
wire [5:0]prefetch_fill_index;
wire valid_buffer_check, valid_fill_check;
reg [prefetch_width-1:0]prefetch_buffer[0:7];
wire [2:0] hit_index;
reg [2:0] way_index;
reg [1:0] find_state;
reg done,updated;
reg [prefetch_width-1:0] temp_data;
integer k;
assign block_offset = address[block_offset_index-1:0];
assign index = address[set_index+block_offset_index-1:block_offset_index];
assign tag =address[31:set_index+block_offset_index];
assign temp_index = index + 1;
assign valid_buffer_check = (prefetch_buffer[0][prefetch_width-1] && (prefetch_buffer[0][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[1][prefetch_width-1] && (prefetch_buffer[1][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[2][prefetch_width-1] && (prefetch_buffer[2][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[3][prefetch_width-1] && (prefetch_buffer[3][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[4][prefetch_width-1] && (prefetch_buffer[4][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[5][prefetch_width-1] && (prefetch_buffer[5][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[6][prefetch_width-1] && (prefetch_buffer[6][prefetch_width-2:0]==address[31:block_offset_index])) || (prefetch_buffer[7][prefetch_width-1] && (prefetch_buffer[7][prefetch_width-2:0]==address[31:block_offset_index]));
assign hit_index = (prefetch_buffer[0][prefetch_width-1] && (prefetch_buffer[0][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b000 :
(prefetch_buffer[1][prefetch_width-1] && (prefetch_buffer[1][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b001 :
(prefetch_buffer[2][prefetch_width-1] && (prefetch_buffer[2][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b010 :
(prefetch_buffer[3][prefetch_width-1] && (prefetch_buffer[3][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b011 :
(prefetch_buffer[4][prefetch_width-1] && (prefetch_buffer[4][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b100 :
(prefetch_buffer[5][prefetch_width-1] && (prefetch_buffer[5][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b101 :
(prefetch_buffer[6][prefetch_width-1] && (prefetch_buffer[6][prefetch_width-2:0]==address[31:block_offset_index])) ? 3'b110 : 3'b111;
assign valid_fill_check = (prefetch_buffer[0][prefetch_width-1] && (prefetch_buffer[0][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[1][prefetch_width-1] && (prefetch_buffer[1][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[2][prefetch_width-1] && (prefetch_buffer[2][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[3][prefetch_width-1] && (prefetch_buffer[3][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[4][prefetch_width-1] && (prefetch_buffer[4][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[5][prefetch_width-1] && (prefetch_buffer[5][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[6][prefetch_width-1] && (prefetch_buffer[6][prefetch_width-2:0]=={tag,temp_index})) || (prefetch_buffer[7][prefetch_width-1] && (prefetch_buffer[7][prefetch_width-2:0]=={tag,temp_index}));
initial
begin
for (k=0;k<8;k=k+1)
prefetch_buffer[k] = 0;
done = 0;
updated = 0;
prefetch_hit = 0;
find_state = 0;
end
always @ (posedge clk)
begin
case(find_state)
2'b00: begin
done = 1'b0;
prefetch_hit = 1'b0;
if(cache_miss)
begin
find_state = 2'b01;
end
end
2'b01: begin
if(done)
find_state = 2'b10;
else
begin
if(valid_buffer_check)
begin
prefetch_hit = 1'b1;
done = 1'b1;
end
else
begin
done =1'b1;
prefetch_hit=1'b0;
end
end
end
2'b10: begin
if(updated)
begin
find_state = 2'b00;
updated = 1'b0;
end
else
begin
if(!prefetch_hit)
begin
if(valid_fill_check)
updated = 1'b1;
else
begin
prefetch_buffer[7] = prefetch_buffer[6];
prefetch_buffer[6] = prefetch_buffer[5];
prefetch_buffer[5] = prefetch_buffer[4];
prefetch_buffer[4] = prefetch_buffer[3];
prefetch_buffer[3] = prefetch_buffer[2];
prefetch_buffer[2] = prefetch_buffer[1];
prefetch_buffer[1] = prefetch_buffer[0];
prefetch_buffer[0] = {1'b1,tag,temp_index};
updated = 1'b1;
end
end
if(prefetch_hit)
begin
temp_data = prefetch_buffer[hit_index];
for (way_index=0;way_index<hit_index;way_index=way_index+1)
prefetch_buffer[hit_index-way_index]= prefetch_buffer[hit_index-way_index-1];
prefetch_buffer[0] = temp_data;
updated = 1'b1;
end
end
end
endcase
end
endmodule