Files
vortex/rtl/cache/VX_d_cache.v
2019-10-22 06:02:08 -04:00

603 lines
25 KiB
Verilog

// Cache Memory (8way 4word) //
// i_ means input port //
// o_ means output port //
// _p_ means data exchange with processor //
// _m_ means data exchange with memory //
// TO DO:
// - Send in a response from memory of what the data is from the test bench
`include "VX_define.v"
//`include "VX_priority_encoder.v"
`include "VX_Cache_Bank.v"
//`include "cache_set.v"
module VX_d_cache(clk,
rst,
i_p_initial_request,
i_p_addr,
//i_p_byte_en,
i_p_writedata,
i_p_read_or_write, // 0 = Read | 1 = Write
i_p_valid,
//i_p_write,
o_p_readdata,
o_p_readdata_valid,
o_p_waitrequest, // 0 = all threads done | 1 = Still threads that need to
o_m_addr,
//o_m_byte_en,
o_m_writedata,
o_m_read_or_write, // 0 = Read | 1 = Write
o_m_valid,
//o_m_write,
i_m_readdata,
//i_m_readdata_ready,
//i_m_waitrequest,
i_m_ready
//cnt_r,
//cnt_w,
//cnt_hit_r,
//cnt_hit_w
//cnt_wb_r,
//cnt_wb_w
);
parameter NUMBER_BANKS = 8;
localparam CACHE_IDLE = 0; // Idle
localparam SORT_BY_BANK = 1; // Determines the bank each thread will access
localparam INITIAL_ACCESS = 2; // Accesses the bank and checks if it is a hit or miss
localparam INITIAL_PROCESSING = 3; // Check to see if there were misses
localparam CONTINUED_PROCESSING = 4; // Keep checking status of banks that need to be written back or fetched
localparam DIRTY_EVICT_GRAB_BLOCK = 5; // Grab the full block of dirty data
localparam DIRTY_EVICT_WB = 6; // Write back this block into memory
localparam FETCH_FROM_MEM = 7; // Send a request to mem looking for read data
localparam FETCH2 = 8; // Stall until memory gets back with the data
localparam UPDATE_CACHE = 9; // Update the cache with the data read from mem
localparam RE_ACCESS = 10; // Access the cache after the block has been fetched from memory
localparam RE_ACCESS_PROCESSING = 11; // Access the cache after the block has been fetched from memory
//parameter cache_entry = 9;
input wire clk, rst;
input wire [`NT_M1:0] i_p_valid;
//input wire [`NT_M1:0][24:0] i_p_addr; // FIXME
input wire [`NT_M1:0][31:0] i_p_addr; // FIXME
input wire i_p_initial_request;
//input wire [3:0] i_p_byte_en;
input wire [`NT_M1:0][31:0] i_p_writedata;
input wire i_p_read_or_write; //, i_p_write;
output reg [`NT_M1:0][31:0] o_p_readdata;
output reg [`NT_M1:0] o_p_readdata_valid;
output wire o_p_waitrequest;
//output reg [24:0] o_m_addr; // Only one address is sent out at a time to memory -- FIXME
output reg [31:0] o_m_addr; // Address is xxxxxxxxxxoooobbbyy
output reg o_m_valid;
//output wire [255:0][31:0] evicted_data;
//output wire [3:0] o_m_byte_en;
//output reg [(NUMBER_BANKS * 32) - 1:0] o_m_writedata;
output reg[NUMBER_BANKS - 1:0][`NUM_WORDS_PER_BLOCK-1:0][31:0] o_m_writedata;
output reg o_m_read_or_write; //, o_m_write;
//input wire [(NUMBER_BANKS * 32) - 1:0] i_m_readdata; // Read Data that is passed from the memory module back to the controller
input wire[NUMBER_BANKS - 1:0][`NUM_WORDS_PER_BLOCK-1:0][31:0] i_m_readdata;
//input wire i_m_readdata_ready;
//input wire i_m_waitrequest;
input wire i_m_ready;
//output reg [31:0] cnt_r;
//output reg [31:0] cnt_w;
//output reg [31:0] cnt_hit_r;
//output reg [31:0] cnt_hit_w;
//output reg [31:0] cnt_wb_r;
//output reg [31:0] cnt_wb_w;
//wire [1:0] tag [`NT_M1:0];
//wire [3:0] index [`NT_M1:0];
//wire [2:0] bank [`NT_M1:0];
//wire all_done;
//integer i;
reg [`NT_M1:0] thread_done; // Maybe should have "thread_serviced" and "thread_done", serviced==checked cache
//reg [`NT_M1:0] thread_serviced; // Maybe should have "thread_serviced" and "thread_done", serviced==checked cache
reg [NUMBER_BANKS - 1:0] banks_ready;
//reg [NUMBER_BANKS - 1:0] banks_missed;
reg [NUMBER_BANKS - 1:0] banks_to_service;
reg [NUMBER_BANKS - 1:0] banks_wb_needed;
reg [NUMBER_BANKS - 1:0][31:0] banks_wb_addr;
//reg [NUMBER_BANKS - 1:0] bank_states;
//reg [NUMBER_BANKS - 1:0][31:0] banks_wb_data;
//reg [NUMBER_BANKS - 1:0][13:0] banks_in_addr;
reg [3:0] state;
reg [NUMBER_BANKS - 1:0][31:0] data_from_bank;
//reg got_valid_data;
//reg [31:0] data_to_write;
//reg [`NT_M1:0] thread_track_bank_0;
//reg [`NT_M1:0] thread_track_bank_1;
//reg [`NT_M1:0] thread_track_bank_2;
//reg [`NT_M1:0] thread_track_bank_3;
//reg [`NT_M1:0] thread_track_bank_4;
//reg [`NT_M1:0] thread_track_bank_5;
//reg [`NT_M1:0] thread_track_bank_6;
//reg [`NT_M1:0] thread_track_bank_7;
reg [NUMBER_BANKS - 1 : 0][`NT_M1:0] thread_track_banks;
reg [NUMBER_BANKS - 1 : 0] bank_has_access; // Will track if a bank has been accessed in this cycle
reg [NUMBER_BANKS - 1 : 0][31:0] bank_access_addr;
reg [NUMBER_BANKS - 1 : 0][31:0] bank_access_data;
reg [NUMBER_BANKS - 1 : 0][1:0] threads_in_banks;
//reg [1:0] thread_in_memory; // keeps track of threadID which is in memory
reg rd_or_wr;
//reg did_miss, needs_service; Commented out Oct 21
integer bnk;
integer found;
integer t_id;
//integer num_misses;
//integer num_evictions_to_wb;
integer i; //reg [1:0] correct_tag;
integer index;
//reg [3:0] correct_index;
//assign tag = i_p_addr[13:12];
assign o_p_waitrequest = (thread_done == 4'hF) ? 1'b0 : 1'b1; // change thread_done to be generic
//assign did_miss = (banks_missed != 8'h0) ? 1'b1 : 1'b0;
//assign needs_service = ((banks_to_service != 8'b0 || banks_to_service_temp != 8'b0)) ? 1'b1 : 1'b0; // added banks_to_service temp
//assign w_Test1 = r_Check ? 1'b1 : 1'b0;
//for ( i = 0;i < `NT_M1;i = i + 1) begin
// assign tag[i] = i_p_addr[i][13:12];
// Fares
// wire no_bank_misses;
// assign no_bank_misses = banks_to_service != 8'b0;
reg[NUMBER_BANKS - 1:0] banks_to_service_temp;
reg[NUMBER_BANKS - 1:0] banks_to_wb;
reg[NUMBER_BANKS - 1:0] banks_to_wb_temp;
reg[NUMBER_BANKS - 1:0] banks_all_help;
always @(posedge clk) begin
if (rst) begin
state <= 0;
//banks_ready <= 8'b0;
//cnt_r <= 0;
//cnt_w <= 0;
//cnt_hit_r <= 0;
//cnt_hit_w <= 0;
//cnt_wb_r <= 0;
//cnt_wb_w <= 0;
end else begin
// Change Logic of which state the cache is in
case (state)
CACHE_IDLE:begin
if (i_p_initial_request == 1'b1) begin
state <= SORT_BY_BANK;
end else begin
state <= CACHE_IDLE;
end
end
SORT_BY_BANK:begin
state <= INITIAL_ACCESS;
end
INITIAL_ACCESS:begin
if (thread_done == 4'hF) begin
state <= CACHE_IDLE;
end else begin
state <= INITIAL_PROCESSING;
end
end
INITIAL_PROCESSING:begin
if (bank_has_access == banks_ready ) begin // if all hits
state <= INITIAL_ACCESS;
end else begin
state <= CONTINUED_PROCESSING;
end
end
CONTINUED_PROCESSING:begin
if (banks_to_wb == 8'b0 && banks_to_service == 8'b0) begin // If all threads are done, then the cache can go back into idle state (not currently fetching any requests)
state <= INITIAL_ACCESS;
//end else if (num_misses > 0) begin
end else if ((banks_to_wb != 8'b0)) begin // change 1pm
state <= DIRTY_EVICT_GRAB_BLOCK;
//end else if (did_miss == 1'b1 || needs_service == 1'b1) begin
end else if(banks_to_service != 8'b0) begin
state <= FETCH_FROM_MEM;
// end else if (did_miss == 1'b0 && num_evictions_to_wb > 0) begin
//end else if (needs_service == 1'b0 && did_miss == 1'b0 && (banks_to_wb != 8'b0)) begin
//end else if (did_miss == 1'b0 && needs_service == 1'b0) begin
//state <= INITIAL_ACCESS;
end
end
FETCH_FROM_MEM:begin
state <= FETCH2;
end
FETCH2:begin
if (i_m_ready == 1'b1) begin
state <= UPDATE_CACHE; // Not sure about this one !!!!!! Check
end else begin
state <= FETCH2;
end
end
UPDATE_CACHE:begin
state <= RE_ACCESS;
end
RE_ACCESS:begin
state <= RE_ACCESS_PROCESSING;
end
RE_ACCESS_PROCESSING: begin
state <= CONTINUED_PROCESSING;
end
DIRTY_EVICT_GRAB_BLOCK:begin
state <= DIRTY_EVICT_WB;
end
DIRTY_EVICT_WB:begin
state <= CONTINUED_PROCESSING;
end
endcase
end
//tag[`NT_M1:0] <= i_p_addr[`NT_M1:0][13:12];
end
// Change values which will be fed into the cache
always @(*) begin
case (state)
CACHE_IDLE:begin
thread_done = 0;
o_m_read_or_write = 0;
o_m_valid = 0;
o_m_writedata = 0;
o_p_readdata = 0;
o_p_readdata_valid = 0;
bank_has_access = 8'b0;
//bank_states = CACHE_IDLE;
//thread_track_bank_0 = 4'b0;
//thread_track_bank_1 = 4'b0;
//thread_track_bank_2 = 4'b0;
//thread_track_bank_3 = 4'b0;
//thread_track_bank_4 = 4'b0;
//thread_track_bank_5 = 4'b0;
//thread_track_bank_6 = 4'b0;
//thread_track_bank_7 = 4'b0;
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
thread_track_banks[bnk] = 4'b0;
end
end
SORT_BY_BANK:begin
//bank_states = SORT_BY_BANK;
rd_or_wr = i_p_read_or_write;
for (t_id = 0; t_id <= `NT_M1; t_id = t_id + 1) begin
//t_id = {1'b0,t_id};
if (i_p_valid[t_id] == 1'b0) begin
thread_done[t_id] = 1'b1;
end
//if (i_p_valid[t_id] == 1'b1 && thread_done[t_id] == 1'b0) begin // Need logic for thread done
else if (i_p_addr[t_id][4:2] == 3'b000) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_0[t_id] = 1'b1;
thread_track_banks[0][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b001) begin // !!!!!!!
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_1[t_id] = 1'b1;
thread_track_banks[1][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b010) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_2[t_id] = 1'b1;
thread_track_banks[2][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b011) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_3[t_id] = 1'b1;
thread_track_banks[3][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b100) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_4[t_id] = 1'b1;
thread_track_banks[4][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b101) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_5[t_id] = 1'b1;
thread_track_banks[5][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b110) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_6[t_id] = 1'b1;
thread_track_banks[6][t_id] = 1'b1;
end
else if (i_p_addr[t_id][4:2] == 3'b111) begin
//banks_in_addr[0] = i_p_addr[t_id]; // WIll need to do this later
//thread_track_bank_7[t_id] = 1'b1;
thread_track_banks[7][t_id] = 1'b1;
end
end
end
INITIAL_ACCESS:begin
//bank_states = INITIAL_ACCESS;
o_m_valid = 1'b0;
// Before Access
// if (no_bank_misses) begin
// Dont do anything, next clock cycle it will switch back to (Fetch from mem)
// end else begin // Do logic to send requests to each bank (look through thread_track_bank regs)
bank_has_access = 8'b0;
for (t_id = 0; t_id <= `NT_M1; t_id = t_id + 1) begin
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
if(thread_track_banks[bnk][t_id] == 1'b1 && bank_has_access[bnk] == 1'b0) begin
bank_has_access[bnk] = 1'b1;
bank_access_data[bnk] = i_p_writedata[t_id];
bank_access_addr[bnk] = i_p_addr[t_id];
threads_in_banks[bnk] = t_id[1:0];
end
end
//if (banks_wb_needed[bnk]) begin // need to fix this for multiple misses
//o_m_read_or_write = 1'b0;
//o_m_addr = banks_wb_addr[bnk];
//o_m_valid = 1'b1;
//o_m_writedata = {banks_wb_data[bnk], 96'b0};
//end
//if(thread_track_bank_0[t_id] == 1'b1 && bank_has_access[0] == 1'b0) begin
//bank_has_access[0] = 1'b1;
//bank_access_data[0] = i_p_writedata[t_id];
//bank_access_addr[0] = i_p_addr[t_id];
//threads_in_banks[0] = t_id;
//end
// NEED TO UPDATE HITS (STORE IN THREADS_DONE)
end
//num_misses = {28'b0, $countones(banks_missed)};
//did_miss = (banks_missed == 4'hF);
// end
end
INITIAL_PROCESSING:begin
//bank_has_access = 8'b0;
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
if(banks_ready[bnk]) begin // FIX to handle hits
thread_done[threads_in_banks[bnk]] = 1'b1;
o_p_readdata[threads_in_banks[bnk]] = data_from_bank[bnk];
if(i_p_read_or_write == 1'b0) begin
o_p_readdata_valid[threads_in_banks[bnk]] = 1'b1;
end
thread_track_banks[bnk][threads_in_banks[bnk]] = 1'b0; // Update that this thread does not need to be serviced again
end
end
//banks_to_service_temp = !banks_ready; // These are clean misses
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
assign banks_to_service_temp[bnk] = (banks_ready[bnk] || (bank_has_access[bnk] == 0)) ? 1'b0 : 1'b1;
assign banks_to_wb_temp[bnk] = (banks_wb_needed[bnk]);
assign banks_all_help[bnk] = banks_to_service_temp[bnk] || banks_to_wb_temp[bnk];
end
end
CONTINUED_PROCESSING:begin
//for (i = `NW-1; i >= 0; i = i - 1) begin
// if (thread_done[threads_in_banks[bnk]] == 1'b1) begin // Not sure about this logic
// //index = i[`NW_M1:0];
// banks_to_service_temp[i] = 1'b0;
// banks_to_wb_temp[i] = 1'b0;
// end
//end
end
FETCH_FROM_MEM:begin
// NEED TO ADD LOGIC TO SEE IF MISSES GO TO SAME BLOCK
index = 0;
found = 0;
for (i = `NW-1; i >= 0; i = i - 1) begin
if (banks_to_service[i]) begin // Not sure about this logic
//index = i[`NW_M1:0];
index = i;
found = 1;
end
end
if (found == 1) begin
//banks_missed[index] = 0;
//thread_done
//thread_in_memory = threads_in_banks[index];
//o_m_writedata = bank_access_data[index];
banks_to_service_temp[index] = 0;
o_m_addr = bank_access_addr[index];
o_m_valid = 1'b1;
o_m_read_or_write = 1'b0;
end
//bank_states = FETCH_FROM_MEM;
end
FETCH2:begin
o_m_valid = 1'b0;
end
UPDATE_CACHE:begin
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
//if(thread_track_banks[bnk][t_id] == 1'b1 && bank_has_access[bnk] == 1'b0) begin
bank_has_access[bnk] = 1'b1;
//bank_access_data[bnk] = i_m_readdata[(bnk+1)*32 - 1:bnk*32];
bank_access_addr[bnk] = o_m_addr;
threads_in_banks[bnk] = t_id[1:0];
//end
end
//bank_access_data = i_m_readdata;
rd_or_wr = 1'b1;
//thread_done[thread_in_memory] = 1'b1; // Removed, new cache style - Oct 21
//o_p_readdata[thread_in_memory] = i_m_readdata[i_p_addr[thread_in_memory][9:5]]; // Removed, new cache style
end
DIRTY_EVICT_WB:begin // this begininng logic should be added to dirty evict grab block
//thread_done[thread_in_memory] = 1'b1;
o_m_valid = 1'b1;
end
DIRTY_EVICT_GRAB_BLOCK:begin
index = 0;
found = 0;
for (i = `NW-1; i >= 0; i = i - 1) begin
if (banks_to_wb_temp[i]) begin
//index = i[`NW_M1:0];
index = i;
found = 1;
end
end
if (found == 1) begin
banks_to_wb_temp[index] = 0;
for (i = `NW-1; i >= 0; i = i - 1) begin
if (banks_to_wb_temp[i] && banks_wb_addr[index][31:7] == banks_wb_addr[i][31:7]) begin
//index = i[`NW_M1:0];
banks_to_wb_temp[i] = 0;
end
end
//thread_done
//thread_in_memory = threads_in_banks[index];
//o_m_writedata[(bnk+1)*32 - 1:bnk*32] = banks_wb_data[index];
o_m_addr = banks_wb_addr[index];
o_m_read_or_write = 1'b1;
end
//for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
//o_m_writedata[(bnk+1)*32 - 1:bnk*32] = banks_wb_data[index];
//end
// NEXT LINE CONTAINS DATA TO WB !!!! Think need to just change this to be read data and can remove banks_wb_data
//o_m_writedata = {banks_wb_data[7],banks_wb_data[6],banks_wb_data[5],banks_wb_data[4],banks_wb_data[3],banks_wb_data[2],banks_wb_data[1],banks_wb_data[0]};
//num_evictions_to_wb = {28'b0, $countones(banks_wb_needed)};
rd_or_wr = 1'b0;
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
//if(thread_track_banks[bnk][t_id] == 1'b1 && bank_has_access[bnk] == 1'b0) begin
bank_has_access[bnk] = 1'b1;
bank_access_addr[bnk] = o_m_addr;
//end
end
end
RE_ACCESS:begin
//bank_states = INITIAL_ACCESS;
o_m_valid = 1'b0;
// Before Access
// if (no_bank_misses) begin
// Dont do anything, next clock cycle it will switch back to (Fetch from mem)
// end else begin // Do logic to send requests to each bank (look through thread_track_bank regs)
//bank_has_access = banks_all_help & !(banks_to_wb) & !(banks_to_service);
for (t_id = 0; t_id <= `NT_M1; t_id = t_id + 1) begin
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
//bank_has_access[bnk] = banks_all_help[bnk] && !thread_done[threads_in_banks[bnk]]; // Not sure
bank_has_access[bnk] = banks_all_help[bnk] && !thread_done[t_id]; // Not sure
if(thread_track_banks[bnk][t_id] == 1'b1 && bank_has_access[bnk] == 1'b1) begin
//bank_has_access[bnk] = 1'b1;
bank_access_data[bnk] = i_p_writedata[t_id];
bank_access_addr[bnk] = i_p_addr[t_id];
threads_in_banks[bnk] = t_id[1:0];
end
end
end
end
RE_ACCESS_PROCESSING:begin
// After Access
for (bnk = 0; bnk < NUMBER_BANKS; bnk = bnk + 1) begin
if(banks_ready[bnk]) begin // FIX to handle hits
thread_done[threads_in_banks[bnk]] = 1'b1;
o_p_readdata[threads_in_banks[bnk]] = data_from_bank[bnk];
if(i_p_read_or_write == 1'b0) begin
o_p_readdata_valid[threads_in_banks[bnk]] = 1'b1;
end
thread_track_banks[bnk][threads_in_banks[bnk]] = 1'b0; // Update that this thread does not need to be serviced again
// Added Oct 21
banks_to_service_temp[bnk] = 1'b0;
banks_to_wb_temp[bnk] = 1'b0;
end
end
end
endcase
end
always @(posedge clk) begin
banks_to_service <= banks_to_service_temp;
banks_to_wb <= banks_to_wb_temp;
end
genvar bank_id;
generate
for (bank_id = 0; bank_id < NUMBER_BANKS; bank_id = bank_id + 1)
begin
//VX_alu vx_alu(
// .in_reg_data (in_reg_data[1:0]),
// .in_1 (in_a_reg_data[index_out_reg]),
// .in_2 (in_b_reg_data[index_out_reg]),
// .in_rs2_src (in_rs2_src),
// .in_itype_immed(in_itype_immed),
// .in_upper_immed(in_upper_immed),
// .in_alu_op (in_alu_op),
// .in_csr_data (in_csr_data),
// .in_curr_PC (in_curr_PC),
// .out_alu_result(VX_exe_mem_req.alu_result[index_out_reg])
//);
// bank VX_banks(
// .clk (clk),
// .rst (rst),
// //.state (bank_states[bank_id]),
// .state (state),
// .read_or_write (rd_or_wr),
// //.index (correct_index),
// //.tag (correct_tag),
// .addr (bank_access_addr[bank_id]),
// .writedata (bank_access_data[bank_id]),
// .fetched_write_data(i_m_readdata[(bank_id+1)*32-1 -: 32]),
// .valid (bank_has_access[bank_id]),
// .readdata (data_from_bank[bank_id]),
// .miss_cache (banks_missed[bank_id]),
// .w2m_needed (banks_wb_needed[bank_id]),
// .w2m_addr (banks_wb_addr[bank_id]),
// .e_data (o_m_writedata[(bank_id+1)*32-1 -: 32]),
// //.w2m_data (banks_wb_data[bank_id]),
// .ready (banks_ready[bank_id])
// //.valid_data (valid_in_set)
// //.read_miss (read_miss)
// );
VX_Cache_Bank bank_structure (
.clk (clk),
.state (state),
.read_or_write (rd_or_wr),
.valid_in (bank_has_access[bank_id]),
.actual_index (bank_access_addr[bank_id][14:7]), // fix when size changes
.o_tag (bank_access_addr[bank_id][31:15]), // fix when size changes
.block_offset (bank_access_addr[bank_id][6:5]),
.writedata (bank_access_data[bank_id]),
//.fetched_writedata (i_m_readdata[(bank_id+1)*32-1 -: 32]),
.fetched_writedata (i_m_readdata[bank_id[3:0]]),
.readdata (data_from_bank[bank_id]),
.hit (banks_ready[bank_id]),
//.miss (banks_missed[bank_id]),
.eviction_wb (banks_wb_needed[bank_id]),
.eviction_addr (banks_wb_addr[bank_id]),
//.data_evicted (o_m_writedata[(bank_id+1)*32-1 -: 32])
.data_evicted (o_m_writedata[bank_id[3:0]])
);
end
endgenerate
//end
endmodule