| /* |
| * |
| * This file is part of the Elpis processor project. |
| * |
| * Copyright © 2020-present. All rights reserved. |
| * Authors: Aurora Tomas and Rodrigo Huerta. |
| * |
| * This file is licensed under both the BSD-3 license for individual/non-commercial |
| * use. Full text of both licenses can be found in LICENSE file. |
| */ |
| |
| `default_nettype none |
| |
| `ifdef TESTS |
| `include "elpis/definitions.v" |
| `else |
| `include "/project/openlane/user_proj_example/../../verilog/rtl/elpis/definitions.v" |
| `endif |
| |
| module cache #(parameter CORE_ID = 0, parameter CACHE_TYPE = `CACHE_TYPE_ICACHE)(input clk, input reset, input[31:0] address_in, input[31:0] data_in, input write_enable_in, |
| input read_enable_in, input mem_ready_in, input[127:0] mem_data_in, input is_byte, input reset_mem_req, input privilege_mode, input tlb_we, input tlb_re, |
| input[19:0] physical_addr_in, input[31:0] virtual_addr_write_tlb_in, input[19:0] physical_addr_write_tlb_in, |
| output reg[31:0] read_data_out, output reg hit_out, output reg[19:0] mem_addr_out, output reg[127:0] mem_data_out, output reg req_mem, output reg mem_we_out, |
| output reg hit_tlb, output reg exc_protected_page_tlb); |
| |
| wire is_hit_tlb, is_exc_protected_page_tlb; |
| wire[19:0] phys_addr_out; |
| |
| always@(*) begin |
| hit_tlb <= is_hit_tlb; |
| exc_protected_page_tlb <= (tlb_we && !privilege_mode) ? 1'b1 : 1'b0; |
| end |
| |
| assign is_hit_tlb = 1'b1; |
| wire[19:0] i_address_candidate = `ITLB_BASE_ADDRESS_SHIFT_CORE0 + address_in[19:0]; |
| wire[19:0] d_address_candidate = `DTLB_BASE_ADDRESS_SHIFT_CORE0 + address_in[19:0]; |
| assign phys_addr_out = privilege_mode ? address_in[19:0] : ( (CACHE_TYPE == `CACHE_TYPE_DCACHE) ? d_address_candidate : i_address_candidate); |
| |
| reg[0:0] cacheValidBits[0:`NUM_CACHE_LINES-1]; |
| reg[0:0] cacheDirtyBits[0:`NUM_CACHE_LINES-1]; |
| reg[`CACHE_TAG_SIZE-1:0] cacheTag[0:`NUM_CACHE_LINES-1]; |
| reg[`CACHE_LINE_SIZE-1:0] cacheData[0:`NUM_CACHE_LINES-1]; |
| |
| // SRAM cache data and tag ports |
| reg[`CACHE_TAG_SIZE-1:0] sram_addr_in_port; |
| wire[`CACHE_TAG_SIZE-1:0] sram_addr_out_port; |
| reg[`CACHE_LINE_SIZE-1:0] sram_data_in_port; |
| wire[`CACHE_LINE_SIZE-1:0] sram_data_out_port; |
| wire sram_we_port, sram_we_valid, sram_we_dirty, sram_value_valid, sram_value_dirty; |
| |
| wire[`CACHE_TAG_SIZE-1:0] tag; |
| wire[1:0] index; |
| wire[3:0] offset; |
| |
| assign tag = phys_addr_out[19:6]; |
| assign index = address_in[5:4]; |
| assign offset = address_in[3:0]; |
| |
| reg[2:0] cache_state, next_cache_state; |
| |
| integer i; |
| |
| always@(posedge clk) |
| begin |
| if (reset) begin |
| cache_state <= `IDLE_STATE; |
| end |
| else cache_state <= next_cache_state; |
| end |
| |
| wire[31:0] auxAL = phys_addr_out>>2; |
| wire[31:0] auxWB = {sram_addr_out_port, index, 2'b0}; |
| |
| wire no_need_write_back = (!hit_out & !cacheDirtyBits[index]); |
| wire need_write_back = (!hit_out & cacheDirtyBits[index]); |
| |
| always@(cache_state or read_enable_in or write_enable_in or reset_mem_req or no_need_write_back or need_write_back or mem_ready_in or is_hit_tlb or hit_out) begin |
| case(cache_state) |
| `IDLE_STATE:begin |
| if ((read_enable_in | write_enable_in) && is_hit_tlb) begin |
| if (hit_out) begin |
| next_cache_state <= `IDLE_STATE; |
| end |
| else if (reset_mem_req) begin |
| next_cache_state <= `IDLE_STATE; |
| end |
| else if (no_need_write_back) begin |
| next_cache_state <= `ALLOCATE_STATE; |
| end |
| else if (need_write_back) begin |
| next_cache_state <= `WRITE_BACK_STATE; |
| end else begin |
| next_cache_state <= `IDLE_STATE; |
| end |
| end |
| else begin |
| next_cache_state <= `IDLE_STATE; |
| end |
| end |
| `ALLOCATE_STATE: begin |
| if (reset_mem_req) next_cache_state <= `IDLE_STATE; |
| else if (!mem_ready_in) next_cache_state <= `ALLOCATE_STATE; |
| else next_cache_state <= `IDLE_STATE; |
| end |
| `WRITE_BACK_STATE: begin |
| if (reset_mem_req) next_cache_state <= `IDLE_STATE; |
| else if (!mem_ready_in) next_cache_state <= `WRITE_BACK_STATE; |
| // else if (mem_ready_in) next_cache_state <= `IDLE_STATE; |
| else next_cache_state <= `ALLOCATE_STATE; |
| end |
| default: next_cache_state <= `IDLE_STATE; |
| endcase |
| end |
| |
| always@(posedge clk) begin |
| if (reset) begin |
| for(i = 0; i < `NUM_CACHE_LINES; i=i+1) begin |
| cacheValidBits[i] <= 1'b0; |
| cacheDirtyBits[i] <= 1'b0; |
| end |
| end else begin |
| if (sram_we_port || (cache_state == `ALLOCATE_STATE && mem_ready_in) ) begin |
| cacheTag[index] <= (cache_state == `ALLOCATE_STATE) ? tag : sram_addr_in_port; |
| cacheData[index] <= (cache_state == `ALLOCATE_STATE) ? mem_data_in : sram_data_in_port; |
| end |
| if (sram_we_valid || (cache_state == `ALLOCATE_STATE && mem_ready_in) ) begin |
| cacheValidBits[index] <= (cache_state == `ALLOCATE_STATE) ? 1'b1 : sram_value_valid; |
| end |
| if (sram_we_dirty || (cache_state == `ALLOCATE_STATE && mem_ready_in)) begin |
| cacheDirtyBits[index] <= (cache_state == `ALLOCATE_STATE) ? 1'b0 : sram_value_dirty; |
| end |
| |
| end |
| end |
| |
| assign sram_addr_out_port = (cache_state == `ALLOCATE_STATE && mem_ready_in) ? tag : cacheTag[index]; |
| assign sram_data_out_port = (cache_state == `ALLOCATE_STATE && mem_ready_in) ? mem_data_in : cacheData[index]; |
| |
| assign sram_we_port = ((hit_out && write_enable_in) || (cache_state == `ALLOCATE_STATE && mem_ready_in)) ? 1'b1 : 1'b0; |
| assign sram_we_dirty = ((hit_out && write_enable_in) || (cache_state == `ALLOCATE_STATE && mem_ready_in)) ? 1'b1 : 1'b0; |
| assign sram_we_valid = ((hit_out && write_enable_in) || (cache_state == `ALLOCATE_STATE && mem_ready_in)) ? 1'b1 : 1'b0; |
| assign sram_value_valid = 1'b1; |
| assign sram_value_dirty = (cacheDirtyBits[index] | write_enable_in); |
| |
| always@(*) begin |
| if (reset) begin |
| mem_data_out <= 128'b0; |
| req_mem <= 0; |
| mem_we_out <= 0; |
| mem_addr_out <= 20'b0; |
| sram_data_in_port <= 128'b0; |
| sram_addr_in_port <= 'b0; |
| end else begin |
| case(cache_state) |
| `IDLE_STATE: begin |
| mem_data_out <= 128'b0; |
| mem_addr_out <= 20'b0; |
| req_mem <= 0; |
| mem_we_out <= 0; |
| if (write_enable_in) begin |
| sram_addr_in_port <= tag; |
| if (is_byte) begin |
| case(offset) |
| 4'b0000:sram_data_in_port <= {sram_data_out_port[127:8], data_in[7:0]}; |
| 4'b0001:sram_data_in_port <= {sram_data_out_port[127:16], data_in[7:0], sram_data_out_port[7:0]}; |
| 4'b0010:sram_data_in_port <= {sram_data_out_port[127:24], data_in[7:0], sram_data_out_port[15:0]}; |
| 4'b0011:sram_data_in_port <= {sram_data_out_port[127:32], data_in[7:0], sram_data_out_port[23:0]}; |
| 4'b0100:sram_data_in_port <= {sram_data_out_port[127:40], data_in[7:0], sram_data_out_port[31:0]}; |
| 4'b0101:sram_data_in_port <= {sram_data_out_port[127:48], data_in[7:0], sram_data_out_port[39:0]}; |
| 4'b0110:sram_data_in_port <= {sram_data_out_port[127:56], data_in[7:0], sram_data_out_port[47:0]}; |
| 4'b0111:sram_data_in_port <= {sram_data_out_port[127:64], data_in[7:0], sram_data_out_port[55:0]}; |
| 4'b1000:sram_data_in_port <= {sram_data_out_port[127:72], data_in[7:0], sram_data_out_port[63:0]}; |
| 4'b1001:sram_data_in_port <= {sram_data_out_port[127:80], data_in[7:0], sram_data_out_port[71:0]}; |
| 4'b1010:sram_data_in_port <= {sram_data_out_port[127:88], data_in[7:0], sram_data_out_port[79:0]}; |
| 4'b1011:sram_data_in_port <= {sram_data_out_port[127:96], data_in[7:0], sram_data_out_port[87:0]}; |
| 4'b1100:sram_data_in_port <= {sram_data_out_port[127:104], data_in[7:0], sram_data_out_port[95:0]}; |
| 4'b1101:sram_data_in_port <= {sram_data_out_port[127:112], data_in[7:0], sram_data_out_port[103:0]}; |
| 4'b1110:sram_data_in_port <= {sram_data_out_port[127:120], data_in[7:0], sram_data_out_port[111:0]}; |
| 4'b1111:sram_data_in_port <= {data_in[7:0], sram_data_out_port[119:0]}; |
| default: sram_data_in_port <= 128'b0; |
| endcase |
| end else begin |
| case(offset) |
| 4'b0000:sram_data_in_port <= {sram_data_out_port[127:32], data_in}; |
| 4'b0100:sram_data_in_port <= {sram_data_out_port[127:64], data_in, sram_data_out_port[31:0]}; |
| 4'b1000:sram_data_in_port <= {sram_data_out_port[127:96], data_in, sram_data_out_port[63:0]}; |
| 4'b1100:sram_data_in_port <= {data_in, sram_data_out_port[95:0]}; |
| default: sram_data_in_port <= 128'b0; |
| endcase |
| end |
| end else begin |
| sram_addr_in_port <= 'b0; |
| sram_data_in_port <= 128'b0; |
| end |
| end |
| `ALLOCATE_STATE: begin |
| mem_data_out <= 128'b0; |
| mem_addr_out <= {auxAL[17:2],2'b00}; |
| mem_we_out <= 1'b0; |
| if (mem_ready_in) begin |
| req_mem <= 1'b0; |
| sram_data_in_port <= mem_data_in; |
| sram_addr_in_port <= tag; |
| end else begin |
| req_mem <= 1'b1; |
| sram_data_in_port <= 128'b0; |
| sram_addr_in_port <= 'b0; |
| end |
| end |
| `WRITE_BACK_STATE: begin |
| req_mem <= 1'b1; |
| mem_we_out <= 1'b1; |
| mem_addr_out <= auxWB[19:0]; |
| mem_data_out <= sram_data_out_port; |
| sram_data_in_port <= 128'b0; |
| sram_addr_in_port <= 'b0; |
| end |
| default: begin |
| sram_addr_in_port <= 'b0; |
| sram_data_in_port <= 128'b0; |
| mem_data_out <= 128'b0; |
| mem_addr_out <= 20'b0; |
| end |
| endcase |
| end |
| end |
| |
| //BIT SELECTOR |
| always@(*) begin |
| if (read_enable_in) begin |
| if (is_byte) begin |
| read_data_out <= {24'b0, sram_data_out_port[offset*8+:8]}; |
| end else begin |
| read_data_out <= sram_data_out_port[offset*8+:32]; |
| end |
| end else begin |
| read_data_out <= 0; |
| end |
| end |
| |
| always@(*) begin : hit_cache_logic |
| if (read_enable_in | write_enable_in) begin |
| if (cache_state != `IDLE_STATE) begin |
| hit_out <= 1'b0; |
| end else begin |
| if(write_enable_in) begin |
| hit_out <= (sram_addr_out_port == tag) && cacheValidBits[index] && is_hit_tlb; |
| end else begin |
| hit_out <= (sram_addr_out_port == tag) && cacheValidBits[index] && is_hit_tlb; |
| end |
| |
| end |
| end |
| else hit_out <= 1; |
| end |
| |
| endmodule |