├── LICENSE ├── README.md └── src_v ├── l2_cache.v ├── l2_cache_axi_input.v ├── l2_cache_core.v ├── l2_cache_data_ram.v ├── l2_cache_inport.v ├── l2_cache_outport.v └── l2_cache_tag_ram.v /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, ultraembedded 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### AXI Cache (32-bit input, 256-bit output) 2 | 3 | Github: [https://github.com/ultraembedded/core_axi_cache](https://github.com/ultraembedded/core_axi_cache) 4 | 5 | #### Features 6 | * This cache instance is 2 way set associative. 7 | * The total size of 128KB. 8 | * The replacement policy is a limited pseudo-random scheme (between lines, toggling on line thrashing). 9 | * The cache is a write-back cache, with allocate on read and write. 10 | * 32-byte lines 11 | * 32-bit AXI4 input, 256-bit AXI4 output. 12 | * Does not support narrow bursts (Axsize != 2). 13 | 14 | -------------------------------------------------------------------------------- /src_v/l2_cache.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache 32 | //----------------------------------------------------------------- 33 | // Params 34 | //----------------------------------------------------------------- 35 | #( 36 | parameter AXI_ID = 0 37 | ) 38 | //----------------------------------------------------------------- 39 | // Ports 40 | //----------------------------------------------------------------- 41 | ( 42 | // Inputs 43 | input clk_i 44 | ,input rst_i 45 | ,input dbg_mode_i 46 | ,input inport_awvalid_i 47 | ,input [ 31:0] inport_awaddr_i 48 | ,input [ 3:0] inport_awid_i 49 | ,input [ 7:0] inport_awlen_i 50 | ,input [ 1:0] inport_awburst_i 51 | ,input [ 2:0] inport_awsize_i 52 | ,input inport_wvalid_i 53 | ,input [ 31:0] inport_wdata_i 54 | ,input [ 3:0] inport_wstrb_i 55 | ,input inport_wlast_i 56 | ,input inport_bready_i 57 | ,input inport_arvalid_i 58 | ,input [ 31:0] inport_araddr_i 59 | ,input [ 3:0] inport_arid_i 60 | ,input [ 7:0] inport_arlen_i 61 | ,input [ 1:0] inport_arburst_i 62 | ,input [ 2:0] inport_arsize_i 63 | ,input inport_rready_i 64 | ,input outport_awready_i 65 | ,input outport_wready_i 66 | ,input outport_bvalid_i 67 | ,input [ 1:0] outport_bresp_i 68 | ,input [ 3:0] outport_bid_i 69 | ,input outport_arready_i 70 | ,input outport_rvalid_i 71 | ,input [255:0] outport_rdata_i 72 | ,input [ 1:0] outport_rresp_i 73 | ,input [ 3:0] outport_rid_i 74 | ,input outport_rlast_i 75 | 76 | // Outputs 77 | ,output inport_awready_o 78 | ,output inport_wready_o 79 | ,output inport_bvalid_o 80 | ,output [ 1:0] inport_bresp_o 81 | ,output [ 3:0] inport_bid_o 82 | ,output inport_arready_o 83 | ,output inport_rvalid_o 84 | ,output [ 31:0] inport_rdata_o 85 | ,output [ 1:0] inport_rresp_o 86 | ,output [ 3:0] inport_rid_o 87 | ,output inport_rlast_o 88 | ,output outport_awvalid_o 89 | ,output [ 31:0] outport_awaddr_o 90 | ,output [ 3:0] outport_awid_o 91 | ,output [ 7:0] outport_awlen_o 92 | ,output [ 1:0] outport_awburst_o 93 | ,output outport_wvalid_o 94 | ,output [255:0] outport_wdata_o 95 | ,output [ 31:0] outport_wstrb_o 96 | ,output outport_wlast_o 97 | ,output outport_bready_o 98 | ,output outport_arvalid_o 99 | ,output [ 31:0] outport_araddr_o 100 | ,output [ 3:0] outport_arid_o 101 | ,output [ 7:0] outport_arlen_o 102 | ,output [ 1:0] outport_arburst_o 103 | ,output outport_rready_o 104 | ); 105 | 106 | 107 | 108 | wire [ 31:0] mem_in_addr_w; 109 | wire [ 31:0] mem_in_data_wr_w; 110 | wire mem_in_rd_w; 111 | wire [ 3:0] mem_in_wr_w; 112 | wire [ 31:0] mem_in_data_rd_w; 113 | wire mem_in_accept_w; 114 | wire mem_in_ack_w; 115 | wire mem_in_error_w; 116 | 117 | wire mem_out_wr_w; 118 | wire mem_out_rd_w; 119 | wire [ 31:0] mem_out_addr_w; 120 | wire [255:0] mem_out_write_data_w; 121 | wire mem_out_accept_w; 122 | wire mem_out_ack_w; 123 | wire mem_out_error_w; 124 | wire [255:0] mem_out_read_data_w; 125 | 126 | reg dbg_mode_q; 127 | 128 | always @ (posedge clk_i ) 129 | if (rst_i) 130 | dbg_mode_q <= 1'b0; 131 | else 132 | dbg_mode_q <= dbg_mode_i; 133 | 134 | wire flush_w = !dbg_mode_i & dbg_mode_q; 135 | 136 | l2_cache_inport 137 | u_ingress 138 | ( 139 | .clk_i(clk_i) 140 | ,.rst_i(rst_i) 141 | 142 | ,.axi_awvalid_i(inport_awvalid_i) 143 | ,.axi_awaddr_i(inport_awaddr_i) 144 | ,.axi_awid_i(inport_awid_i) 145 | ,.axi_awlen_i(inport_awlen_i) 146 | ,.axi_awburst_i(inport_awburst_i) 147 | ,.axi_wvalid_i(inport_wvalid_i) 148 | ,.axi_wdata_i(inport_wdata_i) 149 | ,.axi_wstrb_i(inport_wstrb_i) 150 | ,.axi_wlast_i(inport_wlast_i) 151 | ,.axi_bready_i(inport_bready_i) 152 | ,.axi_arvalid_i(inport_arvalid_i) 153 | ,.axi_araddr_i(inport_araddr_i) 154 | ,.axi_arid_i(inport_arid_i) 155 | ,.axi_arlen_i(inport_arlen_i) 156 | ,.axi_arburst_i(inport_arburst_i) 157 | ,.axi_rready_i(inport_rready_i) 158 | ,.axi_awready_o(inport_awready_o) 159 | ,.axi_wready_o(inport_wready_o) 160 | ,.axi_bvalid_o(inport_bvalid_o) 161 | ,.axi_bresp_o(inport_bresp_o) 162 | ,.axi_bid_o(inport_bid_o) 163 | ,.axi_arready_o(inport_arready_o) 164 | ,.axi_rvalid_o(inport_rvalid_o) 165 | ,.axi_rdata_o(inport_rdata_o) 166 | ,.axi_rresp_o(inport_rresp_o) 167 | ,.axi_rid_o(inport_rid_o) 168 | ,.axi_rlast_o(inport_rlast_o) 169 | 170 | ,.outport_wr_o(mem_in_wr_w) 171 | ,.outport_rd_o(mem_in_rd_w) 172 | ,.outport_addr_o(mem_in_addr_w) 173 | ,.outport_write_data_o(mem_in_data_wr_w) 174 | ,.outport_accept_i(mem_in_accept_w) 175 | ,.outport_ack_i(mem_in_ack_w) 176 | ,.outport_error_i(mem_in_error_w) 177 | ,.outport_read_data_i(mem_in_data_rd_w) 178 | ); 179 | 180 | l2_cache_core 181 | u_core 182 | ( 183 | .clk_i(clk_i) 184 | ,.rst_i(rst_i) 185 | 186 | ,.flush_i(flush_w) 187 | 188 | ,.inport_addr_i(mem_in_addr_w) 189 | ,.inport_data_wr_i(mem_in_data_wr_w) 190 | ,.inport_rd_i(mem_in_rd_w) 191 | ,.inport_wr_i(mem_in_wr_w) 192 | ,.inport_data_rd_o(mem_in_data_rd_w) 193 | ,.inport_accept_o(mem_in_accept_w) 194 | ,.inport_ack_o(mem_in_ack_w) 195 | ,.inport_error_o(mem_in_error_w) 196 | 197 | ,.outport_wr_o(mem_out_wr_w) 198 | ,.outport_rd_o(mem_out_rd_w) 199 | ,.outport_addr_o(mem_out_addr_w) 200 | ,.outport_write_data_o(mem_out_write_data_w) 201 | ,.outport_accept_i(mem_out_accept_w) 202 | ,.outport_ack_i(mem_out_ack_w) 203 | ,.outport_error_i(mem_out_error_w) 204 | ,.outport_read_data_i(mem_out_read_data_w) 205 | ); 206 | 207 | l2_cache_outport 208 | #( 209 | .AXI_ID(AXI_ID) 210 | ) 211 | u_egress 212 | ( 213 | .clk_i(clk_i) 214 | ,.rst_i(rst_i) 215 | 216 | ,.inport_wr_i(mem_out_wr_w) 217 | ,.inport_rd_i(mem_out_rd_w) 218 | ,.inport_addr_i(mem_out_addr_w) 219 | ,.inport_write_data_i(mem_out_write_data_w) 220 | ,.inport_accept_o(mem_out_accept_w) 221 | ,.inport_ack_o(mem_out_ack_w) 222 | ,.inport_error_o(mem_out_error_w) 223 | ,.inport_read_data_o(mem_out_read_data_w) 224 | 225 | ,.outport_awvalid_o(outport_awvalid_o) 226 | ,.outport_awaddr_o(outport_awaddr_o) 227 | ,.outport_awid_o(outport_awid_o) 228 | ,.outport_awlen_o(outport_awlen_o) 229 | ,.outport_awburst_o(outport_awburst_o) 230 | ,.outport_wvalid_o(outport_wvalid_o) 231 | ,.outport_wdata_o(outport_wdata_o) 232 | ,.outport_wstrb_o(outport_wstrb_o) 233 | ,.outport_wlast_o(outport_wlast_o) 234 | ,.outport_bready_o(outport_bready_o) 235 | ,.outport_arvalid_o(outport_arvalid_o) 236 | ,.outport_araddr_o(outport_araddr_o) 237 | ,.outport_arid_o(outport_arid_o) 238 | ,.outport_arlen_o(outport_arlen_o) 239 | ,.outport_arburst_o(outport_arburst_o) 240 | ,.outport_rready_o(outport_rready_o) 241 | ,.outport_awready_i(outport_awready_i) 242 | ,.outport_wready_i(outport_wready_i) 243 | ,.outport_bvalid_i(outport_bvalid_i) 244 | ,.outport_bresp_i(outport_bresp_i) 245 | ,.outport_bid_i(outport_bid_i) 246 | ,.outport_arready_i(outport_arready_i) 247 | ,.outport_rvalid_i(outport_rvalid_i) 248 | ,.outport_rdata_i(outport_rdata_i) 249 | ,.outport_rresp_i(outport_rresp_i) 250 | ,.outport_rid_i(outport_rid_i) 251 | ,.outport_rlast_i(outport_rlast_i) 252 | ); 253 | 254 | 255 | endmodule 256 | -------------------------------------------------------------------------------- /src_v/l2_cache_axi_input.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_axi_input 32 | //----------------------------------------------------------------- 33 | // Params 34 | //----------------------------------------------------------------- 35 | #( 36 | parameter DATA_W = 32 37 | ,parameter STRB_W = 4 38 | ,parameter ID_W = 4 39 | ,parameter RW_ARB = 1 // Arbitrate between reads and writes 40 | ) 41 | //----------------------------------------------------------------- 42 | // Ports 43 | //----------------------------------------------------------------- 44 | ( 45 | input clk_i 46 | ,input rst_i 47 | 48 | // AXI 49 | ,input axi_awvalid_i 50 | ,input [ 31:0] axi_awaddr_i 51 | ,input [ID_W-1:0] axi_awid_i 52 | ,input [ 7:0] axi_awlen_i 53 | ,input [ 1:0] axi_awburst_i 54 | ,input axi_wvalid_i 55 | ,input [DATA_W-1:0] axi_wdata_i 56 | ,input [STRB_W-1:0] axi_wstrb_i 57 | ,input axi_wlast_i 58 | ,input axi_arvalid_i 59 | ,input [ 31:0] axi_araddr_i 60 | ,input [ID_W-1:0] axi_arid_i 61 | ,input [ 7:0] axi_arlen_i 62 | ,input [ 1:0] axi_arburst_i 63 | ,output axi_awready_o 64 | ,output axi_wready_o 65 | ,output axi_arready_o 66 | 67 | // Write 68 | ,output wr_valid_o 69 | ,input wr_accept_i 70 | ,output [ 31:0] wr_addr_o 71 | ,output [ID_W-1:0] wr_id_o 72 | ,output [DATA_W-1:0] wr_data_o 73 | ,output [STRB_W-1:0] wr_strb_o 74 | ,output wr_last_o 75 | 76 | // Read 77 | ,output rd_valid_o 78 | ,input rd_accept_i 79 | ,output [ 31:0] rd_addr_o 80 | ,output [ID_W-1:0] rd_id_o 81 | ,output rd_last_o 82 | ); 83 | 84 | //----------------------------------------------------------------- 85 | // ffs: Find first set (2 input) 86 | //----------------------------------------------------------------- 87 | function [1:0] ffs; 88 | input [1:0] request; 89 | begin 90 | ffs[0] = request[0]; 91 | ffs[1] = ffs[0] | request[1]; 92 | end 93 | endfunction 94 | 95 | //----------------------------------------------------------------- 96 | // Arbitration (optional) 97 | //----------------------------------------------------------------- 98 | wire rd_enable_w; 99 | wire rd_request_w; 100 | wire wr_enable_w; 101 | wire wr_request_w; 102 | 103 | generate 104 | if (RW_ARB) 105 | begin 106 | reg hold_q; 107 | 108 | // Hold the arbitration if in the middle of a burst transfer 109 | // or if the transfer is not accepted. 110 | always @ (posedge clk_i ) 111 | if (rst_i) 112 | hold_q <= 1'b0; 113 | else if ((wr_valid_o && (!wr_accept_i || !wr_last_o)) || 114 | (rd_valid_o && (!rd_accept_i || !rd_last_o))) 115 | hold_q <= 1'b1; 116 | else if ((wr_valid_o && wr_last_o && wr_accept_i) || 117 | (rd_valid_o && rd_last_o && rd_accept_i)) 118 | hold_q <= 1'b0; 119 | 120 | wire [1:0] request_w = {rd_request_w, wr_request_w}; 121 | 122 | wire [1:0] req_ffs_masked_w; 123 | wire [1:0] req_ffs_unmasked_w; 124 | wire [1:0] req_ffs_w; 125 | 126 | reg [1:0] mask_next_q; 127 | reg [1:0] grant_last_q; 128 | wire [1:0] grant_new_w; 129 | wire [1:0] grant_w; 130 | 131 | assign req_ffs_masked_w = ffs(request_w & mask_next_q); 132 | assign req_ffs_unmasked_w = ffs(request_w); 133 | 134 | assign req_ffs_w = (|req_ffs_masked_w) ? req_ffs_masked_w : req_ffs_unmasked_w; 135 | 136 | always @ (posedge clk_i ) 137 | if (rst_i) 138 | begin 139 | mask_next_q <= {2{1'b1}}; 140 | grant_last_q <= 2'b0; 141 | end 142 | else 143 | begin 144 | if (~hold_q) 145 | mask_next_q <= {req_ffs_w[0:0], 1'b0}; 146 | 147 | grant_last_q <= grant_w; 148 | end 149 | 150 | assign grant_new_w = req_ffs_w ^ {req_ffs_w[0:0], 1'b0}; 151 | assign grant_w = hold_q ? grant_last_q : grant_new_w; 152 | 153 | assign {rd_enable_w, wr_enable_w} = grant_w; 154 | end 155 | else 156 | begin 157 | assign rd_enable_w = 1'b1; 158 | assign wr_enable_w = 1'b1; 159 | end 160 | endgenerate 161 | 162 | wire rd_accept_w = rd_enable_w & rd_accept_i; 163 | wire wr_accept_w = wr_enable_w & wr_accept_i; 164 | 165 | //----------------------------------------------------------------- 166 | // Write address skid buffer 167 | //----------------------------------------------------------------- 168 | reg awvalid_q; 169 | reg [31:0] awaddr_q; 170 | reg [1:0] awburst_q; 171 | reg [7:0] awlen_q; 172 | reg [ID_W-1:0] awid_q; 173 | 174 | wire awvalid_w = awvalid_q | axi_awvalid_i; 175 | wire [31:0] awaddr_w = awvalid_q ? awaddr_q : axi_awaddr_i; 176 | wire [1:0] awburst_w = awvalid_q ? awburst_q : axi_awburst_i; 177 | wire [7:0] awlen_w = awvalid_q ? awlen_q : axi_awlen_i; 178 | wire [ID_W-1:0] awid_w = awvalid_q ? awid_q : axi_awid_i; 179 | 180 | reg [31:0] awaddr_r; 181 | 182 | always @ * 183 | begin 184 | awaddr_r = awaddr_w; 185 | 186 | // Last / single 187 | if (wr_valid_o && wr_last_o && wr_accept_w) 188 | awaddr_r = awaddr_w; 189 | // Middle of burst 190 | else if (wr_valid_o && wr_accept_w) 191 | begin 192 | case (awburst_w) 193 | 2'd0: // FIXED 194 | awaddr_r = awaddr_w; 195 | 2'd2: // WRAP 196 | awaddr_r = (awaddr_w & ~((DATA_W/8)-1)) | ((awaddr_w + (DATA_W/8)) & ((DATA_W/8)-1)); 197 | default: // INCR 198 | awaddr_r = awaddr_w + (DATA_W/8); 199 | endcase 200 | end 201 | end 202 | 203 | always @ (posedge clk_i ) 204 | if (rst_i) 205 | awaddr_q <= 32'b0; 206 | else 207 | awaddr_q <= awaddr_r; 208 | 209 | always @ (posedge clk_i ) 210 | if (rst_i) 211 | awburst_q <= 2'b01; 212 | else if (axi_awvalid_i && axi_awready_o) 213 | awburst_q <= axi_awburst_i; 214 | 215 | always @ (posedge clk_i ) 216 | if (rst_i) 217 | awlen_q <= 8'b0; 218 | else if (axi_awvalid_i && axi_awready_o) 219 | awlen_q <= axi_awlen_i; 220 | 221 | always @ (posedge clk_i ) 222 | if (rst_i) 223 | awid_q <= {ID_W{1'b0}}; 224 | else if (axi_awvalid_i && axi_awready_o) 225 | awid_q <= axi_awid_i; 226 | 227 | always @ (posedge clk_i ) 228 | if (rst_i) 229 | awvalid_q <= 1'b0; 230 | else if (wr_valid_o && wr_last_o && wr_accept_w) 231 | awvalid_q <= 1'b0; 232 | else if (axi_awvalid_i) 233 | awvalid_q <= 1'b1; 234 | 235 | assign axi_awready_o = ~awvalid_q; 236 | 237 | //----------------------------------------------------------------- 238 | // Write data skid buffer 239 | //----------------------------------------------------------------- 240 | reg wvalid_q; 241 | reg [DATA_W-1:0] wdata_q; 242 | reg [STRB_W-1:0] wstrb_q; 243 | reg wlast_q; 244 | 245 | wire wvalid_w = wvalid_q | axi_wvalid_i; 246 | wire [DATA_W-1:0] wdata_w = wvalid_q ? wdata_q : axi_wdata_i; 247 | wire [STRB_W-1:0] wstrb_w = wvalid_q ? wstrb_q : axi_wstrb_i; 248 | wire wlast_w = wvalid_q ? wlast_q : axi_wlast_i; 249 | 250 | always @ (posedge clk_i ) 251 | if (rst_i) 252 | wdata_q <= {DATA_W{1'b0}}; 253 | else if (axi_wvalid_i && axi_wready_o) 254 | wdata_q <= axi_wdata_i; 255 | 256 | always @ (posedge clk_i ) 257 | if (rst_i) 258 | wstrb_q <= {STRB_W{1'b0}}; 259 | else if (axi_wvalid_i && axi_wready_o) 260 | wstrb_q <= axi_wstrb_i; 261 | 262 | always @ (posedge clk_i ) 263 | if (rst_i) 264 | wlast_q <= 1'b0; 265 | else if (axi_wvalid_i && axi_wready_o) 266 | wlast_q <= axi_wlast_i; 267 | 268 | always @ (posedge clk_i ) 269 | if (rst_i) 270 | wvalid_q <= 1'b0; 271 | else if (wr_valid_o && wr_accept_w) 272 | wvalid_q <= 1'b0; 273 | else if (axi_wvalid_i) 274 | wvalid_q <= 1'b1; 275 | 276 | assign axi_wready_o = ~wvalid_q; 277 | 278 | //----------------------------------------------------------------- 279 | // Write Output 280 | //----------------------------------------------------------------- 281 | assign wr_request_w = awvalid_w & wvalid_w; 282 | assign wr_valid_o = wr_request_w & wr_enable_w; 283 | assign wr_addr_o = awaddr_w; 284 | assign wr_id_o = awid_w; 285 | assign wr_data_o = wdata_w; 286 | assign wr_strb_o = wstrb_w; 287 | assign wr_last_o = wlast_w; 288 | 289 | //----------------------------------------------------------------- 290 | // Read address skid buffer 291 | //----------------------------------------------------------------- 292 | reg arvalid_q; 293 | reg [31:0] araddr_q; 294 | reg [1:0] arburst_q; 295 | reg [7:0] arlen_q; 296 | reg [ID_W-1:0] arid_q; 297 | 298 | wire arvalid_w = arvalid_q | axi_arvalid_i; 299 | wire [31:0] araddr_w = arvalid_q ? araddr_q : axi_araddr_i; 300 | wire [1:0] arburst_w = arvalid_q ? arburst_q : axi_arburst_i; 301 | wire [7:0] arlen_w = arvalid_q ? arlen_q : axi_arlen_i; 302 | wire [ID_W-1:0] arid_w = arvalid_q ? arid_q : axi_arid_i; 303 | 304 | reg [31:0] araddr_r; 305 | 306 | always @ * 307 | begin 308 | araddr_r = araddr_w; 309 | 310 | // Last / single 311 | if (rd_valid_o && rd_last_o && rd_accept_w) 312 | araddr_r = araddr_w; 313 | // Middle of burst 314 | else if (rd_valid_o && rd_accept_w) 315 | begin 316 | case (arburst_w) 317 | 2'd0: // FIXED 318 | araddr_r = araddr_w; 319 | 2'd2: // WRAP 320 | araddr_r = (araddr_w & ~((DATA_W/8)-1)) | ((araddr_w + (DATA_W/8)) & ((DATA_W/8)-1)); 321 | default: // INCR 322 | araddr_r = araddr_w + (DATA_W/8); 323 | endcase 324 | end 325 | end 326 | 327 | always @ (posedge clk_i ) 328 | if (rst_i) 329 | araddr_q <= 32'b0; 330 | else 331 | araddr_q <= araddr_r; 332 | 333 | always @ (posedge clk_i ) 334 | if (rst_i) 335 | arburst_q <= 2'b01; 336 | else if (axi_arvalid_i && axi_arready_o) 337 | arburst_q <= axi_arburst_i; 338 | 339 | always @ (posedge clk_i ) 340 | if (rst_i) 341 | arlen_q <= 8'b0; 342 | else if (axi_arvalid_i && axi_arready_o) 343 | arlen_q <= axi_arlen_i; 344 | 345 | always @ (posedge clk_i ) 346 | if (rst_i) 347 | arid_q <= {ID_W{1'b0}}; 348 | else if (axi_arvalid_i && axi_arready_o) 349 | arid_q <= axi_arid_i; 350 | 351 | always @ (posedge clk_i ) 352 | if (rst_i) 353 | arvalid_q <= 1'b0; 354 | else if (rd_valid_o && rd_last_o && rd_accept_w) 355 | arvalid_q <= 1'b0; 356 | else if (rd_valid_o && rd_accept_w) 357 | arvalid_q <= 1'b1; 358 | 359 | assign axi_arready_o = rd_accept_w & ~arvalid_q; 360 | 361 | //----------------------------------------------------------------- 362 | // Read burst tracking 363 | //----------------------------------------------------------------- 364 | reg [7:0] rd_idx_q; 365 | 366 | always @ (posedge clk_i ) 367 | if (rst_i) 368 | rd_idx_q <= 8'b0; 369 | else if (rd_valid_o && rd_last_o && rd_accept_w) 370 | rd_idx_q <= 8'b0; 371 | else if (rd_valid_o && rd_accept_w) 372 | rd_idx_q <= rd_idx_q + 8'd1; 373 | 374 | //----------------------------------------------------------------- 375 | // Read Output 376 | //----------------------------------------------------------------- 377 | assign rd_request_w = arvalid_w; 378 | assign rd_valid_o = rd_request_w & rd_enable_w; 379 | assign rd_addr_o = araddr_w; 380 | assign rd_id_o = arid_w; 381 | assign rd_last_o = arlen_w == rd_idx_q; 382 | 383 | endmodule 384 | -------------------------------------------------------------------------------- /src_v/l2_cache_core.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_core 32 | ( 33 | // Inputs 34 | input clk_i 35 | ,input rst_i 36 | ,input flush_i 37 | ,input [ 31:0] inport_addr_i 38 | ,input [ 31:0] inport_data_wr_i 39 | ,input inport_rd_i 40 | ,input [ 3:0] inport_wr_i 41 | ,input outport_accept_i 42 | ,input outport_ack_i 43 | ,input outport_error_i 44 | ,input [255:0] outport_read_data_i 45 | 46 | // Outputs 47 | ,output [31:0] inport_data_rd_o 48 | ,output inport_accept_o 49 | ,output inport_ack_o 50 | ,output inport_error_o 51 | ,output outport_wr_o 52 | ,output outport_rd_o 53 | ,output [ 31:0] outport_addr_o 54 | ,output [255:0] outport_write_data_o 55 | ); 56 | 57 | //----------------------------------------------------------------- 58 | // This cache instance is 2 way set associative. 59 | // The total size is 128KB. 60 | // The replacement policy is a limited pseudo random scheme 61 | // (between lines, toggling on line thrashing). 62 | // The cache is a write back cache, with allocate on read and write. 63 | //----------------------------------------------------------------- 64 | // Number of ways 65 | localparam L2_CACHE_NUM_WAYS = 2; 66 | 67 | // Number of cache lines 68 | localparam L2_CACHE_NUM_LINES = 2048; 69 | localparam L2_CACHE_LINE_ADDR_W = 11; 70 | 71 | // Line size (e.g. 32-bytes) 72 | localparam L2_CACHE_LINE_SIZE_W = 5; 73 | localparam L2_CACHE_LINE_SIZE = 32; 74 | localparam L2_CACHE_LINE_WORDS = 8; 75 | 76 | // Request -> tag address mapping 77 | localparam L2_CACHE_TAG_REQ_LINE_L = 5; // L2_CACHE_LINE_SIZE_W 78 | localparam L2_CACHE_TAG_REQ_LINE_H = 15; // L2_CACHE_LINE_ADDR_W+L2_CACHE_LINE_SIZE_W-1 79 | localparam L2_CACHE_TAG_REQ_LINE_W = 11; // L2_CACHE_LINE_ADDR_W 80 | `define L2_CACHE_TAG_REQ_RNG L2_CACHE_TAG_REQ_LINE_H:L2_CACHE_TAG_REQ_LINE_L 81 | 82 | // Tag fields 83 | `define L2_CACHE_TAG_ADDR_RNG 15:0 84 | localparam L2_CACHE_TAG_ADDR_BITS = 16; 85 | localparam L2_CACHE_TAG_DIRTY_BIT = L2_CACHE_TAG_ADDR_BITS + 0; 86 | localparam L2_CACHE_TAG_VALID_BIT = L2_CACHE_TAG_ADDR_BITS + 1; 87 | localparam L2_CACHE_TAG_DATA_W = L2_CACHE_TAG_ADDR_BITS + 2; 88 | 89 | // Tag compare bits 90 | localparam L2_CACHE_TAG_CMP_ADDR_L = L2_CACHE_TAG_REQ_LINE_H + 1; 91 | localparam L2_CACHE_TAG_CMP_ADDR_H = 32-1; 92 | localparam L2_CACHE_TAG_CMP_ADDR_W = L2_CACHE_TAG_CMP_ADDR_H - L2_CACHE_TAG_CMP_ADDR_L + 1; 93 | `define L2_CACHE_TAG_CMP_ADDR_RNG 31:16 94 | 95 | // Address mapping example: 96 | // 31 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 97 | // |--------------| | | | | | | | | | | | | | | | | 98 | // +--------------------+ +--------------------+ +------------+ 99 | // | Tag address. | | Line address | Address 100 | // | | | | within line 101 | // | | | | 102 | // | | | |- L2_CACHE_TAG_REQ_LINE_L 103 | // | | |- L2_CACHE_TAG_REQ_LINE_H 104 | // | |- L2_CACHE_TAG_CMP_ADDR_L 105 | // |- L2_CACHE_TAG_CMP_ADDR_H 106 | 107 | //----------------------------------------------------------------- 108 | // States 109 | //----------------------------------------------------------------- 110 | localparam STATE_W = 4; 111 | localparam STATE_RESET = 4'd0; 112 | localparam STATE_FLUSH_ADDR = 4'd1; 113 | localparam STATE_FLUSH = 4'd2; 114 | localparam STATE_LOOKUP = 4'd3; 115 | localparam STATE_READ = 4'd4; 116 | localparam STATE_WRITE = 4'd5; 117 | localparam STATE_REFILL = 4'd6; 118 | localparam STATE_EVICT = 4'd7; 119 | localparam STATE_EVICT_WAIT = 4'd8; 120 | 121 | // States 122 | reg [STATE_W-1:0] next_state_r; 123 | reg [STATE_W-1:0] state_q; 124 | 125 | //----------------------------------------------------------------- 126 | // Request buffer 127 | //----------------------------------------------------------------- 128 | reg [31:0] inport_addr_m_q; 129 | reg [31:0] inport_data_m_q; 130 | reg [3:0] inport_wr_m_q; 131 | reg inport_rd_m_q; 132 | 133 | always @ (posedge clk_i ) 134 | if (rst_i) 135 | begin 136 | inport_addr_m_q <= 32'b0; 137 | inport_data_m_q <= 32'b0; 138 | inport_wr_m_q <= 4'b0; 139 | inport_rd_m_q <= 1'b0; 140 | end 141 | else if (inport_accept_o) 142 | begin 143 | inport_addr_m_q <= inport_addr_i; 144 | inport_data_m_q <= inport_data_wr_i; 145 | inport_wr_m_q <= inport_wr_i; 146 | inport_rd_m_q <= inport_rd_i; 147 | end 148 | else if (inport_ack_o) 149 | begin 150 | inport_addr_m_q <= 32'b0; 151 | inport_data_m_q <= 32'b0; 152 | inport_wr_m_q <= 4'b0; 153 | inport_rd_m_q <= 1'b0; 154 | end 155 | 156 | reg inport_accept_r; 157 | 158 | always @ * 159 | begin 160 | inport_accept_r = 1'b0; 161 | 162 | if (state_q == STATE_LOOKUP) 163 | begin 164 | // Previous access missed - do not accept new requests 165 | if ((inport_rd_m_q || (inport_wr_m_q != 4'b0)) && !tag_hit_any_m_w) 166 | inport_accept_r = 1'b0; 167 | // Write followed by read - detect writes to the same line, or addresses which alias in tag lookups 168 | else if ((|inport_wr_m_q) && inport_rd_i && inport_addr_i[31:2] == inport_addr_m_q[31:2]) 169 | inport_accept_r = 1'b0; 170 | else 171 | inport_accept_r = 1'b1; 172 | end 173 | end 174 | 175 | assign inport_accept_o = inport_accept_r; 176 | 177 | // Tag comparison address 178 | wire [L2_CACHE_TAG_CMP_ADDR_W-1:0] req_addr_tag_cmp_m_w = inport_addr_m_q[`L2_CACHE_TAG_CMP_ADDR_RNG]; 179 | 180 | //----------------------------------------------------------------- 181 | // Registers / Wires 182 | //----------------------------------------------------------------- 183 | reg [0:0] replace_way_q; 184 | 185 | wire pmem_wr_w; 186 | wire pmem_rd_w; 187 | wire [ 7:0] pmem_len_w; 188 | wire [ 31:0] pmem_addr_w; 189 | wire [255:0] pmem_write_data_w; 190 | wire pmem_accept_w; 191 | wire pmem_ack_w; 192 | wire pmem_error_w; 193 | wire [255:0] pmem_read_data_w; 194 | 195 | wire evict_way_w; 196 | wire tag_dirty_any_m_w; 197 | wire tag_hit_and_dirty_m_w; 198 | 199 | reg flushing_q; 200 | 201 | //----------------------------------------------------------------- 202 | // TAG RAMS 203 | //----------------------------------------------------------------- 204 | reg [L2_CACHE_TAG_REQ_LINE_W-1:0] tag_addr_x_r; 205 | reg [L2_CACHE_TAG_REQ_LINE_W-1:0] tag_addr_m_r; 206 | 207 | // Tag RAM address 208 | always @ * 209 | begin 210 | // Read Port 211 | tag_addr_x_r = inport_addr_i[`L2_CACHE_TAG_REQ_RNG]; 212 | 213 | // Lookup 214 | if (state_q == STATE_LOOKUP && next_state_r == STATE_LOOKUP) 215 | tag_addr_x_r = inport_addr_i[`L2_CACHE_TAG_REQ_RNG]; 216 | // Cache flush 217 | else if (flushing_q) 218 | tag_addr_x_r = flush_addr_q; 219 | else 220 | tag_addr_x_r = inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG]; 221 | 222 | // Write Port 223 | tag_addr_m_r = flush_addr_q; 224 | 225 | // Cache flush 226 | if (flushing_q || state_q == STATE_RESET) 227 | tag_addr_m_r = flush_addr_q; 228 | // Line refill / write 229 | else 230 | tag_addr_m_r = inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG]; 231 | end 232 | 233 | // Tag RAM write data 234 | reg [L2_CACHE_TAG_DATA_W-1:0] tag_data_in_m_r; 235 | always @ * 236 | begin 237 | tag_data_in_m_r = {(L2_CACHE_TAG_DATA_W){1'b0}}; 238 | 239 | // Cache flush 240 | if (state_q == STATE_FLUSH || state_q == STATE_RESET || flushing_q) 241 | tag_data_in_m_r = {(L2_CACHE_TAG_DATA_W){1'b0}}; 242 | // Line refill 243 | else if (state_q == STATE_REFILL) 244 | begin 245 | tag_data_in_m_r[L2_CACHE_TAG_VALID_BIT] = 1'b1; 246 | tag_data_in_m_r[L2_CACHE_TAG_DIRTY_BIT] = 1'b0; 247 | tag_data_in_m_r[`L2_CACHE_TAG_ADDR_RNG] = inport_addr_m_q[`L2_CACHE_TAG_CMP_ADDR_RNG]; 248 | end 249 | // Evict completion 250 | else if (state_q == STATE_EVICT_WAIT) 251 | begin 252 | tag_data_in_m_r[L2_CACHE_TAG_VALID_BIT] = 1'b1; 253 | tag_data_in_m_r[L2_CACHE_TAG_DIRTY_BIT] = 1'b0; 254 | tag_data_in_m_r[`L2_CACHE_TAG_ADDR_RNG] = inport_addr_m_q[`L2_CACHE_TAG_CMP_ADDR_RNG]; 255 | end 256 | // Write - mark entry as dirty 257 | else if (state_q == STATE_WRITE || (state_q == STATE_LOOKUP && (|inport_wr_m_q))) 258 | begin 259 | tag_data_in_m_r[L2_CACHE_TAG_VALID_BIT] = 1'b1; 260 | tag_data_in_m_r[L2_CACHE_TAG_DIRTY_BIT] = 1'b1; 261 | tag_data_in_m_r[`L2_CACHE_TAG_ADDR_RNG] = inport_addr_m_q[`L2_CACHE_TAG_CMP_ADDR_RNG]; 262 | end 263 | end 264 | 265 | // Tag RAM write enable (way 0) 266 | reg tag0_write_m_r; 267 | always @ * 268 | begin 269 | tag0_write_m_r = 1'b0; 270 | 271 | // Cache flush (reset) 272 | if (state_q == STATE_RESET) 273 | tag0_write_m_r = 1'b1; 274 | // Cache flush 275 | else if (state_q == STATE_FLUSH) 276 | tag0_write_m_r = !tag_dirty_any_m_w; 277 | // Write - hit, mark as dirty 278 | else if (state_q == STATE_LOOKUP && (|inport_wr_m_q)) 279 | tag0_write_m_r = tag0_hit_m_w; 280 | // Write - write after refill 281 | else if (state_q == STATE_WRITE) 282 | tag0_write_m_r = (replace_way_q == 0); 283 | // Write - mark entry as dirty 284 | else if (state_q == STATE_EVICT_WAIT && pmem_ack_w) 285 | tag0_write_m_r = (replace_way_q == 0); 286 | // Line refill 287 | else if (state_q == STATE_REFILL) 288 | tag0_write_m_r = pmem_ack_w && (replace_way_q == 0); 289 | end 290 | 291 | wire [L2_CACHE_TAG_DATA_W-1:0] tag0_data_out_m_w; 292 | 293 | l2_cache_tag_ram 294 | u_tag0 295 | ( 296 | .clk0_i(clk_i), 297 | .rst0_i(rst_i), 298 | .clk1_i(clk_i), 299 | .rst1_i(rst_i), 300 | 301 | // Read 302 | .addr0_i(tag_addr_x_r), 303 | .data0_o(tag0_data_out_m_w), 304 | 305 | // Write 306 | .addr1_i(tag_addr_m_r), 307 | .data1_i(tag_data_in_m_r), 308 | .wr1_i(tag0_write_m_r) 309 | ); 310 | 311 | `ifdef verilator 312 | function addr_hit_way0; /* verilator public */ 313 | input [31:0] addr; 314 | reg [L2_CACHE_TAG_DATA_W-1:0] tag_data; 315 | begin 316 | tag_data = u_tag0.ram[addr[`L2_CACHE_TAG_REQ_RNG]]; 317 | addr_hit_way0 = tag_data[L2_CACHE_TAG_VALID_BIT] && (tag_data[`L2_CACHE_TAG_ADDR_RNG] == addr[`L2_CACHE_TAG_CMP_ADDR_RNG]); 318 | end 319 | endfunction 320 | `endif 321 | 322 | wire tag0_valid_m_w = tag0_data_out_m_w[L2_CACHE_TAG_VALID_BIT]; 323 | wire tag0_dirty_m_w = tag0_data_out_m_w[L2_CACHE_TAG_DIRTY_BIT]; 324 | wire [L2_CACHE_TAG_ADDR_BITS-1:0] tag0_addr_bits_m_w = tag0_data_out_m_w[`L2_CACHE_TAG_ADDR_RNG]; 325 | 326 | // Tag hit? 327 | wire tag0_hit_m_w = tag0_valid_m_w ? (tag0_addr_bits_m_w == req_addr_tag_cmp_m_w) : 1'b0; 328 | 329 | // Tag RAM write enable (way 1) 330 | reg tag1_write_m_r; 331 | always @ * 332 | begin 333 | tag1_write_m_r = 1'b0; 334 | 335 | // Cache flush (reset) 336 | if (state_q == STATE_RESET) 337 | tag1_write_m_r = 1'b1; 338 | // Cache flush 339 | else if (state_q == STATE_FLUSH) 340 | tag1_write_m_r = !tag_dirty_any_m_w; 341 | // Write - hit, mark as dirty 342 | else if (state_q == STATE_LOOKUP && (|inport_wr_m_q)) 343 | tag1_write_m_r = tag1_hit_m_w; 344 | // Write - write after refill 345 | else if (state_q == STATE_WRITE) 346 | tag1_write_m_r = (replace_way_q == 1); 347 | // Write - mark entry as dirty 348 | else if (state_q == STATE_EVICT_WAIT && pmem_ack_w) 349 | tag1_write_m_r = (replace_way_q == 1); 350 | // Line refill 351 | else if (state_q == STATE_REFILL) 352 | tag1_write_m_r = pmem_ack_w && (replace_way_q == 1); 353 | end 354 | 355 | wire [L2_CACHE_TAG_DATA_W-1:0] tag1_data_out_m_w; 356 | 357 | l2_cache_tag_ram 358 | u_tag1 359 | ( 360 | .clk0_i(clk_i), 361 | .rst0_i(rst_i), 362 | .clk1_i(clk_i), 363 | .rst1_i(rst_i), 364 | 365 | // Read 366 | .addr0_i(tag_addr_x_r), 367 | .data0_o(tag1_data_out_m_w), 368 | 369 | // Write 370 | .addr1_i(tag_addr_m_r), 371 | .data1_i(tag_data_in_m_r), 372 | .wr1_i(tag1_write_m_r) 373 | ); 374 | 375 | `ifdef verilator 376 | function addr_hit_way1; /* verilator public */ 377 | input [31:0] addr; 378 | reg [L2_CACHE_TAG_DATA_W-1:0] tag_data; 379 | begin 380 | tag_data = u_tag1.ram[addr[`L2_CACHE_TAG_REQ_RNG]]; 381 | addr_hit_way1 = tag_data[L2_CACHE_TAG_VALID_BIT] && (tag_data[`L2_CACHE_TAG_ADDR_RNG] == addr[`L2_CACHE_TAG_CMP_ADDR_RNG]); 382 | end 383 | endfunction 384 | `endif 385 | 386 | wire tag1_valid_m_w = tag1_data_out_m_w[L2_CACHE_TAG_VALID_BIT]; 387 | wire tag1_dirty_m_w = tag1_data_out_m_w[L2_CACHE_TAG_DIRTY_BIT]; 388 | wire [L2_CACHE_TAG_ADDR_BITS-1:0] tag1_addr_bits_m_w = tag1_data_out_m_w[`L2_CACHE_TAG_ADDR_RNG]; 389 | 390 | // Tag hit? 391 | wire tag1_hit_m_w = tag1_valid_m_w ? (tag1_addr_bits_m_w == req_addr_tag_cmp_m_w) : 1'b0; 392 | 393 | 394 | wire tag_hit_any_m_w = 1'b0 395 | | tag0_hit_m_w 396 | | tag1_hit_m_w 397 | ; 398 | 399 | assign tag_hit_and_dirty_m_w = 1'b0 400 | | (tag0_hit_m_w & tag0_dirty_m_w) 401 | | (tag1_hit_m_w & tag1_dirty_m_w) 402 | ; 403 | 404 | assign tag_dirty_any_m_w = 1'b0 405 | | (tag0_valid_m_w & tag0_dirty_m_w) 406 | | (tag1_valid_m_w & tag1_dirty_m_w) 407 | ; 408 | 409 | localparam EVICT_ADDR_W = 32 - L2_CACHE_LINE_SIZE_W; 410 | reg evict_way_r; 411 | reg [255:0] evict_data_r; 412 | reg [EVICT_ADDR_W-1:0] evict_addr_r; 413 | always @ * 414 | begin 415 | evict_way_r = 1'b0; 416 | evict_addr_r = flushing_q ? {tag0_addr_bits_m_w, flush_addr_q} : 417 | {tag0_addr_bits_m_w, inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG]}; 418 | evict_data_r = data0_data_out_m_w; 419 | 420 | case (replace_way_q) 421 | 1'd0: 422 | begin 423 | evict_way_r = tag0_valid_m_w && tag0_dirty_m_w; 424 | evict_addr_r = flushing_q ? {tag0_addr_bits_m_w, flush_addr_q} : 425 | {tag0_addr_bits_m_w, inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG]}; 426 | evict_data_r = data0_data_out_m_w; 427 | end 428 | 1'd1: 429 | begin 430 | evict_way_r = tag1_valid_m_w && tag1_dirty_m_w; 431 | evict_addr_r = flushing_q ? {tag1_addr_bits_m_w, flush_addr_q} : 432 | {tag1_addr_bits_m_w, inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG]}; 433 | evict_data_r = data1_data_out_m_w; 434 | end 435 | endcase 436 | end 437 | assign evict_way_w = (flushing_q || !tag_hit_any_m_w) && evict_way_r; 438 | wire [EVICT_ADDR_W-1:0] evict_addr_w = evict_addr_r; 439 | wire [255:0] evict_data_w = evict_data_r; 440 | 441 | //----------------------------------------------------------------- 442 | // DATA RAMS 443 | //----------------------------------------------------------------- 444 | // Data addressing 445 | localparam CACHE_DATA_ADDR_W = L2_CACHE_LINE_ADDR_W+L2_CACHE_LINE_SIZE_W-2; 446 | 447 | 448 | reg [CACHE_DATA_ADDR_W-1:0] data_addr_x_r; 449 | reg [CACHE_DATA_ADDR_W-1:0] data_addr_m_r; 450 | reg [CACHE_DATA_ADDR_W-1:0] data_write_addr_q; 451 | 452 | // Data RAM refill write address 453 | always @ (posedge clk_i ) 454 | if (rst_i) 455 | data_write_addr_q <= {(CACHE_DATA_ADDR_W){1'b0}}; 456 | else if (state_q != STATE_REFILL && next_state_r == STATE_REFILL) 457 | data_write_addr_q <= pmem_addr_w[CACHE_DATA_ADDR_W+2-1:2]; 458 | else if (state_q != STATE_EVICT && next_state_r == STATE_EVICT) 459 | data_write_addr_q <= data_addr_m_r + 1; 460 | else if (state_q == STATE_REFILL && pmem_ack_w) 461 | data_write_addr_q <= data_write_addr_q + 1; 462 | else if (state_q == STATE_EVICT && pmem_accept_w) 463 | data_write_addr_q <= data_write_addr_q + 1; 464 | 465 | // Data RAM address 466 | always @ * 467 | begin 468 | data_addr_x_r = inport_addr_i[CACHE_DATA_ADDR_W+2-1:2]; 469 | data_addr_m_r = inport_addr_m_q[CACHE_DATA_ADDR_W+2-1:2]; 470 | 471 | // Line refill / evict 472 | if (state_q == STATE_REFILL || state_q == STATE_EVICT) 473 | begin 474 | data_addr_x_r = data_write_addr_q; 475 | data_addr_m_r = data_addr_x_r; 476 | end 477 | else if (state_q == STATE_FLUSH || state_q == STATE_RESET) 478 | begin 479 | data_addr_x_r = {flush_addr_q, {(L2_CACHE_LINE_SIZE_W-2){1'b0}}}; 480 | data_addr_m_r = data_addr_x_r; 481 | end 482 | else if (state_q != STATE_EVICT && next_state_r == STATE_EVICT) 483 | begin 484 | data_addr_x_r = {inport_addr_m_q[`L2_CACHE_TAG_REQ_RNG], {(L2_CACHE_LINE_SIZE_W-2){1'b0}}}; 485 | data_addr_m_r = data_addr_x_r; 486 | end 487 | // Lookup post refill 488 | else if (state_q == STATE_READ) 489 | begin 490 | data_addr_x_r = inport_addr_m_q[CACHE_DATA_ADDR_W+2-1:2]; 491 | end 492 | // Possible line update on write 493 | else 494 | data_addr_m_r = inport_addr_m_q[CACHE_DATA_ADDR_W+2-1:2]; 495 | end 496 | 497 | 498 | // Data RAM write enable (way 0) 499 | reg [31:0] data0_write_m_r; 500 | always @ * 501 | begin 502 | data0_write_m_r = 32'b0; 503 | 504 | if (state_q == STATE_REFILL) 505 | data0_write_m_r = (pmem_ack_w && replace_way_q == 0) ? 32'hFFFFFFFF : 32'b0; 506 | else if (state_q == STATE_WRITE || state_q == STATE_LOOKUP) 507 | begin 508 | case (inport_addr_m_q[4:2]) 509 | 3'd0: data0_write_m_r[3:0] = inport_wr_m_q & {4{tag0_hit_m_w}}; 510 | 3'd1: data0_write_m_r[7:4] = inport_wr_m_q & {4{tag0_hit_m_w}}; 511 | 3'd2: data0_write_m_r[11:8] = inport_wr_m_q & {4{tag0_hit_m_w}}; 512 | 3'd3: data0_write_m_r[15:12] = inport_wr_m_q & {4{tag0_hit_m_w}}; 513 | 3'd4: data0_write_m_r[19:16] = inport_wr_m_q & {4{tag0_hit_m_w}}; 514 | 3'd5: data0_write_m_r[23:20] = inport_wr_m_q & {4{tag0_hit_m_w}}; 515 | 3'd6: data0_write_m_r[27:24] = inport_wr_m_q & {4{tag0_hit_m_w}}; 516 | 3'd7: data0_write_m_r[31:28] = inport_wr_m_q & {4{tag0_hit_m_w}}; 517 | default: ; 518 | endcase 519 | end 520 | end 521 | 522 | wire [255:0] data0_data_out_m_w; 523 | wire [255:0] data0_data_in_m_w = (state_q == STATE_REFILL) ? pmem_read_data_w : {8{inport_data_m_q}}; 524 | 525 | l2_cache_data_ram 526 | u_data0_0 527 | ( 528 | .clk0_i(clk_i), 529 | .rst0_i(rst_i), 530 | .clk1_i(clk_i), 531 | .rst1_i(rst_i), 532 | 533 | // Read 534 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 535 | .data0_i(32'b0), 536 | .wr0_i(4'b0), 537 | .data0_o(data0_data_out_m_w[31:0]), 538 | 539 | // Write 540 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 541 | .data1_i(data0_data_in_m_w[31:0]), 542 | .wr1_i(data0_write_m_r[3:0]), 543 | .data1_o() 544 | ); 545 | l2_cache_data_ram 546 | u_data0_1 547 | ( 548 | .clk0_i(clk_i), 549 | .rst0_i(rst_i), 550 | .clk1_i(clk_i), 551 | .rst1_i(rst_i), 552 | 553 | // Read 554 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 555 | .data0_i(32'b0), 556 | .wr0_i(4'b0), 557 | .data0_o(data0_data_out_m_w[63:32]), 558 | 559 | // Write 560 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 561 | .data1_i(data0_data_in_m_w[63:32]), 562 | .wr1_i(data0_write_m_r[7:4]), 563 | .data1_o() 564 | ); 565 | l2_cache_data_ram 566 | u_data0_2 567 | ( 568 | .clk0_i(clk_i), 569 | .rst0_i(rst_i), 570 | .clk1_i(clk_i), 571 | .rst1_i(rst_i), 572 | 573 | // Read 574 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 575 | .data0_i(32'b0), 576 | .wr0_i(4'b0), 577 | .data0_o(data0_data_out_m_w[95:64]), 578 | 579 | // Write 580 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 581 | .data1_i(data0_data_in_m_w[95:64]), 582 | .wr1_i(data0_write_m_r[11:8]), 583 | .data1_o() 584 | ); 585 | l2_cache_data_ram 586 | u_data0_3 587 | ( 588 | .clk0_i(clk_i), 589 | .rst0_i(rst_i), 590 | .clk1_i(clk_i), 591 | .rst1_i(rst_i), 592 | 593 | // Read 594 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 595 | .data0_i(32'b0), 596 | .wr0_i(4'b0), 597 | .data0_o(data0_data_out_m_w[127:96]), 598 | 599 | // Write 600 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 601 | .data1_i(data0_data_in_m_w[127:96]), 602 | .wr1_i(data0_write_m_r[15:12]), 603 | .data1_o() 604 | ); 605 | l2_cache_data_ram 606 | u_data0_4 607 | ( 608 | .clk0_i(clk_i), 609 | .rst0_i(rst_i), 610 | .clk1_i(clk_i), 611 | .rst1_i(rst_i), 612 | 613 | // Read 614 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 615 | .data0_i(32'b0), 616 | .wr0_i(4'b0), 617 | .data0_o(data0_data_out_m_w[159:128]), 618 | 619 | // Write 620 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 621 | .data1_i(data0_data_in_m_w[159:128]), 622 | .wr1_i(data0_write_m_r[19:16]), 623 | .data1_o() 624 | ); 625 | l2_cache_data_ram 626 | u_data0_5 627 | ( 628 | .clk0_i(clk_i), 629 | .rst0_i(rst_i), 630 | .clk1_i(clk_i), 631 | .rst1_i(rst_i), 632 | 633 | // Read 634 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 635 | .data0_i(32'b0), 636 | .wr0_i(4'b0), 637 | .data0_o(data0_data_out_m_w[191:160]), 638 | 639 | // Write 640 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 641 | .data1_i(data0_data_in_m_w[191:160]), 642 | .wr1_i(data0_write_m_r[23:20]), 643 | .data1_o() 644 | ); 645 | l2_cache_data_ram 646 | u_data0_6 647 | ( 648 | .clk0_i(clk_i), 649 | .rst0_i(rst_i), 650 | .clk1_i(clk_i), 651 | .rst1_i(rst_i), 652 | 653 | // Read 654 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 655 | .data0_i(32'b0), 656 | .wr0_i(4'b0), 657 | .data0_o(data0_data_out_m_w[223:192]), 658 | 659 | // Write 660 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 661 | .data1_i(data0_data_in_m_w[223:192]), 662 | .wr1_i(data0_write_m_r[27:24]), 663 | .data1_o() 664 | ); 665 | l2_cache_data_ram 666 | u_data0_7 667 | ( 668 | .clk0_i(clk_i), 669 | .rst0_i(rst_i), 670 | .clk1_i(clk_i), 671 | .rst1_i(rst_i), 672 | 673 | // Read 674 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 675 | .data0_i(32'b0), 676 | .wr0_i(4'b0), 677 | .data0_o(data0_data_out_m_w[255:224]), 678 | 679 | // Write 680 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 681 | .data1_i(data0_data_in_m_w[255:224]), 682 | .wr1_i(data0_write_m_r[31:28]), 683 | .data1_o() 684 | ); 685 | 686 | `ifdef verilator 687 | function [31:0] data_way0; /* verilator public */ 688 | input [31:0] addr; 689 | begin 690 | case (addr[4:2]) 691 | 3'd0: data_way0 = u_data0_0.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 692 | 3'd1: data_way0 = u_data0_1.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 693 | 3'd2: data_way0 = u_data0_2.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 694 | 3'd3: data_way0 = u_data0_3.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 695 | 3'd4: data_way0 = u_data0_4.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 696 | 3'd5: data_way0 = u_data0_5.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 697 | 3'd6: data_way0 = u_data0_6.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 698 | 3'd7: data_way0 = u_data0_7.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 699 | default: ; 700 | endcase 701 | end 702 | endfunction 703 | `endif 704 | 705 | 706 | // Data RAM write enable (way 1) 707 | reg [31:0] data1_write_m_r; 708 | always @ * 709 | begin 710 | data1_write_m_r = 32'b0; 711 | 712 | if (state_q == STATE_REFILL) 713 | data1_write_m_r = (pmem_ack_w && replace_way_q == 1) ? 32'hFFFFFFFF : 32'b0; 714 | else if (state_q == STATE_WRITE || state_q == STATE_LOOKUP) 715 | begin 716 | case (inport_addr_m_q[4:2]) 717 | 3'd0: data1_write_m_r[3:0] = inport_wr_m_q & {4{tag1_hit_m_w}}; 718 | 3'd1: data1_write_m_r[7:4] = inport_wr_m_q & {4{tag1_hit_m_w}}; 719 | 3'd2: data1_write_m_r[11:8] = inport_wr_m_q & {4{tag1_hit_m_w}}; 720 | 3'd3: data1_write_m_r[15:12] = inport_wr_m_q & {4{tag1_hit_m_w}}; 721 | 3'd4: data1_write_m_r[19:16] = inport_wr_m_q & {4{tag1_hit_m_w}}; 722 | 3'd5: data1_write_m_r[23:20] = inport_wr_m_q & {4{tag1_hit_m_w}}; 723 | 3'd6: data1_write_m_r[27:24] = inport_wr_m_q & {4{tag1_hit_m_w}}; 724 | 3'd7: data1_write_m_r[31:28] = inport_wr_m_q & {4{tag1_hit_m_w}}; 725 | default: ; 726 | endcase 727 | end 728 | end 729 | 730 | wire [255:0] data1_data_out_m_w; 731 | wire [255:0] data1_data_in_m_w = (state_q == STATE_REFILL) ? pmem_read_data_w : {8{inport_data_m_q}}; 732 | 733 | l2_cache_data_ram 734 | u_data1_0 735 | ( 736 | .clk0_i(clk_i), 737 | .rst0_i(rst_i), 738 | .clk1_i(clk_i), 739 | .rst1_i(rst_i), 740 | 741 | // Read 742 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 743 | .data0_i(32'b0), 744 | .wr0_i(4'b0), 745 | .data0_o(data1_data_out_m_w[31:0]), 746 | 747 | // Write 748 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 749 | .data1_i(data1_data_in_m_w[31:0]), 750 | .wr1_i(data1_write_m_r[3:0]), 751 | .data1_o() 752 | ); 753 | l2_cache_data_ram 754 | u_data1_1 755 | ( 756 | .clk0_i(clk_i), 757 | .rst0_i(rst_i), 758 | .clk1_i(clk_i), 759 | .rst1_i(rst_i), 760 | 761 | // Read 762 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 763 | .data0_i(32'b0), 764 | .wr0_i(4'b0), 765 | .data0_o(data1_data_out_m_w[63:32]), 766 | 767 | // Write 768 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 769 | .data1_i(data1_data_in_m_w[63:32]), 770 | .wr1_i(data1_write_m_r[7:4]), 771 | .data1_o() 772 | ); 773 | l2_cache_data_ram 774 | u_data1_2 775 | ( 776 | .clk0_i(clk_i), 777 | .rst0_i(rst_i), 778 | .clk1_i(clk_i), 779 | .rst1_i(rst_i), 780 | 781 | // Read 782 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 783 | .data0_i(32'b0), 784 | .wr0_i(4'b0), 785 | .data0_o(data1_data_out_m_w[95:64]), 786 | 787 | // Write 788 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 789 | .data1_i(data1_data_in_m_w[95:64]), 790 | .wr1_i(data1_write_m_r[11:8]), 791 | .data1_o() 792 | ); 793 | l2_cache_data_ram 794 | u_data1_3 795 | ( 796 | .clk0_i(clk_i), 797 | .rst0_i(rst_i), 798 | .clk1_i(clk_i), 799 | .rst1_i(rst_i), 800 | 801 | // Read 802 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 803 | .data0_i(32'b0), 804 | .wr0_i(4'b0), 805 | .data0_o(data1_data_out_m_w[127:96]), 806 | 807 | // Write 808 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 809 | .data1_i(data1_data_in_m_w[127:96]), 810 | .wr1_i(data1_write_m_r[15:12]), 811 | .data1_o() 812 | ); 813 | l2_cache_data_ram 814 | u_data1_4 815 | ( 816 | .clk0_i(clk_i), 817 | .rst0_i(rst_i), 818 | .clk1_i(clk_i), 819 | .rst1_i(rst_i), 820 | 821 | // Read 822 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 823 | .data0_i(32'b0), 824 | .wr0_i(4'b0), 825 | .data0_o(data1_data_out_m_w[159:128]), 826 | 827 | // Write 828 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 829 | .data1_i(data1_data_in_m_w[159:128]), 830 | .wr1_i(data1_write_m_r[19:16]), 831 | .data1_o() 832 | ); 833 | l2_cache_data_ram 834 | u_data1_5 835 | ( 836 | .clk0_i(clk_i), 837 | .rst0_i(rst_i), 838 | .clk1_i(clk_i), 839 | .rst1_i(rst_i), 840 | 841 | // Read 842 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 843 | .data0_i(32'b0), 844 | .wr0_i(4'b0), 845 | .data0_o(data1_data_out_m_w[191:160]), 846 | 847 | // Write 848 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 849 | .data1_i(data1_data_in_m_w[191:160]), 850 | .wr1_i(data1_write_m_r[23:20]), 851 | .data1_o() 852 | ); 853 | l2_cache_data_ram 854 | u_data1_6 855 | ( 856 | .clk0_i(clk_i), 857 | .rst0_i(rst_i), 858 | .clk1_i(clk_i), 859 | .rst1_i(rst_i), 860 | 861 | // Read 862 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 863 | .data0_i(32'b0), 864 | .wr0_i(4'b0), 865 | .data0_o(data1_data_out_m_w[223:192]), 866 | 867 | // Write 868 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 869 | .data1_i(data1_data_in_m_w[223:192]), 870 | .wr1_i(data1_write_m_r[27:24]), 871 | .data1_o() 872 | ); 873 | l2_cache_data_ram 874 | u_data1_7 875 | ( 876 | .clk0_i(clk_i), 877 | .rst0_i(rst_i), 878 | .clk1_i(clk_i), 879 | .rst1_i(rst_i), 880 | 881 | // Read 882 | .addr0_i(data_addr_x_r[CACHE_DATA_ADDR_W-1:3]), 883 | .data0_i(32'b0), 884 | .wr0_i(4'b0), 885 | .data0_o(data1_data_out_m_w[255:224]), 886 | 887 | // Write 888 | .addr1_i(data_addr_m_r[CACHE_DATA_ADDR_W-1:3]), 889 | .data1_i(data1_data_in_m_w[255:224]), 890 | .wr1_i(data1_write_m_r[31:28]), 891 | .data1_o() 892 | ); 893 | 894 | `ifdef verilator 895 | function [31:0] data_way1; /* verilator public */ 896 | input [31:0] addr; 897 | begin 898 | case (addr[4:2]) 899 | 3'd0: data_way1 = u_data1_0.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 900 | 3'd1: data_way1 = u_data1_1.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 901 | 3'd2: data_way1 = u_data1_2.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 902 | 3'd3: data_way1 = u_data1_3.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 903 | 3'd4: data_way1 = u_data1_4.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 904 | 3'd5: data_way1 = u_data1_5.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 905 | 3'd6: data_way1 = u_data1_6.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 906 | 3'd7: data_way1 = u_data1_7.ram[addr[CACHE_DATA_ADDR_W+2-1:5]]; 907 | default: ; 908 | endcase 909 | end 910 | endfunction 911 | `endif 912 | 913 | 914 | //----------------------------------------------------------------- 915 | // Flush counter 916 | //----------------------------------------------------------------- 917 | reg [L2_CACHE_TAG_REQ_LINE_W-1:0] flush_addr_q; 918 | 919 | always @ (posedge clk_i ) 920 | if (rst_i) 921 | flush_addr_q <= {(L2_CACHE_TAG_REQ_LINE_W){1'b0}}; 922 | else if ((state_q == STATE_RESET) || (state_q == STATE_FLUSH && next_state_r == STATE_FLUSH_ADDR)) 923 | flush_addr_q <= flush_addr_q + 1; 924 | else if (state_q == STATE_LOOKUP) 925 | flush_addr_q <= {(L2_CACHE_TAG_REQ_LINE_W){1'b0}}; 926 | 927 | always @ (posedge clk_i ) 928 | if (rst_i) 929 | flushing_q <= 1'b0; 930 | else if (state_q == STATE_LOOKUP && next_state_r == STATE_FLUSH_ADDR) 931 | flushing_q <= 1'b1; 932 | else if (state_q == STATE_FLUSH && next_state_r == STATE_LOOKUP) 933 | flushing_q <= 1'b0; 934 | 935 | reg flush_last_q; 936 | always @ (posedge clk_i ) 937 | if (rst_i) 938 | flush_last_q <= 1'b0; 939 | else if (state_q == STATE_LOOKUP) 940 | flush_last_q <= 1'b0; 941 | else if (flush_addr_q == {(L2_CACHE_TAG_REQ_LINE_W){1'b1}}) 942 | flush_last_q <= 1'b1; 943 | 944 | //----------------------------------------------------------------- 945 | // Replacement Policy 946 | //----------------------------------------------------------------- 947 | // Using random replacement policy - this way we cycle through the ways 948 | // when needing to replace a line. 949 | always @ (posedge clk_i ) 950 | if (rst_i) 951 | replace_way_q <= 0; 952 | else if (state_q == STATE_WRITE || state_q == STATE_READ) 953 | replace_way_q <= replace_way_q + 1; 954 | else if (flushing_q && tag_dirty_any_m_w && !evict_way_w && state_q != STATE_FLUSH_ADDR) 955 | replace_way_q <= replace_way_q + 1; 956 | else if (state_q == STATE_EVICT_WAIT && next_state_r == STATE_FLUSH_ADDR) 957 | replace_way_q <= 0; 958 | else if (state_q == STATE_FLUSH && next_state_r == STATE_LOOKUP) 959 | replace_way_q <= 0; 960 | else if (state_q == STATE_LOOKUP && next_state_r == STATE_FLUSH_ADDR) 961 | replace_way_q <= 0; 962 | 963 | //----------------------------------------------------------------- 964 | // Output Result 965 | //----------------------------------------------------------------- 966 | reg [2:0] data_sel_q; 967 | 968 | always @ (posedge clk_i ) 969 | if (rst_i) 970 | data_sel_q <= 3'b0; 971 | else 972 | data_sel_q <= data_addr_x_r[2:0]; 973 | 974 | // Data output mux 975 | reg [31:0] data_r; 976 | reg [255:0] data_wide_r; 977 | always @ * 978 | begin 979 | data_r = 32'b0; 980 | data_wide_r = data0_data_out_m_w; 981 | 982 | case (1'b1) 983 | tag0_hit_m_w: data_wide_r = data0_data_out_m_w; 984 | tag1_hit_m_w: data_wide_r = data1_data_out_m_w; 985 | endcase 986 | 987 | case (data_sel_q) 988 | 3'd0: data_r = data_wide_r[31:0]; 989 | 3'd1: data_r = data_wide_r[63:32]; 990 | 3'd2: data_r = data_wide_r[95:64]; 991 | 3'd3: data_r = data_wide_r[127:96]; 992 | 3'd4: data_r = data_wide_r[159:128]; 993 | 3'd5: data_r = data_wide_r[191:160]; 994 | 3'd6: data_r = data_wide_r[223:192]; 995 | 3'd7: data_r = data_wide_r[255:224]; 996 | endcase 997 | end 998 | 999 | assign inport_data_rd_o = data_r; 1000 | 1001 | //----------------------------------------------------------------- 1002 | // Next State Logic 1003 | //----------------------------------------------------------------- 1004 | always @ * 1005 | begin 1006 | next_state_r = state_q; 1007 | 1008 | case (state_q) 1009 | //----------------------------------------- 1010 | // STATE_RESET 1011 | //----------------------------------------- 1012 | STATE_RESET : 1013 | begin 1014 | // Final line checked 1015 | if (flush_last_q) 1016 | next_state_r = STATE_LOOKUP; 1017 | end 1018 | //----------------------------------------- 1019 | // STATE_FLUSH_ADDR 1020 | //----------------------------------------- 1021 | STATE_FLUSH_ADDR : next_state_r = STATE_FLUSH; 1022 | //----------------------------------------- 1023 | // STATE_FLUSH 1024 | //----------------------------------------- 1025 | STATE_FLUSH : 1026 | begin 1027 | // Dirty line detected - evict unless initial cache reset cycle 1028 | if (tag_dirty_any_m_w) 1029 | begin 1030 | // Evict dirty line - else wait for dirty way to be selected 1031 | if (evict_way_w) 1032 | next_state_r = STATE_EVICT; 1033 | end 1034 | // Final line checked, nothing dirty 1035 | else if (flush_last_q) 1036 | next_state_r = STATE_LOOKUP; 1037 | else 1038 | next_state_r = STATE_FLUSH_ADDR; 1039 | end 1040 | //----------------------------------------- 1041 | // STATE_LOOKUP 1042 | //----------------------------------------- 1043 | STATE_LOOKUP : 1044 | begin 1045 | // Previous access missed in the cache 1046 | if ((inport_rd_m_q || (inport_wr_m_q != 4'b0)) && !tag_hit_any_m_w) 1047 | begin 1048 | // Evict dirty line first 1049 | if (evict_way_w) 1050 | next_state_r = STATE_EVICT; 1051 | // Allocate line and fill 1052 | else 1053 | next_state_r = STATE_REFILL; 1054 | end 1055 | // Flush whole cache 1056 | else if (flush_i) 1057 | next_state_r = STATE_FLUSH_ADDR; 1058 | end 1059 | //----------------------------------------- 1060 | // STATE_REFILL 1061 | //----------------------------------------- 1062 | STATE_REFILL : 1063 | begin 1064 | // End of refill 1065 | if (pmem_ack_w) 1066 | begin 1067 | // Refill reason was write 1068 | if (inport_wr_m_q != 4'b0) 1069 | next_state_r = STATE_WRITE; 1070 | // Refill reason was read 1071 | else 1072 | next_state_r = STATE_READ; 1073 | end 1074 | end 1075 | //----------------------------------------- 1076 | // STATE_WRITE/READ 1077 | //----------------------------------------- 1078 | STATE_WRITE, STATE_READ : 1079 | begin 1080 | next_state_r = STATE_LOOKUP; 1081 | end 1082 | //----------------------------------------- 1083 | // STATE_EVICT 1084 | //----------------------------------------- 1085 | STATE_EVICT : 1086 | begin 1087 | // End of evict, wait for write completion 1088 | if (pmem_accept_w) 1089 | next_state_r = STATE_EVICT_WAIT; 1090 | end 1091 | //----------------------------------------- 1092 | // STATE_EVICT_WAIT 1093 | //----------------------------------------- 1094 | STATE_EVICT_WAIT : 1095 | begin 1096 | // Evict due to flush 1097 | if (pmem_ack_w && flushing_q) 1098 | next_state_r = STATE_FLUSH_ADDR; 1099 | // Write ack, start re-fill now 1100 | else if (pmem_ack_w) 1101 | next_state_r = STATE_REFILL; 1102 | end 1103 | default: 1104 | ; 1105 | endcase 1106 | end 1107 | 1108 | // Update state 1109 | always @ (posedge clk_i ) 1110 | if (rst_i) 1111 | state_q <= STATE_RESET; 1112 | else 1113 | state_q <= next_state_r; 1114 | 1115 | reg inport_ack_r; 1116 | 1117 | always @ * 1118 | begin 1119 | inport_ack_r = 1'b0; 1120 | 1121 | if (state_q == STATE_LOOKUP) 1122 | begin 1123 | // Normal hit - read or write 1124 | if ((inport_rd_m_q || (inport_wr_m_q != 4'b0)) && tag_hit_any_m_w) 1125 | inport_ack_r = 1'b1; 1126 | end 1127 | end 1128 | 1129 | assign inport_ack_o = inport_ack_r; 1130 | 1131 | //----------------------------------------------------------------- 1132 | // Bus Request 1133 | //----------------------------------------------------------------- 1134 | reg pmem_rd_q; 1135 | reg pmem_wr0_q; 1136 | 1137 | always @ (posedge clk_i ) 1138 | if (rst_i) 1139 | pmem_rd_q <= 1'b0; 1140 | else if (pmem_rd_w) 1141 | pmem_rd_q <= ~pmem_accept_w; 1142 | 1143 | always @ (posedge clk_i ) 1144 | if (rst_i) 1145 | pmem_wr0_q <= 1'b0; 1146 | else if (state_q != STATE_EVICT && next_state_r == STATE_EVICT) 1147 | pmem_wr0_q <= 1'b1; 1148 | else if (pmem_accept_w) 1149 | pmem_wr0_q <= 1'b0; 1150 | 1151 | //----------------------------------------------------------------- 1152 | // Skid buffer for write data 1153 | //----------------------------------------------------------------- 1154 | reg pmem_wr_q; 1155 | reg [255:0] pmem_write_data_q; 1156 | 1157 | always @ (posedge clk_i ) 1158 | if (rst_i) 1159 | pmem_wr_q <= 1'b0; 1160 | else if (pmem_wr_w && !pmem_accept_w) 1161 | pmem_wr_q <= pmem_wr_w; 1162 | else if (pmem_accept_w) 1163 | pmem_wr_q <= 1'b0; 1164 | 1165 | always @ (posedge clk_i ) 1166 | if (rst_i) 1167 | pmem_write_data_q <= 256'b0; 1168 | else if (!pmem_accept_w) 1169 | pmem_write_data_q <= pmem_write_data_w; 1170 | 1171 | //----------------------------------------------------------------- 1172 | // AXI Error Handling 1173 | //----------------------------------------------------------------- 1174 | reg error_q; 1175 | always @ (posedge clk_i ) 1176 | if (rst_i) 1177 | error_q <= 1'b0; 1178 | else if (pmem_ack_w && pmem_error_w) 1179 | error_q <= 1'b1; 1180 | else if (inport_ack_o) 1181 | error_q <= 1'b0; 1182 | 1183 | assign inport_error_o = error_q; 1184 | 1185 | //----------------------------------------------------------------- 1186 | // Outport 1187 | //----------------------------------------------------------------- 1188 | wire refill_request_w = (state_q != STATE_REFILL && next_state_r == STATE_REFILL); 1189 | wire evict_request_w = (state_q == STATE_EVICT) && evict_way_w; 1190 | 1191 | // AXI Read channel 1192 | assign pmem_rd_w = (refill_request_w || pmem_rd_q); 1193 | assign pmem_wr_w = (evict_request_w || pmem_wr_q) ? 1'b1 : 1'b0; 1194 | assign pmem_addr_w = pmem_rd_w ? {inport_addr_m_q[31:L2_CACHE_LINE_SIZE_W], {(L2_CACHE_LINE_SIZE_W){1'b0}}} : 1195 | {evict_addr_w, {(L2_CACHE_LINE_SIZE_W){1'b0}}}; 1196 | 1197 | assign pmem_len_w = (refill_request_w || pmem_rd_q || (state_q == STATE_EVICT && pmem_wr0_q)) ? 8'd7 : 8'd0; 1198 | assign pmem_write_data_w = pmem_wr_q ? pmem_write_data_q : evict_data_w; 1199 | 1200 | assign outport_wr_o = pmem_wr_w; 1201 | assign outport_rd_o = pmem_rd_w; 1202 | assign outport_addr_o = pmem_addr_w; 1203 | assign outport_write_data_o = pmem_write_data_w; 1204 | 1205 | assign pmem_accept_w = outport_accept_i; 1206 | assign pmem_ack_w = outport_ack_i; 1207 | assign pmem_error_w = outport_error_i; 1208 | assign pmem_read_data_w = outport_read_data_i; 1209 | 1210 | //------------------------------------------------------------------- 1211 | // Debug 1212 | //------------------------------------------------------------------- 1213 | `ifdef verilator 1214 | /* verilator lint_off WIDTH */ 1215 | reg [79:0] dbg_state; 1216 | always @ * 1217 | begin 1218 | dbg_state = "-"; 1219 | 1220 | case (state_q) 1221 | STATE_RESET: 1222 | dbg_state = "RESET"; 1223 | STATE_FLUSH_ADDR: 1224 | dbg_state = "FLUSH_ADDR"; 1225 | STATE_FLUSH: 1226 | dbg_state = "FLUSH"; 1227 | STATE_LOOKUP: 1228 | dbg_state = "LOOKUP"; 1229 | STATE_READ: 1230 | dbg_state = "READ"; 1231 | STATE_WRITE: 1232 | dbg_state = "WRITE"; 1233 | STATE_REFILL: 1234 | dbg_state = "REFILL"; 1235 | STATE_EVICT: 1236 | dbg_state = "EVICT"; 1237 | STATE_EVICT_WAIT: 1238 | dbg_state = "EVICT_WAIT"; 1239 | default: 1240 | ; 1241 | endcase 1242 | end 1243 | /* verilator lint_on WIDTH */ 1244 | 1245 | 1246 | reg [31:0] stats_read_q; 1247 | reg [31:0] stats_write_q; 1248 | reg [31:0] stats_hit_q; 1249 | reg [31:0] stats_miss_q; 1250 | reg [31:0] stats_evict_q; 1251 | reg [31:0] stats_stalls_q; 1252 | 1253 | always @ (posedge clk_i ) 1254 | if (rst_i) 1255 | stats_read_q <= 32'b0; 1256 | else if (inport_rd_i && inport_accept_o) 1257 | stats_read_q <= stats_read_q + 32'd1; 1258 | 1259 | always @ (posedge clk_i ) 1260 | if (rst_i) 1261 | stats_write_q <= 32'b0; 1262 | else if ((|inport_wr_i) && inport_accept_o) 1263 | stats_write_q <= stats_write_q + 32'd1; 1264 | 1265 | // Note: A miss will also count as a hit when the refill occurs 1266 | always @ (posedge clk_i ) 1267 | if (rst_i) 1268 | stats_hit_q <= 32'b0; 1269 | else if (state_q == STATE_LOOKUP && (inport_rd_m_q || (inport_wr_m_q != 4'b0)) && tag_hit_any_m_w) 1270 | stats_hit_q <= stats_hit_q + 32'd1; 1271 | 1272 | always @ (posedge clk_i ) 1273 | if (rst_i) 1274 | stats_miss_q <= 32'b0; 1275 | else if ((outport_rd_o || (|outport_wr_o)) && outport_accept_i) 1276 | stats_miss_q <= stats_miss_q + 32'd1; 1277 | 1278 | always @ (posedge clk_i ) 1279 | if (rst_i) 1280 | stats_evict_q <= 32'b0; 1281 | else if (state_q == STATE_EVICT && next_state_r == STATE_EVICT_WAIT) 1282 | stats_evict_q <= stats_evict_q + 32'd1; 1283 | 1284 | always @ (posedge clk_i ) 1285 | if (rst_i) 1286 | stats_stalls_q <= 32'b0; 1287 | else if (state_q != STATE_LOOKUP) 1288 | stats_stalls_q <= stats_stalls_q + 32'd1; 1289 | 1290 | `endif 1291 | 1292 | 1293 | endmodule -------------------------------------------------------------------------------- /src_v/l2_cache_data_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_data_ram 32 | ( 33 | // Inputs 34 | input clk0_i 35 | ,input rst0_i 36 | ,input [ 10:0] addr0_i 37 | ,input [ 31:0] data0_i 38 | ,input [ 3:0] wr0_i 39 | ,input clk1_i 40 | ,input rst1_i 41 | ,input [ 10:0] addr1_i 42 | ,input [ 31:0] data1_i 43 | ,input [ 3:0] wr1_i 44 | 45 | // Outputs 46 | ,output [ 31:0] data0_o 47 | ,output [ 31:0] data1_o 48 | ); 49 | 50 | 51 | 52 | //----------------------------------------------------------------- 53 | // Dual Port RAM 8KB 54 | // Mode: Read First 55 | //----------------------------------------------------------------- 56 | /* verilator lint_off MULTIDRIVEN */ 57 | reg [31:0] ram [2047:0] /*verilator public*/; 58 | /* verilator lint_on MULTIDRIVEN */ 59 | 60 | 61 | reg [31:0] ram_read0_q; 62 | reg [31:0] ram_read1_q; 63 | 64 | 65 | // Synchronous write 66 | always @ (posedge clk0_i) 67 | begin 68 | if (wr0_i[0]) 69 | ram[addr0_i][7:0] <= data0_i[7:0]; 70 | if (wr0_i[1]) 71 | ram[addr0_i][15:8] <= data0_i[15:8]; 72 | if (wr0_i[2]) 73 | ram[addr0_i][23:16] <= data0_i[23:16]; 74 | if (wr0_i[3]) 75 | ram[addr0_i][31:24] <= data0_i[31:24]; 76 | 77 | ram_read0_q <= ram[addr0_i]; 78 | end 79 | 80 | always @ (posedge clk1_i) 81 | begin 82 | if (wr1_i[0]) 83 | ram[addr1_i][7:0] <= data1_i[7:0]; 84 | if (wr1_i[1]) 85 | ram[addr1_i][15:8] <= data1_i[15:8]; 86 | if (wr1_i[2]) 87 | ram[addr1_i][23:16] <= data1_i[23:16]; 88 | if (wr1_i[3]) 89 | ram[addr1_i][31:24] <= data1_i[31:24]; 90 | 91 | ram_read1_q <= ram[addr1_i]; 92 | end 93 | 94 | 95 | assign data0_o = ram_read0_q; 96 | assign data1_o = ram_read1_q; 97 | 98 | 99 | 100 | endmodule 101 | -------------------------------------------------------------------------------- /src_v/l2_cache_inport.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_inport 32 | ( 33 | // Inputs 34 | input clk_i 35 | ,input rst_i 36 | ,input axi_awvalid_i 37 | ,input [ 31:0] axi_awaddr_i 38 | ,input [ 3:0] axi_awid_i 39 | ,input [ 7:0] axi_awlen_i 40 | ,input [ 1:0] axi_awburst_i 41 | ,input axi_wvalid_i 42 | ,input [ 31:0] axi_wdata_i 43 | ,input [ 3:0] axi_wstrb_i 44 | ,input axi_wlast_i 45 | ,input axi_bready_i 46 | ,input axi_arvalid_i 47 | ,input [ 31:0] axi_araddr_i 48 | ,input [ 3:0] axi_arid_i 49 | ,input [ 7:0] axi_arlen_i 50 | ,input [ 1:0] axi_arburst_i 51 | ,input axi_rready_i 52 | ,input outport_accept_i 53 | ,input outport_ack_i 54 | ,input outport_error_i 55 | ,input [ 31:0] outport_read_data_i 56 | 57 | // Outputs 58 | ,output axi_awready_o 59 | ,output axi_wready_o 60 | ,output axi_bvalid_o 61 | ,output [ 1:0] axi_bresp_o 62 | ,output [ 3:0] axi_bid_o 63 | ,output axi_arready_o 64 | ,output axi_rvalid_o 65 | ,output [ 31:0] axi_rdata_o 66 | ,output [ 1:0] axi_rresp_o 67 | ,output [ 3:0] axi_rid_o 68 | ,output axi_rlast_o 69 | ,output [ 3:0] outport_wr_o 70 | ,output outport_rd_o 71 | ,output [ 31:0] outport_addr_o 72 | ,output [ 31:0] outport_write_data_o 73 | ); 74 | 75 | localparam RETIME_RESP = 0; 76 | 77 | wire output_busy_w; 78 | 79 | // Write 80 | wire wr_valid_w; 81 | wire wr_accept_w; 82 | wire [ 31:0] wr_addr_w; 83 | wire [3:0] wr_id_w; 84 | wire [31:0] wr_data_w; 85 | wire [3:0] wr_strb_w; 86 | wire wr_last_w; 87 | 88 | // Read 89 | wire rd_valid_w; 90 | wire rd_accept_w; 91 | wire [ 31:0] rd_addr_w; 92 | wire [3:0] rd_id_w; 93 | wire rd_last_w; 94 | 95 | l2_cache_axi_input 96 | #( 97 | .DATA_W(32) 98 | ,.STRB_W(4) 99 | ,.ID_W(4) 100 | ,.RW_ARB(1) 101 | ) 102 | u_input 103 | ( 104 | .clk_i(clk_i) 105 | ,.rst_i(rst_i) 106 | 107 | // AXI 108 | ,.axi_awvalid_i(axi_awvalid_i) 109 | ,.axi_awaddr_i(axi_awaddr_i) 110 | ,.axi_awid_i(axi_awid_i) 111 | ,.axi_awlen_i(axi_awlen_i) 112 | ,.axi_awburst_i(axi_awburst_i) 113 | ,.axi_wvalid_i(axi_wvalid_i) 114 | ,.axi_wdata_i(axi_wdata_i) 115 | ,.axi_wstrb_i(axi_wstrb_i) 116 | ,.axi_wlast_i(axi_wlast_i) 117 | ,.axi_arvalid_i(axi_arvalid_i) 118 | ,.axi_araddr_i(axi_araddr_i) 119 | ,.axi_arid_i(axi_arid_i) 120 | ,.axi_arlen_i(axi_arlen_i) 121 | ,.axi_arburst_i(axi_arburst_i) 122 | ,.axi_awready_o(axi_awready_o) 123 | ,.axi_wready_o(axi_wready_o) 124 | ,.axi_arready_o(axi_arready_o) 125 | 126 | // Write 127 | ,.wr_valid_o(wr_valid_w) 128 | ,.wr_accept_i(wr_accept_w) 129 | ,.wr_addr_o(wr_addr_w) 130 | ,.wr_id_o(wr_id_w) 131 | ,.wr_data_o(wr_data_w) 132 | ,.wr_strb_o(wr_strb_w) 133 | ,.wr_last_o(wr_last_w) 134 | 135 | // Read 136 | ,.rd_valid_o(rd_valid_w) 137 | ,.rd_accept_i(rd_accept_w) 138 | ,.rd_addr_o(rd_addr_w) 139 | ,.rd_id_o(rd_id_w) 140 | ,.rd_last_o(rd_last_w) 141 | ); 142 | 143 | //----------------------------------------------------------------- 144 | // Request 145 | //----------------------------------------------------------------- 146 | wire req_fifo_accept_w; 147 | 148 | wire wr_enable_w = wr_valid_w & req_fifo_accept_w & ~output_busy_w; 149 | wire rd_enable_w = rd_valid_w & req_fifo_accept_w & ~output_busy_w; 150 | 151 | assign outport_addr_o = wr_enable_w ? wr_addr_w : rd_addr_w; 152 | assign outport_write_data_o = wr_data_w; 153 | assign outport_rd_o = rd_enable_w; 154 | assign outport_wr_o = wr_enable_w ? wr_strb_w : 4'b0; 155 | 156 | assign rd_accept_w = rd_enable_w & outport_accept_i & req_fifo_accept_w & ~output_busy_w; 157 | assign wr_accept_w = wr_enable_w & outport_accept_i & req_fifo_accept_w & ~output_busy_w; 158 | 159 | //----------------------------------------------------------------- 160 | // Request tracking 161 | //----------------------------------------------------------------- 162 | wire req_push_w = (outport_rd_o || (outport_wr_o != 4'b0)) && outport_accept_i; 163 | reg [5:0] req_in_r; 164 | 165 | wire req_out_valid_w; 166 | wire [5:0] req_out_w; 167 | wire resp_accept_w; 168 | 169 | always @ * 170 | begin 171 | req_in_r = 6'b0; 172 | 173 | // Read 174 | if (outport_rd_o) 175 | req_in_r = {1'b1, rd_last_w, rd_id_w}; 176 | // Write 177 | else 178 | req_in_r = {1'b0, wr_last_w, wr_id_w}; 179 | end 180 | 181 | l2_cache_inport_fifo2 182 | #( .WIDTH(1 + 1 + 4) ) 183 | u_requests 184 | ( 185 | .clk_i(clk_i), 186 | .rst_i(rst_i), 187 | 188 | // Input 189 | .data_in_i(req_in_r), 190 | .push_i(req_push_w), 191 | .accept_o(req_fifo_accept_w), 192 | 193 | // Output 194 | .pop_i(resp_accept_w), 195 | .data_out_o(req_out_w), 196 | .valid_o(req_out_valid_w) 197 | ); 198 | 199 | wire resp_is_write_w = req_out_valid_w ? ~req_out_w[5] : 1'b0; 200 | wire resp_is_read_w = req_out_valid_w ? req_out_w[5] : 1'b0; 201 | wire resp_is_last_w = req_out_w[4]; 202 | wire [3:0] resp_id_w = req_out_w[3:0]; 203 | 204 | //----------------------------------------------------------------- 205 | // Retimed respone (latency = 1) 206 | //----------------------------------------------------------------- 207 | generate 208 | if (RETIME_RESP) 209 | begin 210 | assign output_busy_w = 1'b0; 211 | 212 | //------------------------------------------------------------- 213 | // Response buffering 214 | //------------------------------------------------------------- 215 | wire resp_valid_w; 216 | 217 | l2_cache_inport_fifo2 218 | #( .WIDTH(32) ) 219 | u_response 220 | ( 221 | .clk_i(clk_i), 222 | .rst_i(rst_i), 223 | 224 | // Input 225 | .data_in_i(outport_read_data_i), 226 | .push_i(outport_ack_i), 227 | .accept_o(), 228 | 229 | // Output 230 | .pop_i(resp_accept_w), 231 | .data_out_o(axi_rdata_o), 232 | .valid_o(resp_valid_w) 233 | ); 234 | 235 | //------------------------------------------------------------- 236 | // Response 237 | //------------------------------------------------------------- 238 | assign axi_bvalid_o = resp_valid_w & resp_is_write_w & resp_is_last_w; 239 | assign axi_bresp_o = 2'b0; 240 | assign axi_bid_o = resp_id_w; 241 | 242 | assign axi_rvalid_o = resp_valid_w & resp_is_read_w; 243 | assign axi_rresp_o = 2'b0; 244 | assign axi_rid_o = resp_id_w; 245 | assign axi_rlast_o = resp_is_last_w; 246 | 247 | assign resp_accept_w = (axi_rvalid_o & axi_rready_i) | 248 | (axi_bvalid_o & axi_bready_i) | 249 | (resp_valid_w & resp_is_write_w & !resp_is_last_w); // Ignore write resps mid burst 250 | end 251 | //----------------------------------------------------------------- 252 | // Direct response (latency = 0) 253 | //----------------------------------------------------------------- 254 | else 255 | begin 256 | reg bvalid_q; 257 | reg rvalid_q; 258 | 259 | always @ (posedge clk_i ) 260 | if (rst_i) 261 | bvalid_q <= 1'b0; 262 | else if (axi_bvalid_o && ~axi_bready_i) 263 | bvalid_q <= 1'b1; 264 | else if (axi_bready_i) 265 | bvalid_q <= 1'b0; 266 | 267 | always @ (posedge clk_i ) 268 | if (rst_i) 269 | rvalid_q <= 1'b0; 270 | else if (axi_rvalid_o && ~axi_rready_i) 271 | rvalid_q <= 1'b1; 272 | else if (axi_rready_i) 273 | rvalid_q <= 1'b0; 274 | 275 | assign axi_bvalid_o = bvalid_q | (resp_is_write_w & resp_is_last_w & outport_ack_i); 276 | assign axi_bid_o = resp_id_w; 277 | assign axi_bresp_o = 2'b0; 278 | 279 | assign axi_rvalid_o = rvalid_q | (resp_is_read_w & outport_ack_i); 280 | assign axi_rid_o = resp_id_w; 281 | assign axi_rresp_o = 2'b0; 282 | 283 | assign output_busy_w = (axi_bvalid_o & ~axi_bready_i) | (axi_rvalid_o & ~axi_rready_i); 284 | 285 | //------------------------------------------------------------- 286 | // Read resp skid 287 | //------------------------------------------------------------- 288 | reg rbuf_valid_q; 289 | reg [31:0] rbuf_data_q; 290 | reg rbuf_last_q; 291 | 292 | always @ (posedge clk_i ) 293 | if (rst_i) 294 | begin 295 | rbuf_valid_q <= 1'b0; 296 | rbuf_data_q <= 32'b0; 297 | end 298 | // Response skid buffer 299 | else if (axi_rvalid_o && !axi_rready_i) 300 | begin 301 | rbuf_valid_q <= 1'b1; 302 | rbuf_data_q <= axi_rdata_o; 303 | end 304 | else 305 | rbuf_valid_q <= 1'b0; 306 | 307 | assign axi_rdata_o = rbuf_valid_q ? rbuf_data_q : outport_read_data_i; 308 | assign axi_rlast_o = resp_is_last_w; 309 | 310 | assign resp_accept_w = (axi_rvalid_o & axi_rready_i) | 311 | (axi_bvalid_o & axi_bready_i) | 312 | (outport_ack_i & resp_is_write_w & !resp_is_last_w); // Ignore write resps mid burst 313 | end 314 | endgenerate 315 | 316 | //------------------------------------------------------------------- 317 | // Stats 318 | //------------------------------------------------------------------- 319 | `ifdef verilator 320 | reg [31:0] stats_rd_singles_q; 321 | reg [31:0] stats_wr_singles_q; 322 | 323 | always @ (posedge clk_i ) 324 | if (rst_i) 325 | stats_rd_singles_q <= 32'b0; 326 | else if (axi_arvalid_i && axi_arready_o && axi_arlen_i == 8'b0) 327 | stats_rd_singles_q <= stats_rd_singles_q + 32'd1; 328 | 329 | always @ (posedge clk_i ) 330 | if (rst_i) 331 | stats_wr_singles_q <= 32'b0; 332 | else if (axi_awvalid_i && axi_awready_o && axi_awlen_i == 8'b0) 333 | stats_wr_singles_q <= stats_wr_singles_q + 32'd1; 334 | 335 | `endif 336 | 337 | endmodule 338 | 339 | //----------------------------------------------------------------- 340 | // FIFO 341 | //----------------------------------------------------------------- 342 | module l2_cache_inport_fifo2 343 | 344 | //----------------------------------------------------------------- 345 | // Params 346 | //----------------------------------------------------------------- 347 | #( 348 | parameter WIDTH = 8, 349 | parameter DEPTH = 4, 350 | parameter ADDR_W = 2 351 | ) 352 | //----------------------------------------------------------------- 353 | // Ports 354 | //----------------------------------------------------------------- 355 | ( 356 | // Inputs 357 | input clk_i 358 | ,input rst_i 359 | ,input [WIDTH-1:0] data_in_i 360 | ,input push_i 361 | ,input pop_i 362 | 363 | // Outputs 364 | ,output [WIDTH-1:0] data_out_o 365 | ,output accept_o 366 | ,output valid_o 367 | ); 368 | 369 | //----------------------------------------------------------------- 370 | // Local Params 371 | //----------------------------------------------------------------- 372 | localparam COUNT_W = ADDR_W + 1; 373 | 374 | //----------------------------------------------------------------- 375 | // Registers 376 | //----------------------------------------------------------------- 377 | reg [WIDTH-1:0] ram [DEPTH-1:0]; 378 | reg [ADDR_W-1:0] rd_ptr; 379 | reg [ADDR_W-1:0] wr_ptr; 380 | reg [COUNT_W-1:0] count; 381 | 382 | //----------------------------------------------------------------- 383 | // Sequential 384 | //----------------------------------------------------------------- 385 | always @ (posedge clk_i ) 386 | if (rst_i) 387 | begin 388 | count <= {(COUNT_W) {1'b0}}; 389 | rd_ptr <= {(ADDR_W) {1'b0}}; 390 | wr_ptr <= {(ADDR_W) {1'b0}}; 391 | end 392 | else 393 | begin 394 | // Push 395 | if (push_i & accept_o) 396 | begin 397 | ram[wr_ptr] <= data_in_i; 398 | wr_ptr <= wr_ptr + 1; 399 | end 400 | 401 | // Pop 402 | if (pop_i & valid_o) 403 | rd_ptr <= rd_ptr + 1; 404 | 405 | // Count up 406 | if ((push_i & accept_o) & ~(pop_i & valid_o)) 407 | count <= count + 1; 408 | // Count down 409 | else if (~(push_i & accept_o) & (pop_i & valid_o)) 410 | count <= count - 1; 411 | end 412 | 413 | //------------------------------------------------------------------- 414 | // Combinatorial 415 | //------------------------------------------------------------------- 416 | /* verilator lint_off WIDTH */ 417 | assign accept_o = (count != DEPTH); 418 | assign valid_o = (count != 0); 419 | /* verilator lint_on WIDTH */ 420 | 421 | assign data_out_o = ram[rd_ptr]; 422 | 423 | 424 | 425 | endmodule 426 | -------------------------------------------------------------------------------- /src_v/l2_cache_outport.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_outport 32 | //----------------------------------------------------------------- 33 | // Params 34 | //----------------------------------------------------------------- 35 | #( 36 | parameter AXI_ID = 0 37 | ) 38 | //----------------------------------------------------------------- 39 | // Ports 40 | //----------------------------------------------------------------- 41 | ( 42 | // Inputs 43 | input clk_i 44 | ,input rst_i 45 | 46 | ,output inport_accept_o 47 | ,output inport_ack_o 48 | ,output inport_error_o 49 | ,output [255:0] inport_read_data_o 50 | ,input inport_wr_i 51 | ,input inport_rd_i 52 | ,input [ 31:0] inport_addr_i 53 | ,input [255:0] inport_write_data_i 54 | 55 | ,input outport_awready_i 56 | ,input outport_wready_i 57 | ,input outport_bvalid_i 58 | ,input [ 1:0] outport_bresp_i 59 | ,input [ 3:0] outport_bid_i 60 | ,input outport_arready_i 61 | ,input outport_rvalid_i 62 | ,input [255:0] outport_rdata_i 63 | ,input [ 1:0] outport_rresp_i 64 | ,input [ 3:0] outport_rid_i 65 | ,input outport_rlast_i 66 | 67 | // Outputs 68 | ,output outport_awvalid_o 69 | ,output [ 31:0] outport_awaddr_o 70 | ,output [ 3:0] outport_awid_o 71 | ,output [ 7:0] outport_awlen_o 72 | ,output [ 1:0] outport_awburst_o 73 | ,output outport_wvalid_o 74 | ,output [255:0] outport_wdata_o 75 | ,output [ 31:0] outport_wstrb_o 76 | ,output outport_wlast_o 77 | ,output outport_bready_o 78 | ,output outport_arvalid_o 79 | ,output [ 31:0] outport_araddr_o 80 | ,output [ 3:0] outport_arid_o 81 | ,output [ 7:0] outport_arlen_o 82 | ,output [ 1:0] outport_arburst_o 83 | ,output outport_rready_o 84 | ); 85 | 86 | //----------------------------------------------------------------- 87 | // Request FIFO 88 | //----------------------------------------------------------------- 89 | wire req_valid_w; 90 | wire [31:0] request_addr_w; 91 | wire [255:0] request_data_w; 92 | wire request_rd_w; 93 | wire req_accept_w; 94 | 95 | l2_cache_outport_fifo2 96 | #( 97 | .WIDTH(256+32+1) 98 | ,.DEPTH(2) 99 | ,.ADDR_W(1) 100 | ) 101 | u_req 102 | ( 103 | .clk_i(clk_i) 104 | ,.rst_i(rst_i) 105 | 106 | ,.push_i(inport_wr_i | inport_rd_i) 107 | ,.data_in_i({inport_rd_i, inport_write_data_i, inport_addr_i}) 108 | ,.accept_o(inport_accept_o) 109 | 110 | ,.valid_o(req_valid_w) 111 | ,.data_out_o({request_rd_w, request_data_w, request_addr_w}) 112 | ,.pop_i(req_accept_w) 113 | ); 114 | 115 | //----------------------------------------------------------------- 116 | // Write Request Output 117 | //----------------------------------------------------------------- 118 | reg awvalid_q; 119 | reg wvalid_q; 120 | 121 | wire wr_cmd_accepted_w = (outport_awvalid_o && outport_awready_i) || awvalid_q; 122 | wire wr_data_accepted_w = (outport_wvalid_o && outport_wready_i) || wvalid_q; 123 | 124 | reg write_pending_q; 125 | reg [31:0] write_addr_q; 126 | 127 | always @ (posedge clk_i ) 128 | if (rst_i) 129 | write_addr_q <= 32'b0; 130 | else if (req_valid_w && !request_rd_w && req_accept_w) 131 | write_addr_q <= request_addr_w; 132 | 133 | always @ (posedge clk_i ) 134 | if (rst_i) 135 | write_pending_q <= 1'b0; 136 | else if (req_valid_w && !request_rd_w && req_accept_w) 137 | write_pending_q <= 1'b1; 138 | else if (outport_bvalid_i && outport_bready_o) 139 | write_pending_q <= 1'b0; 140 | 141 | always @ (posedge clk_i ) 142 | if (rst_i) 143 | awvalid_q <= 1'b0; 144 | else if (outport_awvalid_o && outport_awready_i && !wr_data_accepted_w) 145 | awvalid_q <= 1'b1; 146 | else if (wr_data_accepted_w) 147 | awvalid_q <= 1'b0; 148 | 149 | always @ (posedge clk_i ) 150 | if (rst_i) 151 | wvalid_q <= 1'b0; 152 | else if (outport_wvalid_o && outport_wready_i && !wr_cmd_accepted_w) 153 | wvalid_q <= 1'b1; 154 | else if (wr_cmd_accepted_w) 155 | wvalid_q <= 1'b0; 156 | 157 | assign outport_awvalid_o = req_valid_w & ~awvalid_q & ~request_rd_w & ~write_pending_q; 158 | assign outport_awaddr_o = request_addr_w; 159 | assign outport_awid_o = AXI_ID; 160 | assign outport_awlen_o = 8'b0; // 32-bytes 161 | assign outport_awburst_o = 2'b01; // INCR 162 | assign outport_wvalid_o = req_valid_w & ~wvalid_q & ~request_rd_w & ~write_pending_q; 163 | assign outport_wdata_o = request_data_w; 164 | assign outport_wstrb_o = {32{1'b1}}; 165 | assign outport_wlast_o = 1'b1; // Max length of burst = 32-bytes 166 | 167 | //----------------------------------------------------------------- 168 | // Read Request Output 169 | //----------------------------------------------------------------- 170 | // Stop reads from reading uncommitted write data (writes maybe overtaken in the fabric) 171 | wire read_block_w = write_pending_q && (write_addr_q == request_addr_w); 172 | 173 | assign outport_arvalid_o = req_valid_w & request_rd_w & ~read_block_w; 174 | assign outport_araddr_o = request_addr_w; 175 | assign outport_arid_o = AXI_ID; 176 | assign outport_arlen_o = 8'b0; // Max length is 32-bytes 177 | assign outport_arburst_o = 2'b01; // INCR 178 | 179 | //----------------------------------------------------------------- 180 | // Request Pop 181 | //----------------------------------------------------------------- 182 | assign req_accept_w = request_rd_w ? (outport_arready_i & ~read_block_w): 183 | (((outport_awready_i | awvalid_q) & (outport_wready_i | wvalid_q)) & ~write_pending_q); 184 | 185 | //-------------------------------------------------------------------- 186 | // Response 187 | //-------------------------------------------------------------------- 188 | assign outport_rready_o = 1'b1; 189 | assign outport_bready_o = 1'b1; 190 | 191 | // Posted writes 192 | reg early_wr_ack_q; 193 | 194 | always @ (posedge clk_i ) 195 | if (rst_i) 196 | early_wr_ack_q <= 1'b0; 197 | else 198 | early_wr_ack_q <= inport_wr_i & inport_accept_o; 199 | 200 | assign inport_ack_o = outport_rvalid_i | early_wr_ack_q; 201 | assign inport_error_o = outport_rvalid_i ? (|outport_rresp_i) : 1'b0; 202 | assign inport_read_data_o = outport_rdata_i; 203 | 204 | endmodule 205 | 206 | //----------------------------------------------------------------- 207 | // FIFO 208 | //----------------------------------------------------------------- 209 | module l2_cache_outport_fifo2 210 | 211 | //----------------------------------------------------------------- 212 | // Params 213 | //----------------------------------------------------------------- 214 | #( 215 | parameter WIDTH = 8, 216 | parameter DEPTH = 4, 217 | parameter ADDR_W = 2 218 | ) 219 | //----------------------------------------------------------------- 220 | // Ports 221 | //----------------------------------------------------------------- 222 | ( 223 | // Inputs 224 | input clk_i 225 | ,input rst_i 226 | ,input [WIDTH-1:0] data_in_i 227 | ,input push_i 228 | ,input pop_i 229 | 230 | // Outputs 231 | ,output [WIDTH-1:0] data_out_o 232 | ,output accept_o 233 | ,output valid_o 234 | ); 235 | 236 | //----------------------------------------------------------------- 237 | // Local Params 238 | //----------------------------------------------------------------- 239 | localparam COUNT_W = ADDR_W + 1; 240 | 241 | //----------------------------------------------------------------- 242 | // Registers 243 | //----------------------------------------------------------------- 244 | reg [WIDTH-1:0] ram [DEPTH-1:0]; 245 | reg [ADDR_W-1:0] rd_ptr; 246 | reg [ADDR_W-1:0] wr_ptr; 247 | reg [COUNT_W-1:0] count; 248 | 249 | //----------------------------------------------------------------- 250 | // Sequential 251 | //----------------------------------------------------------------- 252 | always @ (posedge clk_i ) 253 | if (rst_i) 254 | begin 255 | count <= {(COUNT_W) {1'b0}}; 256 | rd_ptr <= {(ADDR_W) {1'b0}}; 257 | wr_ptr <= {(ADDR_W) {1'b0}}; 258 | end 259 | else 260 | begin 261 | // Push 262 | if (push_i & accept_o) 263 | begin 264 | ram[wr_ptr] <= data_in_i; 265 | wr_ptr <= wr_ptr + 1; 266 | end 267 | 268 | // Pop 269 | if (pop_i & valid_o) 270 | rd_ptr <= rd_ptr + 1; 271 | 272 | // Count up 273 | if ((push_i & accept_o) & ~(pop_i & valid_o)) 274 | count <= count + 1; 275 | // Count down 276 | else if (~(push_i & accept_o) & (pop_i & valid_o)) 277 | count <= count - 1; 278 | end 279 | 280 | //------------------------------------------------------------------- 281 | // Combinatorial 282 | //------------------------------------------------------------------- 283 | /* verilator lint_off WIDTH */ 284 | assign accept_o = (count != DEPTH); 285 | assign valid_o = (count != 0); 286 | /* verilator lint_on WIDTH */ 287 | 288 | assign data_out_o = ram[rd_ptr]; 289 | 290 | 291 | 292 | endmodule 293 | 294 | -------------------------------------------------------------------------------- /src_v/l2_cache_tag_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Copyright (c) 2021, admin@ultra-embedded.com 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // - Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // - Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // - Neither the name of the author nor the names of its contributors 15 | // may be used to endorse or promote products derived from this 16 | // software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 | // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | // SUCH DAMAGE. 30 | //----------------------------------------------------------------- 31 | module l2_cache_tag_ram 32 | ( 33 | // Inputs 34 | input clk0_i 35 | ,input rst0_i 36 | ,input [ 10:0] addr0_i 37 | ,input clk1_i 38 | ,input rst1_i 39 | ,input [ 10:0] addr1_i 40 | ,input [ 17:0] data1_i 41 | ,input wr1_i 42 | 43 | // Outputs 44 | ,output [ 17:0] data0_o 45 | ); 46 | 47 | 48 | 49 | //----------------------------------------------------------------- 50 | // Tag RAM 4KB (2048 x 18) 51 | // Mode: Write First 52 | //----------------------------------------------------------------- 53 | /* verilator lint_off MULTIDRIVEN */ 54 | reg [17:0] ram [2047:0] /*verilator public*/; 55 | /* verilator lint_on MULTIDRIVEN */ 56 | 57 | reg [17:0] ram_read0_q; 58 | 59 | always @ (posedge clk1_i) 60 | begin 61 | if (wr1_i) 62 | ram[addr1_i] <= data1_i; 63 | 64 | ram_read0_q <= ram[addr0_i]; 65 | end 66 | 67 | 68 | reg data0_wr_q; 69 | always @ (posedge clk1_i ) 70 | if (rst1_i) 71 | data0_wr_q <= 1'b0; 72 | else 73 | data0_wr_q <= (|wr1_i) && (addr1_i == addr0_i); 74 | 75 | reg [17:0] data0_bypass_q; 76 | always @ (posedge clk1_i) 77 | data0_bypass_q <= data1_i; 78 | 79 | assign data0_o = data0_wr_q ? data0_bypass_q : ram_read0_q; 80 | 81 | 82 | 83 | endmodule 84 | --------------------------------------------------------------------------------