├── doc ├── soc.png ├── hpm │ └── hpm.png ├── igs │ └── igs.png ├── trans_flow.png ├── cdw │ ├── cdw_fsm.png │ └── context_walk.png ├── ptw │ ├── MSI_PTE.png │ ├── pt_walk.png │ ├── ptw_fsm.png │ └── ptw_ifs.png ├── regmap │ ├── field.png │ └── regmap.png ├── soc_minimal.png ├── spec │ ├── msi_mrif.png │ ├── queues.png │ ├── dc_formats.png │ ├── usage_models.png │ └── msi_passthrough.png ├── cq_handler │ └── cq_fsm.png ├── fq_handler │ └── fq_fsm.png ├── ioatc │ └── ioatc_entry.png ├── iommu_design_param.png ├── ext_interfaces │ ├── mem_if.png │ ├── reg_if.png │ └── tr_comp_if.png └── msi_translation │ ├── msi_pte.png │ ├── msiptw_fsm.png │ └── mrif_handler_fsm.png ├── packages ├── rv_iommu │ └── rv_iommu_field_pkg.sv └── dependencies │ ├── cv64a6_imafdc_sv39_config_pkg.sv │ ├── cf_math_pkg.sv │ └── lint_wrapper_pkg.sv ├── vendor ├── apb_to_reg.sv ├── spill_register.sv ├── onehot_to_bin.sv ├── counter.sv ├── stream_demux.sv ├── stream_mux.sv ├── REG_BUS.sv ├── axi_single_slice.sv ├── stream_arbiter.sv ├── axi_b_buffer.sv ├── stream_register.sv ├── axi_w_buffer.sv ├── axi_r_buffer.sv ├── fifo.sv ├── delta_counter.sv ├── stream_arbiter_flushable.sv ├── axi_ar_buffer.sv ├── axi_aw_buffer.sv ├── fifo_v2.sv ├── spill_register_flushable.sv ├── lzc.sv ├── axi_to_reg.sv ├── fifo_v3.sv ├── axi_err_slv.sv └── axi_lite_to_reg.sv ├── include ├── register_interface │ ├── typedef.svh │ └── assign.svh ├── assertions.svh └── common_cells │ └── registers.svh ├── Makefile ├── rtl ├── software_interface │ ├── rv_iommu_wsi_ig.sv │ ├── regmap │ │ ├── rv_iommu_field.sv │ │ └── rv_iommu_field_arb.sv │ └── rv_iommu_msi_ig.sv ├── ext_interfaces │ ├── rv_iommu_axi4_bc.sv │ ├── rv_iommu_ign_slv.sv │ ├── rv_iommu_prog_if.sv │ └── rv_iommu_ds_if.sv └── translation_logic │ └── rv_iommu_ddtc.sv ├── .gitignore ├── lint_checks.sv ├── LICENSE.Solerpad └── LICENSE.Apache /doc/soc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/soc.png -------------------------------------------------------------------------------- /doc/hpm/hpm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/hpm/hpm.png -------------------------------------------------------------------------------- /doc/igs/igs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/igs/igs.png -------------------------------------------------------------------------------- /doc/trans_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/trans_flow.png -------------------------------------------------------------------------------- /doc/cdw/cdw_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/cdw/cdw_fsm.png -------------------------------------------------------------------------------- /doc/ptw/MSI_PTE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ptw/MSI_PTE.png -------------------------------------------------------------------------------- /doc/ptw/pt_walk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ptw/pt_walk.png -------------------------------------------------------------------------------- /doc/ptw/ptw_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ptw/ptw_fsm.png -------------------------------------------------------------------------------- /doc/ptw/ptw_ifs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ptw/ptw_ifs.png -------------------------------------------------------------------------------- /doc/regmap/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/regmap/field.png -------------------------------------------------------------------------------- /doc/regmap/regmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/regmap/regmap.png -------------------------------------------------------------------------------- /doc/soc_minimal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/soc_minimal.png -------------------------------------------------------------------------------- /doc/spec/msi_mrif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/spec/msi_mrif.png -------------------------------------------------------------------------------- /doc/spec/queues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/spec/queues.png -------------------------------------------------------------------------------- /doc/spec/dc_formats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/spec/dc_formats.png -------------------------------------------------------------------------------- /doc/cdw/context_walk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/cdw/context_walk.png -------------------------------------------------------------------------------- /doc/cq_handler/cq_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/cq_handler/cq_fsm.png -------------------------------------------------------------------------------- /doc/fq_handler/fq_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/fq_handler/fq_fsm.png -------------------------------------------------------------------------------- /doc/ioatc/ioatc_entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ioatc/ioatc_entry.png -------------------------------------------------------------------------------- /doc/iommu_design_param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/iommu_design_param.png -------------------------------------------------------------------------------- /doc/spec/usage_models.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/spec/usage_models.png -------------------------------------------------------------------------------- /doc/spec/msi_passthrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/spec/msi_passthrough.png -------------------------------------------------------------------------------- /doc/ext_interfaces/mem_if.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ext_interfaces/mem_if.png -------------------------------------------------------------------------------- /doc/ext_interfaces/reg_if.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ext_interfaces/reg_if.png -------------------------------------------------------------------------------- /doc/msi_translation/msi_pte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/msi_translation/msi_pte.png -------------------------------------------------------------------------------- /doc/ext_interfaces/tr_comp_if.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/ext_interfaces/tr_comp_if.png -------------------------------------------------------------------------------- /doc/msi_translation/msiptw_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/msi_translation/msiptw_fsm.png -------------------------------------------------------------------------------- /doc/msi_translation/mrif_handler_fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zero-day-labs/riscv-iommu/HEAD/doc/msi_translation/mrif_handler_fsm.png -------------------------------------------------------------------------------- /packages/rv_iommu/rv_iommu_field_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // 6 | // Edited by: Manuel Rodríguez 7 | // Edited at: 12/10/2022 8 | // 9 | // IOMMU Register field package: Contains SW access permissions 10 | 11 | `ifndef RV_IOMMU_FIELD_PKG_DEF 12 | `define RV_IOMMU_FIELD_PKG_DEF 13 | 14 | package rv_iommu_field_pkg; 15 | 16 | // SW access permissions specifier 17 | typedef enum logic [2:0] { 18 | SwAccessRW = 3'd0, // Read-write 19 | SwAccessRO = 3'd1, // Read-only 20 | SwAccessWO = 3'd2, // Write-only 21 | SwAccessW1C = 3'd3, // Write 1 to clear 22 | SwAccessW1S = 3'd4, // Write 1 to set 23 | SwAccessW0C = 3'd5, // Write 0 to clear 24 | SwAccessRC = 3'd6 // Read to clear. Do not use, only exists for compatibility. 25 | } sw_access_e; 26 | 27 | endpackage 28 | 29 | `endif 30 | -------------------------------------------------------------------------------- /vendor/apb_to_reg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Florian Zaruba 12 | 13 | module apb_to_reg ( 14 | input logic clk_i, 15 | input logic rst_ni, 16 | 17 | input logic penable_i, 18 | input logic pwrite_i, 19 | input logic [63:0] paddr_i, 20 | input logic psel_i, 21 | input logic [31:0] pwdata_i, 22 | output logic [31:0] prdata_o, 23 | output logic pready_o, 24 | output logic pslverr_o, 25 | 26 | REG_BUS.out reg_o 27 | ); 28 | 29 | always_comb begin 30 | reg_o.addr = paddr_i; 31 | reg_o.write = pwrite_i; 32 | reg_o.wdata = pwdata_i; 33 | reg_o.wstrb = '1; 34 | reg_o.valid = psel_i & penable_i; 35 | pready_o = reg_o.ready; 36 | pslverr_o = reg_o.error; 37 | prdata_o = reg_o.rdata; 38 | end 39 | endmodule 40 | -------------------------------------------------------------------------------- /vendor/spill_register.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | // 12 | // Fabian Schuiki 13 | 14 | 15 | /// Wrapper around the flushable spill register to maintain back-ward 16 | /// compatibility. 17 | module spill_register #( 18 | parameter type T = logic, 19 | parameter bit Bypass = 1'b0 // make this spill register transparent 20 | ) ( 21 | input logic clk_i , 22 | input logic rst_ni , 23 | input logic valid_i , 24 | output logic ready_o , 25 | input T data_i , 26 | output logic valid_o , 27 | input logic ready_i , 28 | output T data_o 29 | ); 30 | 31 | spill_register_flushable #( 32 | .T(T), 33 | .Bypass(Bypass) 34 | ) spill_register_flushable_i ( 35 | .clk_i, 36 | .rst_ni, 37 | .valid_i, 38 | .flush_i(1'b0), 39 | .ready_o, 40 | .data_i, 41 | .valid_o, 42 | .ready_i, 43 | .data_o 44 | ); 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /include/register_interface/typedef.svh: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 ETH Zurich, University of Bologna 2 | // 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | 12 | // Florian Zaruba 13 | /// Macros to define register bus request/response structs. 14 | 15 | `ifndef REGISTER_INTERFACE_TYPEDEF_SVH_ 16 | `define REGISTER_INTERFACE_TYPEDEF_SVH_ 17 | 18 | `define REG_BUS_TYPEDEF_REQ(req_t, addr_t, data_t, strb_t) \ 19 | typedef struct packed { \ 20 | addr_t addr; \ 21 | logic write; \ 22 | data_t wdata; \ 23 | strb_t wstrb; \ 24 | logic valid; \ 25 | } req_t; 26 | 27 | `define REG_BUS_TYPEDEF_RSP(rsp_t, data_t) \ 28 | typedef struct packed { \ 29 | data_t rdata; \ 30 | logic error; \ 31 | logic ready; \ 32 | } rsp_t; 33 | 34 | `define REG_BUS_TYPEDEF_ALL(name, addr_t, data_t, strb_t) \ 35 | `REG_BUS_TYPEDEF_REQ(name``_req_t, addr_t, data_t, strb_t) \ 36 | `REG_BUS_TYPEDEF_RSP(name``_rsp_t, data_t) 37 | 38 | `endif -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Author: Manuel Rodríguez 16 | # Date: 28/03/2023 17 | # 18 | # Description: Makefile to perform lint checks in the RISC-V IOMMU IP using verilator 19 | 20 | WARN_FLAGS := 21 | WARN_FLAGS += -Wno-LATCH 22 | 23 | COMP_FLAGS := 24 | # COMP_FLAGS += --cc 25 | COMP_FLAGS += --lint-only 26 | # COMP_FLAGS += --report-unoptflat 27 | 28 | INC += -I./packages/dependencies 29 | INC += -I./packages/rv_iommu 30 | INC += -I./vendor 31 | INC += -I./include 32 | INC += -I./rtl 33 | INC += -I./rtl/translation_logic 34 | INC += -I./rtl/translation_logic/cdw 35 | INC += -I./rtl/translation_logic/ptw 36 | INC += -I./rtl/translation_logic/wrapper 37 | INC += -I./rtl/software_interface 38 | INC += -I./rtl/software_interface/regmap 39 | INC += -I./rtl/software_interface/wrapper 40 | INC += -I./rtl/ext_interfaces 41 | 42 | all: lint 43 | 44 | lint: 45 | verilator-5.022 ${COMP_FLAGS} lint_checks.sv ${INC} ${WARN_FLAGS} 46 | 47 | lint2log: 48 | verilator-5.022 ${COMP_FLAGS} lint_checks.sv ${INC} ${WARN_FLAGS} 2> verilator.log -------------------------------------------------------------------------------- /vendor/onehot_to_bin.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Franceco Conti 12 | 13 | module onehot_to_bin #( 14 | parameter int unsigned ONEHOT_WIDTH = 16, 15 | // Do Not Change 16 | parameter int unsigned BIN_WIDTH = ONEHOT_WIDTH == 1 ? 1 : $clog2(ONEHOT_WIDTH) 17 | ) ( 18 | input logic [ONEHOT_WIDTH-1:0] onehot, 19 | output logic [BIN_WIDTH-1:0] bin 20 | ); 21 | 22 | for (genvar j = 0; j < BIN_WIDTH; j++) begin : jl 23 | logic [ONEHOT_WIDTH-1:0] tmp_mask; 24 | for (genvar i = 0; i < ONEHOT_WIDTH; i++) begin : il 25 | logic [BIN_WIDTH-1:0] tmp_i; 26 | assign tmp_i = i; 27 | assign tmp_mask[i] = tmp_i[j]; 28 | end 29 | assign bin[j] = |(tmp_mask & onehot); 30 | end 31 | 32 | // pragma translate_off 33 | `ifndef VERILATOR 34 | assert final ($onehot0(onehot)) else 35 | $fatal(1, "[onehot_to_bin] More than two bit set in the one-hot signal"); 36 | `endif 37 | // pragma translate_on 38 | endmodule 39 | -------------------------------------------------------------------------------- /vendor/counter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Author: Florian Zaruba 12 | // Description: Generic up/down counter 13 | 14 | module counter #( 15 | parameter int unsigned WIDTH = 4, 16 | parameter bit STICKY_OVERFLOW = 1'b0 17 | )( 18 | input logic clk_i, 19 | input logic rst_ni, 20 | input logic clear_i, // synchronous clear 21 | input logic en_i, // enable the counter 22 | input logic load_i, // load a new value 23 | input logic down_i, // downcount, default is up 24 | input logic [WIDTH-1:0] d_i, 25 | output logic [WIDTH-1:0] q_o, 26 | output logic overflow_o 27 | ); 28 | delta_counter #( 29 | .WIDTH (WIDTH), 30 | .STICKY_OVERFLOW (STICKY_OVERFLOW) 31 | ) i_counter ( 32 | .clk_i, 33 | .rst_ni, 34 | .clear_i, 35 | .en_i, 36 | .load_i, 37 | .down_i, 38 | .delta_i({{WIDTH-1{1'b0}}, 1'b1}), 39 | .d_i, 40 | .q_o, 41 | .overflow_o 42 | ); 43 | endmodule 44 | -------------------------------------------------------------------------------- /vendor/stream_demux.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | /// Connects the input stream (valid-ready) handshake to one of `N_OUP` output stream handshakes. 12 | /// 13 | /// This module has no data ports because stream data does not need to be demultiplexed: the data of 14 | /// the input stream can just be applied at all output streams. 15 | 16 | /* verilator lint_off WIDTH */ 17 | module stream_demux #( 18 | /// Number of connected outputs. 19 | parameter int unsigned N_OUP = 32'd1, 20 | /// Dependent parameters, DO NOT OVERRIDE! 21 | parameter int unsigned LOG_N_OUP = (N_OUP > 32'd1) ? unsigned'($clog2(N_OUP)) : 1'b1 22 | ) ( 23 | input logic inp_valid_i, 24 | output logic inp_ready_o, 25 | 26 | input logic [LOG_N_OUP-1:0] oup_sel_i, 27 | 28 | output logic [N_OUP-1:0] oup_valid_o, 29 | input logic [N_OUP-1:0] oup_ready_i 30 | ); 31 | 32 | always_comb begin 33 | oup_valid_o = '0; 34 | oup_valid_o[oup_sel_i] = inp_valid_i; 35 | end 36 | assign inp_ready_o = oup_ready_i[oup_sel_i]; 37 | 38 | endmodule 39 | 40 | /* verilator lint_on WIDTH */ 41 | -------------------------------------------------------------------------------- /vendor/stream_mux.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | /// Stream multiplexer: connects the output to one of `N_INP` data streams with valid-ready 12 | /// handshaking. 13 | 14 | module stream_mux #( 15 | parameter type DATA_T = logic, // Vivado requires a default value for type parameters. 16 | parameter integer N_INP = 0, // Synopsys DC requires a default value for value parameters. 17 | /// Dependent parameters, DO NOT OVERRIDE! 18 | parameter integer LOG_N_INP = $clog2(N_INP) 19 | ) ( 20 | input DATA_T [N_INP-1:0] inp_data_i, 21 | input logic [N_INP-1:0] inp_valid_i, 22 | output logic [N_INP-1:0] inp_ready_o, 23 | 24 | input logic [LOG_N_INP-1:0] inp_sel_i, 25 | 26 | output DATA_T oup_data_o, 27 | output logic oup_valid_o, 28 | input logic oup_ready_i 29 | ); 30 | 31 | always_comb begin 32 | inp_ready_o = '0; 33 | inp_ready_o[inp_sel_i] = oup_ready_i; 34 | end 35 | assign oup_data_o = inp_data_i[inp_sel_i]; 36 | assign oup_valid_o = inp_valid_i[inp_sel_i]; 37 | 38 | // pragma translate_off 39 | `ifndef VERILATOR 40 | initial begin: p_assertions 41 | assert (N_INP >= 1) else $fatal (1, "The number of inputs must be at least 1!"); 42 | end 43 | `endif 44 | // pragma translate_on 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /include/register_interface/assign.svh: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 ETH Zurich, University of Bologna 2 | // 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | 12 | // Florian Zaruba 13 | /// Macros to define register bus request/response structs. 14 | 15 | `ifndef REGISTER_INTERFACE_ASSIGN_SVH_ 16 | `define REGISTER_INTERFACE_ASSIGN_SVH_ 17 | 18 | `define REG_BUS_ASSIGN_TO_REQ(lhs, rhs) \ 19 | assign lhs = '{ \ 20 | addr: rhs.addr, \ 21 | write: rhs.write, \ 22 | wdata: rhs.wdata, \ 23 | wstrb: rhs.wstrb, \ 24 | valid: rhs.valid \ 25 | }; 26 | 27 | `define REG_BUS_ASSIGN_FROM_REQ(lhs, rhs) \ 28 | assign lhs.addr = rhs.addr; \ 29 | assign lhs.write = rhs.write; \ 30 | assign lhs.wdata = rhs.wdata; \ 31 | assign lhs.wstrb = rhs.wstrb; \ 32 | assign lhs.valid = rhs.valid; \ 33 | 34 | `define REG_BUS_ASSIGN_TO_RSP(lhs, rhs) \ 35 | assign lhs = '{ \ 36 | rdata: rhs.rdata, \ 37 | error: rhs.error, \ 38 | ready: rhs.ready \ 39 | }; 40 | 41 | `define REG_BUS_ASSIGN_FROM_RSP(lhs, rhs) \ 42 | assign lhs.rdata = rhs.rdata; \ 43 | assign lhs.error = rhs.error; \ 44 | assign lhs.ready = rhs.ready; 45 | 46 | `endif -------------------------------------------------------------------------------- /vendor/REG_BUS.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Fabian Schuiki 12 | 13 | /// A simple register interface. 14 | /// 15 | /// This is pretty much as simple as it gets. Transactions consist of only one 16 | /// phase. The master sets the address, write, write data, and write strobe 17 | /// signals and pulls valid high. Once pulled high, valid must remain high and 18 | /// none of the signals may change. The transaction completes when both valid 19 | /// and ready are high. Valid must not depend on ready. The slave presents the 20 | /// read data and error signals. These signals must be constant while valid and 21 | /// ready are both high. 22 | interface REG_BUS #( 23 | /// The width of the address. 24 | parameter int ADDR_WIDTH = -1, 25 | /// The width of the data. 26 | parameter int DATA_WIDTH = -1 27 | )( 28 | input logic clk_i 29 | ); 30 | 31 | logic [ADDR_WIDTH-1:0] addr; 32 | logic write; // 0=read, 1=write 33 | logic [DATA_WIDTH-1:0] rdata; 34 | logic [DATA_WIDTH-1:0] wdata; 35 | logic [DATA_WIDTH/8-1:0] wstrb; // byte-wise strobe 36 | logic error; // 0=ok, 1=error 37 | logic valid; 38 | logic ready; 39 | 40 | modport in (input addr, write, wdata, wstrb, valid, output rdata, error, ready); 41 | modport out (output addr, write, wdata, wstrb, valid, input rdata, error, ready); 42 | 43 | endinterface 44 | -------------------------------------------------------------------------------- /rtl/software_interface/rv_iommu_wsi_ig.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 10/03/2023 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: RISC-V IOMMU WSI Interrupt Generation Module. 18 | 19 | module rv_iommu_wsi_ig #( 20 | // Number of supported interrupt vectors 21 | parameter int unsigned N_INT_VEC = 16, 22 | // Number of interrupt sources 23 | parameter int unsigned N_INT_SRCS = 3, 24 | 25 | // DO NOT MODIFY 26 | parameter int unsigned LOG2_INTVEC = (N_INT_VEC == 1) ? (1) : ($clog2(N_INT_VEC)) 27 | ) ( 28 | 29 | // fctl.wsi 30 | input logic wsi_en_i, 31 | 32 | // Interrupt pending bits 33 | input logic [(N_INT_SRCS-1):0] intp_i, 34 | 35 | // Interrupt vectors 36 | input logic [3:0] intv_i[N_INT_SRCS], 37 | 38 | // interrupt wires 39 | output logic [(N_INT_VEC-1):0] wsi_wires_o 40 | ); 41 | 42 | always_comb begin : wsi_support 43 | 44 | wsi_wires_o = '0; 45 | 46 | // If WSI generation supported and enabled 47 | if (wsi_en_i) begin 48 | 49 | for (int unsigned i = 0; i < N_INT_SRCS; i++) begin 50 | wsi_wires_o[intv_i[i][(LOG2_INTVEC-1):0]] = intp_i[i]; 51 | end 52 | end 53 | end 54 | 55 | endmodule -------------------------------------------------------------------------------- /vendor/axi_single_slice.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | /// Wrapper for a generic fifo 12 | module axi_single_slice #( 13 | parameter int BUFFER_DEPTH = -1, 14 | parameter int DATA_WIDTH = -1 15 | ) ( 16 | input logic clk_i, // Clock 17 | input logic rst_ni, // Asynchronous reset active low 18 | input logic testmode_i, 19 | input logic valid_i, 20 | output logic ready_o, 21 | input logic [DATA_WIDTH-1:0] data_i, 22 | 23 | input logic ready_i, 24 | output logic valid_o, 25 | output logic [DATA_WIDTH-1:0] data_o 26 | ); 27 | 28 | logic full, empty; 29 | 30 | assign ready_o = ~full; 31 | assign valid_o = ~empty; 32 | 33 | fifo #( 34 | .FALL_THROUGH ( 1'b0 ), 35 | .DATA_WIDTH ( DATA_WIDTH ), 36 | .DEPTH ( BUFFER_DEPTH ) 37 | ) i_fifo ( 38 | .clk_i ( clk_i ), 39 | .rst_ni ( rst_ni ), 40 | .flush_i ( 1'b0 ), 41 | .threshold_o (), // NC 42 | .testmode_i ( testmode_i ), 43 | .full_o ( full ), 44 | .empty_o ( empty ), 45 | .data_i ( data_i ), 46 | .push_i ( valid_i & ready_o ), 47 | .data_o ( data_o ), 48 | .pop_i ( ready_i & valid_o ) 49 | ); 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /packages/dependencies/cv64a6_imafdc_sv39_config_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Thales DIS design services SAS 2 | // 3 | // Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 6 | // You may obtain a copy of the License at https://solderpad.org/licenses/ 7 | // 8 | // Original Author: Jean-Roch COULON - Thales 9 | 10 | `ifndef CVA6_CONFIG 11 | `define CVA6_CONFIG 12 | package cva6_config_pkg; 13 | 14 | localparam CVA6ConfigXlen = 64; 15 | 16 | localparam CVA6ConfigFpuEn = 1; 17 | localparam CVA6ConfigF16En = 0; 18 | localparam CVA6ConfigF16AltEn = 0; 19 | localparam CVA6ConfigF8En = 0; 20 | localparam CVA6ConfigFVecEn = 0; 21 | 22 | localparam CVA6ConfigCvxifEn = 1; 23 | localparam CVA6ConfigCExtEn = 1; 24 | localparam CVA6ConfigAExtEn = 1; 25 | localparam CVA6ConfigHExtEn = 0; // hypervisor extension disabled by default 26 | 27 | localparam CVA6ConfigFetchUserEn = 0; 28 | localparam CVA6ConfigFetchUserWidth = CVA6ConfigXlen; 29 | localparam CVA6ConfigDataUserEn = 0; 30 | localparam CVA6ConfigDataUserWidth = CVA6ConfigXlen; 31 | 32 | localparam CVA6ConfigRenameEn = 0; 33 | 34 | localparam CVA6ConfigIcacheSetAssoc = 4; 35 | localparam CVA6ConfigIcacheLines = 4096; 36 | localparam CVA6ConfigIcacheLineWidth = 128; 37 | localparam CVA6ConfigDcacheSetAssoc = 8; 38 | localparam CVA6ConfigDcacheLines = 4096; 39 | localparam CVA6ConfigDcacheLineWidth = 128; 40 | 41 | localparam CVA6ConfigNrCommitPorts = 2; 42 | localparam CVA6ConfigNrScoreboardEntries = 8; 43 | 44 | localparam CVA6ConfigFPGAEn = 0; 45 | 46 | localparam CVA6ConfigNrLoadPipeRegs = 1; 47 | localparam CVA6ConfigNrStorePipeRegs = 0; 48 | 49 | localparam CVA6ConfigInstrTlbEntries = 16; 50 | localparam CVA6ConfigDataTlbEntries = 16; 51 | 52 | localparam CVA6ConfigRASDepth = 2; 53 | localparam CVA6ConfigBTBEntries = 32; 54 | localparam CVA6ConfigBHTEntries = 128; 55 | 56 | localparam CVA6ConfigNrPMPEntries = 8; 57 | 58 | endpackage 59 | 60 | `endif 61 | -------------------------------------------------------------------------------- /vendor/stream_arbiter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Stream arbiter: Arbitrates a parametrizable number of input streams (i.e., valid-ready 12 | // handshaking with dependency rules as in AXI4) to a single output stream. Once `oup_valid_o` is 13 | // asserted, `oup_data_o` remains invariant until the output handshake has occurred. The 14 | // arbitration scheme is round-robin with "look ahead", see the `rrarbiter` for details. 15 | 16 | module stream_arbiter #( 17 | parameter type DATA_T = logic, // Vivado requires a default value for type parameters. 18 | parameter integer N_INP = -1, // Synopsys DC requires a default value for parameters. 19 | parameter ARBITER = "rr" // "rr" or "prio" 20 | ) ( 21 | input logic clk_i, 22 | input logic rst_ni, 23 | 24 | input DATA_T [N_INP-1:0] inp_data_i, 25 | input logic [N_INP-1:0] inp_valid_i, 26 | output logic [N_INP-1:0] inp_ready_o, 27 | 28 | output DATA_T oup_data_o, 29 | output logic oup_valid_o, 30 | input logic oup_ready_i 31 | ); 32 | 33 | stream_arbiter_flushable #( 34 | .DATA_T (DATA_T), 35 | .N_INP (N_INP), 36 | .ARBITER (ARBITER) 37 | ) i_arb ( 38 | .clk_i (clk_i), 39 | .rst_ni (rst_ni), 40 | .flush_i (1'b0), 41 | .inp_data_i (inp_data_i), 42 | .inp_valid_i (inp_valid_i), 43 | .inp_ready_o (inp_ready_o), 44 | .oup_data_o (oup_data_o), 45 | .oup_valid_o (oup_valid_o), 46 | .oup_ready_i (oup_ready_i) 47 | ); 48 | 49 | endmodule 50 | -------------------------------------------------------------------------------- /vendor/axi_b_buffer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Davide Rossi 12 | 13 | module axi_b_buffer #( 14 | parameter int ID_WIDTH = -1, 15 | parameter int USER_WIDTH = -1, 16 | parameter int BUFFER_DEPTH = -1 17 | )( 18 | input logic clk_i, 19 | input logic rst_ni, 20 | input logic test_en_i, 21 | 22 | input logic slave_valid_i, 23 | input logic [1:0] slave_resp_i, 24 | input logic [ID_WIDTH-1:0] slave_id_i, 25 | input logic [USER_WIDTH-1:0] slave_user_i, 26 | output logic slave_ready_o, 27 | 28 | output logic master_valid_o, 29 | output logic [1:0] master_resp_o, 30 | output logic [ID_WIDTH-1:0] master_id_o, 31 | output logic [USER_WIDTH-1:0] master_user_o, 32 | input logic master_ready_i 33 | ); 34 | 35 | logic [2+USER_WIDTH+ID_WIDTH-1:0] s_data_in; 36 | logic [2+USER_WIDTH+ID_WIDTH-1:0] s_data_out; 37 | 38 | assign s_data_in = {slave_id_i, slave_user_i, slave_resp_i}; 39 | assign {master_id_o, master_user_o, master_resp_o} = s_data_out; 40 | 41 | 42 | axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(2+USER_WIDTH+ID_WIDTH)) i_axi_single_slice ( 43 | .clk_i ( clk_i ), 44 | .rst_ni ( rst_ni ), 45 | .testmode_i ( test_en_i ), 46 | .valid_i ( slave_valid_i ), 47 | .ready_o ( slave_ready_o ), 48 | .data_i ( s_data_in ), 49 | .ready_i ( master_ready_i ), 50 | .valid_o ( master_valid_o ), 51 | .data_o ( s_data_out ) 52 | ); 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /vendor/stream_register.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | /// Register with a simple stream-like ready/valid handshake. 12 | /// This register does not cut combinatorial paths on all control signals; if you need a complete 13 | /// cut, use the `spill_register`. 14 | module stream_register #( 15 | parameter type T = logic // Vivado requires a default value for type parameters. 16 | ) ( 17 | input logic clk_i, // Clock 18 | input logic rst_ni, // Asynchronous active-low reset 19 | input logic clr_i, // Synchronous clear 20 | input logic testmode_i, // Test mode to bypass clock gating 21 | // Input port 22 | input logic valid_i, 23 | output logic ready_o, 24 | input T data_i, 25 | // Output port 26 | output logic valid_o, 27 | input logic ready_i, 28 | output T data_o 29 | ); 30 | 31 | logic fifo_empty, 32 | fifo_full; 33 | 34 | fifo_v2 #( 35 | .FALL_THROUGH (1'b0), 36 | .DATA_WIDTH ($bits(T)), 37 | .DEPTH (1), 38 | .dtype (T) 39 | ) i_fifo ( 40 | .clk_i (clk_i), 41 | .rst_ni (rst_ni), 42 | .flush_i (clr_i), 43 | .testmode_i (testmode_i), 44 | .full_o (fifo_full), 45 | .empty_o (fifo_empty), 46 | .alm_full_o ( ), 47 | .alm_empty_o ( ), 48 | .data_i (data_i), 49 | .push_i (valid_i & ~fifo_full), 50 | .data_o (data_o), 51 | .pop_i (ready_i & ~fifo_empty) 52 | ); 53 | 54 | assign ready_o = ~fifo_full; 55 | assign valid_o = ~fifo_empty; 56 | 57 | endmodule 58 | -------------------------------------------------------------------------------- /vendor/axi_w_buffer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Davide Rossi 12 | 13 | module axi_w_buffer #( 14 | parameter int DATA_WIDTH = -1, 15 | parameter int USER_WIDTH = -1, 16 | parameter int BUFFER_DEPTH = -1, 17 | parameter int STRB_WIDTH = DATA_WIDTH/8 // DO NOT OVERRIDE 18 | )( 19 | input logic clk_i, 20 | input logic rst_ni, 21 | input logic test_en_i, 22 | 23 | input logic slave_valid_i, 24 | input logic [DATA_WIDTH-1:0] slave_data_i, 25 | input logic [STRB_WIDTH-1:0] slave_strb_i, 26 | input logic [USER_WIDTH-1:0] slave_user_i, 27 | input logic slave_last_i, 28 | output logic slave_ready_o, 29 | 30 | output logic master_valid_o, 31 | output logic [DATA_WIDTH-1:0] master_data_o, 32 | output logic [STRB_WIDTH-1:0] master_strb_o, 33 | output logic [USER_WIDTH-1:0] master_user_o, 34 | output logic master_last_o, 35 | input logic master_ready_i 36 | ); 37 | 38 | logic [DATA_WIDTH+STRB_WIDTH+USER_WIDTH:0] s_data_in; 39 | logic [DATA_WIDTH+STRB_WIDTH+USER_WIDTH:0] s_data_out; 40 | 41 | assign s_data_in = { slave_user_i, slave_strb_i, slave_data_i, slave_last_i }; 42 | assign { master_user_o, master_strb_o, master_data_o, master_last_o } = s_data_out; 43 | 44 | axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(1+DATA_WIDTH+STRB_WIDTH+USER_WIDTH)) i_axi_single_slice ( 45 | .clk_i ( clk_i ), 46 | .rst_ni ( rst_ni ), 47 | .testmode_i ( test_en_i ), 48 | .valid_i ( slave_valid_i ), 49 | .ready_o ( slave_ready_o ), 50 | .data_i ( s_data_in ), 51 | .ready_i ( master_ready_i ), 52 | .valid_o ( master_valid_o ), 53 | .data_o ( s_data_out ) 54 | ); 55 | endmodule 56 | -------------------------------------------------------------------------------- /vendor/axi_r_buffer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Davide Rossi 12 | 13 | module axi_r_buffer #( 14 | parameter ID_WIDTH = 4, 15 | parameter DATA_WIDTH = 64, 16 | parameter USER_WIDTH = 6, 17 | parameter BUFFER_DEPTH = 8, 18 | parameter STRB_WIDTH = DATA_WIDTH/8 // DO NOT OVERRIDE 19 | )( 20 | input logic clk_i, 21 | input logic rst_ni, 22 | input logic test_en_i, 23 | 24 | input logic slave_valid_i, 25 | input logic [DATA_WIDTH-1:0] slave_data_i, 26 | input logic [1:0] slave_resp_i, 27 | input logic [USER_WIDTH-1:0] slave_user_i, 28 | input logic [ID_WIDTH-1:0] slave_id_i, 29 | input logic slave_last_i, 30 | output logic slave_ready_o, 31 | 32 | output logic master_valid_o, 33 | output logic [DATA_WIDTH-1:0] master_data_o, 34 | output logic [1:0] master_resp_o, 35 | output logic [USER_WIDTH-1:0] master_user_o, 36 | output logic [ID_WIDTH-1:0] master_id_o, 37 | output logic master_last_o, 38 | input logic master_ready_i 39 | ); 40 | 41 | logic [2+DATA_WIDTH+USER_WIDTH+ID_WIDTH:0] s_data_in; 42 | logic [2+DATA_WIDTH+USER_WIDTH+ID_WIDTH:0] s_data_out; 43 | 44 | 45 | assign s_data_in = {slave_id_i, slave_user_i, slave_data_i, slave_resp_i, slave_last_i}; 46 | assign {master_id_o, master_user_o, master_data_o, master_resp_o, master_last_o} = s_data_out; 47 | 48 | axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(3+DATA_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice ( 49 | .clk_i ( clk_i ), 50 | .rst_ni ( rst_ni ), 51 | .testmode_i ( test_en_i ), 52 | .valid_i ( slave_valid_i ), 53 | .ready_o ( slave_ready_o ), 54 | .data_i ( s_data_in ), 55 | .ready_i ( master_ready_i ), 56 | .valid_o ( master_valid_o ), 57 | .data_o ( s_data_out ) 58 | ); 59 | 60 | endmodule 61 | -------------------------------------------------------------------------------- /packages/dependencies/cf_math_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2016 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | /// cf_math_pkg: Constant Function Implementations of Mathematical Functions for HDL Elaboration 12 | /// 13 | /// This package contains a collection of mathematical functions that are commonly used when defining 14 | /// the value of constants in HDL code. These functions are implemented as Verilog constants 15 | /// functions. Introduced in Verilog 2001 (IEEE Std 1364-2001), a constant function (§ 10.3.5) is a 16 | /// function whose value can be evaluated at compile time or during elaboration. A constant function 17 | /// must be called with arguments that are constants. 18 | 19 | `ifndef CF_MATH_PKG_DEF 20 | `define CF_MATH_PKG_DEF 21 | 22 | package cf_math_pkg; 23 | 24 | /// Ceiled Division of Two Natural Numbers 25 | /// 26 | /// Returns the quotient of two natural numbers, rounded towards plus infinity. 27 | function automatic integer ceil_div (input longint dividend, input longint divisor); 28 | automatic longint remainder; 29 | 30 | // pragma translate_off 31 | `ifndef VERILATOR 32 | if (dividend < 0) begin 33 | $fatal(1, "Dividend %0d is not a natural number!", dividend); 34 | end 35 | 36 | if (divisor < 0) begin 37 | $fatal(1, "Divisor %0d is not a natural number!", divisor); 38 | end 39 | 40 | if (divisor == 0) begin 41 | $fatal(1, "Division by zero!"); 42 | end 43 | `endif 44 | // pragma translate_on 45 | 46 | remainder = dividend; 47 | for (ceil_div = 0; remainder > 0; ceil_div++) begin 48 | remainder = remainder - divisor; 49 | end 50 | endfunction 51 | 52 | /// Index width required to be able to represent up to `num_idx` indices as a binary 53 | /// encoded signal. 54 | /// Ensures that the minimum width if an index signal is `1`, regardless of parametrization. 55 | /// 56 | /// Sample usage in type definition: 57 | /// As parameter: 58 | /// `parameter type idx_t = logic[cf_math_pkg::idx_width(NumIdx)-1:0]` 59 | /// As typedef: 60 | /// `typedef logic [cf_math_pkg::idx_width(NumIdx)-1:0] idx_t` 61 | function automatic integer unsigned idx_width (input integer unsigned num_idx); 62 | return (num_idx > 32'd1) ? unsigned'($clog2(num_idx)) : 32'd1; 63 | endfunction 64 | 65 | endpackage 66 | 67 | `endif -------------------------------------------------------------------------------- /vendor/fifo.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Author: Florian Zaruba 12 | 13 | /* verilator lint_off DECLFILENAME */ 14 | module fifo #( 15 | parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode 16 | parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic 17 | parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32 18 | parameter int unsigned THRESHOLD = 1, // fill count until when to assert threshold_o 19 | parameter type dtype = logic [DATA_WIDTH-1:0] 20 | )( 21 | input logic clk_i, // Clock 22 | input logic rst_ni, // Asynchronous reset active low 23 | input logic flush_i, // flush the queue 24 | input logic testmode_i, // test_mode to bypass clock gating 25 | // status flags 26 | output logic full_o, // queue is full 27 | output logic empty_o, // queue is empty 28 | output logic threshold_o, // the FIFO is above the specified threshold 29 | // as long as the queue is not full we can push new data 30 | input dtype data_i, // data to push into the queue 31 | input logic push_i, // data is valid and can be pushed to the queue 32 | // as long as the queue is not empty we can pop new elements 33 | output dtype data_o, // output data 34 | input logic pop_i // pop head from queue 35 | ); 36 | fifo_v2 #( 37 | .FALL_THROUGH ( FALL_THROUGH ), 38 | .DATA_WIDTH ( DATA_WIDTH ), 39 | .DEPTH ( DEPTH ), 40 | .ALM_FULL_TH ( THRESHOLD ), 41 | .dtype ( dtype ) 42 | ) impl ( 43 | .clk_i ( clk_i ), 44 | .rst_ni ( rst_ni ), 45 | .flush_i ( flush_i ), 46 | .testmode_i ( testmode_i ), 47 | .full_o ( full_o ), 48 | .empty_o ( empty_o ), 49 | .alm_full_o ( threshold_o ), 50 | .alm_empty_o ( ), 51 | .data_i ( data_i ), 52 | .push_i ( push_i ), 53 | .data_o ( data_o ), 54 | .pop_i ( pop_i ) 55 | ); 56 | endmodule 57 | /* verilator lint_on DECLFILENAME */ 58 | -------------------------------------------------------------------------------- /vendor/delta_counter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Up/down counter with variable delta 12 | 13 | module delta_counter #( 14 | parameter int unsigned WIDTH = 4, 15 | parameter bit STICKY_OVERFLOW = 1'b0 16 | )( 17 | input logic clk_i, 18 | input logic rst_ni, 19 | input logic clear_i, // synchronous clear 20 | input logic en_i, // enable the counter 21 | input logic load_i, // load a new value 22 | input logic down_i, // downcount, default is up 23 | input logic [WIDTH-1:0] delta_i, 24 | input logic [WIDTH-1:0] d_i, 25 | output logic [WIDTH-1:0] q_o, 26 | output logic overflow_o 27 | ); 28 | logic [WIDTH:0] counter_q, counter_d; 29 | if (STICKY_OVERFLOW) begin : gen_sticky_overflow 30 | logic overflow_d, overflow_q; 31 | always_ff @(posedge clk_i or negedge rst_ni) overflow_q <= ~rst_ni ? 1'b0 : overflow_d; 32 | always_comb begin 33 | overflow_d = overflow_q; 34 | if (clear_i || load_i) begin 35 | overflow_d = 1'b0; 36 | end else if (!overflow_q && en_i) begin 37 | if (down_i) begin 38 | overflow_d = delta_i > counter_q[WIDTH-1:0]; 39 | end else begin 40 | overflow_d = counter_q[WIDTH-1:0] > ({WIDTH{1'b1}} - delta_i); 41 | end 42 | end 43 | end 44 | assign overflow_o = overflow_q; 45 | end else begin : gen_transient_overflow 46 | // counter overflowed if the MSB is set 47 | assign overflow_o = counter_q[WIDTH]; 48 | end 49 | assign q_o = counter_q[WIDTH-1:0]; 50 | 51 | always_comb begin 52 | counter_d = counter_q; 53 | 54 | if (clear_i) begin 55 | counter_d = '0; 56 | end else if (load_i) begin 57 | counter_d = {1'b0, d_i}; 58 | end else if (en_i) begin 59 | if (down_i) begin 60 | counter_d = counter_q - delta_i; 61 | end else begin 62 | counter_d = counter_q + delta_i; 63 | end 64 | end 65 | end 66 | 67 | always_ff @(posedge clk_i or negedge rst_ni) begin 68 | if (!rst_ni) begin 69 | counter_q <= '0; 70 | end else begin 71 | counter_q <= counter_d; 72 | end 73 | end 74 | endmodule 75 | -------------------------------------------------------------------------------- /vendor/stream_arbiter_flushable.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Stream arbiter: Arbitrates a parametrizable number of input streams (i.e., valid-ready 12 | // handshaking with dependency rules as in AXI4) to a single output stream. Once `oup_valid_o` is 13 | // asserted, `oup_data_o` remains invariant until the output handshake has occurred. The 14 | // arbitration scheme is fair round-robin tree, see `rr_arb_tree` for details. 15 | 16 | module stream_arbiter_flushable #( 17 | parameter type DATA_T = logic, // Vivado requires a default value for type parameters. 18 | parameter integer N_INP = -1, // Synopsys DC requires a default value for parameters. 19 | parameter ARBITER = "rr" // "rr" or "prio" 20 | ) ( 21 | input logic clk_i, 22 | input logic rst_ni, 23 | input logic flush_i, 24 | 25 | input DATA_T [N_INP-1:0] inp_data_i, 26 | input logic [N_INP-1:0] inp_valid_i, 27 | output logic [N_INP-1:0] inp_ready_o, 28 | 29 | output DATA_T oup_data_o, 30 | output logic oup_valid_o, 31 | input logic oup_ready_i 32 | ); 33 | 34 | if (ARBITER == "rr") begin : gen_rr_arb 35 | rr_arb_tree #( 36 | .NumIn (N_INP), 37 | .DataType (DATA_T), 38 | .ExtPrio (1'b0), 39 | .AxiVldRdy (1'b1), 40 | .LockIn (1'b1) 41 | ) i_arbiter ( 42 | .clk_i, 43 | .rst_ni, 44 | .flush_i, 45 | .rr_i ('0), 46 | .req_i (inp_valid_i), 47 | .gnt_o (inp_ready_o), 48 | .data_i (inp_data_i), 49 | .gnt_i (oup_ready_i), 50 | .req_o (oup_valid_o), 51 | .data_o (oup_data_o), 52 | .idx_o () 53 | ); 54 | 55 | end else if (ARBITER == "prio") begin : gen_prio_arb 56 | rr_arb_tree #( 57 | .NumIn (N_INP), 58 | .DataType (DATA_T), 59 | .ExtPrio (1'b1), 60 | .AxiVldRdy (1'b1), 61 | .LockIn (1'b1) 62 | ) i_arbiter ( 63 | .clk_i, 64 | .rst_ni, 65 | .flush_i, 66 | .rr_i ('0), 67 | .req_i (inp_valid_i), 68 | .gnt_o (inp_ready_o), 69 | .data_i (inp_data_i), 70 | .gnt_i (oup_ready_i), 71 | .req_o (oup_valid_o), 72 | .data_o (oup_data_o), 73 | .idx_o () 74 | ); 75 | 76 | end else begin : gen_arb_error 77 | // pragma translate_off 78 | $fatal(1, "Invalid value for parameter 'ARBITER'!"); 79 | // pragma translate_on 80 | end 81 | 82 | endmodule 83 | -------------------------------------------------------------------------------- /rtl/software_interface/regmap/rv_iommu_field.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 12/10/2022 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: IOMMU Register Field module. 18 | // 19 | // Disclaimer: This file was generated using LowRISC `reggen` tool. Edit at your own risk. 20 | 21 | module rv_iommu_field 22 | import rv_iommu_field_pkg::*; 23 | #( 24 | parameter int DATA_WIDTH = 32, // bit width of the register field (2-state) 25 | parameter rv_iommu_field_pkg::sw_access_e SwAccess = SwAccessRW, // SW access permission 26 | parameter logic [DATA_WIDTH-1:0] RESVAL = '0 // reset value, 27 | ) 28 | ( 29 | input clk_i, 30 | input rst_ni, 31 | 32 | // Signals from SW side: valid for RW, WO, W1C, W1S, W0C, RC 33 | // In case of RC, top module connects Read Pulse to WE. WD should be 1'b0 in this case ??? 34 | input we, // SW WE 35 | input [DATA_WIDTH-1:0] wd, // SW WD 36 | 37 | // From HW: valid for HRW, HWO 38 | input de, // HW WE 39 | input [DATA_WIDTH-1:0] d, // HW WD 40 | 41 | // To HW and SW Reg IF read 42 | output logic qe, // definitive write enable 43 | output logic [DATA_WIDTH-1:0] q, // HW read port 44 | 45 | output logic [DATA_WIDTH-1:0] ds, 46 | output logic [DATA_WIDTH-1:0] qs // SW read port 47 | ); 48 | 49 | import rv_iommu_field_pkg::*; 50 | 51 | // Write arbiter output signals. 52 | // It takes WE, WD, DE, D, Q signals and yields the valid WE and WD that will cause writes to the register 53 | logic arb_wr_en; 54 | logic [DATA_WIDTH-1:0] arb_wr_data; 55 | 56 | // Data write arbiter 57 | rv_iommu_field_arb #( 58 | .DATA_WIDTH(DATA_WIDTH), 59 | .SwAccess(SwAccess) 60 | ) int_wr_arb( 61 | .we(we), 62 | .wd(wd), 63 | .de(de), 64 | .d(d), 65 | .q(q), 66 | 67 | .wr_en(arb_wr_en), // Arbitrated WE 68 | .wr_data(arb_wr_data) // Arbitrated WD 69 | ); 70 | 71 | // Register update logic 72 | always_ff @(posedge clk_i or negedge rst_ni) begin 73 | if (!rst_ni) begin 74 | q <= RESVAL; 75 | end 76 | else if (arb_wr_en) begin 77 | q <= arb_wr_data; 78 | end 79 | end 80 | 81 | // outputs 82 | assign ds = arb_wr_en ? arb_wr_data : qs; 83 | assign qe = arb_wr_en; 84 | assign qs = q; 85 | endmodule -------------------------------------------------------------------------------- /vendor/axi_ar_buffer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Davide Rossi 12 | 13 | module axi_ar_buffer #( 14 | parameter int ID_WIDTH = -1, 15 | parameter int ADDR_WIDTH = -1, 16 | parameter int USER_WIDTH = -1, 17 | parameter int BUFFER_DEPTH = -1 18 | )( 19 | 20 | input logic clk_i, 21 | input logic rst_ni, 22 | input logic test_en_i, 23 | 24 | input logic slave_valid_i, 25 | input logic [ADDR_WIDTH-1:0] slave_addr_i, 26 | input logic [2:0] slave_prot_i, 27 | input logic [3:0] slave_region_i, 28 | input logic [7:0] slave_len_i, 29 | input logic [2:0] slave_size_i, 30 | input logic [1:0] slave_burst_i, 31 | input logic slave_lock_i, 32 | input logic [3:0] slave_cache_i, 33 | input logic [3:0] slave_qos_i, 34 | input logic [ID_WIDTH-1:0] slave_id_i, 35 | input logic [USER_WIDTH-1:0] slave_user_i, 36 | output logic slave_ready_o, 37 | 38 | output logic master_valid_o, 39 | output logic [ADDR_WIDTH-1:0] master_addr_o, 40 | output logic [2:0] master_prot_o, 41 | output logic [3:0] master_region_o, 42 | output logic [7:0] master_len_o, 43 | output logic [2:0] master_size_o, 44 | output logic [1:0] master_burst_o, 45 | output logic master_lock_o, 46 | output logic [3:0] master_cache_o, 47 | output logic [3:0] master_qos_o, 48 | output logic [ID_WIDTH-1:0] master_id_o, 49 | output logic [USER_WIDTH-1:0] master_user_o, 50 | input logic master_ready_i 51 | ); 52 | 53 | logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_in; 54 | logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_out; 55 | 56 | assign s_data_in = {slave_cache_i, slave_prot_i, slave_lock_i, slave_burst_i, slave_size_i, slave_len_i, slave_qos_i, slave_region_i, slave_addr_i, slave_user_i, slave_id_i} ; 57 | assign {master_cache_o, master_prot_o, master_lock_o, master_burst_o, master_size_o, master_len_o, master_qos_o, master_region_o, master_addr_o, master_user_o, master_id_o} = s_data_out; 58 | 59 | 60 | 61 | axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice ( 62 | .clk_i ( clk_i ), 63 | .rst_ni ( rst_ni ), 64 | .testmode_i ( test_en_i ), 65 | .valid_i ( slave_valid_i ), 66 | .ready_o ( slave_ready_o ), 67 | .data_i ( s_data_in ), 68 | .ready_i ( master_ready_i ), 69 | .valid_o ( master_valid_o ), 70 | .data_o ( s_data_out ) 71 | ); 72 | 73 | 74 | endmodule 75 | -------------------------------------------------------------------------------- /vendor/axi_aw_buffer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Davide Rossi 12 | 13 | module axi_aw_buffer #( 14 | parameter int ID_WIDTH = -1, 15 | parameter int ADDR_WIDTH = -1, 16 | parameter int USER_WIDTH = -1, 17 | parameter int BUFFER_DEPTH = -1 18 | )( 19 | 20 | input logic clk_i, 21 | input logic rst_ni, 22 | input logic test_en_i, 23 | 24 | input logic slave_valid_i, 25 | input logic [ADDR_WIDTH-1:0] slave_addr_i, 26 | input logic [2:0] slave_prot_i, 27 | input logic [3:0] slave_region_i, 28 | input logic [7:0] slave_len_i, 29 | input logic [2:0] slave_size_i, 30 | input logic [1:0] slave_burst_i, 31 | input logic slave_lock_i, 32 | input logic [3:0] slave_cache_i, 33 | input logic [3:0] slave_qos_i, 34 | input logic [ID_WIDTH-1:0] slave_id_i, 35 | input logic [USER_WIDTH-1:0] slave_user_i, 36 | output logic slave_ready_o, 37 | 38 | output logic master_valid_o, 39 | output logic [ADDR_WIDTH-1:0] master_addr_o, 40 | output logic [2:0] master_prot_o, 41 | output logic [3:0] master_region_o, 42 | output logic [7:0] master_len_o, 43 | output logic [2:0] master_size_o, 44 | output logic [1:0] master_burst_o, 45 | output logic master_lock_o, 46 | output logic [3:0] master_cache_o, 47 | output logic [3:0] master_qos_o, 48 | output logic [ID_WIDTH-1:0] master_id_o, 49 | output logic [USER_WIDTH-1:0] master_user_o, 50 | input logic master_ready_i 51 | ); 52 | 53 | logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_in; 54 | logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_out; 55 | 56 | 57 | 58 | assign s_data_in = {slave_cache_i, slave_prot_i, slave_lock_i, slave_burst_i, slave_size_i, slave_len_i, slave_qos_i, slave_region_i, slave_addr_i, slave_user_i, slave_id_i}; 59 | assign {master_cache_o, master_prot_o, master_lock_o, master_burst_o, master_size_o, master_len_o, master_qos_o, master_region_o, master_addr_o, master_user_o, master_id_o} = s_data_out; 60 | 61 | 62 | axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice ( 63 | .clk_i ( clk_i ), 64 | .rst_ni ( rst_ni ), 65 | .testmode_i ( test_en_i ), 66 | .valid_i ( slave_valid_i ), 67 | .ready_o ( slave_ready_o ), 68 | .data_i ( s_data_in ), 69 | .ready_i ( master_ready_i ), 70 | .valid_o ( master_valid_o ), 71 | .data_o ( s_data_out ) 72 | ); 73 | 74 | endmodule 75 | -------------------------------------------------------------------------------- /vendor/fifo_v2.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Author: Florian Zaruba 12 | 13 | module fifo_v2 #( 14 | parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode 15 | parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic 16 | parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32 17 | parameter int unsigned ALM_EMPTY_TH = 1, // almost empty threshold (when to assert alm_empty_o) 18 | parameter int unsigned ALM_FULL_TH = 1, // almost full threshold (when to assert alm_full_o) 19 | parameter type dtype = logic [DATA_WIDTH-1:0], 20 | // DO NOT OVERWRITE THIS PARAMETER 21 | parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 22 | )( 23 | input logic clk_i, // Clock 24 | input logic rst_ni, // Asynchronous reset active low 25 | input logic flush_i, // flush the queue 26 | input logic testmode_i, // test_mode to bypass clock gating 27 | // status flags 28 | output logic full_o, // queue is full 29 | output logic empty_o, // queue is empty 30 | output logic alm_full_o, // FIFO fillstate >= the specified threshold 31 | output logic alm_empty_o, // FIFO fillstate <= the specified threshold 32 | // as long as the queue is not full we can push new data 33 | input dtype data_i, // data to push into the queue 34 | input logic push_i, // data is valid and can be pushed to the queue 35 | // as long as the queue is not empty we can pop new elements 36 | output dtype data_o, // output data 37 | input logic pop_i // pop head from queue 38 | ); 39 | 40 | logic [ADDR_DEPTH-1:0] usage; 41 | 42 | // generate threshold parameters 43 | if (DEPTH == 0) begin 44 | assign alm_full_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0 45 | assign alm_empty_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0 46 | end else begin 47 | assign alm_full_o = (usage >= ALM_FULL_TH[ADDR_DEPTH-1:0]); 48 | /* verilator lint_off CMPCONST */ 49 | assign alm_empty_o = (usage <= ALM_EMPTY_TH[ADDR_DEPTH-1:0]); 50 | /* verilator lint_on CMPCONST */ 51 | end 52 | 53 | fifo_v3 #( 54 | .FALL_THROUGH ( FALL_THROUGH ), 55 | .DATA_WIDTH ( DATA_WIDTH ), 56 | .DEPTH ( DEPTH ), 57 | .dtype ( dtype ) 58 | ) i_fifo_v3 ( 59 | .clk_i, 60 | .rst_ni, 61 | .flush_i, 62 | .testmode_i, 63 | .full_o, 64 | .empty_o, 65 | .usage_o (usage), 66 | .data_i, 67 | .push_i, 68 | .data_o, 69 | .pop_i 70 | ); 71 | 72 | // pragma translate_off 73 | `ifndef VERILATOR 74 | initial begin 75 | assert (ALM_FULL_TH <= DEPTH) else $error("ALM_FULL_TH can't be larger than the DEPTH."); 76 | assert (ALM_EMPTY_TH <= DEPTH) else $error("ALM_EMPTY_TH can't be larger than the DEPTH."); 77 | end 78 | `endif 79 | // pragma translate_on 80 | 81 | endmodule // fifo_v2 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | __pycache__/* 4 | sim_build/ 5 | sim_build/* 6 | *.py[cod] 7 | *$py.class 8 | *.xml 9 | *.fst 10 | *.vcd 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | cover/ 59 | 60 | # Translations 61 | *.mo 62 | *.pot 63 | 64 | # Django stuff: 65 | *.log 66 | local_settings.py 67 | db.sqlite3 68 | db.sqlite3-journal 69 | 70 | # Flask stuff: 71 | instance/ 72 | .webassets-cache 73 | 74 | # Scrapy stuff: 75 | .scrapy 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | .pybuilder/ 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | # For a library or package, you might want to ignore these files since the code is 93 | # intended to run in multiple environments; otherwise, check them in: 94 | # .python-version 95 | 96 | # pipenv 97 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 98 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 99 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 100 | # install all needed dependencies. 101 | #Pipfile.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/#use-with-ide 116 | .pdm.toml 117 | 118 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 119 | __pypackages__/ 120 | 121 | # Celery stuff 122 | celerybeat-schedule 123 | celerybeat.pid 124 | 125 | # SageMath parsed files 126 | *.sage.py 127 | 128 | # Environments 129 | .env 130 | .venv 131 | env/ 132 | venv/ 133 | ENV/ 134 | env.bak/ 135 | venv.bak/ 136 | 137 | # Spyder project settings 138 | .spyderproject 139 | .spyproject 140 | 141 | # Rope project settings 142 | .ropeproject 143 | 144 | # mkdocs documentation 145 | /site 146 | 147 | # mypy 148 | .mypy_cache/ 149 | .dmypy.json 150 | dmypy.json 151 | 152 | # Pyre type checker 153 | .pyre/ 154 | 155 | # pytype static type analyzer 156 | .pytype/ 157 | 158 | # Cython debug symbols 159 | cython_debug/ 160 | 161 | # PyCharm 162 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 163 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 164 | # and can be added to the global gitignore or merged into this file. For a more nuclear 165 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 166 | #.idea/ 167 | 168 | # Custom 169 | *.txt 170 | formal/ -------------------------------------------------------------------------------- /lint_checks.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 28/03/2023 15 | // 16 | // Description: Top module to instance riscv_iommu module, 17 | // defining parameters and types for lint checks. 18 | 19 | `include "assertions.svh" 20 | `include "register_interface/typedef.svh" 21 | 22 | `include "riscv_pkg.sv" 23 | `include "lint_wrapper_pkg.sv" 24 | 25 | `include "rv_iommu_pkg.sv" 26 | `include "rv_iommu_reg_pkg.sv" 27 | `include "rv_iommu_field_pkg.sv" 28 | 29 | module lint_checks 30 | import lint_wrapper::*; 31 | import rv_iommu::*; 32 | ( 33 | 34 | input logic clk_i, 35 | input logic rst_ni, 36 | 37 | // Translation Request Interface (Slave) 38 | input req_iommu_t dev_tr_req_i, 39 | output resp_t dev_tr_resp_o, 40 | 41 | // Translation Completion Interface (Master) 42 | input resp_t dev_comp_resp_i, 43 | output req_t dev_comp_req_o, 44 | 45 | // Data Structures Interface (Master) 46 | input resp_t ds_resp_i, 47 | output req_t ds_req_o, 48 | 49 | // Programming Interface (Slave) 50 | input req_slv_t prog_req_i, 51 | output resp_slv_t prog_resp_o, 52 | 53 | output logic [NumIRQWires-1:0] wsi_wires_o 54 | ); 55 | 56 | typedef logic [64-1:0] reg_addr_t; 57 | typedef logic [32-1:0] reg_data_t; 58 | typedef logic [4-1:0] reg_strb_t; 59 | 60 | // Define reg_req_t and reg_rsp_t structs 61 | `REG_BUS_TYPEDEF_ALL(iommu_reg, reg_addr_t, reg_data_t, reg_strb_t) 62 | 63 | riscv_iommu #( 64 | .IOTLB_ENTRIES ( 16 ), 65 | .DDTC_ENTRIES ( 8 ), 66 | .PDTC_ENTRIES ( 8 ), 67 | .MRIFC_ENTRIES ( 4 ), 68 | 69 | .InclPC ( 1'b1 ), 70 | .InclBC ( 1'b1 ), 71 | .InclDBG ( 1'b1 ), 72 | 73 | .MSITrans ( MSI_FLAT_MRIF ), 74 | .IGS ( BOTH ), 75 | .N_INT_VEC ( NumIRQWires ), 76 | .N_IOHPMCTR ( 16 ), 77 | 78 | .ADDR_WIDTH ( AddrWidth ), 79 | .DATA_WIDTH ( DataWidth ), 80 | .ID_WIDTH ( IdWidth ), 81 | .ID_SLV_WIDTH ( IdWidthSlv ), 82 | .USER_WIDTH ( UserWidth ), 83 | .aw_chan_t ( aw_chan_t ), 84 | .w_chan_t ( w_chan_t ), 85 | .b_chan_t ( b_chan_t ), 86 | .ar_chan_t ( ar_chan_t ), 87 | .r_chan_t ( r_chan_t ), 88 | .axi_req_t ( req_t ), 89 | .axi_rsp_t ( resp_t ), 90 | .axi_req_slv_t ( req_slv_t ), 91 | .axi_rsp_slv_t ( resp_slv_t ), 92 | .axi_req_iommu_t ( req_iommu_t ), 93 | .reg_req_t ( iommu_reg_req_t ), 94 | .reg_rsp_t ( iommu_reg_rsp_t ) 95 | ) i_riscv_iommu ( 96 | 97 | .clk_i ( clk_i ), 98 | .rst_ni ( rst_ni ), 99 | 100 | // Translation Request Interface (Slave) 101 | .dev_tr_req_i ( dev_tr_req_i ), 102 | .dev_tr_resp_o ( dev_tr_resp_o ), 103 | 104 | // Translation Completion Interface (Master) 105 | .dev_comp_resp_i ( dev_comp_resp_i ), 106 | .dev_comp_req_o ( dev_comp_req_o ), 107 | 108 | // Implicit Memory Accesses Interface (Master) 109 | .ds_resp_i ( ds_resp_i ), 110 | .ds_req_o ( ds_req_o ), 111 | 112 | // Programming Interface (Slave) 113 | .prog_req_i ( prog_req_i ), 114 | .prog_resp_o ( prog_resp_o ), 115 | 116 | .wsi_wires_o ( wsi_wires_o ) 117 | ); 118 | 119 | endmodule -------------------------------------------------------------------------------- /vendor/spill_register_flushable.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | // 12 | // Fabian Schuiki 13 | 14 | 15 | /// A register with handshakes that completely cuts any combinational paths 16 | /// between the input and output. This spill register can be flushed. 17 | module spill_register_flushable #( 18 | parameter type T = logic, 19 | parameter bit Bypass = 1'b0 // make this spill register transparent 20 | ) ( 21 | input logic clk_i , 22 | input logic rst_ni , 23 | input logic valid_i , 24 | input logic flush_i , 25 | output logic ready_o , 26 | input T data_i , 27 | output logic valid_o , 28 | input logic ready_i , 29 | output T data_o 30 | ); 31 | 32 | if (Bypass) begin : gen_bypass 33 | assign valid_o = valid_i; 34 | assign ready_o = ready_i; 35 | assign data_o = data_i; 36 | end else begin : gen_spill_reg 37 | // The A register. 38 | T a_data_q; 39 | logic a_full_q; 40 | logic a_fill, a_drain; 41 | 42 | always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data 43 | if (!rst_ni) 44 | a_data_q <= '0; 45 | else if (a_fill) 46 | a_data_q <= data_i; 47 | end 48 | 49 | always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full 50 | if (!rst_ni) 51 | a_full_q <= 0; 52 | else if (a_fill || a_drain) 53 | a_full_q <= a_fill; 54 | end 55 | 56 | // The B register. 57 | T b_data_q; 58 | logic b_full_q; 59 | logic b_fill, b_drain; 60 | 61 | always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data 62 | if (!rst_ni) 63 | b_data_q <= '0; 64 | else if (b_fill) 65 | b_data_q <= a_data_q; 66 | end 67 | 68 | always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full 69 | if (!rst_ni) 70 | b_full_q <= 0; 71 | else if (b_fill || b_drain) 72 | b_full_q <= b_fill; 73 | end 74 | 75 | // Fill the A register when the A or B register is empty. Drain the A register 76 | // whenever it is full and being filled, or if a flush is requested. 77 | assign a_fill = valid_i && ready_o && (!flush_i); 78 | assign a_drain = (a_full_q && !b_full_q) || flush_i; 79 | 80 | // Fill the B register whenever the A register is drained, but the downstream 81 | // circuit is not ready. Drain the B register whenever it is full and the 82 | // downstream circuit is ready, or if a flush is requested. 83 | assign b_fill = a_drain && (!ready_i) && (!flush_i); 84 | assign b_drain = (b_full_q && ready_i) || flush_i; 85 | 86 | // We can accept input as long as register B is not full. 87 | // Note: flush_i and valid_i must not be high at the same time, 88 | // otherwise an invalid handshake may occur 89 | assign ready_o = !a_full_q || !b_full_q; 90 | 91 | // The unit provides output as long as one of the registers is filled. 92 | assign valid_o = a_full_q | b_full_q; 93 | 94 | // We empty the spill register before the slice register. 95 | assign data_o = b_full_q ? b_data_q : a_data_q; 96 | 97 | // pragma translate_off 98 | `ifndef VERILATOR 99 | flush_valid : assert property ( 100 | @(posedge clk_i) disable iff (~rst_ni) (flush_i |-> ~valid_i)) else 101 | $warning("Trying to flush and feed the spill register simultaneously. You will lose data!"); 102 | `endif 103 | // pragma translate_on 104 | end 105 | endmodule 106 | -------------------------------------------------------------------------------- /LICENSE.Solerpad: -------------------------------------------------------------------------------- 1 | Solderpad Hardware License v2.1 2 | 3 | This license operates as a wraparound license to the Apache License Version 2.0 (the “Apache License”) and incorporates the terms and conditions of the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following additions and modifications. It must be read in conjunction with the Apache License. Section 1 below modifies definitions and terminology in the Apache License and Section 2 below replaces Section 2 of the Apache License. The Appendix replaces the Appendix in the Apache License. You may, at your option, choose to treat any Work released under this license as released under the Apache License (thus ignoring all sections written below entirely). 4 | 5 | 1. Terminology in the Apache License is supplemented or modified as follows: 6 | 7 | “Authorship”: any reference to ‘authorship’ shall be taken to read “authorship or design”. 8 | 9 | “Copyright owner”: any reference to ‘copyright owner’ shall be taken to read “Rights owner”. 10 | 11 | “Copyright statement”: the reference to ‘copyright statement’ shall be taken to read ‘copyright or other statement pertaining to Rights’. 12 | 13 | The following new definition shall be added to the Definitions section of the Apache License: 14 | 15 | “Rights” means copyright and any similar right including design right (whether registered or unregistered), rights in semiconductor topographies (mask works) and database rights (but excluding Patents and Trademarks). 16 | 17 | The following definitions shall replace the corresponding definitions in the Apache License: 18 | 19 | “License” shall mean this Solderpad Hardware License version 2.1, being the terms and conditions for use, manufacture, instantiation, adaptation, reproduction, and distribution as defined by Sections 1 through 9 of this document. 20 | 21 | “Licensor” shall mean the owner of the Rights or entity authorized by the owner of the Rights that is granting the License. 22 | 23 | “Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship or design. For the purposes of this License, Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the Work and Derivative Works thereof. 24 | 25 | “Object” form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object or material and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works). 26 | 27 | “Source” form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files. 28 | 29 | “Work” shall mean the work of authorship or design, whether in Source or Object form, made available under the License, as indicated by a notice relating to Rights that is included in or attached to the work (an example is provided in the Appendix below). 30 | 31 | 2. Grant of License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist. 32 | 33 | APPENDIX 34 | 35 | Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 36 | SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 37 | 38 | Licensed under the Solderpad Hardware License v 2.1 (the "License"); you may not use this file except in compliance with the License, or, at your option, the Apache License version 2.0. You may obtain a copy of the License at 39 | 40 | https://solderpad.org/licenses/SHL-2.1/ 41 | 42 | Unless required by applicable law or agreed to in writing, any work distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /rtl/software_interface/regmap/rv_iommu_field_arb.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 12/10/2022 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: IOMMU Register field internal write arbiter. 18 | // 19 | // Disclaimer: This file was generated using LowRISC `reggen` tool. Edit at your own risk. 20 | 21 | module rv_iommu_field_arb 22 | import rv_iommu_field_pkg::*; 23 | #( 24 | parameter int DATA_WIDTH = 32, 25 | parameter sw_access_e SwAccess = SwAccessRW 26 | ) 27 | ( 28 | // From SW: valid for RW, WO, W1C, W1S, W0C, RC. 29 | // In case of RC, top connects read pulse to we. 30 | input we, 31 | input [DATA_WIDTH-1:0] wd, 32 | 33 | // From HW: valid for HRW, HWO. 34 | input de, 35 | input [DATA_WIDTH-1:0] d, 36 | 37 | // From register: actual reg value. (Needed to mask input value when W1S, W1C) 38 | input [DATA_WIDTH-1:0] q, 39 | 40 | // To register: actual write enable and write data. 41 | output logic wr_en, 42 | output logic [DATA_WIDTH-1:0] wr_data 43 | ); 44 | 45 | // If RW or WO, allow write (if SW is not requesting write, set WD with HW D value) 46 | if (SwAccess inside {SwAccessRW, SwAccessWO}) begin : gen_w 47 | assign wr_en = we | de; 48 | assign wr_data = (we == 1'b1) ? wd : d; // SW higher priority 49 | // Unused q - Prevent lint errors. 50 | logic [DATA_WIDTH-1:0] unused_q; 51 | assign unused_q = q; 52 | end 53 | 54 | // If RO, only allow HW writes 55 | else if (SwAccess == SwAccessRO) begin : gen_ro 56 | assign wr_en = de; 57 | assign wr_data = d; 58 | // Unused we, wd, q - Prevent lint errors. 59 | logic unused_we; 60 | logic [DATA_WIDTH-1:0] unused_wd; 61 | logic [DATA_WIDTH-1:0] unused_q; 62 | assign unused_we = we; 63 | assign unused_wd = wd; 64 | assign unused_q = q; 65 | end 66 | 67 | else if (SwAccess == SwAccessW1S) begin : gen_w1s 68 | // If SwAccess is W1S, then assume hw tries to clear. (Possible conflict case) 69 | // So, give a chance HW to clear when SW tries to set. 70 | // If both try to set/clr at the same bit pos, SW wins. 71 | assign wr_en = we | de; 72 | assign wr_data = (de ? d : q) | (we ? wd : '0); // OR-mask input set bits with current reg value to set 73 | end 74 | 75 | else if (SwAccess == SwAccessW1C) begin : gen_w1c 76 | // If SwAccess is W1C, then assume hw tries to set. 77 | // So, give a chance HW to set when SW tries to clear. 78 | // If both try to set/clr at the same bit pos, SW wins. 79 | assign wr_en = we | de; 80 | assign wr_data = (de ? d : q) & (we ? ~wd : '1); // AND-ask input set bits (inverted) with current reg value to clear 81 | end 82 | 83 | else if (SwAccess == SwAccessW0C) begin : gen_w0c 84 | assign wr_en = we | de; 85 | assign wr_data = (de ? d : q) & (we ? wd : '1); // AND-ask input set bits with current reg value to clear 86 | end 87 | 88 | else if (SwAccess == SwAccessRC) begin : gen_rc 89 | // This swtype is not recommended but exists for compatibility. 90 | // WARN: we signal is actually read signal not write enable. 91 | assign wr_en = we | de; 92 | assign wr_data = (de ? d : q) & (we ? '0 : '1); // 93 | // Unused wd - Prevent lint errors. 94 | logic [DATA_WIDTH-1:0] unused_wd; 95 | assign unused_wd = wd; 96 | end 97 | 98 | else begin : gen_hw 99 | assign wr_en = de; 100 | assign wr_data = d; 101 | // Unused we, wd, q - Prevent lint errors. 102 | logic unused_we; 103 | logic [DATA_WIDTH-1:0] unused_wd; 104 | logic [DATA_WIDTH-1:0] unused_q; 105 | assign unused_we = we; 106 | assign unused_wd = wd; 107 | assign unused_q = q; 108 | end 109 | 110 | endmodule -------------------------------------------------------------------------------- /vendor/lzc.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 - 2019 ETH Zurich, University of Bologna 2 | // All rights reserved. 3 | // 4 | // This code is under development and not yet released to the public. 5 | // Until it is released, the code is under the copyright of ETH Zurich and 6 | // the University of Bologna, and may contain confidential and/or unpublished 7 | // work. Any reuse/redistribution is strictly forbidden without written 8 | // permission from ETH Zurich. 9 | // 10 | // Bug fixes and contributions will eventually be released under the 11 | // SolderPad open hardware license in the context of the PULP platform 12 | // (http://www.pulp-platform.org), under the copyright of ETH Zurich and the 13 | // University of Bologna. 14 | 15 | /// A trailing zero counter / leading zero counter. 16 | /// Set MODE to 0 for trailing zero counter => cnt_o is the number of trailing zeros (from the LSB) 17 | /// Set MODE to 1 for leading zero counter => cnt_o is the number of leading zeros (from the MSB) 18 | /// If the input does not contain a zero, `empty_o` is asserted. Additionally `cnt_o` contains 19 | /// the maximum number of zeros - 1. For example: 20 | /// in_i = 000_0000, empty_o = 1, cnt_o = 6 (mode = 0) 21 | /// in_i = 000_0001, empty_o = 0, cnt_o = 0 (mode = 0) 22 | /// in_i = 000_1000, empty_o = 0, cnt_o = 3 (mode = 0) 23 | /// Furthermore, this unit contains a more efficient implementation for Verilator (simulation only). 24 | /// This speeds up simulation significantly. 25 | 26 | `include "cf_math_pkg.sv" 27 | 28 | /* verilator lint_off UNOPTFLAT */ 29 | 30 | module lzc #( 31 | /// The width of the input vector. 32 | parameter int unsigned WIDTH = 2, 33 | /// Mode selection: 0 -> trailing zero, 1 -> leading zero 34 | parameter bit MODE = 1'b0, 35 | /// Dependent parameter. Do **not** change! 36 | /// 37 | /// Width of the output signal with the zero count. 38 | parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH) 39 | ) ( 40 | /// Input vector to be counted. 41 | input logic [WIDTH-1:0] in_i, 42 | /// Count of the leading / trailing zeros. 43 | output logic [CNT_WIDTH-1:0] cnt_o, 44 | /// Counter is empty: Asserted if all bits in in_i are zero. 45 | output logic empty_o 46 | ); 47 | 48 | if (WIDTH == 1) begin : gen_degenerate_lzc 49 | 50 | assign cnt_o[0] = !in_i[0]; 51 | assign empty_o = !in_i[0]; 52 | 53 | end else begin : gen_lzc 54 | 55 | localparam int unsigned NumLevels = $clog2(WIDTH); 56 | 57 | // pragma translate_off 58 | initial begin 59 | assert(WIDTH > 0) else $fatal(1, "input must be at least one bit wide"); 60 | end 61 | // pragma translate_on 62 | 63 | logic [WIDTH-1:0][NumLevels-1:0] index_lut; 64 | logic [2**NumLevels-1:0] sel_nodes; 65 | logic [2**NumLevels-1:0][NumLevels-1:0] index_nodes; 66 | 67 | logic [WIDTH-1:0] in_tmp; 68 | 69 | // reverse vector if required 70 | always_comb begin : flip_vector 71 | for (int unsigned i = 0; i < WIDTH; i++) begin 72 | in_tmp[i] = (MODE) ? in_i[WIDTH-1-i] : in_i[i]; 73 | end 74 | end 75 | 76 | for (genvar j = 0; unsigned'(j) < WIDTH; j++) begin : g_index_lut 77 | assign index_lut[j] = (NumLevels)'(unsigned'(j)); 78 | end 79 | 80 | for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : g_levels 81 | if (unsigned'(level) == NumLevels - 1) begin : g_last_level 82 | for (genvar k = 0; k < 2 ** level; k++) begin : g_level 83 | // if two successive indices are still in the vector... 84 | if (unsigned'(k) * 2 < WIDTH - 1) begin : g_reduce 85 | assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2] | in_tmp[k * 2 + 1]; 86 | assign index_nodes[2 ** level - 1 + k] = (in_tmp[k * 2] == 1'b1) 87 | ? index_lut[k * 2] : 88 | index_lut[k * 2 + 1]; 89 | end 90 | // if only the first index is still in the vector... 91 | if (unsigned'(k) * 2 == WIDTH - 1) begin : g_base 92 | assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2]; 93 | assign index_nodes[2 ** level - 1 + k] = index_lut[k * 2]; 94 | end 95 | // if index is out of range 96 | if (unsigned'(k) * 2 > WIDTH - 1) begin : g_out_of_range 97 | assign sel_nodes[2 ** level - 1 + k] = 1'b0; 98 | assign index_nodes[2 ** level - 1 + k] = '0; 99 | end 100 | end 101 | end else begin : g_not_last_level 102 | for (genvar l = 0; l < 2 ** level; l++) begin : g_level 103 | assign sel_nodes[2 ** level - 1 + l] = 104 | sel_nodes[2 ** (level + 1) - 1 + l * 2] | sel_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; 105 | assign index_nodes[2 ** level - 1 + l] = (sel_nodes[2 ** (level + 1) - 1 + l * 2] == 1'b1) 106 | ? index_nodes[2 ** (level + 1) - 1 + l * 2] : 107 | index_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; 108 | end 109 | end 110 | end 111 | 112 | assign cnt_o = NumLevels > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)) {1'b0}}; 113 | assign empty_o = NumLevels > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i); 114 | 115 | end : gen_lzc 116 | 117 | endmodule : lzc 118 | 119 | /* verilator lint_on UNOPTFLAT */ 120 | -------------------------------------------------------------------------------- /rtl/ext_interfaces/rv_iommu_axi4_bc.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 15/08/2023 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: AXI4 Boundary Checker module for RISC-V IOMMU: 18 | // Checks whether an AXI transaction crosses a 4-kiB address boundary, 19 | // which is illegal in AXI4 transactions. 20 | 21 | /* verilator lint_off WIDTH */ 22 | 23 | module rv_iommu_axi4_bc ( 24 | // AxVALID 25 | input logic request_i, 26 | // AxADDR 27 | input logic [riscv::VLEN-1:0] addr_i, 28 | // AxBURST 29 | input axi_pkg::burst_t burst_type_i, 30 | // AxLEN 31 | input axi_pkg::len_t burst_length_i, 32 | // AxSIZE 33 | input axi_pkg::size_t n_bytes_i, 34 | 35 | // To indicate valid requests or boundary violations 36 | output logic allow_request_o, 37 | output logic bound_violation_o 38 | ); 39 | 40 | always_comb begin : boundary_check 41 | 42 | allow_request_o = 1'b0; 43 | bound_violation_o = 1'b0; 44 | 45 | // Request received 46 | if (request_i) begin 47 | 48 | // Consider burst type, N of beats and size of the beat (always 64 bits) to calculate number of bytes accessed: 49 | case (burst_type_i) 50 | 51 | // BURST_FIXED: The final address is Start Addr + 8 (ex: ARADDR + 8) 52 | axi_pkg::BURST_FIXED: begin 53 | // May be optimized with bitwise AND 54 | if (((addr_i & 12'hfff) + (1'b1 << n_bytes_i)) < (1'b1 << 12)) begin 55 | allow_request_o = 1'b1; // Allow transaction 56 | end 57 | 58 | // Boundary violation 59 | else begin 60 | bound_violation_o = 1'b1; 61 | end 62 | end 63 | 64 | // BURST_WRAP: The final address is the Wrap Boundary (Lower address) + size of the transfer 65 | axi_pkg::BURST_WRAP: begin 66 | // wrap_boundary = (start_address/(number_bytes*burst_length_i)) * (number_bytes*burst_length_i) 67 | // address_n = wrap_boundary + (number_bytes * burst_length_i) 68 | logic [riscv::PLEN-1:0] wrap_boundary; 69 | 70 | // by spec, N of transfers must be {2, 4, 8, 16} 71 | // So, ARLEN must be {1, 3, 7, 15} 72 | logic [2:0] log2_len; 73 | case (burst_length_i) 74 | 8'd1: log2_len = 3'b001; 75 | 8'd3: log2_len = 3'b010; 76 | 8'd7: log2_len = 3'b011; 77 | 8'd15: log2_len = 3'b100; 78 | default: log2_len = 3'b111; // invalid 79 | endcase 80 | 81 | // The lowest address within a wrapping burst 82 | // Wrap_Boundary = (INT(Start_Address / (Burst_Length x Number_Bytes))) x (Burst_Length x Number_Bytes) 83 | wrap_boundary = (addr_i >> (log2_len + n_bytes_i)) << (log2_len + n_bytes_i); 84 | 85 | // Check if the highest address crosses a 4 kiB boundary (Highest Addr - Lower Addr >= 4kiB) 86 | // Highest addr_i = Wrap_Boundary + (Burst_Length x Number_Bytes) 87 | if (!(&log2_len) && 88 | (((wrap_boundary & 12'hfff) + ((burst_length_i + 1) << n_bytes_i)) < (1'b1 << 12))) begin 89 | allow_request_o = 1'b1; // Allow transaction 90 | end 91 | 92 | // Boundary violation 93 | else begin 94 | bound_violation_o = 1'b1; 95 | end 96 | 97 | end 98 | 99 | // BURST_INCR: The final address is Start Addr + Burst_Length x Number_Bytes 100 | axi_pkg::BURST_INCR: begin 101 | // check if burst is within 4K range 102 | if (((addr_i & 12'hfff) + ((burst_length_i + 1) << n_bytes_i)) < (1'b1 << 12)) begin 103 | allow_request_o = 1'b1; // Allow transaction 104 | end 105 | 106 | // Boundary violation 107 | else begin 108 | bound_violation_o = 1'b1; 109 | end 110 | end 111 | 112 | default:; 113 | endcase 114 | end 115 | end 116 | 117 | endmodule 118 | 119 | /* verilator lint_on WIDTH */ -------------------------------------------------------------------------------- /rtl/ext_interfaces/rv_iommu_ign_slv.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 21/05/2024 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: Slave module to ignore requests within the IOMMU and provide completions. 18 | 19 | module rv_iommu_ign_slv #( 20 | /// AXI ID Width 21 | parameter int unsigned AxiIdWidth = 0, 22 | /// Response generated by the slave 23 | parameter axi_pkg::resp_t Resp = axi_pkg::RESP_OKAY, 24 | /// Data response width, gets zero extended or truncated to r.data 25 | parameter int unsigned RespWidth = 32'd64, 26 | /// Hexvalue for data return value 27 | parameter logic [RespWidth-1:0] RespData = 64'h0, 28 | /// AXI Full request struct type 29 | parameter type axi_req_t = logic, 30 | /// AXI Full response struct type 31 | parameter type axi_rsp_t = logic 32 | ) ( 33 | input logic clk_i, 34 | input logic rst_ni, 35 | 36 | input axi_req_t ignore_req_i, 37 | output axi_rsp_t ignore_resp_o 38 | ); 39 | 40 | logic [(AxiIdWidth-1):0] b_id_q, b_id_n; 41 | logic [(AxiIdWidth-1):0] r_id_q, r_id_n; 42 | logic [7:0] r_counter_q, r_counter_n; 43 | 44 | logic ign_aw_ready_q, ign_aw_ready_n; 45 | logic ign_w_ready_q, ign_w_ready_n; 46 | logic ign_b_valid_q, ign_b_valid_n; 47 | logic ign_ar_ready_q, ign_ar_ready_n; 48 | logic ign_r_valid_q, ign_r_valid_n; 49 | 50 | always_comb begin : ignore_req_comb 51 | 52 | // Set output signals 53 | ignore_resp_o.aw_ready = ign_aw_ready_q; 54 | ignore_resp_o.w_ready = ign_w_ready_q; 55 | ignore_resp_o.b_valid = ign_b_valid_q; 56 | ignore_resp_o.ar_ready = ign_ar_ready_q; 57 | ignore_resp_o.r_valid = ign_r_valid_q; 58 | 59 | ignore_resp_o.b.id = b_id_q; 60 | ignore_resp_o.b.resp = Resp; 61 | ignore_resp_o.b.user = '0; 62 | 63 | ignore_resp_o.r.id = r_id_q; 64 | ignore_resp_o.r.data = RespData; 65 | ignore_resp_o.r.resp = Resp; 66 | ignore_resp_o.r.last = (r_counter_q == '0) & ign_r_valid_q; 67 | ignore_resp_o.r.user = '0; 68 | 69 | // Default assignments 70 | b_id_n = b_id_q; 71 | r_id_n = r_id_q; 72 | r_counter_n = r_counter_q; 73 | 74 | ign_aw_ready_n = 1'b0; 75 | ign_w_ready_n = ign_w_ready_q; 76 | ign_b_valid_n = ign_b_valid_q; 77 | ign_ar_ready_n = 1'b0; 78 | ign_r_valid_n = ign_r_valid_q; 79 | 80 | // Read transaction 81 | if (ignore_req_i.ar_valid) begin 82 | 83 | // Save ARID 84 | r_id_n = ignore_req_i.ar.id; 85 | // Save number of read transfers 86 | r_counter_n = ignore_req_i.ar.len; 87 | 88 | if (!ign_ar_ready_q) 89 | // Set ARREADY 90 | ign_ar_ready_n = 1'b1; 91 | else 92 | // Set RVALID when ARREADY is set by IOMMU 93 | ign_r_valid_n = 1'b1; 94 | end 95 | 96 | // Send requested beats 97 | if (ign_r_valid_q && ignore_req_i.r_ready) begin 98 | 99 | // Clear RVALID when counter reaches zero 100 | if (r_counter_q == '0) 101 | ign_r_valid_n = 1'b0; 102 | else 103 | // Decrement counter 104 | r_counter_n = r_counter_q - 1; 105 | end 106 | 107 | // Write transaction 108 | if (ignore_req_i.aw_valid) begin 109 | // Set AWREADY 110 | if (!ign_aw_ready_q) 111 | ign_aw_ready_n = 1'b1; 112 | // Save AWID 113 | b_id_n = ignore_req_i.aw.id; 114 | end 115 | 116 | // Receive all write beats 117 | if (ignore_req_i.w_valid) begin 118 | // Set WREADY after WVALID is set by master 119 | ign_w_ready_n = 1'b1; 120 | 121 | if (ignore_req_i.w.last && ign_w_ready_q) begin 122 | // Clear WREADY when WLAST is set by master 123 | ign_w_ready_n = 1'b0; 124 | // Set BVALID 125 | ign_b_valid_n = 1'b1; 126 | end 127 | end 128 | 129 | // Clear BVALID when master sets BREADY 130 | if (ign_b_valid_q && ignore_req_i.b_ready) 131 | ign_b_valid_n = 1'b0; 132 | 133 | end : ignore_req_comb 134 | 135 | always_ff @( posedge clk_i or negedge rst_ni ) begin : ignore_req_ff 136 | 137 | if (~rst_ni) begin 138 | b_id_q <= '0; 139 | r_id_q <= '0; 140 | r_counter_q <= '0; 141 | 142 | ign_aw_ready_q <= 1'b0; 143 | ign_w_ready_q <= 1'b0; 144 | ign_b_valid_q <= 1'b0; 145 | ign_ar_ready_q <= 1'b0; 146 | ign_r_valid_q <= 1'b0; 147 | end 148 | 149 | else begin 150 | b_id_q <= b_id_n; 151 | r_id_q <= r_id_n; 152 | r_counter_q <= r_counter_n; 153 | 154 | ign_aw_ready_q <= ign_aw_ready_n; 155 | ign_w_ready_q <= ign_w_ready_n; 156 | ign_b_valid_q <= ign_b_valid_n; 157 | ign_ar_ready_q <= ign_ar_ready_n; 158 | ign_r_valid_q <= ign_r_valid_n; 159 | end 160 | end : ignore_req_ff 161 | endmodule -------------------------------------------------------------------------------- /vendor/axi_to_reg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Fabian Schuiki 12 | 13 | /// A protocol converter from AXI4 to a register interface. 14 | 15 | `include "axi/typedef.svh" 16 | 17 | module axi_to_reg #( 18 | /// The width of the address. 19 | parameter int ADDR_WIDTH = -1, 20 | /// The width of the data. 21 | parameter int DATA_WIDTH = -1, 22 | /// The width of the id. 23 | parameter int ID_WIDTH = -1, 24 | /// The width of the user signal. 25 | parameter int USER_WIDTH = -1, 26 | /// Maximum number of outstanding writes. 27 | parameter int unsigned AXI_MAX_WRITE_TXNS = 32'd2, 28 | /// Maximum number of outstanding reads. 29 | parameter int unsigned AXI_MAX_READ_TXNS = 32'd2, 30 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 31 | /// can help break long paths at the expense of registers. 32 | parameter bit DECOUPLE_W = 1, 33 | /// AXI request struct type. 34 | parameter type axi_req_t = logic, 35 | /// AXI response struct type. 36 | parameter type axi_rsp_t = logic, 37 | /// Regbus request struct type. 38 | parameter type reg_req_t = logic, 39 | /// Regbus response struct type. 40 | parameter type reg_rsp_t = logic 41 | )( 42 | input logic clk_i , 43 | input logic rst_ni , 44 | input logic testmode_i , 45 | input axi_req_t axi_req_i, 46 | output axi_rsp_t axi_rsp_o, 47 | output reg_req_t reg_req_o , 48 | input reg_rsp_t reg_rsp_i 49 | ); 50 | 51 | typedef logic [ADDR_WIDTH-1:0] addr_t; 52 | typedef logic [DATA_WIDTH-1:0] data_t; 53 | typedef logic [DATA_WIDTH/8-1:0] strb_t; 54 | 55 | `AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t) 56 | `AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t) 57 | `AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t) 58 | `AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t) 59 | `AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t) 60 | `AXI_LITE_TYPEDEF_REQ_T(axi_lite_req_t, aw_chan_t, w_chan_t, ar_chan_t) 61 | `AXI_LITE_TYPEDEF_RESP_T(axi_lite_resp_t, b_chan_t, r_chan_t) 62 | 63 | axi_lite_req_t axi_lite_req; 64 | axi_lite_resp_t axi_lite_resp; 65 | 66 | // convert axi to axi-lite 67 | axi_to_axi_lite #( 68 | .AxiAddrWidth ( ADDR_WIDTH ), 69 | .AxiDataWidth ( DATA_WIDTH ), 70 | .AxiIdWidth ( ID_WIDTH ), 71 | .AxiUserWidth ( USER_WIDTH ), 72 | /// Maximum number of outstanding writes. 73 | .AxiMaxWriteTxns ( AXI_MAX_WRITE_TXNS ), 74 | /// Maximum number of outstanding reads. 75 | .AxiMaxReadTxns ( AXI_MAX_READ_TXNS ), 76 | .FallThrough ( 0 ), 77 | .full_req_t ( axi_req_t ), 78 | .full_resp_t ( axi_rsp_t ), 79 | .lite_req_t ( axi_lite_req_t ), 80 | .lite_resp_t ( axi_lite_resp_t ) 81 | ) i_axi_to_axi_lite ( 82 | .clk_i, 83 | .rst_ni, 84 | .test_i ( testmode_i ), 85 | .slv_req_i (axi_req_i), 86 | .slv_resp_o (axi_rsp_o), 87 | .mst_req_o (axi_lite_req), 88 | .mst_resp_i (axi_lite_resp) 89 | ); 90 | 91 | axi_lite_to_reg #( 92 | /// The width of the address. 93 | .ADDR_WIDTH ( ADDR_WIDTH ), 94 | /// The width of the data. 95 | .DATA_WIDTH ( DATA_WIDTH ), 96 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 97 | /// can help break long paths at the expense of registers. 98 | .DECOUPLE_W ( DECOUPLE_W ), 99 | .axi_lite_req_t ( axi_lite_req_t ), 100 | .axi_lite_rsp_t ( axi_lite_resp_t ), 101 | .reg_req_t (reg_req_t), 102 | .reg_rsp_t (reg_rsp_t) 103 | ) i_axi_lite_to_reg ( 104 | .clk_i, 105 | .rst_ni, 106 | .axi_lite_req_i (axi_lite_req), 107 | .axi_lite_rsp_o (axi_lite_resp), 108 | .reg_req_o, 109 | .reg_rsp_i 110 | ); 111 | 112 | endmodule 113 | 114 | 115 | module axi_to_reg_intf #( 116 | /// The width of the address. 117 | parameter int ADDR_WIDTH = -1, 118 | /// The width of the data. 119 | parameter int DATA_WIDTH = -1, 120 | /// The width of the id. 121 | parameter int ID_WIDTH = -1, 122 | /// The width of the user signal. 123 | parameter int USER_WIDTH = -1, 124 | /// Maximum number of outstanding writes. 125 | parameter int unsigned AXI_MAX_WRITE_TXNS = 32'd2, 126 | /// Maximum number of outstanding reads. 127 | parameter int unsigned AXI_MAX_READ_TXNS = 32'd2, 128 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 129 | /// can help break long paths at the expense of registers. 130 | parameter bit DECOUPLE_W = 1 131 | )( 132 | input logic clk_i , 133 | input logic rst_ni , 134 | input logic testmode_i, 135 | AXI_BUS.Slave in , 136 | REG_BUS.out reg_o 137 | ); 138 | 139 | AXI_LITE #( 140 | .AXI_ADDR_WIDTH ( ADDR_WIDTH ), 141 | .AXI_DATA_WIDTH ( DATA_WIDTH ) 142 | ) axi_lite (); 143 | 144 | // convert axi to axi-lite 145 | axi_to_axi_lite_intf #( 146 | .AXI_ADDR_WIDTH ( ADDR_WIDTH ), 147 | .AXI_DATA_WIDTH ( DATA_WIDTH ), 148 | .AXI_ID_WIDTH ( ID_WIDTH ), 149 | .AXI_USER_WIDTH ( USER_WIDTH ), 150 | /// Maximum number of outstanding writes. 151 | .AXI_MAX_WRITE_TXNS ( AXI_MAX_WRITE_TXNS ), 152 | /// Maximum number of outstanding reads. 153 | .AXI_MAX_READ_TXNS ( AXI_MAX_READ_TXNS ), 154 | .FALL_THROUGH ( 0 ) 155 | ) i_axi_to_axi_lite ( 156 | .clk_i, 157 | .rst_ni, 158 | .testmode_i, 159 | .slv ( in ), 160 | .mst ( axi_lite ) 161 | ); 162 | 163 | axi_lite_to_reg_intf #( 164 | /// The width of the address. 165 | .ADDR_WIDTH ( ADDR_WIDTH ), 166 | /// The width of the data. 167 | .DATA_WIDTH ( DATA_WIDTH ), 168 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 169 | /// can help break long paths at the expense of registers. 170 | .DECOUPLE_W ( DECOUPLE_W ) 171 | ) i_axi_lite_to_reg ( 172 | .clk_i, 173 | .rst_ni, 174 | .axi_i ( axi_lite ), 175 | .reg_o 176 | ); 177 | 178 | endmodule 179 | -------------------------------------------------------------------------------- /rtl/ext_interfaces/rv_iommu_prog_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 02/02/2023 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: Wrapper module for the RISC-V IOMMU register programming interface. 18 | // Instantiates the IOMMU register map and performs conversion between 19 | // register interface protocol and AXI4. 20 | // 21 | 22 | `include "register_interface/assign.svh" 23 | 24 | module rv_iommu_prog_if #( 25 | /// The width of the address. 26 | parameter int ADDR_WIDTH = -1, 27 | /// The width of the data. 28 | parameter int DATA_WIDTH = -1, 29 | /// AXI ID width 30 | parameter int ID_WIDTH = -1, 31 | /// AXI user width 32 | parameter int USER_WIDTH = 1, 33 | 34 | /// AXI Full request struct type 35 | parameter type axi_req_t = logic, 36 | /// AXI Full response struct type 37 | parameter type axi_rsp_t = logic, 38 | /// Regbus request struct type. 39 | parameter type reg_req_t = logic, 40 | /// Regbus response struct type. 41 | parameter type reg_rsp_t = logic 42 | ) ( 43 | // rising-edge clock 44 | input logic clk_i, 45 | // asynchronous reset, active low 46 | input logic rst_ni, 47 | 48 | // From IOMMU programing interface 49 | input axi_req_t prog_req_i, 50 | output axi_rsp_t prog_resp_o, 51 | 52 | // To register map 53 | output reg_req_t regmap_req_o, 54 | input reg_rsp_t regmap_resp_i 55 | ); 56 | 57 | REG_BUS #( 58 | .ADDR_WIDTH ( ADDR_WIDTH ), 59 | .DATA_WIDTH ( 32 ) 60 | ) iommu_reg_bus (clk_i); 61 | 62 | logic penable; 63 | logic pwrite; 64 | logic [(ADDR_WIDTH-1):0] paddr; 65 | logic psel; 66 | logic [31:0] pwdata; 67 | logic [31:0] prdata; 68 | logic pready; 69 | logic pslverr; 70 | 71 | // AXI4 to APB IF 72 | axi2apb_64_32 #( 73 | .AXI4_ADDRESS_WIDTH ( ADDR_WIDTH ), 74 | .AXI4_RDATA_WIDTH ( DATA_WIDTH ), 75 | .AXI4_WDATA_WIDTH ( DATA_WIDTH ), 76 | .AXI4_ID_WIDTH ( ID_WIDTH ), 77 | .AXI4_USER_WIDTH ( USER_WIDTH ), 78 | .BUFF_DEPTH_SLAVE ( 2 ), 79 | .APB_ADDR_WIDTH ( ADDR_WIDTH ) 80 | ) i_axi2apb_64_32_iommu ( 81 | .ACLK ( clk_i ), 82 | .ARESETn ( rst_ni ), 83 | .test_en_i ( 1'b0 ), 84 | // AW 85 | .AWID_i ( prog_req_i.aw.id ), 86 | .AWADDR_i ( prog_req_i.aw.addr ), 87 | .AWLEN_i ( prog_req_i.aw.len ), 88 | .AWSIZE_i ( prog_req_i.aw.size ), 89 | .AWBURST_i ( prog_req_i.aw.burst ), 90 | .AWLOCK_i ( prog_req_i.aw.lock ), 91 | .AWCACHE_i ( prog_req_i.aw.cache ), 92 | .AWPROT_i ( prog_req_i.aw.prot ), 93 | .AWREGION_i( prog_req_i.aw.region ), 94 | .AWUSER_i ( prog_req_i.aw.user ), 95 | .AWQOS_i ( prog_req_i.aw.qos ), 96 | .AWVALID_i ( prog_req_i.aw_valid ), 97 | .AWREADY_o ( prog_resp_o.aw_ready ), 98 | // W 99 | .WDATA_i ( prog_req_i.w.data ), 100 | .WSTRB_i ( prog_req_i.w.strb ), 101 | .WLAST_i ( prog_req_i.w.last ), 102 | .WUSER_i ( prog_req_i.w.user ), 103 | .WVALID_i ( prog_req_i.w_valid ), 104 | .WREADY_o ( prog_resp_o.w_ready ), 105 | // B 106 | .BID_o ( prog_resp_o.b.id ), 107 | .BRESP_o ( prog_resp_o.b.resp ), 108 | .BUSER_o ( prog_resp_o.b.user ), 109 | .BVALID_o ( prog_resp_o.b_valid ), 110 | .BREADY_i ( prog_req_i.b_ready ), 111 | // AR 112 | .ARID_i ( prog_req_i.ar.id ), 113 | .ARADDR_i ( prog_req_i.ar.addr ), 114 | .ARLEN_i ( prog_req_i.ar.len ), 115 | .ARSIZE_i ( prog_req_i.ar.size ), 116 | .ARBURST_i ( prog_req_i.ar.burst ), 117 | .ARLOCK_i ( prog_req_i.ar.lock ), 118 | .ARCACHE_i ( prog_req_i.ar.cache ), 119 | .ARPROT_i ( prog_req_i.ar.prot ), 120 | .ARREGION_i( prog_req_i.ar.region ), 121 | .ARUSER_i ( prog_req_i.ar.user ), 122 | .ARQOS_i ( prog_req_i.ar.qos ), 123 | .ARVALID_i ( prog_req_i.ar_valid ), 124 | .ARREADY_o ( prog_resp_o.ar_ready ), 125 | // R 126 | .RID_o ( prog_resp_o.r.id ), 127 | .RDATA_o ( prog_resp_o.r.data ), 128 | .RRESP_o ( prog_resp_o.r.resp ), 129 | .RLAST_o ( prog_resp_o.r.last ), 130 | .RUSER_o ( prog_resp_o.r.user ), 131 | .RVALID_o ( prog_resp_o.r_valid ), 132 | .RREADY_i ( prog_req_i.r_ready ), 133 | // APB IF 134 | .PENABLE ( penable ), 135 | .PWRITE ( pwrite ), 136 | .PADDR ( paddr ), 137 | .PSEL ( psel ), 138 | .PWDATA ( pwdata ), 139 | .PRDATA ( prdata ), 140 | .PREADY ( pready ), 141 | .PSLVERR ( pslverr ) 142 | ); 143 | 144 | // APB to REG IF 145 | apb_to_reg i_apb_to_reg ( 146 | .clk_i ( clk_i ), 147 | .rst_ni ( rst_ni ), 148 | .penable_i ( penable ), 149 | .pwrite_i ( pwrite ), 150 | .paddr_i ( paddr ), 151 | .psel_i ( psel ), 152 | .pwdata_i ( pwdata ), 153 | .prdata_o ( prdata ), 154 | .pready_o ( pready ), 155 | .pslverr_o ( pslverr ), 156 | .reg_o ( iommu_reg_bus ) 157 | ); 158 | 159 | // assign REG_BUS.out to (req_t, rsp_t) pair 160 | `REG_BUS_ASSIGN_TO_REQ(regmap_req_o, iommu_reg_bus) 161 | `REG_BUS_ASSIGN_FROM_RSP(iommu_reg_bus, regmap_resp_i) 162 | 163 | endmodule -------------------------------------------------------------------------------- /vendor/fifo_v3.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | // Author: Florian Zaruba 12 | 13 | module fifo_v3 #( 14 | parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode 15 | parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic 16 | parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32 17 | parameter type dtype = logic [DATA_WIDTH-1:0], 18 | // DO NOT OVERWRITE THIS PARAMETER 19 | parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 20 | )( 21 | input logic clk_i, // Clock 22 | input logic rst_ni, // Asynchronous reset active low 23 | input logic flush_i, // flush the queue 24 | input logic testmode_i, // test_mode to bypass clock gating 25 | // status flags 26 | output logic full_o, // queue is full 27 | output logic empty_o, // queue is empty 28 | output logic [ADDR_DEPTH-1:0] usage_o, // fill pointer 29 | // as long as the queue is not full we can push new data 30 | input dtype data_i, // data to push into the queue 31 | input logic push_i, // data is valid and can be pushed to the queue 32 | // as long as the queue is not empty we can pop new elements 33 | output dtype data_o, // output data 34 | input logic pop_i // pop head from queue 35 | ); 36 | // local parameter 37 | // FIFO depth - handle the case of pass-through, synthesizer will do constant propagation 38 | localparam int unsigned FifoDepth = (DEPTH > 0) ? DEPTH : 1; 39 | // clock gating control 40 | logic gate_clock; 41 | // pointer to the read and write section of the queue 42 | logic [ADDR_DEPTH - 1:0] read_pointer_n, read_pointer_q, write_pointer_n, write_pointer_q; 43 | // keep a counter to keep track of the current queue status 44 | // this integer will be truncated by the synthesis tool 45 | logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q; 46 | // actual memory 47 | dtype [FifoDepth - 1:0] mem_n, mem_q; 48 | 49 | // fifo ram signals for fpga target 50 | logic fifo_ram_we; 51 | logic [ADDR_DEPTH-1:0] fifo_ram_read_address; 52 | logic [ADDR_DEPTH-1:0] fifo_ram_write_address; 53 | logic [$bits(dtype)-1:0] fifo_ram_wdata; 54 | logic [$bits(dtype)-1:0] fifo_ram_rdata; 55 | 56 | assign usage_o = status_cnt_q[ADDR_DEPTH-1:0]; 57 | 58 | if (DEPTH == 0) begin : gen_pass_through 59 | assign empty_o = ~push_i; 60 | assign full_o = ~pop_i; 61 | end else begin : gen_fifo 62 | assign full_o = (status_cnt_q == FifoDepth[ADDR_DEPTH:0]); 63 | assign empty_o = (status_cnt_q == 0) & ~(FALL_THROUGH & push_i); 64 | end 65 | // status flags 66 | 67 | // read and write queue logic 68 | always_comb begin : read_write_comb 69 | // default assignment 70 | read_pointer_n = read_pointer_q; 71 | write_pointer_n = write_pointer_q; 72 | status_cnt_n = status_cnt_q; 73 | data_o = (DEPTH == 0) ? data_i : mem_q[read_pointer_q]; 74 | mem_n = mem_q; 75 | gate_clock = 1'b1; 76 | 77 | // push a new element to the queue 78 | if (push_i && ~full_o) begin 79 | // push the data onto the queue 80 | mem_n[write_pointer_q] = data_i; 81 | // un-gate the clock, we want to write something 82 | gate_clock = 1'b0; 83 | 84 | // increment the write counter 85 | if (write_pointer_q == FifoDepth[ADDR_DEPTH-1:0] - 1) 86 | write_pointer_n = '0; 87 | else 88 | write_pointer_n = write_pointer_q + 1; 89 | // increment the overall counter 90 | status_cnt_n = status_cnt_q + 1; 91 | end 92 | 93 | if (pop_i && ~empty_o) begin 94 | // read from the queue is a default assignment 95 | // but increment the read pointer... 96 | if (read_pointer_n == FifoDepth[ADDR_DEPTH-1:0] - 1) 97 | read_pointer_n = '0; 98 | else 99 | read_pointer_n = read_pointer_q + 1; 100 | // ... and decrement the overall count 101 | status_cnt_n = status_cnt_q - 1; 102 | end 103 | 104 | // keep the count pointer stable if we push and pop at the same time 105 | if (push_i && pop_i && ~full_o && ~empty_o) 106 | status_cnt_n = status_cnt_q; 107 | 108 | // FIFO is in pass through mode -> do not change the pointers 109 | if (FALL_THROUGH && (status_cnt_q == 0) && push_i) begin 110 | data_o = data_i; 111 | if (pop_i) begin 112 | status_cnt_n = status_cnt_q; 113 | read_pointer_n = read_pointer_q; 114 | write_pointer_n = write_pointer_q; 115 | end 116 | end 117 | end 118 | 119 | // sequential process 120 | always_ff @(posedge clk_i or negedge rst_ni) begin 121 | if(~rst_ni) begin 122 | read_pointer_q <= '0; 123 | write_pointer_q <= '0; 124 | status_cnt_q <= '0; 125 | end else begin 126 | if (flush_i) begin 127 | read_pointer_q <= '0; 128 | write_pointer_q <= '0; 129 | status_cnt_q <= '0; 130 | end else begin 131 | read_pointer_q <= read_pointer_n; 132 | write_pointer_q <= write_pointer_n; 133 | status_cnt_q <= status_cnt_n; 134 | end 135 | end 136 | end 137 | 138 | always_ff @(posedge clk_i or negedge rst_ni) begin 139 | if(~rst_ni) begin 140 | mem_q <= '0; 141 | end else if (!gate_clock) begin 142 | mem_q <= mem_n; 143 | end 144 | end 145 | 146 | // pragma translate_off 147 | `ifndef VERILATOR 148 | initial begin 149 | assert (DEPTH > 0) else $error("DEPTH must be greater than 0."); 150 | end 151 | 152 | full_write : assert property( 153 | @(posedge clk_i) disable iff (~rst_ni) (full_o |-> ~push_i)) 154 | else $fatal (1, "Trying to push new data although the FIFO is full."); 155 | 156 | empty_read : assert property( 157 | @(posedge clk_i) disable iff (~rst_ni) (empty_o |-> ~pop_i)) 158 | else $fatal (1, "Trying to pop data although the FIFO is empty."); 159 | `endif 160 | // pragma translate_on 161 | 162 | endmodule // fifo_v3 163 | -------------------------------------------------------------------------------- /packages/dependencies/lint_wrapper_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 24/04/2024 15 | // 16 | // Description: Auiliary package with constants and typedefs for linting. 17 | 18 | `ifndef LINT_WRAPPER 19 | `define LINT_WRAPPER 20 | 21 | `include "axi_pkg.sv" 22 | 23 | package lint_wrapper; 24 | 25 | localparam UserWidth = 1; 26 | localparam AddrWidth = 64; 27 | localparam DataWidth = 64; 28 | localparam StrbWidth = DataWidth / 8; 29 | localparam IdWidth = 4; 30 | localparam IdWidthSlv = 6; 31 | 32 | typedef logic [IdWidth-1:0] id_t; 33 | typedef logic [IdWidthSlv-1:0] id_slv_t; 34 | typedef logic [AddrWidth-1:0] addr_t; 35 | typedef logic [DataWidth-1:0] data_t; 36 | typedef logic [StrbWidth-1:0] strb_t; 37 | typedef logic [UserWidth-1:0] user_t; 38 | 39 | // AXI DVM extension 40 | localparam DevIDWidth = 24; 41 | localparam ProcIDWidth = 20; 42 | 43 | typedef logic [DevIDWidth-1:0] iommu_sid_t; 44 | typedef logic iommu_ssidv_t; 45 | typedef logic [ProcIDWidth-1:0] iommu_ssid_t; 46 | 47 | localparam NumIRQWires = 4; 48 | 49 | // AW Channel 50 | typedef struct packed { 51 | id_t id; 52 | addr_t addr; 53 | axi_pkg::len_t len; 54 | axi_pkg::size_t size; 55 | axi_pkg::burst_t burst; 56 | logic lock; 57 | axi_pkg::cache_t cache; 58 | axi_pkg::prot_t prot; 59 | axi_pkg::qos_t qos; 60 | axi_pkg::region_t region; 61 | axi_pkg::atop_t atop; 62 | user_t user; 63 | } aw_chan_t; 64 | 65 | // AW Channel - Slave 66 | typedef struct packed { 67 | id_slv_t id; 68 | addr_t addr; 69 | axi_pkg::len_t len; 70 | axi_pkg::size_t size; 71 | axi_pkg::burst_t burst; 72 | logic lock; 73 | axi_pkg::cache_t cache; 74 | axi_pkg::prot_t prot; 75 | axi_pkg::qos_t qos; 76 | axi_pkg::region_t region; 77 | axi_pkg::atop_t atop; 78 | user_t user; 79 | } aw_chan_slv_t; 80 | 81 | // AW Channel - AXI DVM extension for SMMU 82 | typedef struct packed { 83 | id_t id; 84 | addr_t addr; 85 | axi_pkg::len_t len; 86 | axi_pkg::size_t size; 87 | axi_pkg::burst_t burst; 88 | logic lock; 89 | axi_pkg::cache_t cache; 90 | axi_pkg::prot_t prot; 91 | axi_pkg::qos_t qos; 92 | axi_pkg::region_t region; 93 | axi_pkg::atop_t atop; 94 | user_t user; 95 | iommu_sid_t stream_id; 96 | iommu_ssidv_t ss_id_valid; 97 | iommu_ssid_t substream_id; 98 | } aw_chan_iommu_t; 99 | 100 | // W Channel - AXI4 doesn't define a wid 101 | typedef struct packed { 102 | data_t data; 103 | strb_t strb; 104 | logic last; 105 | user_t user; 106 | } w_chan_t; 107 | 108 | // B Channel 109 | typedef struct packed { 110 | id_t id; 111 | axi_pkg::resp_t resp; 112 | user_t user; 113 | } b_chan_t; 114 | 115 | // B Channel - Slave 116 | typedef struct packed { 117 | id_slv_t id; 118 | axi_pkg::resp_t resp; 119 | user_t user; 120 | } b_chan_slv_t; 121 | 122 | // AR Channel 123 | typedef struct packed { 124 | id_t id; 125 | addr_t addr; 126 | axi_pkg::len_t len; 127 | axi_pkg::size_t size; 128 | axi_pkg::burst_t burst; 129 | logic lock; 130 | axi_pkg::cache_t cache; 131 | axi_pkg::prot_t prot; 132 | axi_pkg::qos_t qos; 133 | axi_pkg::region_t region; 134 | user_t user; 135 | } ar_chan_t; 136 | 137 | // AR Channel - Slave 138 | typedef struct packed { 139 | id_slv_t id; 140 | addr_t addr; 141 | axi_pkg::len_t len; 142 | axi_pkg::size_t size; 143 | axi_pkg::burst_t burst; 144 | logic lock; 145 | axi_pkg::cache_t cache; 146 | axi_pkg::prot_t prot; 147 | axi_pkg::qos_t qos; 148 | axi_pkg::region_t region; 149 | user_t user; 150 | } ar_chan_slv_t; 151 | 152 | // AR Channel - AXI DVM extension for SMMU 153 | typedef struct packed { 154 | id_t id; 155 | addr_t addr; 156 | axi_pkg::len_t len; 157 | axi_pkg::size_t size; 158 | axi_pkg::burst_t burst; 159 | logic lock; 160 | axi_pkg::cache_t cache; 161 | axi_pkg::prot_t prot; 162 | axi_pkg::qos_t qos; 163 | axi_pkg::region_t region; 164 | user_t user; 165 | iommu_sid_t stream_id; 166 | iommu_ssidv_t ss_id_valid; 167 | iommu_ssid_t substream_id; 168 | } ar_chan_iommu_t; 169 | 170 | // R Channel 171 | typedef struct packed { 172 | id_t id; 173 | data_t data; 174 | axi_pkg::resp_t resp; 175 | logic last; 176 | user_t user; 177 | } r_chan_t; 178 | 179 | // R Channel - Slave 180 | typedef struct packed { 181 | id_slv_t id; 182 | data_t data; 183 | axi_pkg::resp_t resp; 184 | logic last; 185 | user_t user; 186 | } r_chan_slv_t; 187 | 188 | // Request/Response structs 189 | typedef struct packed { 190 | aw_chan_t aw; 191 | logic aw_valid; 192 | w_chan_t w; 193 | logic w_valid; 194 | logic b_ready; 195 | ar_chan_t ar; 196 | logic ar_valid; 197 | logic r_ready; 198 | } req_t; 199 | 200 | typedef struct packed { 201 | logic aw_ready; 202 | logic ar_ready; 203 | logic w_ready; 204 | logic b_valid; 205 | b_chan_t b; 206 | logic r_valid; 207 | r_chan_t r; 208 | } resp_t; 209 | 210 | typedef struct packed { 211 | aw_chan_slv_t aw; 212 | logic aw_valid; 213 | w_chan_t w; 214 | logic w_valid; 215 | logic b_ready; 216 | ar_chan_slv_t ar; 217 | logic ar_valid; 218 | logic r_ready; 219 | } req_slv_t; 220 | 221 | typedef struct packed { 222 | logic aw_ready; 223 | logic ar_ready; 224 | logic w_ready; 225 | logic b_valid; 226 | b_chan_slv_t b; 227 | logic r_valid; 228 | r_chan_slv_t r; 229 | } resp_slv_t; 230 | 231 | // AXI DVM extension for SMMU 232 | typedef struct packed { 233 | aw_chan_iommu_t aw; 234 | logic aw_valid; 235 | w_chan_t w; 236 | logic w_valid; 237 | logic b_ready; 238 | ar_chan_iommu_t ar; 239 | logic ar_valid; 240 | logic r_ready; 241 | } req_iommu_t; 242 | 243 | endpackage 244 | 245 | `endif 246 | -------------------------------------------------------------------------------- /vendor/axi_err_slv.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2019 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Authors: 12 | // - Wolfgang Roenninger 13 | // - Andreas Kurth 14 | // - Matheus Cavalcante 15 | 16 | // AXI Error Slave: This module always responds with an AXI error for transactions that are sent to 17 | // it. This module optionally supports ATOPs if the `ATOPs` parameter is set. 18 | 19 | module axi_err_slv #( 20 | parameter int unsigned AxiIdWidth = 0, // AXI ID Width 21 | parameter type req_t = logic, // AXI 4 request struct, with atop field 22 | parameter type resp_t = logic, // AXI 4 response struct 23 | parameter axi_pkg::resp_t Resp = axi_pkg::RESP_DECERR, // Error generated by this slave. 24 | parameter int unsigned RespWidth = 32'd64, // Data response width, gets zero extended or truncated to r.data. 25 | parameter logic [RespWidth-1:0] RespData = 64'hCA11AB1EBADCAB1E, // Hexvalue for data return value 26 | parameter bit ATOPs = 1'b1, // Activate support for ATOPs. Set to 1 if this slave could ever get an atomic AXI transaction. 27 | parameter int unsigned MaxTrans = 1 // Maximum # of accepted transactions before stalling 28 | ) ( 29 | input logic clk_i, // Clock 30 | input logic rst_ni, // Asynchronous reset active low 31 | input logic test_i, // Testmode enable 32 | // slave port 33 | input req_t slv_req_i, 34 | output resp_t slv_resp_o 35 | ); 36 | typedef logic [AxiIdWidth-1:0] id_t; 37 | typedef struct packed { 38 | id_t id; 39 | axi_pkg::len_t len; 40 | } r_data_t; 41 | 42 | req_t err_req; 43 | resp_t err_resp; 44 | 45 | if (ATOPs) begin 46 | axi_atop_filter #( 47 | .AxiIdWidth ( AxiIdWidth ), 48 | .AxiMaxWriteTxns ( MaxTrans ), 49 | .req_t ( req_t ), 50 | .resp_t ( resp_t ) 51 | ) i_atop_filter ( 52 | .clk_i, 53 | .rst_ni, 54 | .slv_req_i ( slv_req_i ), 55 | .slv_resp_o ( slv_resp_o ), 56 | .mst_req_o ( err_req ), 57 | .mst_resp_i ( err_resp ) 58 | ); 59 | end else begin 60 | assign err_req = slv_req_i; 61 | assign slv_resp_o = err_resp; 62 | end 63 | 64 | // w fifo 65 | logic w_fifo_full, w_fifo_empty; 66 | logic w_fifo_push, w_fifo_pop; 67 | id_t w_fifo_data; 68 | // b fifo 69 | logic b_fifo_full, b_fifo_empty; 70 | logic b_fifo_push, b_fifo_pop; 71 | id_t b_fifo_data; 72 | // r fifo 73 | r_data_t r_fifo_inp; 74 | logic r_fifo_full, r_fifo_empty; 75 | logic r_fifo_push, r_fifo_pop; 76 | r_data_t r_fifo_data; 77 | // r counter 78 | logic r_cnt_clear, r_cnt_en, r_cnt_load; 79 | axi_pkg::len_t r_current_beat; 80 | // r status 81 | logic r_busy_d, r_busy_q, r_busy_load; 82 | 83 | //-------------------------------------- 84 | // Write Transactions 85 | //-------------------------------------- 86 | // push, when there is room in the fifo 87 | assign w_fifo_push = err_req.aw_valid & ~w_fifo_full; 88 | assign err_resp.aw_ready = ~w_fifo_full; 89 | 90 | fifo_v3 #( 91 | .FALL_THROUGH ( 1'b1 ), 92 | .DEPTH ( MaxTrans ), 93 | .dtype ( id_t ) 94 | ) i_w_fifo ( 95 | .clk_i ( clk_i ), 96 | .rst_ni ( rst_ni ), 97 | .flush_i ( 1'b0 ), 98 | .testmode_i ( test_i ), 99 | .full_o ( w_fifo_full ), 100 | .empty_o ( w_fifo_empty ), 101 | .usage_o ( ), 102 | .data_i ( err_req.aw.id ), 103 | .push_i ( w_fifo_push ), 104 | .data_o ( w_fifo_data ), 105 | .pop_i ( w_fifo_pop ) 106 | ); 107 | 108 | always_comb begin : proc_w_channel 109 | err_resp.w_ready = 1'b0; 110 | w_fifo_pop = 1'b0; 111 | b_fifo_push = 1'b0; 112 | if (!w_fifo_empty && !b_fifo_full) begin 113 | // eat the beats 114 | err_resp.w_ready = 1'b1; 115 | // on the last w transaction 116 | if (err_req.w_valid && err_req.w.last) begin 117 | w_fifo_pop = 1'b1; 118 | b_fifo_push = 1'b1; 119 | end 120 | end 121 | end 122 | 123 | fifo_v3 #( 124 | .FALL_THROUGH ( 1'b0 ), 125 | .DEPTH ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent 126 | .dtype ( id_t ) 127 | ) i_b_fifo ( 128 | .clk_i ( clk_i ), 129 | .rst_ni ( rst_ni ), 130 | .flush_i ( 1'b0 ), 131 | .testmode_i ( test_i ), 132 | .full_o ( b_fifo_full ), 133 | .empty_o ( b_fifo_empty ), 134 | .usage_o ( ), 135 | .data_i ( w_fifo_data ), 136 | .push_i ( b_fifo_push ), 137 | .data_o ( b_fifo_data ), 138 | .pop_i ( b_fifo_pop ) 139 | ); 140 | 141 | always_comb begin : proc_b_channel 142 | b_fifo_pop = 1'b0; 143 | err_resp.b = '0; 144 | err_resp.b.id = b_fifo_data; 145 | err_resp.b.resp = Resp; 146 | err_resp.b_valid = 1'b0; 147 | if (!b_fifo_empty) begin 148 | err_resp.b_valid = 1'b1; 149 | // b transaction 150 | b_fifo_pop = err_req.b_ready; 151 | end 152 | end 153 | 154 | //-------------------------------------- 155 | // Read Transactions 156 | //-------------------------------------- 157 | // push if there is room in the fifo 158 | assign r_fifo_push = err_req.ar_valid & ~r_fifo_full; 159 | assign err_resp.ar_ready = ~r_fifo_full; 160 | 161 | // fifo data assignment 162 | assign r_fifo_inp.id = err_req.ar.id; 163 | assign r_fifo_inp.len = err_req.ar.len; 164 | 165 | fifo_v3 #( 166 | .FALL_THROUGH ( 1'b0 ), 167 | .DEPTH ( MaxTrans ), 168 | .dtype ( r_data_t ) 169 | ) i_r_fifo ( 170 | .clk_i ( clk_i ), 171 | .rst_ni ( rst_ni ), 172 | .flush_i ( 1'b0 ), 173 | .testmode_i( test_i ), 174 | .full_o ( r_fifo_full ), 175 | .empty_o ( r_fifo_empty ), 176 | .usage_o ( ), 177 | .data_i ( r_fifo_inp ), 178 | .push_i ( r_fifo_push ), 179 | .data_o ( r_fifo_data ), 180 | .pop_i ( r_fifo_pop ) 181 | ); 182 | 183 | always_comb begin : proc_r_channel 184 | // default assignments 185 | r_busy_d = r_busy_q; 186 | r_busy_load = 1'b0; 187 | // r fifo signals 188 | r_fifo_pop = 1'b0; 189 | // r counter signals 190 | r_cnt_clear = 1'b0; 191 | r_cnt_en = 1'b0; 192 | r_cnt_load = 1'b0; 193 | // r_channel 194 | err_resp.r = '0; 195 | err_resp.r.id = r_fifo_data.id; 196 | err_resp.r.data = RespData; 197 | err_resp.r.resp = Resp; 198 | err_resp.r_valid = 1'b0; 199 | // control 200 | if (r_busy_q) begin 201 | err_resp.r_valid = 1'b1; 202 | err_resp.r.last = (r_current_beat == '0); 203 | // r transaction 204 | if (err_req.r_ready) begin 205 | r_cnt_en = 1'b1; 206 | if (r_current_beat == '0) begin 207 | r_busy_d = 1'b0; 208 | r_busy_load = 1'b1; 209 | r_cnt_clear = 1'b1; 210 | r_fifo_pop = 1'b1; 211 | end 212 | end 213 | end else begin 214 | // when not busy and fifo not empty, start counter err gen 215 | if (!r_fifo_empty) begin 216 | r_busy_d = 1'b1; 217 | r_busy_load = 1'b1; 218 | r_cnt_load = 1'b1; 219 | end 220 | end 221 | end 222 | 223 | always_ff @(posedge clk_i, negedge rst_ni) begin 224 | if (!rst_ni) begin 225 | r_busy_q <= '0; 226 | end else if (r_busy_load) begin 227 | r_busy_q <= r_busy_d; 228 | end 229 | end 230 | 231 | counter #( 232 | .WIDTH ($bits(axi_pkg::len_t)) 233 | ) i_r_counter ( 234 | .clk_i ( clk_i ), 235 | .rst_ni ( rst_ni ), 236 | .clear_i ( r_cnt_clear ), 237 | .en_i ( r_cnt_en ), 238 | .load_i ( r_cnt_load ), 239 | .down_i ( 1'b1 ), 240 | .d_i ( r_fifo_data.len ), 241 | .q_o ( r_current_beat ), 242 | .overflow_o( ) 243 | ); 244 | 245 | // pragma translate_off 246 | `ifndef VERILATOR 247 | `ifndef XSIM 248 | initial begin 249 | assert (Resp == axi_pkg::RESP_DECERR || Resp == axi_pkg::RESP_SLVERR) else 250 | $fatal(1, "This module may only generate RESP_DECERR or RESP_SLVERR responses!"); 251 | end 252 | default disable iff (!rst_ni); 253 | if (!ATOPs) begin : gen_assert_atops_unsupported 254 | assume property( @(posedge clk_i) (slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0)) else 255 | $fatal(1, "Got ATOP but not configured to support ATOPs!"); 256 | end 257 | `endif 258 | `endif 259 | // pragma translate_on 260 | 261 | endmodule 262 | -------------------------------------------------------------------------------- /include/assertions.svh: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Macros and helper code for using assertions. 6 | // - Provides default clk and rst options to simplify code 7 | // - Provides boiler plate template for common assertions 8 | 9 | `ifndef PRIM_ASSERT_SV 10 | `define PRIM_ASSERT_SV 11 | 12 | `ifdef UVM 13 | // report assertion error with UVM if compiled 14 | package assert_rpt_pkg; 15 | import uvm_pkg::*; 16 | `include "uvm_macros.svh" 17 | function void assert_rpt(string msg); 18 | `uvm_error("ASSERT FAILED", msg) 19 | endfunction 20 | endpackage 21 | `endif 22 | 23 | /////////////////// 24 | // Helper macros // 25 | /////////////////// 26 | 27 | // local helper macro to reduce code clutter. undefined at the end of this file 28 | `ifndef VERILATOR 29 | `ifndef SYNTHESIS 30 | `ifndef XSIM 31 | `define INC_ASSERT 32 | `endif 33 | `endif 34 | `endif 35 | 36 | // Converts an arbitrary block of code into a Verilog string 37 | `define PRIM_STRINGIFY(__x) `"__x`" 38 | 39 | // ASSERT_RPT is available to change the reporting mechanism when an assert fails 40 | `define ASSERT_RPT(__name) \ 41 | `ifdef UVM \ 42 | assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \ 43 | __name, `__FILE__, `__LINE__)); \ 44 | `else \ 45 | $error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \ 46 | `endif 47 | 48 | /////////////////////////////////////// 49 | // Simple assertion and cover macros // 50 | /////////////////////////////////////// 51 | 52 | // Default clk and reset signals used by assertion macros below. 53 | `define ASSERT_DEFAULT_CLK clk_i 54 | `define ASSERT_DEFAULT_RST !rst_ni 55 | 56 | // Immediate assertion 57 | // Note that immediate assertions are sensitive to simulation glitches. 58 | `define ASSERT_I(__name, __prop) \ 59 | `ifdef INC_ASSERT \ 60 | __name: assert (__prop) \ 61 | else begin \ 62 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 63 | end \ 64 | `endif 65 | 66 | // Assertion in initial block. Can be used for things like parameter checking. 67 | `define ASSERT_INIT(__name, __prop) \ 68 | `ifdef INC_ASSERT \ 69 | initial begin \ 70 | __name: assert (__prop) \ 71 | else begin \ 72 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 73 | end \ 74 | end \ 75 | `endif 76 | 77 | // Assertion in final block. Can be used for things like queues being empty 78 | // at end of sim, all credits returned at end of sim, state machines in idle 79 | // at end of sim. 80 | `define ASSERT_FINAL(__name, __prop) \ 81 | `ifdef INC_ASSERT \ 82 | final begin \ 83 | __name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \ 84 | else begin \ 85 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 86 | end \ 87 | end \ 88 | `endif 89 | 90 | // Assert a concurrent property directly. 91 | // It can be called as a module (or interface) body item. 92 | `define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 93 | `ifdef INC_ASSERT \ 94 | __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ 95 | else begin \ 96 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 97 | end \ 98 | `endif 99 | // Note: Above we use (__rst !== '0) in the disable iff statements instead of 100 | // (__rst == '1). This properly disables the assertion in cases when reset is X at 101 | // the beginning of a simulation. For that case, (reset == '1) does not disable the 102 | // assertion. 103 | 104 | // Assert a concurrent property NEVER happens 105 | `define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 106 | `ifdef INC_ASSERT \ 107 | __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \ 108 | else begin \ 109 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 110 | end \ 111 | `endif 112 | 113 | // Assert that signal has a known value (each bit is either '0' or '1') after reset. 114 | // It can be called as a module (or interface) body item. 115 | `define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 116 | `ifdef INC_ASSERT \ 117 | `ASSERT(__name, !$isunknown(__sig), __clk, __rst) \ 118 | `endif 119 | 120 | // Cover a concurrent property 121 | `define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 122 | `ifdef INC_ASSERT \ 123 | __name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); \ 124 | `endif 125 | 126 | ////////////////////////////// 127 | // Complex assertion macros // 128 | ////////////////////////////// 129 | 130 | // Assert that signal is an active-high pulse with pulse length of 1 clock cycle 131 | `define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 132 | `ifdef INC_ASSERT \ 133 | `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \ 134 | `endif 135 | 136 | // Assert that a property is true only when an enable signal is set. It can be called as a module 137 | // (or interface) body item. 138 | `define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 139 | `ifdef INC_ASSERT \ 140 | `ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) \ 141 | `endif 142 | 143 | // Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is 144 | // set. It can be called as a module (or interface) body item. 145 | `define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 146 | `ifdef INC_ASSERT \ 147 | `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \ 148 | `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) \ 149 | `endif 150 | 151 | /////////////////////// 152 | // Assumption macros // 153 | /////////////////////// 154 | 155 | // Assume a concurrent property 156 | `define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 157 | `ifdef INC_ASSERT \ 158 | __name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ 159 | else begin \ 160 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 161 | end \ 162 | `endif 163 | 164 | // Assume an immediate property 165 | `define ASSUME_I(__name, __prop) \ 166 | `ifdef INC_ASSERT \ 167 | __name: assume (__prop) \ 168 | else begin \ 169 | `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 170 | end \ 171 | `endif 172 | 173 | ////////////////////////////////// 174 | // For formal verification only // 175 | ////////////////////////////////// 176 | 177 | // Note that the existing set of ASSERT macros specified above shall be used for FPV, 178 | // thereby ensuring that the assertions are evaluated during DV simulations as well. 179 | 180 | // ASSUME_FPV 181 | // Assume a concurrent property during formal verification only. 182 | `define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 183 | `ifdef FPV_ON \ 184 | `ASSUME(__name, __prop, __clk, __rst) \ 185 | `endif 186 | 187 | // ASSUME_I_FPV 188 | // Assume a concurrent property during formal verification only. 189 | `define ASSUME_I_FPV(__name, __prop) \ 190 | `ifdef FPV_ON \ 191 | `ASSUME_I(__name, __prop) \ 192 | `endif 193 | 194 | // COVER_FPV 195 | // Cover a concurrent property during formal verification 196 | `define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 197 | `ifdef FPV_ON \ 198 | `COVER(__name, __prop, __clk, __rst) \ 199 | `endif 200 | 201 | `endif // PRIM_ASSERT_SV 202 | -------------------------------------------------------------------------------- /include/common_cells/registers.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018, 2021 ETH Zurich and University of Bologna. 2 | // 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | // SPDX-License-Identifier: SHL-0.51 12 | // 13 | // Author: Stefan Mach 14 | // Description: Common register defines for RTL designs 15 | 16 | `ifndef COMMON_CELLS_REGISTERS_SVH_ 17 | `define COMMON_CELLS_REGISTERS_SVH_ 18 | 19 | // Abridged Summary of available FF macros: 20 | // `FF: asynchronous active-low reset 21 | // `FFAR: asynchronous active-high reset 22 | // `FFARN: [deprecated] asynchronous active-low reset 23 | // `FFSR: synchronous active-high reset 24 | // `FFSRN: synchronous active-low reset 25 | // `FFNR: without reset 26 | // `FFL: load-enable and asynchronous active-low reset 27 | // `FFLAR: load-enable and asynchronous active-high reset 28 | // `FFLARN: [deprecated] load-enable and asynchronous active-low reset 29 | // `FFLARNC: load-enable and asynchronous active-low reset and synchronous active-high clear 30 | // `FFLSR: load-enable and synchronous active-high reset 31 | // `FFLSRN: load-enable and synchronous active-low reset 32 | // `FFLNR: load-enable without reset 33 | 34 | `ifdef VERILATOR 35 | `define NO_SYNOPSYS_FF 1 36 | `endif 37 | 38 | `define REG_DFLT_CLK clk_i 39 | `define REG_DFLT_RST rst_ni 40 | 41 | // Flip-Flop with asynchronous active-low reset 42 | // __q: Q output of FF 43 | // __d: D input of FF 44 | // __reset_value: value assigned upon reset 45 | // (__clk: clock input) 46 | // (__arst_n: asynchronous reset, active-low) 47 | `define FF(__q, __d, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \ 48 | always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ 49 | if (!__arst_n) begin \ 50 | __q <= (__reset_value); \ 51 | end else begin \ 52 | __q <= (__d); \ 53 | end \ 54 | end 55 | 56 | // Flip-Flop with asynchronous active-high reset 57 | // __q: Q output of FF 58 | // __d: D input of FF 59 | // __reset_value: value assigned upon reset 60 | // __clk: clock input 61 | // __arst: asynchronous reset, active-high 62 | `define FFAR(__q, __d, __reset_value, __clk, __arst) \ 63 | always_ff @(posedge (__clk) or posedge (__arst)) begin \ 64 | if (__arst) begin \ 65 | __q <= (__reset_value); \ 66 | end else begin \ 67 | __q <= (__d); \ 68 | end \ 69 | end 70 | 71 | // DEPRECATED - use `FF instead 72 | // Flip-Flop with asynchronous active-low reset 73 | // __q: Q output of FF 74 | // __d: D input of FF 75 | // __reset_value: value assigned upon reset 76 | // __clk: clock input 77 | // __arst_n: asynchronous reset, active-low 78 | `define FFARN(__q, __d, __reset_value, __clk, __arst_n) \ 79 | `FF(__q, __d, __reset_value, __clk, __arst_n) 80 | 81 | // Flip-Flop with synchronous active-high reset 82 | // __q: Q output of FF 83 | // __d: D input of FF 84 | // __reset_value: value assigned upon reset 85 | // __clk: clock input 86 | // __reset_clk: reset input, active-high 87 | `define FFSR(__q, __d, __reset_value, __clk, __reset_clk) \ 88 | `ifndef NO_SYNOPSYS_FF \ 89 | /``* synopsys sync_set_reset `"__reset_clk`" *``/ \ 90 | `endif \ 91 | always_ff @(posedge (__clk)) begin \ 92 | __q <= (__reset_clk) ? (__reset_value) : (__d); \ 93 | end 94 | 95 | // Flip-Flop with synchronous active-low reset 96 | // __q: Q output of FF 97 | // __d: D input of FF 98 | // __reset_value: value assigned upon reset 99 | // __clk: clock input 100 | // __reset_n_clk: reset input, active-low 101 | `define FFSRN(__q, __d, __reset_value, __clk, __reset_n_clk) \ 102 | `ifndef NO_SYNOPSYS_FF \ 103 | /``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \ 104 | `endif \ 105 | always_ff @(posedge (__clk)) begin \ 106 | __q <= (!__reset_n_clk) ? (__reset_value) : (__d); \ 107 | end 108 | 109 | // Always-enable Flip-Flop without reset 110 | // __q: Q output of FF 111 | // __d: D input of FF 112 | // __clk: clock input 113 | `define FFNR(__q, __d, __clk) \ 114 | always_ff @(posedge (__clk)) begin \ 115 | __q <= (__d); \ 116 | end 117 | 118 | // Flip-Flop with load-enable and asynchronous active-low reset (implicit clock and reset) 119 | // __q: Q output of FF 120 | // __d: D input of FF 121 | // __load: load d value into FF 122 | // __reset_value: value assigned upon reset 123 | // (__clk: clock input) 124 | // (__arst_n: asynchronous reset, active-low) 125 | `define FFL(__q, __d, __load, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \ 126 | always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ 127 | if (!__arst_n) begin \ 128 | __q <= (__reset_value); \ 129 | end else begin \ 130 | __q <= (__load) ? (__d) : (__q); \ 131 | end \ 132 | end 133 | 134 | // Flip-Flop with load-enable and asynchronous active-high reset 135 | // __q: Q output of FF 136 | // __d: D input of FF 137 | // __load: load d value into FF 138 | // __reset_value: value assigned upon reset 139 | // __clk: clock input 140 | // __arst: asynchronous reset, active-high 141 | `define FFLAR(__q, __d, __load, __reset_value, __clk, __arst) \ 142 | always_ff @(posedge (__clk) or posedge (__arst)) begin \ 143 | if (__arst) begin \ 144 | __q <= (__reset_value); \ 145 | end else begin \ 146 | __q <= (__load) ? (__d) : (__q); \ 147 | end \ 148 | end 149 | 150 | // DEPRECATED - use `FFL instead 151 | // Flip-Flop with load-enable and asynchronous active-low reset 152 | // __q: Q output of FF 153 | // __d: D input of FF 154 | // __load: load d value into FF 155 | // __reset_value: value assigned upon reset 156 | // __clk: clock input 157 | // __arst_n: asynchronous reset, active-low 158 | `define FFLARN(__q, __d, __load, __reset_value, __clk, __arst_n) \ 159 | `FFL(__q, __d, __load, __reset_value, __clk, __arst_n) 160 | 161 | // Flip-Flop with load-enable and synchronous active-high reset 162 | // __q: Q output of FF 163 | // __d: D input of FF 164 | // __load: load d value into FF 165 | // __reset_value: value assigned upon reset 166 | // __clk: clock input 167 | // __reset_clk: reset input, active-high 168 | `define FFLSR(__q, __d, __load, __reset_value, __clk, __reset_clk) \ 169 | `ifndef NO_SYNOPSYS_FF \ 170 | /``* synopsys sync_set_reset `"__reset_clk`" *``/ \ 171 | `endif \ 172 | always_ff @(posedge (__clk)) begin \ 173 | __q <= (__reset_clk) ? (__reset_value) : ((__load) ? (__d) : (__q)); \ 174 | end 175 | 176 | // Flip-Flop with load-enable and synchronous active-low reset 177 | // __q: Q output of FF 178 | // __d: D input of FF 179 | // __load: load d value into FF 180 | // __reset_value: value assigned upon reset 181 | // __clk: clock input 182 | // __reset_n_clk: reset input, active-low 183 | `define FFLSRN(__q, __d, __load, __reset_value, __clk, __reset_n_clk) \ 184 | `ifndef NO_SYNOPSYS_FF \ 185 | /``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \ 186 | `endif \ 187 | always_ff @(posedge (__clk)) begin \ 188 | __q <= (!__reset_n_clk) ? (__reset_value) : ((__load) ? (__d) : (__q)); \ 189 | end 190 | 191 | // Flip-Flop with load-enable and asynchronous active-low reset and synchronous clear 192 | // __q: Q output of FF 193 | // __d: D input of FF 194 | // __load: load d value into FF 195 | // __clear: assign reset value into FF 196 | // __reset_value: value assigned upon reset 197 | // __clk: clock input 198 | // __arst_n: asynchronous reset, active-low 199 | `define FFLARNC(__q, __d, __load, __clear, __reset_value, __clk, __arst_n) \ 200 | `ifndef NO_SYNOPSYS_FF \ 201 | /``* synopsys sync_set_reset `"__clear`" *``/ \ 202 | `endif \ 203 | always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ 204 | if (!__arst_n) begin \ 205 | __q <= (__reset_value); \ 206 | end else begin \ 207 | __q <= (__clear) ? (__reset_value) : (__load) ? (__d) : (__q); \ 208 | end \ 209 | end 210 | 211 | // Load-enable Flip-Flop without reset 212 | // __q: Q output of FF 213 | // __d: D input of FF 214 | // __load: load d value into FF 215 | // __clk: clock input 216 | `define FFLNR(__q, __d, __load, __clk) \ 217 | always_ff @(posedge (__clk)) begin \ 218 | __q <= (__load) ? (__d) : (__q); \ 219 | end 220 | 221 | `endif 222 | -------------------------------------------------------------------------------- /vendor/axi_lite_to_reg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Fabian Schuiki 12 | // Florian Zaruba 13 | 14 | /// A protocol converter from AXI4-Lite to a register interface. 15 | module axi_lite_to_reg #( 16 | /// The width of the address. 17 | parameter int ADDR_WIDTH = -1, 18 | /// The width of the data. 19 | parameter int DATA_WIDTH = -1, 20 | /// Buffer depth (how many outstanding transactions do we allow) 21 | parameter int BUFFER_DEPTH = 2, 22 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 23 | /// can help break long paths at the expense of registers. 24 | parameter bit DECOUPLE_W = 1, 25 | /// AXI-Lite request struct type. 26 | parameter type axi_lite_req_t = logic, 27 | /// AXI-Lite response struct type. 28 | parameter type axi_lite_rsp_t = logic, 29 | /// Regbus request struct type. 30 | parameter type reg_req_t = logic, 31 | /// Regbus response struct type. 32 | parameter type reg_rsp_t = logic 33 | ) ( 34 | input logic clk_i , 35 | input logic rst_ni , 36 | input axi_lite_req_t axi_lite_req_i, 37 | output axi_lite_rsp_t axi_lite_rsp_o, 38 | output reg_req_t reg_req_o , 39 | input reg_rsp_t reg_rsp_i 40 | ); 41 | 42 | `ifndef SYNTHESIS 43 | initial begin 44 | assert(BUFFER_DEPTH > 0); 45 | assert(ADDR_WIDTH > 0); 46 | assert(DATA_WIDTH > 0); 47 | end 48 | `endif 49 | 50 | typedef struct packed { 51 | logic [ADDR_WIDTH-1:0] addr; 52 | logic [DATA_WIDTH-1:0] data; 53 | logic [DATA_WIDTH/8-1:0] strb; // byte-wise strobe 54 | } write_t; 55 | 56 | typedef struct packed { 57 | logic [ADDR_WIDTH-1:0] addr; 58 | logic write; 59 | } req_t; 60 | 61 | typedef struct packed { 62 | logic [DATA_WIDTH-1:0] data; 63 | logic error; 64 | } resp_t; 65 | 66 | logic write_fifo_full, write_fifo_empty; 67 | write_t write_fifo_in, write_fifo_out; 68 | logic write_fifo_push, write_fifo_pop; 69 | 70 | logic write_resp_fifo_full, write_resp_fifo_empty; 71 | logic write_resp_fifo_in, write_resp_fifo_out; 72 | logic write_resp_fifo_push, write_resp_fifo_pop; 73 | 74 | logic read_fifo_full, read_fifo_empty; 75 | logic [ADDR_WIDTH-1:0] read_fifo_in, read_fifo_out; 76 | logic read_fifo_push, read_fifo_pop; 77 | 78 | logic read_resp_fifo_full, read_resp_fifo_empty; 79 | resp_t read_resp_fifo_in, read_resp_fifo_out; 80 | logic read_resp_fifo_push, read_resp_fifo_pop; 81 | 82 | req_t read_req, write_req, arb_req; 83 | logic read_valid, write_valid; 84 | logic read_ready, write_ready; 85 | 86 | // Combine AW/W Channel 87 | fifo_v3 #( 88 | .FALL_THROUGH ( !DECOUPLE_W ), 89 | .DEPTH ( BUFFER_DEPTH ), 90 | .dtype ( write_t ) 91 | ) i_fifo_write_req ( 92 | .clk_i, 93 | .rst_ni, 94 | .flush_i ( 1'b0 ), 95 | .testmode_i ( 1'b0 ), 96 | .full_o ( write_fifo_full ), 97 | .empty_o ( write_fifo_empty ), 98 | .usage_o ( /* open */ ), 99 | .data_i ( write_fifo_in ), 100 | .push_i ( write_fifo_push ), 101 | .data_o ( write_fifo_out ), 102 | .pop_i ( write_fifo_pop ) 103 | ); 104 | 105 | assign axi_lite_rsp_o.aw_ready = write_fifo_push; 106 | assign axi_lite_rsp_o.w_ready = write_fifo_push; 107 | assign write_fifo_push = axi_lite_req_i.aw_valid & axi_lite_req_i.w_valid & ~write_fifo_full; 108 | assign write_fifo_in.addr = axi_lite_req_i.aw.addr; 109 | assign write_fifo_in.data = axi_lite_req_i.w.data; 110 | assign write_fifo_in.strb = axi_lite_req_i.w.strb; 111 | assign write_fifo_pop = write_valid & write_ready; 112 | 113 | // B Channel 114 | fifo_v3 #( 115 | .DEPTH ( BUFFER_DEPTH ), 116 | .dtype ( logic ) 117 | ) i_fifo_write_resp ( 118 | .clk_i, 119 | .rst_ni, 120 | .flush_i ( 1'b0 ), 121 | .testmode_i ( 1'b0 ), 122 | .full_o ( write_resp_fifo_full ), 123 | .empty_o ( write_resp_fifo_empty ), 124 | .usage_o ( /* open */ ), 125 | .data_i ( write_resp_fifo_in ), 126 | .push_i ( write_resp_fifo_push ), 127 | .data_o ( write_resp_fifo_out ), 128 | .pop_i ( write_resp_fifo_pop ) 129 | ); 130 | 131 | assign axi_lite_rsp_o.b_valid = ~write_resp_fifo_empty; 132 | assign axi_lite_rsp_o.b.resp = write_resp_fifo_out ? axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY; 133 | assign write_resp_fifo_in = reg_rsp_i.error; 134 | assign write_resp_fifo_push = reg_req_o.valid & reg_rsp_i.ready & reg_req_o.write; 135 | assign write_resp_fifo_pop = axi_lite_rsp_o.b_valid & axi_lite_req_i.b_ready; 136 | 137 | // AR Channel 138 | fifo_v3 #( 139 | .DEPTH ( BUFFER_DEPTH ), 140 | .DATA_WIDTH ( ADDR_WIDTH ) 141 | ) i_fifo_read ( 142 | .clk_i, 143 | .rst_ni, 144 | .flush_i ( 1'b0 ), 145 | .testmode_i ( 1'b0 ), 146 | .full_o ( read_fifo_full ), 147 | .empty_o ( read_fifo_empty ), 148 | .usage_o ( /* open */ ), 149 | .data_i ( read_fifo_in ), 150 | .push_i ( read_fifo_push ), 151 | .data_o ( read_fifo_out ), 152 | .pop_i ( read_fifo_pop ) 153 | ); 154 | 155 | assign read_fifo_pop = read_valid && read_ready; 156 | assign axi_lite_rsp_o.ar_ready = ~read_fifo_full; 157 | assign read_fifo_push = axi_lite_rsp_o.ar_ready & axi_lite_req_i.ar_valid; 158 | assign read_fifo_in = axi_lite_req_i.ar.addr; 159 | 160 | // R Channel 161 | fifo_v3 #( 162 | .DEPTH ( BUFFER_DEPTH ), 163 | .dtype ( resp_t ) 164 | ) i_fifo_read_resp ( 165 | .clk_i, 166 | .rst_ni, 167 | .flush_i ( 1'b0 ), 168 | .testmode_i ( 1'b0 ), 169 | .full_o ( read_resp_fifo_full ), 170 | .empty_o ( read_resp_fifo_empty ), 171 | .usage_o ( /* open */ ), 172 | .data_i ( read_resp_fifo_in ), 173 | .push_i ( read_resp_fifo_push ), 174 | .data_o ( read_resp_fifo_out ), 175 | .pop_i ( read_resp_fifo_pop ) 176 | ); 177 | 178 | assign axi_lite_rsp_o.r.data = read_resp_fifo_out.data; 179 | assign axi_lite_rsp_o.r.resp = 180 | read_resp_fifo_out.error ? axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY; 181 | assign axi_lite_rsp_o.r_valid = ~read_resp_fifo_empty; 182 | assign read_resp_fifo_pop = axi_lite_rsp_o.r_valid & axi_lite_req_i.r_ready; 183 | assign read_resp_fifo_push = reg_req_o.valid & reg_rsp_i.ready & ~reg_req_o.write; 184 | assign read_resp_fifo_in.data = reg_rsp_i.rdata; 185 | assign read_resp_fifo_in.error = reg_rsp_i.error; 186 | 187 | // Make sure we can capture the responses (e.g. have enough fifo space) 188 | assign read_valid = ~read_fifo_empty & ~read_resp_fifo_full; 189 | assign write_valid = ~write_fifo_empty & ~write_resp_fifo_full; 190 | 191 | // Arbitrate between read/write 192 | assign read_req.addr = read_fifo_out; 193 | assign read_req.write = 1'b0; 194 | assign write_req.addr = write_fifo_out.addr; 195 | assign write_req.write = 1'b1; 196 | 197 | stream_arbiter #( 198 | .DATA_T ( req_t ), 199 | .N_INP ( 2 ), 200 | .ARBITER ( "rr" ) 201 | ) i_stream_arbiter ( 202 | .clk_i, 203 | .rst_ni, 204 | .inp_data_i ( {read_req, write_req} ), 205 | .inp_valid_i ( {read_valid, write_valid} ), 206 | .inp_ready_o ( {read_ready, write_ready} ), 207 | .oup_data_o ( arb_req ), 208 | .oup_valid_o ( reg_req_o.valid ), 209 | .oup_ready_i ( reg_rsp_i.ready ) 210 | ); 211 | 212 | assign reg_req_o.addr = arb_req.addr; 213 | assign reg_req_o.write = arb_req.write; 214 | assign reg_req_o.wdata = write_fifo_out.data; 215 | assign reg_req_o.wstrb = write_fifo_out.strb; 216 | 217 | endmodule 218 | 219 | `include "register_interface/typedef.svh" 220 | `include "register_interface/assign.svh" 221 | `include "axi/typedef.svh" 222 | `include "axi/assign.svh" 223 | 224 | /// Interface wrapper. 225 | module axi_lite_to_reg_intf #( 226 | /// The width of the address. 227 | parameter int ADDR_WIDTH = -1, 228 | /// The width of the data. 229 | parameter int DATA_WIDTH = -1, 230 | /// Buffer depth (how many outstanding transactions do we allow) 231 | parameter int BUFFER_DEPTH = 2, 232 | /// Whether the AXI-Lite W channel should be decoupled with a register. This 233 | /// can help break long paths at the expense of registers. 234 | parameter bit DECOUPLE_W = 1 235 | ) ( 236 | input logic clk_i , 237 | input logic rst_ni , 238 | AXI_LITE.Slave axi_i , 239 | REG_BUS.out reg_o 240 | ); 241 | 242 | typedef logic [ADDR_WIDTH-1:0] addr_t; 243 | typedef logic [DATA_WIDTH-1:0] data_t; 244 | typedef logic [DATA_WIDTH/8-1:0] strb_t; 245 | 246 | `REG_BUS_TYPEDEF_REQ(reg_req_t, addr_t, data_t, strb_t) 247 | `REG_BUS_TYPEDEF_RSP(reg_rsp_t, data_t) 248 | 249 | `AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t) 250 | `AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t) 251 | `AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t) 252 | `AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t) 253 | `AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t) 254 | `AXI_LITE_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t) 255 | `AXI_LITE_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t) 256 | 257 | axi_req_t axi_req; 258 | axi_resp_t axi_resp; 259 | reg_req_t reg_req; 260 | reg_rsp_t reg_rsp; 261 | 262 | `AXI_LITE_ASSIGN_TO_REQ(axi_req, axi_i) 263 | `AXI_LITE_ASSIGN_FROM_RESP(axi_i, axi_resp) 264 | 265 | `REG_BUS_ASSIGN_FROM_REQ(reg_o, reg_req) 266 | `REG_BUS_ASSIGN_TO_RSP(reg_rsp, reg_o) 267 | 268 | axi_lite_to_reg #( 269 | .ADDR_WIDTH (ADDR_WIDTH), 270 | .DATA_WIDTH (DATA_WIDTH), 271 | .BUFFER_DEPTH (BUFFER_DEPTH), 272 | .DECOUPLE_W (DECOUPLE_W), 273 | .axi_lite_req_t (axi_req_t), 274 | .axi_lite_rsp_t (axi_resp_t), 275 | .reg_req_t (reg_req_t), 276 | .reg_rsp_t (reg_rsp_t) 277 | ) i_axi_lite_to_reg ( 278 | .clk_i (clk_i), 279 | .rst_ni (rst_ni), 280 | .axi_lite_req_i (axi_req), 281 | .axi_lite_rsp_o (axi_resp), 282 | .reg_req_o (reg_req), 283 | .reg_rsp_i (reg_rsp) 284 | ); 285 | 286 | endmodule 287 | -------------------------------------------------------------------------------- /rtl/software_interface/rv_iommu_msi_ig.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 08/03/2023 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: RISC-V IOMMU MSI Interrupt Generation Module. 18 | 19 | //! NOTES: 20 | /* 21 | - Interrupt generation is triggered on a possitive transition of cip, fip or pmip. 22 | - The IOMMU must not send MSIs for interrupt vectors with mask M = 1. These messages must be saved and later sent if 23 | the corresponding mask is cleared to 0. 24 | - A register could be used for each vector to save messages M = 1. When a source generates an interrupt whose MSI 25 | vector is masked, the index is saved so that the corresponding MSI is sent after clearing the flag. This means 26 | that the mask is associated with one vector, but may be associated with multiple interrupt sources if they 27 | share the same MSI vector. 28 | */ 29 | 30 | module rv_iommu_msi_ig #( 31 | // Number of interrupt vectors implemented 32 | parameter int unsigned N_INT_VEC = 16, 33 | // Number of interrupt sources 34 | parameter int unsigned N_INT_SRCS = 3, 35 | 36 | /// AXI Full request struct type 37 | parameter type axi_req_t = logic, 38 | /// AXI Full response struct type 39 | parameter type axi_rsp_t = logic, 40 | 41 | // DO NOT MODIFY 42 | parameter int unsigned LOG2_INTVEC = (N_INT_VEC == 1) ? (1) : ($clog2(N_INT_VEC)) 43 | ) ( 44 | input logic clk_i, 45 | input logic rst_ni, 46 | 47 | input logic msi_ig_enabled_i, 48 | 49 | // Interrupt pending bits 50 | input logic [(N_INT_SRCS-1):0] intp_i, 51 | 52 | // Interrupt vectors 53 | input logic [3:0] intv_i[N_INT_SRCS], 54 | 55 | // MSI config table 56 | input logic [53:0] msi_addr_x_i[16], 57 | input logic [31:0] msi_data_x_i[16], 58 | input logic msi_vec_masked_x_i[16], 59 | 60 | // MSI write error 61 | output logic msi_write_error_o, 62 | 63 | // AXI Master interface to write to memory 64 | input axi_rsp_t mem_resp_i, 65 | output axi_req_t mem_req_o 66 | ); 67 | 68 | // FSM States 69 | enum logic [1:0] { 70 | IDLE, 71 | WRITE, 72 | ERROR 73 | } state_q, state_n; 74 | 75 | // Write FSM states 76 | enum logic [1:0] { 77 | AW_REQ, 78 | W_DATA, 79 | B_RESP 80 | } wr_state_q, wr_state_n; 81 | 82 | // To detect rising edge transition of IP bits 83 | logic [(N_INT_SRCS-1):0] edged_q, edged_n; 84 | 85 | // Interrupt source index 86 | enum logic [1:0] { 87 | CQ, 88 | FQ, 89 | HPM 90 | } int_idx; 91 | 92 | // Interrupt source selector 93 | logic [3:0] intv_q, intv_n; 94 | 95 | // Pending interrupts 96 | logic [(N_INT_VEC-1):0] pending_q, pending_n; 97 | 98 | always_comb begin : msi_generation_fsm 99 | 100 | // Default values 101 | // AXI parameters 102 | // AW 103 | mem_req_o.aw.id = 4'b0010; 104 | mem_req_o.aw.addr = {{riscv::XLEN-riscv::PLEN{1'b0}}, msi_addr_x_i[intv_q], 2'b0}; 105 | mem_req_o.aw.len = 8'd0; // MSI writes only 32 bits 106 | mem_req_o.aw.size = 3'b010; // 4-bytes beat 107 | mem_req_o.aw.burst = axi_pkg::BURST_FIXED; 108 | mem_req_o.aw.lock = '0; 109 | mem_req_o.aw.cache = '0; 110 | mem_req_o.aw.prot = '0; 111 | mem_req_o.aw.qos = '0; 112 | mem_req_o.aw.region = '0; 113 | mem_req_o.aw.atop = '0; 114 | mem_req_o.aw.user = '0; 115 | 116 | mem_req_o.aw_valid = 1'b0; 117 | 118 | // W 119 | mem_req_o.w.data = {32'b0, msi_data_x_i[intv_q]}; 120 | mem_req_o.w.strb = 8'b0000_1111; 121 | mem_req_o.w.last = 1'b0; 122 | mem_req_o.w.user = '0; 123 | 124 | mem_req_o.w_valid = 1'b0; 125 | 126 | // B 127 | mem_req_o.b_ready = 1'b0; 128 | 129 | // AR 130 | mem_req_o.ar.id = 4'b0011; 131 | mem_req_o.ar.addr = '0; // we never read here 132 | mem_req_o.ar.len = '0; 133 | mem_req_o.ar.size = 3'b011; 134 | mem_req_o.ar.burst = axi_pkg::BURST_FIXED; 135 | mem_req_o.ar.lock = '0; 136 | mem_req_o.ar.cache = '0; 137 | mem_req_o.ar.prot = '0; 138 | mem_req_o.ar.qos = '0; 139 | mem_req_o.ar.region = '0; 140 | mem_req_o.ar.user = '0; 141 | 142 | mem_req_o.ar_valid = 1'b0; // we never read here 143 | 144 | // R 145 | mem_req_o.r_ready = 1'b0; // we never read here 146 | 147 | msi_write_error_o = 1'b0; 148 | 149 | state_n = state_q; 150 | wr_state_n = wr_state_q; 151 | intv_n = intv_q; 152 | edged_n = edged_q; 153 | pending_n = pending_q; 154 | 155 | case (state_q) 156 | 157 | // Monitor interrupt-pending bits. Select corresponding vector (addr, data and mask). 158 | IDLE: begin 159 | 160 | // If MSI IG is not enabled, do nothing 161 | if (msi_ig_enabled_i) begin 162 | 163 | for (int unsigned i = 0; i < N_INT_SRCS; i++) begin 164 | 165 | //# Prioritize pending messages 166 | if (pending_q[intv_i[i][(LOG2_INTVEC-1):0]] && !msi_vec_masked_x_i[intv_i[i]]) begin 167 | intv_n = intv_i[i]; 168 | pending_n[intv_i[i][(LOG2_INTVEC-1):0]] = 1'b0; 169 | state_n = WRITE; 170 | break; // Use break to set priority 171 | end 172 | 173 | //# Incoming interrupt 174 | else if (intp_i[i] && !edged_q[i]) begin 175 | 176 | // We do not attribute IP value directly to avoid missing 177 | // any IP bit transition while sending another interrupt. 178 | edged_n[i] = 1'b1; 179 | 180 | // IP bit was set in the last cycle, send MSI if vector is not masked 181 | if (!msi_vec_masked_x_i[intv_i[i]]) begin 182 | intv_n = intv_i[i]; 183 | state_n = WRITE; 184 | end 185 | 186 | // if vector is masked, then save request 187 | else begin 188 | pending_n[intv_i[i][(LOG2_INTVEC-1):0]] = 1'b1; 189 | end 190 | 191 | break; // Use break to set priority 192 | end 193 | end 194 | 195 | for (int unsigned j = 0; j < N_INT_SRCS; j++) begin 196 | 197 | // Clear edged IP bits when input is clear 198 | if (!intp_i[j] && edged_q[j]) begin 199 | edged_n[j] = 1'b0; 200 | end 201 | end 202 | end 203 | end 204 | 205 | // Write MSI to the corresponding address 206 | WRITE: begin 207 | 208 | // Send request to AW Channel 209 | if (wr_state_q == AW_REQ) begin 210 | mem_req_o.aw_valid = 1'b1; 211 | 212 | if (mem_resp_i.aw_ready) begin 213 | wr_state_n = W_DATA; 214 | end 215 | end 216 | 217 | else if (wr_state_q == W_DATA) begin 218 | // Send data through W channel 219 | mem_req_o.w_valid = 1'b1; 220 | mem_req_o.w.last = 1'b1; 221 | 222 | if(mem_resp_i.w_ready) begin 223 | wr_state_n = B_RESP; 224 | end 225 | end 226 | 227 | // Check response code 228 | else if (wr_state_q == B_RESP) begin 229 | if (mem_resp_i.b_valid) begin 230 | 231 | mem_req_o.b_ready = 1'b1; 232 | state_n = IDLE; 233 | wr_state_n = AW_REQ; 234 | 235 | // TODO: IOPMP access faults are reported as AXI faults. We need a way to 236 | // TODO: differentiate these faults from normal AXI faults. 237 | if (mem_resp_i.b.resp != axi_pkg::RESP_OKAY) begin 238 | // AXI error 239 | state_n = ERROR; 240 | end 241 | end 242 | end 243 | else 244 | state_n = IDLE; 245 | end 246 | 247 | // We may receive an AXI or access error when writing 248 | ERROR: begin 249 | msi_write_error_o = 1'b1; 250 | state_n = IDLE; 251 | end 252 | 253 | default: state_n = IDLE; 254 | endcase 255 | end 256 | 257 | always_ff @(posedge clk_i or negedge rst_ni) begin : sequential_logic 258 | 259 | if (~rst_ni) begin 260 | // Reset values 261 | state_q <= IDLE; 262 | wr_state_q <= AW_REQ; 263 | intv_q <= '0; 264 | edged_q <= '0; 265 | pending_q <= '0; 266 | end 267 | 268 | else begin 269 | state_q <= state_n; 270 | wr_state_q <= wr_state_n; 271 | intv_q <= intv_n; 272 | edged_q <= edged_n; 273 | pending_q <= pending_n; 274 | end 275 | end 276 | 277 | endmodule 278 | -------------------------------------------------------------------------------- /rtl/ext_interfaces/rv_iommu_ds_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 01/03/2023 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: RISC-V IOMMU Data Structures Interface Wrapper. 18 | 19 | module rv_iommu_ds_if #( 20 | /// AXI AW Channel struct type 21 | parameter type aw_chan_t = logic, 22 | /// AXI W Channel struct type 23 | parameter type w_chan_t = logic, 24 | /// AXI B Channel struct type 25 | parameter type b_chan_t = logic, 26 | /// AXI AR Channel struct type 27 | parameter type ar_chan_t = logic, 28 | /// AXI R Channel struct type 29 | parameter type r_chan_t = logic, 30 | /// AXI Full request struct type 31 | parameter type axi_req_t = logic, 32 | /// AXI Full response struct type 33 | parameter type axi_rsp_t = logic 34 | ) ( 35 | input logic clk_i, 36 | input logic rst_ni, 37 | 38 | // External ports: To DS IF Bus 39 | input axi_rsp_t ds_resp_i, 40 | output axi_req_t ds_req_o, 41 | 42 | /*--------------------------------------------*/ 43 | 44 | // PTW 45 | output axi_rsp_t ptw_resp_o, 46 | input axi_req_t ptw_req_i, 47 | 48 | // CDW 49 | output axi_rsp_t cdw_resp_o, 50 | input axi_req_t cdw_req_i, 51 | 52 | // MSI PTW 53 | output axi_rsp_t msiptw_resp_o, 54 | input axi_req_t msiptw_req_i, 55 | 56 | // MRIF handler 57 | output axi_rsp_t mrif_handler_resp_o, 58 | input axi_req_t mrif_handler_req_i, 59 | 60 | // CQ 61 | output axi_rsp_t cq_resp_o, 62 | input axi_req_t cq_req_i, 63 | 64 | // FQ 65 | output axi_rsp_t fq_resp_o, 66 | input axi_req_t fq_req_i, 67 | 68 | // MSI IG 69 | output axi_rsp_t msi_ig_resp_o, 70 | input axi_req_t msi_ig_req_i 71 | ); 72 | 73 | logic[1:0] w_select, w_select_fifo; 74 | 75 | //# AR Channel (PTW, CDW, CQ, MSIPTW, MRIF handler) 76 | stream_arbiter #( 77 | .DATA_T ( ar_chan_t ), 78 | .N_INP ( 5 ) 79 | ) i_stream_arbiter_ar ( 80 | .clk_i (clk_i), 81 | .rst_ni (rst_ni), 82 | .inp_data_i ( {ptw_req_i.ar, cdw_req_i.ar, cq_req_i.ar, msiptw_req_i.ar, mrif_handler_req_i.ar} ), 83 | .inp_valid_i ( {ptw_req_i.ar_valid, cdw_req_i.ar_valid, cq_req_i.ar_valid, msiptw_req_i.ar_valid, mrif_handler_req_i.ar_valid} ), 84 | .inp_ready_o ( {ptw_resp_o.ar_ready, cdw_resp_o.ar_ready, cq_resp_o.ar_ready, msiptw_resp_o.ar_ready, mrif_handler_resp_o.ar_ready} ), 85 | .oup_data_o ( ds_req_o.ar ), 86 | .oup_valid_o ( ds_req_o.ar_valid ), 87 | .oup_ready_i ( ds_resp_i.ar_ready ) 88 | ); 89 | 90 | //# AW Channel (CQ, FQ, MSI IG, MRIF handler) 91 | stream_arbiter #( 92 | .DATA_T ( aw_chan_t ), 93 | .N_INP ( 4 ) 94 | ) i_stream_arbiter_aw ( 95 | .clk_i (clk_i), 96 | .rst_ni (rst_ni), 97 | .inp_data_i ( {cq_req_i.aw, fq_req_i.aw, msi_ig_req_i.aw, mrif_handler_req_i.aw} ), 98 | .inp_valid_i ( {cq_req_i.aw_valid, fq_req_i.aw_valid, msi_ig_req_i.aw_valid, mrif_handler_req_i.aw_valid} ), 99 | .inp_ready_o ( {cq_resp_o.aw_ready, fq_resp_o.aw_ready, msi_ig_resp_o.aw_ready, mrif_handler_resp_o.aw_ready} ), 100 | .oup_data_o ( ds_req_o.aw ), 101 | .oup_valid_o ( ds_req_o.aw_valid ), 102 | .oup_ready_i ( ds_resp_i.aw_ready ) 103 | ); 104 | 105 | //# W Channel 106 | // Control signal to select accepted AWID for writing data to W Channel 107 | always_comb begin 108 | w_select = '0; 109 | unique case (ds_req_o.aw.id) // Selected AWID 110 | 0: w_select = 2'd0; // CQ 111 | 1: w_select = 2'd1; // FQ 112 | 2: w_select = 2'd2; // MSI IG 113 | 3: w_select = 2'd3; // MRIF Handler 114 | default: w_select = 2'd0; // CQ 115 | endcase 116 | end 117 | 118 | // Save AWID whenever a transaction is accepted in AW Channel. 119 | // While writing data to W Channel, another AW transaction may be accepted, so we need to queue the AWIDs 120 | // Only CQ, FQ and MSI IG perform writes to memory, so we can have max 3 outstanding transactions 121 | fifo_v3 #( 122 | .DATA_WIDTH ( 2 ), 123 | // we can have a maximum of 2 oustanding transactions as each port is blocking 124 | .DEPTH ( 2 ) 125 | ) i_fifo_w_channel ( 126 | .clk_i ( clk_i ), 127 | .rst_ni ( rst_ni ), 128 | .flush_i ( 1'b0 ), 129 | .testmode_i ( 1'b0 ), 130 | .full_o ( ), 131 | .empty_o ( ), 132 | .usage_o ( ), 133 | .data_i ( w_select ), 134 | .push_i ( ds_req_o.aw_valid & ds_resp_i.aw_ready ), // a new AW transaction was requested and granted 135 | .data_o ( w_select_fifo ), // WID to select the W MUX 136 | .pop_i ( ds_req_o.w_valid & ds_resp_i.w_ready & ds_req_o.w.last ) // W transaction has finished 137 | ); 138 | 139 | // For invalid AWIDs for which the request was accepted, or when AW FIFO is empty, CQ channel is selected 140 | stream_mux #( 141 | .DATA_T ( w_chan_t ), 142 | .N_INP ( 4 ) 143 | ) i_stream_mux_w ( 144 | .inp_data_i ( {mrif_handler_req_i.w, msi_ig_req_i.w, fq_req_i.w, cq_req_i.w} ), 145 | .inp_valid_i ( {mrif_handler_req_i.w_valid, msi_ig_req_i.w_valid, fq_req_i.w_valid, cq_req_i.w_valid} ), 146 | .inp_ready_o ( {mrif_handler_resp_o.w_ready, msi_ig_resp_o.w_ready, fq_resp_o.w_ready, cq_resp_o.w_ready} ), 147 | .inp_sel_i ( w_select_fifo ), 148 | .oup_data_o ( ds_req_o.w ), 149 | .oup_valid_o ( ds_req_o.w_valid ), 150 | .oup_ready_i ( ds_resp_i.w_ready ) 151 | ); 152 | 153 | // Route responses based on ID 154 | // 0000 -> PTW 155 | // 0001 -> CDW 156 | // 0010 -> CQ 157 | // 0011 -> MSIPTW 158 | // 0100 -> MRIF Handler 159 | 160 | //# R Channel: We only demux RVALID/RREADY signals 161 | assign ptw_resp_o.r = ds_resp_i.r; 162 | assign cdw_resp_o.r = ds_resp_i.r; 163 | assign cq_resp_o.r = ds_resp_i.r; 164 | assign msiptw_resp_o.r = ds_resp_i.r; 165 | assign mrif_handler_resp_o.r = ds_resp_i.r; 166 | 167 | logic [2:0] r_select; 168 | 169 | // Demux RVALID/RREADY signals 170 | always_comb begin 171 | r_select = 0; 172 | unique case (ds_resp_i.r.id) 173 | 0: r_select = 0; // PTW 174 | 1: r_select = 1; // CDW 175 | 2: r_select = 2; // CQ 176 | 3: r_select = 3; // MSIPTW 177 | 4: r_select = 4; // MRIF Handler 178 | default: r_select = 0; 179 | endcase 180 | end 181 | 182 | stream_demux #( 183 | .N_OUP ( 5 ) 184 | ) i_stream_demux_r ( 185 | .inp_valid_i ( ds_resp_i.r_valid ), 186 | .inp_ready_o ( ds_req_o.r_ready ), 187 | .oup_sel_i ( r_select ), 188 | .oup_valid_o ( {mrif_handler_resp_o.r_valid, msiptw_resp_o.r_valid, cq_resp_o.r_valid, cdw_resp_o.r_valid, ptw_resp_o.r_valid} ), 189 | .oup_ready_i ( {mrif_handler_req_i.r_ready, msiptw_req_i.r_ready, cq_req_i.r_ready, cdw_req_i.r_ready, ptw_req_i.r_ready} ) 190 | ); 191 | 192 | //# B Channel: We only demux BVALID/BREADY signals 193 | logic [1:0] b_select; 194 | 195 | assign cq_resp_o.b = ds_resp_i.b; 196 | assign fq_resp_o.b = ds_resp_i.b; 197 | assign msi_ig_resp_o.b = ds_resp_i.b; 198 | assign mrif_handler_resp_o.b = ds_resp_i.b; 199 | 200 | always_comb begin 201 | b_select = 0; 202 | unique case (ds_resp_i.b.id) 203 | 0: b_select = 0; // CQ 204 | 1: b_select = 1; // FQ 205 | 2: b_select = 2; // MSI IG 206 | 3: b_select = 3; // MRIF Handler 207 | default: b_select = 0; // CQ 208 | endcase 209 | end 210 | 211 | stream_demux #( 212 | .N_OUP ( 4 ) 213 | ) i_stream_demux_b ( 214 | .inp_valid_i ( ds_resp_i.b_valid ), 215 | .inp_ready_o ( ds_req_o.b_ready ), 216 | .oup_sel_i ( b_select ), 217 | .oup_valid_o ( {mrif_handler_resp_o.b_valid, msi_ig_resp_o.b_valid, fq_resp_o.b_valid, cq_resp_o.b_valid} ), 218 | .oup_ready_i ( {mrif_handler_req_i.b_ready, msi_ig_req_i.b_ready, fq_req_i.b_ready, cq_req_i.b_ready} ) 219 | ); 220 | 221 | //# Unused signals 222 | // Read-only modules 223 | assign ptw_resp_o.aw_ready = 1'b0; 224 | assign ptw_resp_o.w_ready = 1'b0; 225 | assign ptw_resp_o.b_valid = 1'b0; 226 | assign ptw_resp_o.b.id = '0; 227 | assign ptw_resp_o.b.resp = axi_pkg::RESP_SLVERR; 228 | assign ptw_resp_o.b.user = '0; 229 | 230 | assign cdw_resp_o.aw_ready = 1'b0; 231 | assign cdw_resp_o.w_ready = 1'b0; 232 | assign cdw_resp_o.b_valid = 1'b0; 233 | assign cdw_resp_o.b.id = '0; 234 | assign cdw_resp_o.b.resp = axi_pkg::RESP_SLVERR; 235 | assign cdw_resp_o.b.user = '0; 236 | 237 | assign msiptw_resp_o.aw_ready = 1'b0; 238 | assign msiptw_resp_o.w_ready = 1'b0; 239 | assign msiptw_resp_o.b_valid = 1'b0; 240 | assign msiptw_resp_o.b.id = '0; 241 | assign msiptw_resp_o.b.resp = axi_pkg::RESP_SLVERR; 242 | assign msiptw_resp_o.b.user = '0; 243 | 244 | // Write-only modules 245 | assign fq_resp_o.ar_ready = 1'b0; 246 | assign fq_resp_o.r_valid = 1'b0; 247 | assign fq_resp_o.r.id = '0; 248 | assign fq_resp_o.r.data = '0; 249 | assign fq_resp_o.r.resp = axi_pkg::RESP_SLVERR; 250 | assign fq_resp_o.r.last = 1'b0; 251 | assign fq_resp_o.r.user = '0; 252 | 253 | assign msi_ig_resp_o.ar_ready = 1'b0; 254 | assign msi_ig_resp_o.r_valid = 1'b0; 255 | assign msi_ig_resp_o.r.id = '0; 256 | assign msi_ig_resp_o.r.data = '0; 257 | assign msi_ig_resp_o.r.resp = axi_pkg::RESP_SLVERR; 258 | assign msi_ig_resp_o.r.last = 1'b0; 259 | assign msi_ig_resp_o.r.user = '0; 260 | 261 | endmodule -------------------------------------------------------------------------------- /rtl/translation_logic/rv_iommu_ddtc.sv: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 2 | // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 3 | 4 | // Licensed under the Solderpad Hardware License v 2.1 (the “License”); 5 | // you may not use this file except in compliance with the License, 6 | // or, at your option, the Apache License version 2.0. 7 | // You may obtain a copy of the License at https://solderpad.org/licenses/SHL-2.1/. 8 | // Unless required by applicable law or agreed to in writing, 9 | // any work distributed under the License is distributed on an “AS IS” BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and limitations under the License. 12 | // 13 | // Author: Manuel Rodríguez 14 | // Date: 10/11/2022 15 | // Acknowledges: SSRC - Technology Innovation Institute (TII) 16 | // 17 | // Description: RISC-V IOMMU Device Directory Table Cache (DDTC). 18 | // Fully-associative cache to store Device Contexts. 19 | 20 | module rv_iommu_ddtc #( 21 | // Number of DDTC entries 22 | parameter int unsigned DDTC_ENTRIES = 4, 23 | // DC width 24 | parameter int DC_WIDTH = -1 25 | )( 26 | input logic clk_i, // Clock 27 | input logic rst_ni, // Asynchronous reset active low 28 | 29 | // Flush signals 30 | input logic flush_i, // IODIR.INVAL_DDT 31 | input logic flush_dv_i, // device_id valid 32 | input logic [23:0] flush_did_i, // device_id to be flushed 33 | 34 | // Update signals 35 | input logic update_i, // update flag 36 | input logic [23:0] up_did_i, // device ID to be inserted 37 | input logic [(DC_WIDTH-1):0] up_content_i, // DC to be inserted 38 | 39 | // Lookup signals 40 | input logic lookup_i, // lookup flag 41 | input logic [23:0] lu_did_i, // device_id to look for 42 | output logic [(DC_WIDTH-1):0] lu_content_o, // DC 43 | output logic lu_hit_o // hit flag 44 | ); 45 | 46 | //# Tags to identify DDTC entries 47 | struct packed { 48 | logic [23:0] device_id; // device_id 49 | logic valid; // valid bit 50 | } [DDTC_ENTRIES-1:0] tags_q, tags_n; 51 | 52 | //* DDTC entries: Device Contexts 53 | struct packed { 54 | logic [(DC_WIDTH-1):0] dc; 55 | } [DDTC_ENTRIES-1:0] content_q, content_n; 56 | 57 | logic [DDTC_ENTRIES-1:0] lu_hit; // to replacement logic 58 | logic [DDTC_ENTRIES-1:0] replace_en; // replace the following entry, set by replacement strategy 59 | 60 | //--------- 61 | //# Lookup 62 | //--------- 63 | always_comb begin : lookup 64 | 65 | // default assignment 66 | lu_hit = '{default: 0}; 67 | lu_hit_o = 1'b0; 68 | lu_content_o = '{default: 0}; 69 | 70 | // To guarantee that hit signal is only set when we want to access the cache 71 | if (lookup_i) begin 72 | 73 | for (int unsigned i = 0; i < DDTC_ENTRIES; i++) begin 74 | 75 | // An entry match occurs if the entry is valid and if a device_id match occurs 76 | if (tags_q[i].valid && tags_q[i].device_id == lu_did_i) begin 77 | 78 | lu_content_o = content_q[i].dc; 79 | lu_hit_o = 1'b1; 80 | lu_hit[i] = 1'b1; 81 | end 82 | end 83 | end 84 | end 85 | 86 | // ------------------ 87 | //# Update and Flush 88 | // ------------------ 89 | 90 | /* 91 | # IODIR.INVAL_DDT 92 | IODIR.INVAL_DDT guarantees that any previous stores made by a RISC-V hart to the DDT are observed 93 | before all subsequent implicit reads from IOMMU to DDT. If DV is 0, then the command invalidates 94 | all DDT and PDT entries cached for all devices. If DV is 1, then the command invalidates cached leaf 95 | level DDT entry for the device identified by DID operand and all associated PDT entries. 96 | */ 97 | 98 | always_comb begin : update_flush 99 | tags_n = tags_q; 100 | content_n = content_q; 101 | 102 | for (int unsigned i = 0; i < DDTC_ENTRIES; i++) begin 103 | 104 | // overall flush flag 105 | if (flush_i) begin 106 | 107 | // DV = 0: Invalidate all DDTC entries 108 | if (!flush_dv_i) begin 109 | tags_n[i].valid = 1'b0; 110 | end 111 | 112 | // DV = 1: Invalidate only the DDTC entry that matches given device_id (and corresponding PDT entries) 113 | else if (tags_q[i].device_id == flush_did_i) begin 114 | tags_n[i].valid = 1'b0; 115 | end 116 | end 117 | 118 | // normal replacement 119 | // only valid entries can be cached 120 | else if (update_i && replace_en[i] && up_content_i[0]) begin 121 | 122 | // update tags 123 | tags_n[i] = '{ 124 | device_id: up_did_i, 125 | valid: 1'b1 126 | }; 127 | 128 | // update device context 129 | content_n[i].dc = up_content_i; 130 | end 131 | end 132 | end 133 | 134 | // ----------------------------------------------- 135 | //# PLRU - Pseudo Least Recently Used Replacement 136 | // ----------------------------------------------- 137 | 138 | logic[2*(DDTC_ENTRIES-1)-1:0] plru_tree_q, plru_tree_n; 139 | always_comb begin : plru_replacement 140 | plru_tree_n = plru_tree_q; 141 | // The PLRU-tree indexing: 142 | // lvl0 0 143 | // / \ 144 | // / \ 145 | // lvl1 1 2 146 | // / \ / \ 147 | // lvl2 3 4 5 6 148 | // / \ /\/\ /\ 149 | // ... ... ... ... 150 | // Just predefine which nodes will be set/cleared 151 | // E.g. for a DDTC with 8 entries, the for-loop is semantically 152 | // equivalent to the following pseudo-code: 153 | // unique case (1'b1) 154 | // lu_hit[7]: plru_tree_n[0, 2, 6] = {1, 1, 1}; 155 | // lu_hit[6]: plru_tree_n[0, 2, 6] = {1, 1, 0}; 156 | // lu_hit[5]: plru_tree_n[0, 2, 5] = {1, 0, 1}; 157 | // lu_hit[4]: plru_tree_n[0, 2, 5] = {1, 0, 0}; 158 | // lu_hit[3]: plru_tree_n[0, 1, 4] = {0, 1, 1}; 159 | // lu_hit[2]: plru_tree_n[0, 1, 4] = {0, 1, 0}; 160 | // lu_hit[1]: plru_tree_n[0, 1, 3] = {0, 0, 1}; 161 | // lu_hit[0]: plru_tree_n[0, 1, 3] = {0, 0, 0}; 162 | // default: begin /* No hit */ end 163 | // endcase 164 | for (int unsigned i = 0; i < DDTC_ENTRIES; i++) begin 165 | automatic int unsigned idx_base, shift, new_index; 166 | // we got a hit so update the pointer as it was least recently used 167 | if (lu_hit[i] && lookup_i) begin // LRU updated on LU hits and updates 168 | // Set the nodes to the values we would expect 169 | for (int unsigned lvl = 0; lvl < $clog2(DDTC_ENTRIES); lvl++) begin // 3 for 8 entries 170 | idx_base = $unsigned((2**lvl)-1); // 0 for lvl0, 1 for lvl1, 3 for lvl2 171 | // lvl0 <=> MSB, lvl1 <=> MSB-1, ... 172 | shift = $clog2(DDTC_ENTRIES) - lvl; // 3 for lvl0, 2 for lvl1, 1 for lvl2 173 | // to circumvent the 32 bit integer arithmetic assignment 174 | new_index = ~((i >> (shift-1)) & 32'b1); 175 | plru_tree_n[idx_base + (i >> shift)] = new_index[0]; 176 | end 177 | end 178 | end 179 | // Decode tree to write enable signals 180 | // Next for-loop basically creates the following logic for e.g. an 8 entry 181 | // DDTC (note: pseudo-code obviously): 182 | // replace_en[7] = &plru_tree_q[ 6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,1} 183 | // replace_en[6] = &plru_tree_q[~6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,0} 184 | // replace_en[5] = &plru_tree_q[ 5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,1} 185 | // replace_en[4] = &plru_tree_q[~5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,0} 186 | // replace_en[3] = &plru_tree_q[ 4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,1} 187 | // replace_en[2] = &plru_tree_q[~4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,0} 188 | // replace_en[1] = &plru_tree_q[ 3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,1} 189 | // replace_en[0] = &plru_tree_q[~3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,0} 190 | // For each entry traverse the tree. If every tree-node matches, 191 | // the corresponding bit of the entry's index, this is 192 | // the next entry to replace. 193 | for (int unsigned i = 0; i < DDTC_ENTRIES; i += 1) begin 194 | automatic logic en; 195 | automatic int unsigned idx_base, shift, new_index; 196 | en = 1'b1; 197 | for (int unsigned lvl = 0; lvl < $clog2(DDTC_ENTRIES); lvl++) begin 198 | idx_base = $unsigned((2**lvl)-1); 199 | // lvl0 <=> MSB, lvl1 <=> MSB-1, ... 200 | shift = $clog2(DDTC_ENTRIES) - lvl; 201 | 202 | // en &= plru_tree_q[idx_base + (i>>shift)] == ((i >> (shift-1)) & 1'b1); 203 | new_index = (i >> (shift-1)) & 32'b1; 204 | if (new_index[0]) begin 205 | en &= plru_tree_q[idx_base + (i>>shift)]; 206 | end else begin 207 | en &= ~plru_tree_q[idx_base + (i>>shift)]; 208 | end 209 | end 210 | replace_en[i] = en; 211 | end 212 | end 213 | 214 | // sequential process 215 | always_ff @(posedge clk_i or negedge rst_ni) begin 216 | if (~rst_ni) begin 217 | tags_q <= '{default: 0}; 218 | content_q <= '{default: 0}; 219 | plru_tree_q <= '{default: 0}; 220 | end 221 | else begin 222 | tags_q <= tags_n; 223 | content_q <= content_n; 224 | plru_tree_q <= plru_tree_n; 225 | end 226 | end 227 | 228 | //-------------- 229 | // Sanity checks 230 | //-------------- 231 | 232 | //pragma translate_off 233 | `ifndef VERILATOR 234 | 235 | initial begin : p_assertions 236 | assert ((DDTC_ENTRIES % 2 == 0) && (DDTC_ENTRIES > 1)) 237 | else begin $error("DDTC size must be a multiple of 2 and greater than 1"); $stop(); end 238 | end 239 | 240 | // Just for checking 241 | function int countSetBits(logic[DDTC_ENTRIES-1:0] vector); 242 | automatic int count = 0; 243 | foreach (vector[idx]) begin 244 | count += vector[idx]; 245 | end 246 | return count; 247 | endfunction 248 | 249 | assert property (@(posedge clk_i)(countSetBits(lu_hit) <= 1)) 250 | else begin $error("More than one hit in DDTC!"); $stop(); end 251 | assert property (@(posedge clk_i)(countSetBits(replace_en) <= 1)) 252 | else begin $error("More than one DDTC entry selected for next replace!"); $stop(); end 253 | 254 | `endif 255 | //pragma translate_on 256 | 257 | endmodule -------------------------------------------------------------------------------- /LICENSE.Apache: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright © 2023 Manuel Rodríguez & Zero-Day Labs, Lda. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. --------------------------------------------------------------------------------