├── doc ├── .DS_Store ├── PTW_fsm.png ├── ptw │ ├── PTW Spec.pdf │ ├── ptw-FSM.drawio.png │ ├── ptw-Página-3.drawio.png │ └── ptw-PTW Diagram.drawio-4.png ├── tlb │ └── TLB_Spec.pdf └── block_diagram.png ├── CONTRIBUTORS.md ├── filelist.f ├── README.md ├── .gitlab └── issue_templates │ └── issue_template.md ├── rtl ├── bsc_mmu.sv ├── ptw │ ├── ptw_arb.sv │ └── ptw.sv ├── dcache_adapters │ └── bsc_mmu_hpdc_adapter.sv ├── common │ └── pseudoLRU.sv ├── tlb │ ├── tlb_wrapper.sv │ └── tlb.sv └── mmu_top.sv ├── LICENSE └── includes └── mmu_pkg.sv /doc/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/.DS_Store -------------------------------------------------------------------------------- /doc/PTW_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/PTW_fsm.png -------------------------------------------------------------------------------- /doc/ptw/PTW Spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/ptw/PTW Spec.pdf -------------------------------------------------------------------------------- /doc/tlb/TLB_Spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/tlb/TLB_Spec.pdf -------------------------------------------------------------------------------- /doc/block_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/block_diagram.png -------------------------------------------------------------------------------- /doc/ptw/ptw-FSM.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/ptw/ptw-FSM.drawio.png -------------------------------------------------------------------------------- /doc/ptw/ptw-Página-3.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/ptw/ptw-Página-3.drawio.png -------------------------------------------------------------------------------- /doc/ptw/ptw-PTW Diagram.drawio-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-loca/mmu/HEAD/doc/ptw/ptw-PTW Diagram.drawio-4.png -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | - Arnau Bigas Soldevilla (arnau.bigas@bsc.es) 2 | - Javier Salamero (javier.salamero@bsc.es) 3 | - Xavier Carril (xavier.carril@bsc.es) -------------------------------------------------------------------------------- /filelist.f: -------------------------------------------------------------------------------- 1 | +incdir+./includes 2 | ./includes/mmu_pkg.sv 3 | ./rtl/common/pseudoLRU.sv 4 | ./rtl/ptw/ptw_arb.sv 5 | ./rtl/ptw/ptw.sv 6 | ./rtl/tlb/tlb.sv 7 | ./rtl/bsc_mmu.sv -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Memory Management Unit (MMU) 2 | 3 | This repository includes a Translation Lookaside Buffer (TLB) and a Page Table Walker, both forming a Memory Management Unit. The modules are designed to be used in a RISC-V processor, following the page-based 39-bit Virtual-Memory System specification (SV39). 4 | 5 |

6 | block 7 |

8 | 9 | #### - TLB characteristics: 10 | - Page-based SV39 mode by default 11 | - Virtual Address (39-bit) to Physical Address (56-bit) translation 12 | - TLB entries are parametrizable (8 by default) in includes/mmu_pkg.sv 13 | - Checks Access Permissions 14 | - Raises Page Fault Exceptions 15 | 16 | #### - PTW characteristics: 17 | - Support for kilo (4KB), mega (2MB) and giga (1GB) page-size 18 | - 3 level tree hierarchy 19 | - Mealy FSM following the steps mentioned in the "Virtual Address Translation Process" chapter (4.3.2) of the [RISC-V privileged specs](https://riscv.org/technical/specifications/): 20 | 21 |

22 | block 23 |

-------------------------------------------------------------------------------- /.gitlab/issue_templates/issue_template.md: -------------------------------------------------------------------------------- 1 | # Issue Report Template 2 | 3 | ### **Description** 4 | - **Summary:** 5 | Describe what the issue is about and the consequences of delaying its resolution. 6 | 7 | ### **Environment** 8 | - **Details:** 9 | Provide a detailed description of all the circumstances present when the issue was found. Include tools used, data, and history, ensuring to be exhaustive. 10 | 11 | ### **Conditions for Reproduction** 12 | - **Steps to Reproduce:** 13 | Explain all the necessary steps to execute and reproduce the issue. If it does not always happen, specify under which circumstances it occurs, or at least the ones with higher probability of happening. 14 | 15 | ### **Hypothesis / Comments** 16 | - **Additional Information:** 17 | Use this field to add any additional information, guesses about the cause, or comments that might help in resolving the issue. This can be edited by anyone involved in the issue. 18 | 19 | ### **As a creator of the issue make sure** 20 | - Add a severity label to the issue 21 | - Set a due date for the issue to be fixed 22 | - Name a verificator (can not be the same as the fixer) here : @xxxx 23 | - Assign the issue to a fixer ( can be yourself as long as you are not the verifier) -------------------------------------------------------------------------------- /rtl/bsc_mmu.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module bsc_mmu 22 | import mmu_pkg::*; 23 | #( 24 | )( 25 | input logic clk_i, 26 | input logic rstn_i, 27 | 28 | // iTLB Interface 29 | input cache_tlb_comm_t icache_itlb_comm_i, 30 | output tlb_cache_comm_t itlb_icache_comm_o, 31 | 32 | // dTLB Interface 33 | input cache_tlb_comm_t core_dtlb_comm_i, 34 | output tlb_cache_comm_t dtlb_core_comm_o, 35 | 36 | // CSR Interface 37 | input csr_ptw_comm_t csr_ptw_comm_i, 38 | 39 | // PTW - Memory Interface 40 | output ptw_dmem_comm_t ptw_dmem_comm_o, 41 | input dmem_ptw_comm_t dmem_ptw_comm_i, 42 | 43 | // PMU Events 44 | output logic itlb_access_o, 45 | output logic itlb_miss_o, 46 | output logic dtlb_access_o, 47 | output logic dtlb_miss_o, 48 | output logic pmu_ptw_hit_o, 49 | output logic pmu_ptw_miss_o 50 | ); 51 | 52 | // Page Table Walker - iTLB/dTLB Connections 53 | tlb_ptw_comm_t itlb_ptw_comm, dtlb_ptw_comm; 54 | ptw_tlb_comm_t ptw_itlb_comm, ptw_dtlb_comm; 55 | 56 | tlb itlb ( 57 | .clk_i(clk_i), 58 | .rstn_i(rstn_i), 59 | .cache_tlb_comm_i(icache_itlb_comm_i), 60 | .tlb_cache_comm_o(itlb_icache_comm_o), 61 | .ptw_tlb_comm_i(ptw_itlb_comm), 62 | .tlb_ptw_comm_o(itlb_ptw_comm), 63 | .pmu_tlb_access_o(itlb_access_o), 64 | .pmu_tlb_miss_o(itlb_miss_o) 65 | ); 66 | 67 | tlb dtlb ( 68 | .clk_i(clk_i), 69 | .rstn_i(rstn_i), 70 | .cache_tlb_comm_i(core_dtlb_comm_i), 71 | .tlb_cache_comm_o(dtlb_core_comm_o), 72 | .ptw_tlb_comm_i(ptw_dtlb_comm), 73 | .tlb_ptw_comm_o(dtlb_ptw_comm), 74 | .pmu_tlb_access_o(dtlb_access_o), 75 | .pmu_tlb_miss_o(dtlb_miss_o ) 76 | ); 77 | 78 | ptw ptw_inst ( 79 | .clk_i(clk_i), 80 | .rstn_i(rstn_i), 81 | 82 | // iTLB request-response 83 | .itlb_ptw_comm_i(itlb_ptw_comm), 84 | .ptw_itlb_comm_o(ptw_itlb_comm), 85 | 86 | // dTLB request-response 87 | .dtlb_ptw_comm_i(dtlb_ptw_comm), 88 | .ptw_dtlb_comm_o(ptw_dtlb_comm), 89 | 90 | // dmem request-response 91 | .dmem_ptw_comm_i(dmem_ptw_comm_i), 92 | .ptw_dmem_comm_o(ptw_dmem_comm_o), 93 | 94 | // csr interface 95 | .csr_ptw_comm_i(csr_ptw_comm_i), 96 | 97 | // pmu interface 98 | .pmu_ptw_hit_o(pmu_ptw_hit_o), 99 | .pmu_ptw_miss_o(pmu_ptw_miss_o) 100 | ); 101 | 102 | endmodule 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Solderpad Hardware License v2.1 2 | 3 | This license operates as a wraparound license to the Apache License 4 | Version 2.0 (the “Apache License”) and incorporates the terms and 5 | conditions of the Apache License (which can be found here: 6 | http://apache.org/licenses/LICENSE-2.0), with the following additions and 7 | modifications. It must be read in conjunction with the Apache License. 8 | Section 1 below modifies definitions and terminology in the Apache 9 | License and Section 2 below replaces Section 2 of the Apache License. 10 | The Appendix replaces the Appendix in the Apache License. You may, at 11 | your option, choose to treat any Work released under this license as 12 | released under the Apache License (thus ignoring all sections written 13 | below entirely). 14 | 15 | 1. Terminology in the Apache License is supplemented or modified as 16 | follows: 17 | 18 | “Authorship”: any reference to ‘authorship’ shall be taken to read 19 | “authorship or design”. 20 | 21 | “Copyright owner”: any reference to ‘copyright owner’ shall be taken to 22 | read “Rights owner”. 23 | 24 | “Copyright statement”: the reference to ‘copyright statement’ shall be 25 | taken to read ‘copyright or other statement pertaining to Rights’. 26 | 27 | The following new definition shall be added to the Definitions section of 28 | the Apache License: 29 | 30 | “Rights” means copyright and any similar right including design right 31 | (whether registered or unregistered), rights in semiconductor 32 | topographies (mask works) and database rights (but excluding Patents and 33 | Trademarks). 34 | 35 | The following definitions shall replace the corresponding definitions in 36 | the Apache License: 37 | 38 | “License” shall mean this Solderpad Hardware License version 2.1, being 39 | the terms and conditions for use, manufacture, instantiation, adaptation, 40 | reproduction, and distribution as defined by Sections 1 through 9 of this 41 | document. 42 | 43 | “Licensor” shall mean the owner of the Rights or entity authorized by the 44 | owner of the Rights that is granting the License. 45 | 46 | “Derivative Works” shall mean any work, whether in Source or Object form, 47 | that is based on (or derived from) the Work and for which the editorial 48 | revisions, annotations, elaborations, or other modifications represent, 49 | as a whole, an original work of authorship or design. For the purposes of 50 | this License, Derivative Works shall not include works that remain 51 | reversibly separable from, or merely link (or bind by name) or physically 52 | connect to or interoperate with the Work and Derivative Works thereof. 53 | 54 | “Object” form shall mean any form resulting from mechanical 55 | transformation or translation of a Source form or the application of a 56 | Source form to physical material, including but not limited to compiled 57 | object code, generated documentation, the instantiation of a hardware 58 | design or physical object or material and conversions to other media 59 | types, including intermediate forms such as bytecodes, FPGA bitstreams, 60 | moulds, artwork and semiconductor topographies (mask works). 61 | 62 | “Source” form shall mean the preferred form for making modifications, 63 | including but not limited to source code, net lists, board layouts, CAD 64 | files, documentation source, and configuration files. 65 | 66 | “Work” shall mean the work of authorship or design, whether in Source or 67 | Object form, made available under the License, as indicated by a notice 68 | relating to Rights that is included in or attached to the work (an 69 | example is provided in the Appendix below). 70 | 71 | 2. Grant of License. Subject to the terms and conditions of this License, 72 | each Contributor hereby grants to You a perpetual, worldwide, 73 | non-exclusive, no-charge, royalty-free, irrevocable license under the 74 | Rights to reproduce, prepare Derivative Works of, make, adapt, repair, 75 | publicly display, publicly perform, sublicense, and distribute the Work 76 | and such Derivative Works in Source or Object form and do anything in 77 | relation to the Work as if the Rights did not exist. 78 | 79 | APPENDIX 80 | 81 | Copyright 2023 BSC* 82 | *Barcelona Supercomputing Center (BSC) 83 | 84 | SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 85 | 86 | Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 87 | may not use this file except in compliance with the License, or, at your 88 | option, the Apache License version 2.0. You may obtain a copy of the 89 | License at 90 | 91 | https://solderpad.org/licenses/SHL-2.1/ 92 | 93 | Unless required by applicable law or agreed to in writing, any work 94 | distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 95 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 96 | License for the specific language governing permissions and limitations 97 | under the License. -------------------------------------------------------------------------------- /rtl/ptw/ptw_arb.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module ptw_arb 22 | import mmu_pkg::*; 23 | #( 24 | )( 25 | input logic clk_i, 26 | input logic rstn_i, 27 | 28 | // iTLB & dTLB interfaces 29 | input tlb_ptw_comm_t itlb_ptw_comm_i, 30 | input tlb_ptw_comm_t dtlb_ptw_comm_i, 31 | output ptw_tlb_comm_t ptw_itlb_comm_o, 32 | output ptw_tlb_comm_t ptw_dtlb_comm_o, 33 | 34 | // PTW interface 35 | input ptw_tlb_comm_t ptw_tlb_comm_i, 36 | output tlb_ptw_comm_t tlb_ptw_comm_o 37 | ); 38 | 39 | logic is_req_waiting_d, is_req_waiting_q; 40 | tlb_ptw_comm_t itlb_req_waiting_d, itlb_req_waiting_q; 41 | 42 | typedef enum logic [1:0] { 43 | IDLE, 44 | SERVING_iTLB, 45 | SERVING_dTLB 46 | } arbptw_state; 47 | 48 | arbptw_state current_state, next_state; 49 | always_ff @(posedge clk_i, negedge rstn_i) begin 50 | if (!rstn_i) begin 51 | current_state <= IDLE; 52 | is_req_waiting_q <= 1'b0; 53 | itlb_req_waiting_q <= '0; 54 | end 55 | else begin 56 | current_state <= next_state; 57 | is_req_waiting_q <= is_req_waiting_d; 58 | itlb_req_waiting_q <= itlb_req_waiting_d; 59 | end 60 | end 61 | 62 | always_comb begin 63 | is_req_waiting_d = is_req_waiting_q; 64 | itlb_req_waiting_d = itlb_req_waiting_q; 65 | tlb_ptw_comm_o = '0; 66 | next_state = current_state; 67 | 68 | ptw_itlb_comm_o.resp.valid = 1'b0; 69 | ptw_itlb_comm_o.resp.error = 1'b0; 70 | ptw_itlb_comm_o.resp.pte = '0; 71 | ptw_itlb_comm_o.resp.level = '0; 72 | ptw_dtlb_comm_o.resp.valid = 1'b0; 73 | ptw_dtlb_comm_o.resp.error = 1'b0; 74 | ptw_dtlb_comm_o.resp.pte = '0; 75 | ptw_dtlb_comm_o.resp.level = '0; 76 | 77 | ptw_itlb_comm_o.ptw_ready = 1'b0; 78 | ptw_dtlb_comm_o.ptw_ready = 1'b0; 79 | 80 | ptw_itlb_comm_o.ptw_status = ptw_tlb_comm_i.ptw_status; 81 | ptw_dtlb_comm_o.ptw_status = ptw_tlb_comm_i.ptw_status; 82 | 83 | ptw_itlb_comm_o.invalidate_tlb = ptw_tlb_comm_i.invalidate_tlb; 84 | ptw_dtlb_comm_o.invalidate_tlb = ptw_tlb_comm_i.invalidate_tlb; 85 | 86 | case (current_state) 87 | IDLE : begin 88 | ptw_itlb_comm_o.resp = '0; 89 | ptw_dtlb_comm_o.resp = '0; 90 | ptw_itlb_comm_o.ptw_ready = 1'b1; 91 | ptw_dtlb_comm_o.ptw_ready = 1'b1; 92 | if (dtlb_ptw_comm_i.req.valid && itlb_ptw_comm_i.req.valid) begin 93 | is_req_waiting_d = 1'b1; 94 | itlb_req_waiting_d = itlb_ptw_comm_i; 95 | tlb_ptw_comm_o = dtlb_ptw_comm_i; 96 | next_state = SERVING_dTLB; 97 | end else if (is_req_waiting_q) begin 98 | ptw_itlb_comm_o.ptw_ready = 1'b0; 99 | ptw_dtlb_comm_o.ptw_ready = 1'b0; 100 | next_state = SERVING_iTLB; 101 | end else if (dtlb_ptw_comm_i.req.valid) begin 102 | tlb_ptw_comm_o = dtlb_ptw_comm_i; 103 | next_state = SERVING_dTLB; 104 | end else if (itlb_ptw_comm_i.req.valid) begin 105 | tlb_ptw_comm_o = itlb_ptw_comm_i; 106 | next_state = SERVING_iTLB; 107 | end else begin 108 | tlb_ptw_comm_o = '0; 109 | next_state = IDLE; 110 | end 111 | end 112 | SERVING_iTLB : begin 113 | ptw_itlb_comm_o.resp = ptw_tlb_comm_i.resp; 114 | ptw_dtlb_comm_o.resp = '0; 115 | tlb_ptw_comm_o = (is_req_waiting_q) ? itlb_req_waiting_q : itlb_ptw_comm_i; 116 | if (!ptw_tlb_comm_i.resp.valid) begin 117 | next_state = SERVING_iTLB; 118 | end else begin 119 | next_state = IDLE; 120 | is_req_waiting_d = 1'b0; 121 | end 122 | end 123 | SERVING_dTLB : begin 124 | ptw_itlb_comm_o.resp = '0; 125 | ptw_dtlb_comm_o.resp = ptw_tlb_comm_i.resp; 126 | tlb_ptw_comm_o = dtlb_ptw_comm_i; 127 | if (!ptw_tlb_comm_i.resp.valid) begin 128 | next_state = SERVING_dTLB; 129 | end else begin 130 | next_state = IDLE; 131 | end 132 | end 133 | endcase 134 | end 135 | 136 | endmodule 137 | -------------------------------------------------------------------------------- /rtl/dcache_adapters/bsc_mmu_hpdc_adapter.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module bsc_mmu_hpdc_adapter 22 | import mmu_pkg::*; 23 | #( 24 | parameter int unsigned SID, 25 | 26 | parameter type hpdcache_req_t = logic, 27 | parameter type hpdcache_tag_t = logic, 28 | parameter type hpdcache_rsp_t = logic 29 | )( 30 | // PTW interface 31 | output dmem_ptw_comm_t dmem_ptw_comm_o, 32 | input ptw_dmem_comm_t ptw_dmem_comm_i, 33 | 34 | // dCache Interface 35 | input logic req_dcache_ready_i, 36 | output logic req_dcache_valid_o, 37 | output hpdcache_req_t req_dcache_o, 38 | output logic req_dcache_abort_o, 39 | output hpdcache_tag_t req_dcache_tag_o, 40 | output hpdcache_pkg::hpdcache_pma_t req_dcache_pma_o, 41 | input logic rsp_dcache_valid_i, 42 | input hpdcache_rsp_t rsp_dcache_i 43 | ); 44 | 45 | // Number of bits used in the request's offset address 46 | localparam int unsigned ADDR_OFFSET_BITS = $bits(req_dcache_o.addr_offset); 47 | 48 | // Number of words in the request 49 | localparam int unsigned REQ_WORDS = $size(req_dcache_o.wdata); 50 | 51 | // Word size 52 | localparam int unsigned WORD_SIZE = $bits(req_dcache_o.wdata[0]); 53 | 54 | // Number of bits used to index the bytes in a word 55 | localparam int unsigned WORD_BYTE_IDX_SIZE = $clog2(WORD_SIZE/8); 56 | 57 | // Number of bits needed to index a byte within the request 58 | localparam int unsigned REQ_INDEX_BITS = $clog2(REQ_WORDS)+WORD_BYTE_IDX_SIZE; 59 | 60 | // MMU CMD that identifies an atomic OR 61 | localparam logic[4:0] MMU_AMO_OR = 5'b01010; 62 | 63 | // PTW to HPDC 64 | always_comb begin 65 | req_dcache_valid_o = ptw_dmem_comm_i.req.valid; 66 | 67 | req_dcache_o.addr_tag = ptw_dmem_comm_i.req.addr[SIZE_VADDR:ADDR_OFFSET_BITS]; 68 | req_dcache_o.addr_offset = ptw_dmem_comm_i.req.addr[ADDR_OFFSET_BITS-1:0]; 69 | req_dcache_o.op = ((ptw_dmem_comm_i.req.cmd == MMU_AMO_OR) ? hpdcache_pkg::HPDCACHE_REQ_AMO_OR : hpdcache_pkg::HPDCACHE_REQ_LOAD); 70 | req_dcache_o.size = ptw_dmem_comm_i.req.typ[2:0]; 71 | 72 | // Put the data in the corresponding word within the request 73 | for (int unsigned i = 0; i < REQ_WORDS; ++i) begin 74 | if (i == ptw_dmem_comm_i.req.addr[REQ_INDEX_BITS-1:WORD_BYTE_IDX_SIZE]) begin 75 | req_dcache_o.wdata[i] = ptw_dmem_comm_i.req.data; 76 | req_dcache_o.be[i] = (ptw_dmem_comm_i.req.cmd == MMU_AMO_OR) ? 8'hff : 8'h00; 77 | end else begin 78 | req_dcache_o.wdata[i] = '0; 79 | req_dcache_o.be[i] = 8'h00; 80 | end 81 | end 82 | 83 | req_dcache_o.sid = SID; 84 | req_dcache_o.tid = '0; 85 | req_dcache_o.need_rsp = 1'b1; 86 | req_dcache_o.phys_indexed = 1'b1; 87 | req_dcache_o.pma.io = 1'b0; 88 | req_dcache_o.pma.uncacheable = 1'b0; 89 | req_dcache_o.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO; 90 | 91 | req_dcache_abort_o = 1'b0; 92 | req_dcache_tag_o = '0; 93 | req_dcache_pma_o = '0; 94 | end 95 | 96 | // HPDC to PTW 97 | always_comb begin 98 | dmem_ptw_comm_o.dmem_ready = req_dcache_ready_i; 99 | dmem_ptw_comm_o.resp.valid = rsp_dcache_valid_i; 100 | dmem_ptw_comm_o.resp.nack = '0; 101 | dmem_ptw_comm_o.resp.addr = '0; 102 | dmem_ptw_comm_o.resp.tag_addr = '0; 103 | dmem_ptw_comm_o.resp.cmd = '0; 104 | dmem_ptw_comm_o.resp.typ = '0; 105 | dmem_ptw_comm_o.resp.replay = '0; 106 | dmem_ptw_comm_o.resp.has_data = '0; 107 | dmem_ptw_comm_o.resp.data_subw = '0; 108 | dmem_ptw_comm_o.resp.store_data = '0; 109 | dmem_ptw_comm_o.resp.rnvalid = '0; 110 | dmem_ptw_comm_o.resp.rnext = '0; 111 | dmem_ptw_comm_o.resp.xcpt_ma_ld = '0; 112 | dmem_ptw_comm_o.resp.xcpt_ma_st = '0; 113 | dmem_ptw_comm_o.resp.xcpt_pf_ld = '0; 114 | dmem_ptw_comm_o.resp.xcpt_pf_st = '0; 115 | dmem_ptw_comm_o.resp.ordered = '0; 116 | dmem_ptw_comm_o.resp.data = 117 | rsp_dcache_i.rdata[ptw_dmem_comm_i.req.addr[REQ_INDEX_BITS-1:WORD_BYTE_IDX_SIZE]]; 118 | end 119 | 120 | endmodule 121 | -------------------------------------------------------------------------------- /rtl/common/pseudoLRU.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module pseudoLRU #( 22 | parameter int unsigned ENTRIES = 8 23 | )( 24 | input logic clk_i, 25 | input logic rstn_i, 26 | 27 | input logic access_hit_i, // only update the PLRU when there is a hit in the storage mechanism 28 | input logic [$clog2(ENTRIES)-1:0] access_idx_i, 29 | output logic [$clog2(ENTRIES)-1:0] replacement_idx_o 30 | ); 31 | 32 | // Decode access_idx 33 | logic [ENTRIES-1:0] access_array; 34 | logic found; 35 | logic found2; 36 | 37 | logic [ENTRIES-1:0] replace_en; 38 | 39 | function logic [$clog2(ENTRIES)-1:0] cast_integer(input [31:0] iter); 40 | cast_integer = iter[$clog2(ENTRIES)-1:0]; 41 | endfunction 42 | 43 | always_comb begin 44 | access_array = '0; // don't care if no 'in' bits set 45 | found = 0; 46 | for (int unsigned i = 0; (i < ENTRIES) && (!found); i++) begin 47 | if (i == access_idx_i) begin 48 | access_array[i] = 1'b1; 49 | found = 1; 50 | end 51 | end 52 | end 53 | 54 | 55 | // ----------------------------------------------- 56 | // PLRU - Pseudo Least Recently Used Replacement 57 | // ----------------------------------------------- 58 | logic [2*(ENTRIES-1)-1:0] plru_tree_q, plru_tree_d; 59 | always_comb begin : plru_replacement 60 | plru_tree_d = plru_tree_q; 61 | // The PLRU-tree indexing: 62 | // lvl0 0 63 | // / \ 64 | // / \ 65 | // lvl1 1 2 66 | // / \ / \ 67 | // lvl2 3 4 5 6 68 | // / \ /\/\ /\ 69 | // ... ... ... ... 70 | // Just predefine which nodes will be set/cleared 71 | // E.g. for a TLB with 8 entries, the for-loop is semantically 72 | // equivalent to the following pseudo-code: 73 | // unique case (1'b1) 74 | // lu_hit[7]: plru_tree_d[0, 2, 6] = {1, 1, 1}; 75 | // lu_hit[6]: plru_tree_d[0, 2, 6] = {1, 1, 0}; 76 | // lu_hit[5]: plru_tree_d[0, 2, 5] = {1, 0, 1}; 77 | // lu_hit[4]: plru_tree_d[0, 2, 5] = {1, 0, 0}; 78 | // lu_hit[3]: plru_tree_d[0, 1, 4] = {0, 1, 1}; 79 | // lu_hit[2]: plru_tree_d[0, 1, 4] = {0, 1, 0}; 80 | // lu_hit[1]: plru_tree_d[0, 1, 3] = {0, 0, 1}; 81 | // lu_hit[0]: plru_tree_d[0, 1, 3] = {0, 0, 0}; 82 | // default: begin /* No hit */ end 83 | // endcase 84 | for (int unsigned i = 0; i < ENTRIES; i++) begin 85 | automatic int unsigned idx_base = 0; 86 | automatic int unsigned shift = 0; 87 | automatic logic [31:0] new_index = '0; 88 | // we got a hit so update the pointer as it was least recently used 89 | if (access_array[i] & access_hit_i) begin 90 | // Set the nodes to the values we would expect 91 | for (int unsigned lvl = 0; lvl < $unsigned($clog2(ENTRIES)); lvl++) begin 92 | idx_base = $unsigned((2**lvl)-1); 93 | // lvl0 <=> MSB, lvl1 <=> MSB-1, ... 94 | shift = $unsigned($clog2(ENTRIES)) - lvl; 95 | // to circumvent the 32 bit integer arithmetic assignment 96 | new_index = ~((i >> (shift-1)) & 32'b1); 97 | plru_tree_d[idx_base + (i >> shift)] = new_index[0]; 98 | end 99 | end 100 | end 101 | // Decode tree to write enable signals 102 | // Next for-loop basically creates the following logic for e.g. an 8 entry 103 | // TLB (note: pseudo-code obviously): 104 | // replace_en[7] = &plru_tree_q[ 6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,1} 105 | // replace_en[6] = &plru_tree_q[~6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,0} 106 | // replace_en[5] = &plru_tree_q[ 5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,1} 107 | // replace_en[4] = &plru_tree_q[~5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,0} 108 | // replace_en[3] = &plru_tree_q[ 4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,1} 109 | // replace_en[2] = &plru_tree_q[~4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,0} 110 | // replace_en[1] = &plru_tree_q[ 3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,1} 111 | // replace_en[0] = &plru_tree_q[~3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,0} 112 | // For each entry traverse the tree. If every tree-node matches, 113 | // the corresponding bit of the entry's index, this is 114 | // the next entry to replace. 115 | for (int unsigned i = 0; i < ENTRIES; i += 1) begin 116 | automatic logic en = 1'b1; 117 | automatic logic [31:0] new_index2 = '0; 118 | automatic int unsigned idx_base, shift; 119 | for (int unsigned lvl = 0; lvl < $unsigned($clog2(ENTRIES)); lvl++) begin 120 | idx_base = $unsigned((2**lvl)-1); 121 | // lvl0 <=> MSB, lvl1 <=> MSB-1, ... 122 | shift = $unsigned($clog2(ENTRIES)) - lvl; 123 | 124 | // en &= plru_tree_q[idx_base + (i>>shift)] == ((i >> (shift-1)) & 1'b1); 125 | new_index2 = (i >> (shift-1)) & 32'b1; 126 | if (new_index2[0]) begin 127 | en &= plru_tree_q[idx_base + (i>>shift)]; 128 | end else begin 129 | en &= ~plru_tree_q[idx_base + (i>>shift)]; 130 | end 131 | end 132 | replace_en[i] = en; 133 | end 134 | end 135 | 136 | // sequential process 137 | always_ff @(posedge clk_i or negedge rstn_i) begin 138 | if (!rstn_i) begin 139 | plru_tree_q <= '0; 140 | end else begin 141 | plru_tree_q <= plru_tree_d; 142 | end 143 | end 144 | 145 | // Encode replace_en 146 | always_comb begin 147 | replacement_idx_o = '0; // don't care if no 'in' bits set 148 | found2 = 1'b0; 149 | for (int unsigned iter = 0; (iter < $unsigned(ENTRIES)) && (!found2); iter++) begin 150 | if (replace_en[iter] == 1'b1) begin 151 | replacement_idx_o = cast_integer(iter); 152 | found2 = 1'b1; 153 | end 154 | end 155 | end 156 | 157 | 158 | endmodule -------------------------------------------------------------------------------- /rtl/tlb/tlb_wrapper.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module tlb_wrapper 22 | import mmu_pkg::*; 23 | #( 24 | )( 25 | input logic clk_i, 26 | input logic rstn_i, 27 | // cache interface 28 | input logic mem_treq_i_valid, 29 | input logic [6:0] mem_treq_i_asid, 30 | input logic [27:0] mem_treq_i_vpn, 31 | input logic mem_treq_i_passthrough, 32 | input logic mem_treq_i_instruction, 33 | input logic mem_treq_i_store, 34 | output logic mem_req_ready_o, 35 | output logic tlb_tresp_o_miss, 36 | output logic [19:0] tlb_tresp_o_ppn, 37 | output logic tlb_tresp_o_xcpt__if, 38 | output logic tlb_tresp_o_xcpt_ld, 39 | output logic tlb_tresp_o_xcpt_st, 40 | output logic [7:0] tlb_tresp_o_hit_idx, 41 | // ptw interface 42 | input logic ptw_req_ready_i, 43 | input logic ptw_invalidate_i, 44 | input logic ptw_resp_i_valid, 45 | input logic ptw_resp_i_error, 46 | input logic [19:0] ptw_resp_i_pte_ppn, 47 | input logic [1:0] ptw_resp_i_pte_rfs, 48 | input logic ptw_resp_i_pte_d, 49 | input logic ptw_resp_i_pte_a, 50 | input logic ptw_resp_i_pte_g, 51 | input logic ptw_resp_i_pte_u, 52 | input logic ptw_resp_i_pte_x, 53 | input logic ptw_resp_i_pte_w, 54 | input logic ptw_resp_i_pte_r, 55 | input logic ptw_resp_i_pte_v, 56 | input logic [1:0] ptw_resp_i_level, 57 | input logic ptw_status_i_sd, 58 | input logic [26:0] ptw_status_i_zero5, 59 | input logic [1:0] ptw_status_i_sxl, 60 | input logic [1:0] ptw_status_i_uxl, 61 | input logic [8:0] ptw_status_i_zero4, 62 | input logic ptw_status_i_tsr, 63 | input logic ptw_status_i_tw, 64 | input logic ptw_status_i_tvm, 65 | input logic ptw_status_i_mxr, 66 | input logic ptw_status_i_sum, 67 | input logic ptw_status_i_mprv, 68 | input logic [1:0] ptw_status_i_xs, 69 | input logic [1:0] ptw_status_i_fs, 70 | input logic [1:0] ptw_status_i_mpp, 71 | input logic [1:0] ptw_status_i_zero3, 72 | input logic ptw_status_i_spp, 73 | input logic ptw_status_i_mpie, 74 | input logic ptw_status_i_zero2, 75 | input logic ptw_status_i_spie, 76 | input logic ptw_status_i_upie, 77 | input logic ptw_status_i_mie, 78 | input logic ptw_status_i_zero1, 79 | input logic ptw_status_i_sie, 80 | input logic ptw_status_i_uie, 81 | output logic ptw_req_o_valid, 82 | output logic [26:0] ptw_req_o_addr, 83 | output logic [1:0] ptw_req_o_prv, 84 | output logic ptw_req_o_store, 85 | output logic ptw_req_o_fetch, 86 | // csr interface 87 | input logic [1:0] csr_priv_lvl_i, 88 | input logic csr_en_translation_i, 89 | // pmu interface 90 | output logic pmu_tlb_access_o, 91 | output logic pmu_tlb_miss_o 92 | ); 93 | 94 | cache_tlb_comm_t cache_tlb_comm; 95 | tlb_cache_comm_t tlb_cache_comm; 96 | tlb_ptw_comm_t tlb_ptw_comm; 97 | ptw_tlb_comm_t ptw_tlb_comm; 98 | 99 | // INPUTS 100 | // cache_tlb_comm assignaments 101 | assign cache_tlb_comm.req.valid = mem_treq_i_valid; 102 | assign cache_tlb_comm.req.asid = mem_treq_i_asid; 103 | assign cache_tlb_comm.req.vpn = mem_treq_i_vpn; 104 | assign cache_tlb_comm.req.passthrough = mem_treq_i_passthrough; 105 | assign cache_tlb_comm.req.instruction = mem_treq_i_instruction; 106 | assign cache_tlb_comm.req.store = mem_treq_i_store; 107 | assign cache_tlb_comm.priv_lvl = csr_priv_lvl_i; 108 | assign cache_tlb_comm.vm_enable = csr_en_translation_i; 109 | 110 | // ptw_tlb_comm assignaments 111 | assign ptw_tlb_comm.resp.valid = ptw_resp_i_valid; 112 | assign ptw_tlb_comm.resp.error = ptw_resp_i_error; 113 | assign ptw_tlb_comm.resp.pte.ppn = ptw_resp_i_pte_ppn; 114 | assign ptw_tlb_comm.resp.pte.rfs = ptw_resp_i_pte_rfs; 115 | assign ptw_tlb_comm.resp.pte.d = ptw_resp_i_pte_d; 116 | assign ptw_tlb_comm.resp.pte.a = ptw_resp_i_pte_a; 117 | assign ptw_tlb_comm.resp.pte.g = ptw_resp_i_pte_g; 118 | assign ptw_tlb_comm.resp.pte.u = ptw_resp_i_pte_u; 119 | assign ptw_tlb_comm.resp.pte.x = ptw_resp_i_pte_x; 120 | assign ptw_tlb_comm.resp.pte.w = ptw_resp_i_pte_w; 121 | assign ptw_tlb_comm.resp.pte.r = ptw_resp_i_pte_r; 122 | assign ptw_tlb_comm.resp.pte.v = ptw_resp_i_pte_v; 123 | assign ptw_tlb_comm.resp.level = ptw_resp_i_level; 124 | assign ptw_tlb_comm.ptw_ready = ptw_req_ready_i; 125 | assign ptw_tlb_comm.ptw_status.sd = ptw_status_i_sd; 126 | assign ptw_tlb_comm.ptw_status.zero5 = ptw_status_i_zero5; 127 | assign ptw_tlb_comm.ptw_status.sxl = ptw_status_i_sxl; 128 | assign ptw_tlb_comm.ptw_status.uxl = ptw_status_i_uxl; 129 | assign ptw_tlb_comm.ptw_status.zero4 = ptw_status_i_zero4; 130 | assign ptw_tlb_comm.ptw_status.tsr = ptw_status_i_tsr; 131 | assign ptw_tlb_comm.ptw_status.tw = ptw_status_i_tw; 132 | assign ptw_tlb_comm.ptw_status.tvm = ptw_status_i_tvm; 133 | assign ptw_tlb_comm.ptw_status.mxr = ptw_status_i_mxr; 134 | assign ptw_tlb_comm.ptw_status.sum = ptw_status_i_sum; 135 | assign ptw_tlb_comm.ptw_status.mprv = ptw_status_i_mprv; 136 | assign ptw_tlb_comm.ptw_status.xs = ptw_status_i_xs; 137 | assign ptw_tlb_comm.ptw_status.fs = ptw_status_i_fs; 138 | assign ptw_tlb_comm.ptw_status.mpp = ptw_status_i_mpp; 139 | assign ptw_tlb_comm.ptw_status.zero3 = ptw_status_i_zero3; 140 | assign ptw_tlb_comm.ptw_status.spp = ptw_status_i_spp; 141 | assign ptw_tlb_comm.ptw_status.mpie = ptw_status_i_mpie; 142 | assign ptw_tlb_comm.ptw_status.zero2 = ptw_status_i_zero2; 143 | assign ptw_tlb_comm.ptw_status.spie = ptw_status_i_spie; 144 | assign ptw_tlb_comm.ptw_status.upie = ptw_status_i_upie; 145 | assign ptw_tlb_comm.ptw_status.mie = ptw_status_i_mie; 146 | assign ptw_tlb_comm.ptw_status.zero1 = ptw_status_i_zero1; 147 | assign ptw_tlb_comm.ptw_status.sie = ptw_status_i_sie; 148 | assign ptw_tlb_comm.ptw_status.uie = ptw_status_i_uie; 149 | assign ptw_tlb_comm.invalidate_tlb = ptw_invalidate_i; 150 | 151 | tlb tlb_inst ( 152 | .clk_i(clk_i), 153 | .rstn_i(rstn_i), 154 | .cache_tlb_comm_i(cache_tlb_comm), 155 | .tlb_cache_comm_o(tlb_cache_comm), 156 | .ptw_tlb_comm_i(ptw_tlb_comm), 157 | .tlb_ptw_comm_o(tlb_ptw_comm), 158 | .pmu_tlb_access_o(pmu_tlb_access_o), 159 | .pmu_tlb_miss_o(pmu_tlb_miss_o) 160 | ); 161 | 162 | // OUTPUTS 163 | assign mem_req_ready_o = tlb_cache_comm.tlb_ready; 164 | assign tlb_tresp_o_miss = tlb_cache_comm.resp.miss; 165 | assign tlb_tresp_o_ppn = tlb_cache_comm.resp.ppn; 166 | assign tlb_tresp_o_xcpt_ld = tlb_cache_comm.resp.xcpt.load; 167 | assign tlb_tresp_o_xcpt_st = tlb_cache_comm.resp.xcpt.store; 168 | assign tlb_tresp_o_xcpt__if = tlb_cache_comm.resp.xcpt.fetch; 169 | assign tlb_tresp_o_hit_idx = '0; 170 | assign ptw_req_o_valid = tlb_ptw_comm.req.valid; 171 | assign ptw_req_o_addr = tlb_ptw_comm.req.vpn; 172 | assign ptw_req_o_prv = tlb_ptw_comm.req.prv; 173 | assign ptw_req_o_store = tlb_ptw_comm.req.store; 174 | assign ptw_req_o_fetch = tlb_ptw_comm.req.fetch; 175 | 176 | endmodule 177 | -------------------------------------------------------------------------------- /includes/mmu_pkg.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | package mmu_pkg; 22 | 23 | // SV39 Parameters 24 | parameter VPN_SIZE = 27; 25 | parameter PPN_SIZE = 44; 26 | parameter SIZE_VADDR = 39; 27 | parameter ASID_SIZE = 7; 28 | parameter LEVELS = 3; 29 | parameter PAGE_LVL_BITS = 9; 30 | parameter PTESIZE = 8; 31 | 32 | parameter TLB_ENTRIES = 8; 33 | parameter TLB_IDX_SIZE = $clog2(TLB_ENTRIES); 34 | 35 | parameter PTW_CACHE_SIZE = $clog2(LEVELS*2); 36 | 37 | parameter [1:0] GIGA_PAGE = 2'b00; // 1 GiB Page 38 | parameter [1:0] MEGA_PAGE = 2'b01; // 2 MiB Page 39 | parameter [1:0] KILO_PAGE = 2'b10; // 4 KiB Page 40 | 41 | typedef struct packed { 42 | logic [PPN_SIZE-1:0] ppn; 43 | logic [1:0] rfs; 44 | logic d; 45 | logic a; 46 | logic g; 47 | logic u; 48 | logic x; 49 | logic w; 50 | logic r; 51 | logic v; 52 | } pte_t; 53 | 54 | typedef struct packed { 55 | logic sd ; 56 | logic [26:0] zero5 ; 57 | logic [1:0] sxl ; 58 | logic [1:0] uxl ; 59 | logic [8:0] zero4 ; 60 | logic tsr ; 61 | logic tw ; 62 | logic tvm ; 63 | logic mxr ; 64 | logic sum ; 65 | logic mprv ; 66 | logic [1:0] xs ; 67 | logic [1:0] fs ; 68 | logic [1:0] mpp ; 69 | logic [1:0] zero3 ; 70 | logic spp ; 71 | logic mpie ; 72 | logic zero2 ; 73 | logic spie ; 74 | logic upie ; 75 | logic mie ; 76 | logic zero1 ; 77 | logic sie ; 78 | logic uie ; 79 | } csr_mstatus_t; 80 | 81 | //////////////////////////////// 82 | // 83 | // Cache-TLB communication 84 | // 85 | /////////////////////////////// 86 | 87 | // Cache-TLB request 88 | typedef struct packed { 89 | logic valid; // Translation request valid. 90 | logic [ASID_SIZE-1:0] asid; // Address space identifier. 91 | logic [VPN_SIZE:0] vpn; // Virtual page number. 92 | logic passthrough; // Virtual address directly corresponds to physical address, for direct assignment between a virtual machine and the physical device. 93 | logic instruction; // The translation request is for a instruction fetch address. 94 | logic store; // The translation request is for a store address. 95 | } cache_tlb_req_t; // Translation request. 96 | 97 | typedef struct packed { 98 | cache_tlb_req_t req; // Translation request. 99 | logic [1:0] priv_lvl; // Privilege level of the translation: 2'b00 (User), 2'b01 (Supervisor), 2'b11 (Machine). 100 | logic vm_enable; // Memory virtualization is active. 101 | } cache_tlb_comm_t; // Communication from translation requester to TLB. 102 | 103 | typedef struct packed { 104 | logic load; // Load operation. 105 | logic store; // Store operation. 106 | logic fetch; // Fetch operation. 107 | } tlb_ex_t; // Exception origin. 108 | 109 | // TLB-Cache response 110 | typedef struct packed { 111 | logic miss; // If the translation request missed set to 1 Otherwise, the rest of the signals have valid information of the response. 112 | logic [PPN_SIZE-1:0] ppn; // Physical page number. 113 | tlb_ex_t xcpt; // Exceptions produced by the requests. 114 | logic [7:0] hit_idx; // CAM hit index of the translation request. 115 | } tlb_cache_resp_t; // Translation response. 116 | 117 | typedef struct packed { 118 | logic tlb_ready; // The tlb is ready to accept a translation request. If 0 it shouldn't receive any translation request. 119 | tlb_cache_resp_t resp; // Translation response. 120 | } tlb_cache_comm_t; // Communication from TLB to translation requester. 121 | 122 | //////////////////////////////// 123 | // 124 | // TLB-PTW communication 125 | // 126 | /////////////////////////////// 127 | 128 | // TLB-PTW request 129 | typedef struct packed { 130 | logic valid; // Translation request valid. 131 | logic [VPN_SIZE-1:0] vpn; // Virtual page number. 132 | logic [ASID_SIZE-1:0] asid; // Address space identifier. 133 | logic [1:0] prv; // Privilege level of the translation: 2'b00 (User), 2'b01 (Supervisor), 2'b11 (Machine). 134 | logic store; // Store operation. 135 | logic fetch; // Fetch operation. 136 | } tlb_ptw_req_t; // Translation request of the TLB to the PTW. 137 | 138 | typedef struct packed { 139 | tlb_ptw_req_t req; // Translation request of the TLB to the PTW. 140 | } tlb_ptw_comm_t; // Communication from TLB to PTW. 141 | 142 | // PTW-TLB response 143 | typedef struct packed { 144 | logic valid; // Translation response valid. 145 | logic error; // An error has ocurred with the translation request. Only check if the response is valid. 146 | pte_t pte; // Page table entry. 147 | logic [$clog2(LEVELS)-1:0] level; // Page entry size: 2'b00 (1 GiB Page), 2'b01 (2 MiB Page), 2'b10 (4 KiB Page). 148 | } ptw_tlb_resp_t; // PTW response to TLB translation request. 149 | 150 | typedef struct packed { 151 | ptw_tlb_resp_t resp; // PTW response to TLB translation request. 152 | logic ptw_ready; // PTW is ready to receive a translation request. 153 | csr_mstatus_t ptw_status; // mstatus csr register value, sent through the ptw. 154 | logic invalidate_tlb; // Signal to flush all entries in TLB and don't allocate in-progress transactions with the PTW. 155 | } ptw_tlb_comm_t; // Communication from to PTW to TLB. 156 | 157 | //////////////////////////////// 158 | // 159 | // TLB 160 | // 161 | /////////////////////////////// 162 | 163 | typedef struct packed { 164 | logic ur; // User read permission. 165 | logic uw; // User write permission. 166 | logic ux; // User execute permission. 167 | logic sr; // Supervisor read permission. 168 | logic sw; // Supervisor write permission. 169 | logic sx; // Supervisor execute permission. 170 | } tlb_entry_permissions_t; // TLB page entry permissions. 171 | 172 | typedef struct packed { 173 | logic [VPN_SIZE-1:0] vpn; // Virtual page number. 174 | logic [ASID_SIZE-1:0] asid; // Address space identifier. 175 | logic [PPN_SIZE-1:0] ppn; // Physical page number. 176 | logic [1:0] level; // Page entry size: 2'b00 (1 GiB Page), 2'b01 (2 MiB Page), 2'b10 (4 KiB Page). 177 | logic dirty; // The page entry is set as dirty. 178 | logic access; // The page entry has been accessed. 179 | tlb_entry_permissions_t perms; // TLB page entry permissions 180 | logic valid; // The tlb entry is valid, set to 1 when the PTW sends a translation response without errors. 181 | logic nempty; // The tlb entry is not empty, when the PTW sends a translation response that we don't have to ignore, it is set to 1. 182 | } tlb_entry_t; // TLB page entry. 183 | 184 | typedef struct packed { 185 | logic [VPN_SIZE-1:0] vpn; // Virtual page number. 186 | logic [ASID_SIZE-1:0] asid; // Address space identifier. 187 | logic store; // Store operation. 188 | logic fetch; // Fetch operation. 189 | logic [TLB_IDX_SIZE-1:0] write_idx; // Index where the page requested to the PTW will be stored in the TLB's CAM. 190 | } tlb_req_tmp_storage_t; // Stored information of the translation request saved on a miss. 191 | 192 | //////////////////////////////// 193 | // 194 | // PTW 195 | // 196 | /////////////////////////////// 197 | // 198 | typedef struct packed { 199 | logic valid; 200 | logic [SIZE_VADDR:0] tags; 201 | logic [PPN_SIZE-1:0] data; 202 | } ptw_ptecache_entry_t; 203 | 204 | //////////////////////////////// 205 | // 206 | // PTW Communications 207 | // 208 | /////////////////////////////// 209 | 210 | // PTW-DMEM request 211 | typedef struct packed { 212 | logic valid ; 213 | logic [SIZE_VADDR:0] addr ; 214 | logic [4:0] cmd ; 215 | logic [3:0] typ ; 216 | logic kill ; 217 | logic phys ; 218 | logic [63:0] data ; 219 | } ptw_dmem_req_t; 220 | 221 | typedef struct packed { 222 | ptw_dmem_req_t req; 223 | } ptw_dmem_comm_t; 224 | 225 | // PTW-DMEM response 226 | typedef struct packed { 227 | logic valid ; 228 | logic [SIZE_VADDR:0] addr ; 229 | logic [7:0] tag_addr ; 230 | logic [4:0] cmd ; 231 | logic [3:0] typ ; 232 | logic [63:0] data ; 233 | logic nack ; 234 | logic replay ; 235 | logic has_data ; 236 | logic [63:0] data_subw ; 237 | logic [63:0] store_data ; 238 | logic rnvalid ; 239 | logic [7:0] rnext ; 240 | logic xcpt_ma_ld ; 241 | logic xcpt_ma_st ; 242 | logic xcpt_pf_ld ; 243 | logic xcpt_pf_st ; 244 | logic ordered ; 245 | } dmem_ptw_resp_t; 246 | 247 | typedef struct packed { 248 | logic dmem_ready; 249 | dmem_ptw_resp_t resp; 250 | } dmem_ptw_comm_t; 251 | 252 | // CSR interface 253 | 254 | typedef struct packed { 255 | logic [63:0] satp; 256 | logic flush; 257 | csr_mstatus_t mstatus; 258 | } csr_ptw_comm_t; 259 | 260 | endpackage 261 | -------------------------------------------------------------------------------- /rtl/mmu_top.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module mmu_top 22 | import mmu_pkg::*; 23 | import sargantana_icache_pkg::*; 24 | import lagarto_pkg::*; 25 | #( 26 | )( 27 | input logic clk_i, 28 | input logic rstn_i, 29 | 30 | //iCache interface 31 | input treq_o_t icache_treq_i , 32 | output tresp_i_t icache_tresp_o , 33 | 34 | //dTLB interface 35 | // dTLB requests 36 | input logic [26:0] io_dtlb_ptw_req_bits_addr , 37 | input logic [1:0] io_dtlb_ptw_req_bits_prv , 38 | input logic io_dtlb_ptw_req_bits_store , 39 | input logic io_dtlb_ptw_req_valid , 40 | output logic io_dtlb_ptw_req_ready , 41 | // dTLB responses 42 | output logic io_dtlb_ptw_resp_bits_error , 43 | output logic [26:0] io_dtlb_ptw_resp_bits_pte_ppn , 44 | output logic io_dtlb_ptw_resp_bits_pte_d , 45 | output logic io_dtlb_ptw_resp_bits_pte_u , 46 | output logic io_dtlb_ptw_resp_bits_pte_x , 47 | output logic io_dtlb_ptw_resp_bits_pte_w , 48 | output logic io_dtlb_ptw_resp_bits_pte_r , 49 | output logic io_dtlb_ptw_resp_bits_pte_v , 50 | output logic [1:0] io_dtlb_ptw_resp_bits_level , 51 | output logic io_dtlb_ptw_resp_valid , 52 | 53 | output logic io_dtlb_ptw_status_mxr , 54 | output logic io_dtlb_ptw_status_sum , 55 | output logic io_dtlb_ptw_invalidate , 56 | 57 | //dCache interface 58 | // dCache requests 59 | output logic io_ptw_mem_req_valid , 60 | output logic [39:0] io_ptw_mem_req_bits_addr , 61 | output logic [4:0] io_ptw_mem_req_bits_cmd , 62 | output logic [63:0] io_ptw_mem_req_bits_data , 63 | output logic io_ptw_mem_req_bits_phys , 64 | output logic [3:0] io_ptw_mem_req_bits_typ , 65 | output logic io_ptw_mem_req_bits_kill , 66 | input logic io_ptw_mem_req_ready , 67 | // dCache response 68 | input logic io_ptw_mem_resp_valid , 69 | input logic [63:0] io_ptw_mem_resp_bits_data , 70 | input logic io_ptw_mem_resp_bits_nack , 71 | 72 | //PTW interface 73 | output logic io_ptw_invalidate , 74 | 75 | // CSRs TLB 76 | input logic [1:0] csr_priv_lvl_i , 77 | input logic csr_en_translation_i , 78 | 79 | // CSRs PTW 80 | input logic [31:0] csr_satp_i , 81 | input logic csr_flush_i , 82 | input logic [63:0] csr_status_i , 83 | 84 | //PMU 85 | output logic io_core_pmu_itlb_access , 86 | output logic io_core_pmu_itlb_miss , 87 | output logic io_core_pmu_itlb_miss_cycle , 88 | output logic io_core_pmu_ptw_hit , 89 | output logic io_core_pmu_ptw_miss , 90 | output logic io_core_pmu_ptw_mem_req 91 | ); 92 | 93 | /**************************************************/ 94 | /* -- iTLB -- */ 95 | /**************************************************/ 96 | 97 | //iCache 98 | cache_tlb_comm_t icache_itlb_comm; 99 | tlb_cache_comm_t itlb_icache_comm; 100 | logic [26:0] itlb_icache_resp_ppn_27bits; // 27 bit ppn truncation 101 | 102 | assign icache_itlb_comm.req.valid = icache_treq_i.valid; 103 | assign icache_itlb_comm.req.asid = '0; 104 | assign icache_itlb_comm.req.vpn = icache_treq_i.vpn; 105 | assign icache_itlb_comm.req.passthrough = 1'b0; 106 | assign icache_itlb_comm.req.instruction = 1'b1; 107 | assign icache_itlb_comm.req.store = '0; 108 | 109 | assign icache_tresp_o.miss = itlb_icache_comm.resp.miss; 110 | assign icache_tresp_o.ppn = itlb_icache_resp_ppn_27bits; 111 | assign icache_tresp_o.xcpt = itlb_icache_comm.resp.xcpt; 112 | 113 | //PTW 114 | tlb_ptw_comm_t itlb_ptw_comm; 115 | ptw_tlb_comm_t ptw_itlb_comm; 116 | 117 | //PMU 118 | assign io_core_pmu_itlb_miss_cycle = itlb_icache_comm.resp.miss && !itlb_icache_comm.tlb_ready; 119 | 120 | tlb_wrapper __itlb__( 121 | .clk_i (clk_i), 122 | .rstn_i (rstn_i), 123 | // iCache 124 | // Input 125 | .mem_treq_i_valid (icache_itlb_comm.req.valid), 126 | .mem_treq_i_asid (icache_itlb_comm.req.asid), 127 | .mem_treq_i_vpn (icache_itlb_comm.req.vpn), 128 | .mem_treq_i_passthrough (icache_itlb_comm.req.passthrough), 129 | .mem_treq_i_instruction (icache_itlb_comm.req.instruction), 130 | .mem_treq_i_store (icache_itlb_comm.req.store), 131 | // Output 132 | .mem_req_ready_o (itlb_icache_comm.tlb_ready), 133 | .tlb_tresp_o_miss (itlb_icache_comm.resp.miss), 134 | .tlb_tresp_o_ppn (itlb_icache_resp_ppn_27bits), 135 | .tlb_tresp_o_xcpt__if (itlb_icache_comm.resp.xcpt.fetch), 136 | .tlb_tresp_o_xcpt_ld (itlb_icache_comm.resp.xcpt.load), 137 | .tlb_tresp_o_xcpt_st (itlb_icache_comm.resp.xcpt.store), 138 | .tlb_tresp_o_hit_idx (itlb_icache_comm.resp.hit_idx), 139 | // PTW connection 140 | // Input 141 | .ptw_req_ready_i (ptw_itlb_comm.ptw_ready), 142 | .ptw_invalidate_i (ptw_itlb_comm.invalidate_tlb), 143 | .ptw_resp_i_valid (ptw_itlb_comm.resp.valid), 144 | .ptw_resp_i_error (ptw_itlb_comm.resp.error), 145 | .ptw_resp_i_pte_ppn (ptw_itlb_comm.resp.pte.ppn), 146 | .ptw_resp_i_pte_rfs (ptw_itlb_comm.resp.pte.rfs), 147 | .ptw_resp_i_pte_d (ptw_itlb_comm.resp.pte.d), 148 | .ptw_resp_i_pte_a (ptw_itlb_comm.resp.pte.a), 149 | .ptw_resp_i_pte_g (ptw_itlb_comm.resp.pte.g), 150 | .ptw_resp_i_pte_u (ptw_itlb_comm.resp.pte.u), 151 | .ptw_resp_i_pte_x (ptw_itlb_comm.resp.pte.x), 152 | .ptw_resp_i_pte_w (ptw_itlb_comm.resp.pte.w), 153 | .ptw_resp_i_pte_r (ptw_itlb_comm.resp.pte.r), 154 | .ptw_resp_i_pte_v (ptw_itlb_comm.resp.pte.v), 155 | .ptw_resp_i_level (ptw_itlb_comm.resp.level), 156 | .ptw_status_i_sd (ptw_itlb_comm.ptw_status.sd), 157 | .ptw_status_i_zero5 (ptw_itlb_comm.ptw_status.zero5), 158 | .ptw_status_i_sxl (ptw_itlb_comm.ptw_status.sxl), 159 | .ptw_status_i_uxl (ptw_itlb_comm.ptw_status.uxl), 160 | .ptw_status_i_zero4 (ptw_itlb_comm.ptw_status.zero4), 161 | .ptw_status_i_tsr (ptw_itlb_comm.ptw_status.tsr), 162 | .ptw_status_i_tw (ptw_itlb_comm.ptw_status.tw), 163 | .ptw_status_i_tvm (ptw_itlb_comm.ptw_status.tvm), 164 | .ptw_status_i_mxr (ptw_itlb_comm.ptw_status.mxr), 165 | .ptw_status_i_sum (ptw_itlb_comm.ptw_status.sum), 166 | .ptw_status_i_mprv (ptw_itlb_comm.ptw_status.mprv), 167 | .ptw_status_i_xs (ptw_itlb_comm.ptw_status.xs), 168 | .ptw_status_i_fs (ptw_itlb_comm.ptw_status.fs), 169 | .ptw_status_i_mpp (ptw_itlb_comm.ptw_status.mpp), 170 | .ptw_status_i_zero3 (ptw_itlb_comm.ptw_status.zero3), 171 | .ptw_status_i_spp (ptw_itlb_comm.ptw_status.spp), 172 | .ptw_status_i_mpie (ptw_itlb_comm.ptw_status.mpie), 173 | .ptw_status_i_zero2 (ptw_itlb_comm.ptw_status.zero2), 174 | .ptw_status_i_spie (ptw_itlb_comm.ptw_status.spie), 175 | .ptw_status_i_upie (ptw_itlb_comm.ptw_status.upie), 176 | .ptw_status_i_mie (ptw_itlb_comm.ptw_status.mie), 177 | .ptw_status_i_zero1 (ptw_itlb_comm.ptw_status.zero1), 178 | .ptw_status_i_sie (ptw_itlb_comm.ptw_status.sie), 179 | .ptw_status_i_uie (ptw_itlb_comm.ptw_status.uie), 180 | // Output 181 | .ptw_req_o_valid (itlb_ptw_comm.req.valid), 182 | .ptw_req_o_addr (itlb_ptw_comm.req.vpn), 183 | .ptw_req_o_prv (itlb_ptw_comm.req.prv), 184 | .ptw_req_o_store (itlb_ptw_comm.req.store), 185 | .ptw_req_o_fetch (itlb_ptw_comm.req.fetch), 186 | // CSRs 187 | // Input 188 | .csr_priv_lvl_i (csr_priv_lvl_i), 189 | .csr_en_translation_i (csr_en_translation_i), 190 | // PMU 191 | // Output 192 | .pmu_tlb_access_o (io_core_pmu_itlb_access), 193 | .pmu_tlb_miss_o (io_core_pmu_itlb_miss) 194 | ); 195 | 196 | /**************************************************/ 197 | /* -- PTW -- */ 198 | /**************************************************/ 199 | 200 | // dTLB-PTW signals 201 | tlb_ptw_comm_t dtlb_ptw_comm; 202 | assign dtlb_ptw_comm.req.valid = io_dtlb_ptw_req_valid; 203 | assign dtlb_ptw_comm.req.vpn = io_dtlb_ptw_req_bits_addr; 204 | assign dtlb_ptw_comm.req.prv = io_dtlb_ptw_req_bits_prv; 205 | assign dtlb_ptw_comm.req.store = io_dtlb_ptw_req_bits_store; 206 | assign dtlb_ptw_comm.req.fetch = '0; 207 | 208 | ptw_tlb_comm_t ptw_dtlb_comm; 209 | assign io_dtlb_ptw_req_ready = ptw_dtlb_comm.ptw_ready; 210 | assign io_dtlb_ptw_resp_valid = ptw_dtlb_comm.resp.valid; 211 | assign io_dtlb_ptw_resp_bits_error = ptw_dtlb_comm.resp.error; 212 | assign io_dtlb_ptw_resp_bits_pte_ppn = ptw_dtlb_comm.resp.pte.ppn; 213 | assign io_dtlb_ptw_resp_bits_pte_u = ptw_dtlb_comm.resp.pte.u; 214 | assign io_dtlb_ptw_resp_bits_pte_x = ptw_dtlb_comm.resp.pte.x; 215 | assign io_dtlb_ptw_resp_bits_pte_w = ptw_dtlb_comm.resp.pte.w; 216 | assign io_dtlb_ptw_resp_bits_pte_r = ptw_dtlb_comm.resp.pte.r; 217 | assign io_dtlb_ptw_resp_bits_pte_v = ptw_dtlb_comm.resp.pte.v; 218 | assign io_dtlb_ptw_resp_bits_pte_d = ptw_dtlb_comm.resp.pte.d; 219 | assign io_dtlb_ptw_resp_bits_level = ptw_dtlb_comm.resp.level; 220 | assign io_dtlb_ptw_status_mxr = ptw_dtlb_comm.ptw_status.mxr; 221 | assign io_dtlb_ptw_status_sum = ptw_dtlb_comm.ptw_status.sum; 222 | assign io_dtlb_ptw_invalidate = ptw_dtlb_comm.invalidate_tlb; 223 | 224 | // PTW-dMEM signals 225 | ptw_dmem_comm_t ptw_dmem_comm; 226 | assign io_ptw_mem_req_valid = ptw_dmem_comm.req.valid; 227 | assign io_ptw_mem_req_bits_addr = ptw_dmem_comm.req.addr; 228 | assign io_ptw_mem_req_bits_cmd = ptw_dmem_comm.req.cmd; 229 | assign io_ptw_mem_req_bits_data = ptw_dmem_comm.req.data; 230 | assign io_ptw_mem_req_bits_kill = ptw_dmem_comm.req.kill; 231 | assign io_ptw_mem_req_bits_phys = 1'b1; 232 | assign io_ptw_mem_req_bits_typ = 4'b0011; 233 | 234 | assign io_core_pmu_ptw_mem_req = ptw_dmem_comm.req.valid && io_ptw_mem_req_ready; 235 | 236 | dmem_ptw_comm_t dmem_ptw_comm; 237 | assign dmem_ptw_comm.dmem_ready = io_ptw_mem_req_ready; 238 | assign dmem_ptw_comm.resp.valid = io_ptw_mem_resp_valid; 239 | assign dmem_ptw_comm.resp.addr = '0; 240 | assign dmem_ptw_comm.resp.tag_addr = '0; 241 | assign dmem_ptw_comm.resp.cmd = '0; 242 | assign dmem_ptw_comm.resp.typ = '0; 243 | assign dmem_ptw_comm.resp.data = io_ptw_mem_resp_bits_data; 244 | assign dmem_ptw_comm.resp.nack = io_ptw_mem_resp_bits_nack; 245 | assign dmem_ptw_comm.resp.replay = '0; 246 | assign dmem_ptw_comm.resp.has_data = '0; 247 | assign dmem_ptw_comm.resp.data_subw = '0; 248 | assign dmem_ptw_comm.resp.store_data = '0; 249 | assign dmem_ptw_comm.resp.rnvalid = '0; 250 | assign dmem_ptw_comm.resp.rnext = '0; 251 | assign dmem_ptw_comm.resp.xcpt_ma_ld = '0; 252 | assign dmem_ptw_comm.resp.xcpt_ma_st = '0; 253 | assign dmem_ptw_comm.resp.xcpt_pf_ld = '0; 254 | assign dmem_ptw_comm.resp.xcpt_pf_st = '0; 255 | assign dmem_ptw_comm.resp.ordered = '0; 256 | 257 | //CSR 258 | csr_ptw_comm_t csr_ptw_comm; 259 | assign csr_ptw_comm.satp = {32'b0, csr_satp_i}; //The PTW obtains ALWAYS a satp of 64 bits 260 | assign csr_ptw_comm.flush = csr_flush_i; 261 | assign csr_ptw_comm.mstatus = csr_status_i; 262 | 263 | assign io_ptw_invalidate = ptw_itlb_comm.invalidate_tlb; 264 | 265 | //iCache 266 | assign icache_tresp_o.ptw_v = ptw_itlb_comm.resp.valid; 267 | 268 | ptw __ptw__ ( 269 | .clk_i(clk_i), 270 | .rstn_i(rstn_i), 271 | 272 | // iTLB request-response 273 | .itlb_ptw_comm_i(itlb_ptw_comm), 274 | .ptw_itlb_comm_o(ptw_itlb_comm), 275 | 276 | // dTLB request-response 277 | .dtlb_ptw_comm_i(dtlb_ptw_comm), 278 | .ptw_dtlb_comm_o(ptw_dtlb_comm), 279 | 280 | // dmem request-response 281 | .dmem_ptw_comm_i(dmem_ptw_comm), 282 | .ptw_dmem_comm_o(ptw_dmem_comm), 283 | 284 | // csr interface 285 | .csr_ptw_comm_i(csr_ptw_comm), 286 | 287 | // pmu interface 288 | .pmu_ptw_hit_o(io_core_pmu_ptw_hit), 289 | .pmu_ptw_miss_o(io_core_pmu_ptw_miss) 290 | ); 291 | 292 | endmodule 293 | -------------------------------------------------------------------------------- /rtl/ptw/ptw.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | module ptw 22 | import mmu_pkg::*; 23 | #( 24 | )( 25 | input logic clk_i, 26 | input logic rstn_i, 27 | 28 | // iTLB request-response 29 | input tlb_ptw_comm_t itlb_ptw_comm_i, 30 | output ptw_tlb_comm_t ptw_itlb_comm_o, 31 | 32 | // dTLB request-response 33 | input tlb_ptw_comm_t dtlb_ptw_comm_i, 34 | output ptw_tlb_comm_t ptw_dtlb_comm_o, 35 | 36 | // dmem request-response 37 | input dmem_ptw_comm_t dmem_ptw_comm_i, 38 | output ptw_dmem_comm_t ptw_dmem_comm_o, 39 | 40 | // csr interface 41 | input csr_ptw_comm_t csr_ptw_comm_i, 42 | 43 | // pmu interface 44 | output logic pmu_ptw_hit_o, 45 | output logic pmu_ptw_miss_o 46 | ); 47 | //Mem commands 48 | //localparam [4:0] M_XA_OR = 5'b01010; 49 | localparam [4:0] M_XRD = 5'b00000; 50 | localparam [3:0] MT_D = 4'b0011; 51 | 52 | // Page-Table Walker FSM States 53 | typedef enum logic [2:0] { 54 | S_READY, 55 | S_REQ, 56 | S_WAIT, 57 | S_DONE, 58 | S_ERROR 59 | } ptw_state; 60 | 61 | // Signal declaration 62 | logic unsigned [$clog2(LEVELS)-1:0] count_d, count_q; 63 | logic unsigned [$clog2(LEVELS):0] count; 64 | 65 | ptw_tlb_comm_t ptw_tlb_comm; 66 | tlb_ptw_comm_t tlb_ptw_comm; 67 | 68 | ptw_state current_state, next_state; 69 | 70 | logic ptw_ready; 71 | tlb_ptw_req_t r_req; 72 | pte_t r_pte; 73 | pte_t pte; 74 | pte_t pte_wdata; 75 | 76 | logic [PAGE_LVL_BITS-1:0] vpn_req [LEVELS-1:0]; 77 | logic [PAGE_LVL_BITS-1:0] vpn_idx; 78 | logic [SIZE_VADDR:0] pte_addr; 79 | logic invalid_pte; 80 | logic valid_pte_lvl [LEVELS-1:0]; 81 | logic is_pte_leaf, is_pte_table; 82 | logic is_pte_ur, is_pte_uw, is_pte_ux; 83 | logic is_pte_sr, is_pte_sw, is_pte_sx; 84 | 85 | logic [1:0] prv_req; 86 | logic perm_ok; 87 | 88 | logic resp_err, resp_val; 89 | logic [63:0] r_resp_ppn; 90 | logic [PPN_SIZE-1:0] resp_ppn_lvl [LEVELS-1:0]; 91 | logic [PPN_SIZE-1:0] resp_ppn; 92 | 93 | logic pte_cache_hit; 94 | logic [PPN_SIZE-1:0] pte_cache_data; 95 | 96 | // Truncate function 97 | function [$clog2(PTW_CACHE_SIZE)-1:0] trunc_ptw_cache_size(input [31:0] val_in); 98 | trunc_ptw_cache_size = val_in[$clog2(PTW_CACHE_SIZE)-1:0]; 99 | endfunction 100 | 101 | // PTW Arbiter 102 | ptw_arb ptw_arb_inst( 103 | .clk_i(clk_i), 104 | .rstn_i(rstn_i), 105 | .itlb_ptw_comm_i(itlb_ptw_comm_i), 106 | .dtlb_ptw_comm_i(dtlb_ptw_comm_i), 107 | .ptw_itlb_comm_o(ptw_itlb_comm_o), 108 | .ptw_dtlb_comm_o(ptw_dtlb_comm_o), 109 | .ptw_tlb_comm_i(ptw_tlb_comm), 110 | .tlb_ptw_comm_o(tlb_ptw_comm) 111 | ); 112 | 113 | // VPN indexation depending on the page level 114 | genvar lvl; 115 | generate 116 | for (lvl = 0; lvl < LEVELS; lvl++) begin 117 | logic [VPN_SIZE-1:0] aux_vpn_req; 118 | assign aux_vpn_req = (r_req.vpn >> ((LEVELS-lvl-1)*PAGE_LVL_BITS)); 119 | assign vpn_req[lvl] = aux_vpn_req[PAGE_LVL_BITS-1:0]; 120 | end 121 | endgenerate 122 | assign vpn_idx = vpn_req[count_q]; 123 | 124 | // Formatting pte data from dmem 125 | assign pte.ppn = dmem_ptw_comm_i.resp.data[10+:(PPN_SIZE)]; 126 | assign pte.rfs = dmem_ptw_comm_i.resp.data[9:8]; 127 | assign pte.d = dmem_ptw_comm_i.resp.data[7]; 128 | assign pte.a = dmem_ptw_comm_i.resp.data[6]; 129 | assign pte.g = dmem_ptw_comm_i.resp.data[5]; 130 | assign pte.u = dmem_ptw_comm_i.resp.data[4]; 131 | assign pte.x = dmem_ptw_comm_i.resp.data[3]; 132 | assign pte.w = dmem_ptw_comm_i.resp.data[2]; 133 | assign pte.r = dmem_ptw_comm_i.resp.data[1]; 134 | 135 | genvar c; 136 | generate 137 | for (c = 0; c < (LEVELS-1); c++) begin 138 | always_comb begin 139 | if (pte.r || pte.w || pte.x) begin 140 | valid_pte_lvl[c] = (pte.ppn[((LEVELS-c-1)*PAGE_LVL_BITS)-1:0] == '0) ? dmem_ptw_comm_i.resp.data[0] : 1'b0; //Make sure PPN LSB are 0 141 | end else begin 142 | valid_pte_lvl[c] = dmem_ptw_comm_i.resp.data[0]; 143 | end 144 | end 145 | end 146 | endgenerate 147 | assign valid_pte_lvl[LEVELS-1] = dmem_ptw_comm_i.resp.data[0]; 148 | assign pte.v = valid_pte_lvl[count_q]; 149 | 150 | assign invalid_pte = (((dmem_ptw_comm_i.resp.data >> (PPN_SIZE+10)) != '0) || 151 | ((is_pte_table & pte.v & (pte.d || pte.a || pte.u)))) ? 1'b1 : 1'b0; //Make sure that N, PBMT and Reserved are 0 152 | 153 | assign is_pte_table = pte.v && !pte.x && !pte.w && !pte.r; 154 | assign is_pte_leaf = pte.v && (pte.x || pte.w || pte.r); 155 | 156 | assign is_pte_ur = is_pte_leaf && pte.u && pte.r; 157 | assign is_pte_uw = is_pte_ur && pte.w; 158 | assign is_pte_ux = pte.v && pte.x && pte.u; 159 | assign is_pte_sr = is_pte_leaf && pte.r && !pte.u; 160 | assign is_pte_sw = is_pte_sr && pte.w; 161 | assign is_pte_sx = pte.v && pte.x && !pte.u; 162 | 163 | // Page Table Entry pointer 164 | logic [63:0] aux_pte_addr; 165 | assign aux_pte_addr = {{(64-(PPN_SIZE+PAGE_LVL_BITS+$clog2(riscv_pkg::XLEN/8))){1'b0}}, {r_pte.ppn, vpn_idx, {{($clog2(riscv_pkg::XLEN/8))}{1'b0}}}}; 166 | assign pte_addr = aux_pte_addr[SIZE_VADDR:0] ; // For Sv39: (r_pte.ppn << 12) + (vpn_idx << 3) 167 | 168 | // PTW Ready 169 | assign ptw_ready = (current_state == S_READY); 170 | 171 | // Catch Request from TLB(Arb) & PTE response from dmem 172 | always_ff @(posedge clk_i, negedge rstn_i) begin 173 | if (!rstn_i) begin 174 | r_req <= '0; 175 | r_pte <= '0; 176 | end else begin 177 | if ((current_state == S_WAIT) && dmem_ptw_comm_i.resp.valid) begin 178 | r_pte <= pte; 179 | end else if ((current_state == S_REQ) && pte_cache_hit && (count_q < $unsigned(LEVELS-1))) begin 180 | r_pte.ppn <= pte_cache_data; 181 | end else if (ptw_ready & tlb_ptw_comm.req.valid) begin 182 | r_req <= tlb_ptw_comm.req; 183 | r_pte.ppn <= csr_ptw_comm_i.satp[PPN_SIZE-1:0]; 184 | end 185 | end 186 | end 187 | `ifndef NO_PTW_CACHE 188 | /////////////////////// 189 | // PTE cache 190 | /////////////////////// 191 | ptw_ptecache_entry_t [PTW_CACHE_SIZE-1:0] ptecache_entry; 192 | logic access_hit; 193 | logic full_cache; 194 | logic unsigned [$clog2(PTW_CACHE_SIZE)-1:0] hit_idx; 195 | logic unsigned [$clog2(PTW_CACHE_SIZE)-1:0] plru_eviction_idx; 196 | logic unsigned [$clog2(PTW_CACHE_SIZE)-1:0] priorityEncoder_idx; 197 | logic [PTW_CACHE_SIZE-1:0] valid_vector; 198 | logic [PTW_CACHE_SIZE-1:0] hit_vector; 199 | 200 | pseudoLRU #( 201 | .ENTRIES(PTW_CACHE_SIZE) 202 | ) ptw_PLRU ( 203 | .clk_i(clk_i), 204 | .rstn_i(rstn_i), 205 | .access_hit_i(access_hit), 206 | .access_idx_i(hit_idx), 207 | .replacement_idx_o(plru_eviction_idx) 208 | ); 209 | 210 | always_ff @(posedge clk_i, negedge rstn_i) begin 211 | if (!rstn_i) begin 212 | for (int i = 0; i < PTW_CACHE_SIZE; i++) begin 213 | ptecache_entry[i] <= '0; 214 | access_hit <= 1'b0; 215 | end 216 | end else begin 217 | access_hit <= 1'b0; 218 | if (dmem_ptw_comm_i.resp.valid && is_pte_table && !pte_cache_hit) begin 219 | if (full_cache) begin 220 | ptecache_entry[plru_eviction_idx].valid <= 1'b1; 221 | ptecache_entry[plru_eviction_idx].tags <= pte_addr; 222 | ptecache_entry[plru_eviction_idx].data <= pte.ppn; 223 | end else begin 224 | ptecache_entry[priorityEncoder_idx].valid <= 1'b1; 225 | ptecache_entry[priorityEncoder_idx].tags <= pte_addr; 226 | ptecache_entry[priorityEncoder_idx].data <= pte.ppn; 227 | end 228 | end 229 | else if (pte_cache_hit && (current_state == S_REQ)) begin 230 | access_hit <= 1'b1; 231 | end 232 | else if (csr_ptw_comm_i.flush) begin 233 | for (int i = 0; i < PTW_CACHE_SIZE; i++) begin 234 | ptecache_entry[i].valid <= 1'b0; 235 | end 236 | end 237 | end 238 | end 239 | 240 | always_comb begin 241 | for (int i = 0; i < PTW_CACHE_SIZE; i++) begin 242 | hit_vector[i] = ((ptecache_entry[i].tags == pte_addr) && ptecache_entry[i].valid) ? 1'b1 : 1'b0; 243 | valid_vector[i] = ptecache_entry[i].valid; 244 | end 245 | end 246 | assign full_cache =& valid_vector; //And Reduction 247 | assign pte_cache_hit =| hit_vector; //Or Reduction 248 | 249 | //Find hit index and data of the data[hit_idx] 250 | logic found; 251 | always_comb begin 252 | hit_idx = '0; 253 | pte_cache_data = '0; 254 | found = 1'b0; // Control variable 255 | for (int i = 0; (i < PTW_CACHE_SIZE) && (!found); i++) begin 256 | if (hit_vector[i]) begin 257 | hit_idx = $unsigned(trunc_ptw_cache_size($unsigned(i))); 258 | pte_cache_data = ptecache_entry[i].data; 259 | found = 1'b1; 260 | end 261 | end 262 | end 263 | 264 | //Priority Encoder 265 | logic found2; 266 | always_comb begin 267 | priorityEncoder_idx = '0; 268 | found2 = 1'b0; 269 | for (int i = 0; (i < PTW_CACHE_SIZE) && (!found2); i++) begin 270 | if (!valid_vector[i]) begin 271 | priorityEncoder_idx = trunc_ptw_cache_size($unsigned(i)); 272 | found2 = 1'b1; 273 | end 274 | end 275 | end 276 | ///////////////////////////////// 277 | `else 278 | assign pte_cache_hit = 1'b0; //Temporal 279 | assign pte_cache_data = '0; //Temporal 280 | `endif 281 | 282 | // Check permissons for set_dirty 283 | assign prv_req = r_req.prv; 284 | 285 | always_comb begin 286 | if (prv_req[0]) begin //Supervisor 287 | if (csr_ptw_comm_i.mstatus.sum) begin 288 | if (r_req.fetch) perm_ok = is_pte_sx || is_pte_ux; 289 | else begin 290 | if (r_req.store) perm_ok = is_pte_sw || is_pte_uw; 291 | else if (csr_ptw_comm_i.mstatus.mxr) perm_ok = is_pte_sr || is_pte_ur || is_pte_ux || is_pte_sx; 292 | else perm_ok = is_pte_sr || is_pte_ur; 293 | end 294 | end else begin 295 | if (r_req.fetch) perm_ok = is_pte_sx; 296 | else begin 297 | if (r_req.store) perm_ok = is_pte_sw; 298 | else if (csr_ptw_comm_i.mstatus.mxr) perm_ok = is_pte_sr || is_pte_sx; 299 | else perm_ok = is_pte_sr; 300 | end 301 | end 302 | end else begin //User 303 | if (r_req.fetch) perm_ok = is_pte_ux; 304 | else begin 305 | if (r_req.store) perm_ok = is_pte_uw; 306 | else if (csr_ptw_comm_i.mstatus.mxr) perm_ok = is_pte_ur || is_pte_ux; 307 | else perm_ok = is_pte_ur; 308 | end 309 | end 310 | end 311 | 312 | // dmem Request 313 | always_comb begin 314 | pte_wdata = '0; 315 | pte_wdata.a = 1'b1; 316 | end 317 | 318 | assign ptw_dmem_comm_o.req.phys = 1'b1; 319 | assign ptw_dmem_comm_o.req.cmd = M_XRD; 320 | assign ptw_dmem_comm_o.req.typ = MT_D; 321 | assign ptw_dmem_comm_o.req.addr = pte_addr; 322 | assign ptw_dmem_comm_o.req.kill = 1'b0; 323 | assign ptw_dmem_comm_o.req.data = { {(64-$bits(pte_wdata)){1'b0}}, 324 | pte_wdata.ppn, 325 | pte_wdata.rfs, 326 | pte_wdata.d, 327 | pte_wdata.a, 328 | pte_wdata.g, 329 | pte_wdata.u, 330 | pte_wdata.x, 331 | pte_wdata.w, 332 | pte_wdata.r, 333 | pte_wdata.v 334 | }; 335 | 336 | // TLB Response 337 | assign resp_err = (current_state == S_ERROR); 338 | assign resp_val = (current_state == S_DONE) || resp_err; 339 | 340 | assign r_resp_ppn = {{(64-(SIZE_VADDR-11)){1'b0}}, pte_addr[SIZE_VADDR:12]}; // pte_addr >> 12 341 | genvar j; 342 | generate 343 | for (j = 0; j < (LEVELS-1); j++) begin 344 | logic [63:0] aux_resp_ppn_lvl; 345 | assign aux_resp_ppn_lvl = {{(64-$bits(r_resp_ppn[63:(LEVELS-j-1)*PAGE_LVL_BITS])-$bits(r_req.vpn[PAGE_LVL_BITS*(LEVELS-j-1)-1:0])){1'b0}}, 346 | r_resp_ppn[63:(LEVELS-j-1)*PAGE_LVL_BITS], 347 | r_req.vpn[PAGE_LVL_BITS*(LEVELS-j-1)-1:0]}; 348 | assign resp_ppn_lvl[j] = aux_resp_ppn_lvl[PPN_SIZE-1:0]; 349 | end 350 | endgenerate 351 | assign resp_ppn_lvl[LEVELS-1] = r_resp_ppn[PPN_SIZE-1:0]; 352 | assign resp_ppn = resp_ppn_lvl[count_q]; 353 | 354 | // Send TLB Response to Arb 355 | assign ptw_tlb_comm.resp.valid = resp_val; 356 | assign ptw_tlb_comm.resp.error = resp_err; 357 | assign ptw_tlb_comm.resp.level = count_q; 358 | assign ptw_tlb_comm.resp.pte.ppn = resp_ppn; 359 | assign ptw_tlb_comm.resp.pte.rfs = r_pte.rfs; 360 | assign ptw_tlb_comm.resp.pte.d = r_pte.d; 361 | assign ptw_tlb_comm.resp.pte.a = r_pte.a; 362 | assign ptw_tlb_comm.resp.pte.g = r_pte.g; 363 | assign ptw_tlb_comm.resp.pte.u = r_pte.u; 364 | assign ptw_tlb_comm.resp.pte.x = r_pte.x; 365 | assign ptw_tlb_comm.resp.pte.w = r_pte.w; 366 | assign ptw_tlb_comm.resp.pte.r = r_pte.r; 367 | assign ptw_tlb_comm.resp.pte.v = r_pte.v; 368 | assign ptw_tlb_comm.ptw_ready = ptw_ready; 369 | assign ptw_tlb_comm.ptw_status = csr_ptw_comm_i.mstatus; 370 | assign ptw_tlb_comm.invalidate_tlb = csr_ptw_comm_i.flush; 371 | 372 | // Page-Table Walker FSM 373 | always_ff @(posedge clk_i, negedge rstn_i) begin 374 | if (!rstn_i) begin 375 | current_state <= S_READY; 376 | count_q <= '0; 377 | end 378 | else begin 379 | current_state <= next_state; 380 | count_q <= count_d; 381 | end 382 | end 383 | 384 | always_comb begin 385 | count_d = count_q; 386 | count = count_q + 1'b1; 387 | pmu_ptw_hit_o = 1'b0; 388 | pmu_ptw_miss_o = 1'b0; 389 | ptw_dmem_comm_o.req.valid = 1'b0; 390 | next_state = current_state; 391 | case (current_state) 392 | S_READY : begin 393 | count_d = '0; 394 | if (tlb_ptw_comm.req.valid) next_state = S_REQ; 395 | else next_state = S_READY; 396 | end 397 | S_REQ : begin 398 | ptw_dmem_comm_o.req.valid = 1'b1; 399 | if (pte_cache_hit && (count_q < $unsigned(LEVELS-1))) begin 400 | ptw_dmem_comm_o.req.valid = 1'b0; 401 | pmu_ptw_hit_o = 1'b1; 402 | count_d = count[1:0]; 403 | next_state = S_REQ; 404 | end else if (dmem_ptw_comm_i.dmem_ready) begin 405 | next_state = S_WAIT; 406 | end else begin 407 | next_state = S_REQ; 408 | end 409 | end 410 | S_WAIT : begin 411 | if (dmem_ptw_comm_i.resp.nack) begin 412 | next_state = S_REQ; 413 | end else if (dmem_ptw_comm_i.resp.valid) begin 414 | if (invalid_pte) begin 415 | next_state = S_ERROR; 416 | end else if (is_pte_table && (count_q < $unsigned(LEVELS-1))) begin 417 | count_d = count[1:0]; 418 | pmu_ptw_miss_o = 1'b1; 419 | next_state = S_REQ; 420 | end else if (is_pte_leaf) begin 421 | next_state = S_DONE; 422 | end 423 | else begin 424 | next_state = S_ERROR; 425 | end 426 | end 427 | else begin 428 | next_state = S_WAIT; 429 | end 430 | end 431 | S_DONE : begin 432 | next_state = S_READY; 433 | end 434 | S_ERROR : begin 435 | next_state = S_READY; 436 | end 437 | endcase 438 | end 439 | 440 | endmodule 441 | -------------------------------------------------------------------------------- /rtl/tlb/tlb.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 BSC* 3 | * *Barcelona Supercomputing Center (BSC) 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 6 | * 7 | * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you 8 | * may not use this file except in compliance with the License, or, at your 9 | * option, the Apache License version 2.0. You may obtain a copy of the 10 | * License at 11 | * 12 | * https://solderpad.org/licenses/SHL-2.1/ 13 | * 14 | * Unless required by applicable law or agreed to in writing, any work 15 | * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 16 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 | * License for the specific language governing permissions and limitations 18 | * under the License. 19 | */ 20 | 21 | /* TLB follows SV39 specification*/ 22 | 23 | module tlb 24 | import mmu_pkg::*; 25 | #( 26 | )( 27 | input logic clk_i, // System clock signal. 28 | input logic rstn_i, // System reset signal (active low). 29 | 30 | // TLB request-response 31 | input cache_tlb_comm_t cache_tlb_comm_i, // Communication from translation requester to TLB. 32 | output tlb_cache_comm_t tlb_cache_comm_o, // Communication from TLB to translation requester. 33 | 34 | // PTW request-response 35 | input ptw_tlb_comm_t ptw_tlb_comm_i, // Communication from TLB to PTW. 36 | output tlb_ptw_comm_t tlb_ptw_comm_o, // Communication from to PTW to TLB. 37 | 38 | // PMU counter events 39 | output logic pmu_tlb_access_o, // Accepted Translation request to TLB. 40 | output logic pmu_tlb_miss_o // Accepted Translation request to TLB misses. 41 | ); 42 | 43 | tlb_entry_t [TLB_ENTRIES-1:0] tlb_entries; 44 | 45 | // Truncate function 46 | function [TLB_IDX_SIZE-1:0] trunc_tlb_idx_size(input [31:0] val_in); 47 | trunc_tlb_idx_size = val_in[TLB_IDX_SIZE-1:0]; 48 | endfunction 49 | 50 | function [TLB_IDX_SIZE-1:0] trunc_tlb_idx_size_4in(input [3:0] val_in); 51 | trunc_tlb_idx_size_4in = val_in[TLB_IDX_SIZE-1:0]; 52 | endfunction 53 | 54 | // TLB WRITE LOGIC 55 | /////////////////////////////// 56 | 57 | logic clear_tlb, write_tlb; 58 | logic [TLB_ENTRIES-1:0] clear_mask; 59 | logic [TLB_IDX_SIZE-1:0] write_idx; 60 | 61 | assign write_idx = tlb_req_tmp.write_idx; // stored write_idx with the eviction idx (calculated in the first cycle of the req) 62 | always_ff @(posedge clk_i, negedge rstn_i) begin 63 | if(~rstn_i) begin 64 | for (int i=0; i supervisor 315 | 316 | // Read permission 317 | always_comb begin 318 | if (sv_priv_lvl) begin 319 | if (ptw_tlb_comm_i.ptw_status.sum) begin // if SUM bit is set, in SV we can read in readable user pages 320 | if (ptw_tlb_comm_i.ptw_status.mxr) begin // if MXR bit is set, executable pages can be also readed 321 | read_ok = tlb_entries[hit_idx].perms.sr | tlb_entries[hit_idx].perms.ur | tlb_entries[hit_idx].perms.sx | tlb_entries[hit_idx].perms.ux; 322 | end else begin 323 | read_ok = tlb_entries[hit_idx].perms.sr | tlb_entries[hit_idx].perms.ur; 324 | end 325 | end else begin 326 | if (ptw_tlb_comm_i.ptw_status.mxr) begin // if MXR bit is set, executable pages can be also readed 327 | read_ok = tlb_entries[hit_idx].perms.sr | tlb_entries[hit_idx].perms.sx; 328 | end else begin 329 | read_ok = tlb_entries[hit_idx].perms.sr; 330 | end 331 | end 332 | end else begin // User mode 333 | if (ptw_tlb_comm_i.ptw_status.mxr) begin // if MXR bit is set, executable pages can be also readed 334 | read_ok = tlb_entries[hit_idx].perms.ur | tlb_entries[hit_idx].perms.ux; 335 | end else begin 336 | read_ok = tlb_entries[hit_idx].perms.ur; 337 | end 338 | end 339 | end 340 | 341 | // Write permission 342 | always_comb begin 343 | if(sv_priv_lvl) begin 344 | if (ptw_tlb_comm_i.ptw_status.sum) begin // if SUM bit is set, in SV we can write in writable user pages 345 | write_ok = tlb_entries[hit_idx].perms.sw | tlb_entries[hit_idx].perms.uw; 346 | end else begin 347 | write_ok = tlb_entries[hit_idx].perms.sw; 348 | end 349 | end else begin 350 | write_ok = tlb_entries[hit_idx].perms.uw; 351 | end 352 | end 353 | 354 | // Execution permission 355 | assign exec_ok = (sv_priv_lvl) ? tlb_entries[hit_idx].perms.sx : tlb_entries[hit_idx].perms.ux; 356 | 357 | logic xcpt_if, xcpt_st, xcpt_ld; 358 | assign xcpt_if = (vm_enable && ((tlb_hit && !exec_ok) || tlb_entry_access_is_zero)) ? 1'b1 : 1'b0; 359 | assign xcpt_st = (vm_enable && ((tlb_hit && !write_ok) || tlb_entry_access_is_zero || tlb_entry_dirty_is_zero)) ? 1'b1 : 1'b0; 360 | assign xcpt_ld = (vm_enable && ((tlb_hit && !read_ok) || tlb_entry_access_is_zero)) ? 1'b1 : 1'b0; 361 | 362 | // PPN ASSIGNAMENT 363 | /////////////////////////////// 364 | 365 | logic [PPN_SIZE-1:0] ppn_k, ppn_m, ppn_g; 366 | 367 | // We receive superpages from PTW as if they were 4KB pages (implementation decision in LowRisc) 368 | // For example 2MB ppn 1 is encoded as 100000000b -> 512 in 4KB pages 369 | // therefore, it is required exctracting the page number in its real size and fill the 0s with the 370 | // corresponding bits of the vpn to get the correct translation 371 | 372 | assign ppn_k = tlb_entries[hit_idx].ppn; 373 | assign ppn_m = {tlb_entries[hit_idx].ppn >> PAGE_LVL_BITS, cache_vpn[PAGE_LVL_BITS-1:0]}; 374 | assign ppn_g = {tlb_entries[hit_idx].ppn >> (PAGE_LVL_BITS * 2), cache_vpn[PAGE_LVL_BITS*2-1:0]}; 375 | 376 | // TLB RESPONSE 377 | /////////////////////////////// 378 | 379 | assign tlb_cache_comm_o.tlb_ready = tlb_ready; 380 | assign tlb_cache_comm_o.resp.miss = tlb_miss; 381 | assign tlb_cache_comm_o.resp.ppn = 382 | ((ppn_k & {PPN_SIZE{hit_k & vm_enable & ~passthrough}}) | (ppn_m & {PPN_SIZE{hit_m & vm_enable & ~passthrough}})) | 383 | ((ppn_g & {PPN_SIZE{hit_g & vm_enable & ~passthrough}}) | {{(PPN_SIZE-VPN_SIZE-1){1'b0}}, cache_vpn & {(VPN_SIZE+1){~(vm_enable & ~passthrough)}}}); 384 | assign tlb_cache_comm_o.resp.xcpt.load = xcpt_ld; 385 | assign tlb_cache_comm_o.resp.xcpt.store = xcpt_st; 386 | assign tlb_cache_comm_o.resp.xcpt.fetch = xcpt_if; 387 | 388 | assign tlb_cache_comm_o.resp.hit_idx = 'h0; 389 | 390 | // PMU EVENTS 391 | /////////////////////////////// 392 | assign pmu_tlb_access_o = pmu_tlb_access; 393 | assign pmu_tlb_miss_o = pmu_tlb_miss; 394 | 395 | endmodule 396 | --------------------------------------------------------------------------------