diff --git a/litex/soc/cores/cpu/cva6/core.py b/litex/soc/cores/cpu/cva6/core.py index 8d7adef4a..d53b9b597 100644 --- a/litex/soc/cores/cpu/cva6/core.py +++ b/litex/soc/cores/cpu/cva6/core.py @@ -38,15 +38,20 @@ GCC_FLAGS = { # Helpers ------------------------------------------------------------------------------------------ def add_manifest_sources(platform, manifest): - basedir = get_data_mod("cpu", "cva6").data_location - with open(os.path.join(basedir, manifest), 'r') as f: + cva6_dir = get_data_mod("cpu", "cva6").data_location + lx_core_dir = os.path.abspath(os.path.dirname(__file__)) + with open(os.path.join(manifest), 'r') as f: for l in f: - res = re.search('\$\{CVA6_REPO_DIR\}/(.+)', l) + res = re.search('\$\{(CVA6_REPO_DIR|LX_CVA6_CORE_DIR)\}/(.+)', l) if res and not re.match('//', l): - if re.match('\+incdir\+', l): - platform.add_verilog_include_path(os.path.join(basedir, res.group(1))) + if res.group(1) == "LX_CVA6_CORE_DIR": + basedir = lx_core_dir else: - platform.add_source(os.path.join(basedir, res.group(1))) + basedir = cva6_dir + if re.match('\+incdir\+', l): + platform.add_verilog_include_path(os.path.join(basedir, res.group(2))) + else: + platform.add_source(os.path.join(basedir, res.group(2))) # CVA6 --------------------------------------------------------------------------------------------- @@ -154,9 +159,14 @@ class CVA6(CPU): ) # Add Verilog sources. + # Defines must come first + wrapper_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), "cva6_wrapper") + platform.add_source(os.path.join(wrapper_root, "cva6_defines.sv")) # TODO: use Flist.cv64a6_imafdc_sv39 and Flist.cv32a6_imac_sv0 instead - add_manifest_sources(platform, "Flist.cv64a6_imafdc_sv39") - add_manifest_sources(platform, "Flist.cva6_wrapper") + add_manifest_sources(platform, os.path.join(get_data_mod("cpu", "cva6").data_location, + "core", "Flist.cv64a6_imafdc_sv39")) + # Add wrapper sources + add_manifest_sources(platform, os.path.join(wrapper_root, "Flist.cva6_wrapper")) def add_jtag(self, pads): from migen.fhdl.specials import Tristate diff --git a/litex/soc/cores/cpu/cva6/cva6_wrapper/Flist.cva6_wrapper b/litex/soc/cores/cpu/cva6/cva6_wrapper/Flist.cva6_wrapper new file mode 100644 index 000000000..6bc9c5f75 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/cva6_wrapper/Flist.cva6_wrapper @@ -0,0 +1,96 @@ +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_pkg.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/debug_rom/debug_rom.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/debug_rom/debug_rom_one_scratch.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_csrs.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_mem.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_top.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_obi_top.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dmi_cdc.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dmi_jtag.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dmi_jtag_tap.sv +${CVA6_REPO_DIR}/corev_apu/riscv-dbg/src/dm_sba.sv + ++incdir+${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl + +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/top_pkg.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/tlul_pkg.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/rv_plic_reg_pkg.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/plic_regmap.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/plic_top.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/prim_subreg_ext.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/prim_subreg.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/rv_plic_gateway.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/rv_plic_reg_top.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/rv_plic.sv +${CVA6_REPO_DIR}/corev_apu/rv_plic/rtl/rv_plic_target.sv + +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_err_slv.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_atop_filter.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_burst_splitter.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_cdc_dst.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_cdc_src.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_cdc.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_cut.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_delayer.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_demux.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_dw_converter.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_dw_downsizer.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_dw_upsizer.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_err_slv.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_id_prepend.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_id_serialize.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_intf.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_isolate.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_iw_converter.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_join.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_demux.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_join.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_mailbox.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_mux.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_regs.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_to_apb.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_to_axi.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_lite_xbar.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_modify_address.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_multicut.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_mux.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_pkg.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_serializer.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_to_axi_lite.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_xbar.sv + +${CVA6_REPO_DIR}/corev_apu/axi_mem_if/src/axi2mem.sv +${CVA6_REPO_DIR}/core/axi_adapter.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi2apb/src/axi2apb_64_32.sv + +${CVA6_REPO_DIR}/corev_apu/register_interface/src/apb_to_reg.sv + +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_ar_buffer.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_aw_buffer.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_b_buffer.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_r_buffer.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_single_slice.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_slice.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_slice_wrap.sv +${CVA6_REPO_DIR}/corev_apu/fpga/src/axi_slice/src/axi_w_buffer.sv + +${CVA6_REPO_DIR}/corev_apu/clint/clint.sv +${CVA6_REPO_DIR}/corev_apu/clint/axi_lite_interface.sv + +${CVA6_REPO_DIR}/common/submodules/common_cells/src/deprecated/fifo_v1.sv +${CVA6_REPO_DIR}/common/submodules/common_cells/src/deprecated/fifo_v2.sv +${CVA6_REPO_DIR}/corev_apu/src/tech_cells_generic/src/deprecated/pulp_clk_cells.sv +${CVA6_REPO_DIR}/corev_apu/src/tech_cells_generic/src/deprecated/cluster_clk_cells.sv +${CVA6_REPO_DIR}/corev_apu/src/tech_cells_generic/src/rtl/tc_clk.sv +${CVA6_REPO_DIR}/corev_apu/axi/src/axi_xbar.sv + ++incdir+${CVA6_REPO_DIR}/corev_apu/axi/include ++incdir+${CVA6_REPO_DIR}/corev_apu/register_interface/include/ ++incdir+${LX_CVA6_CORE_DIR}/cva6_wrapper + +${CVA6_REPO_DIR}/corev_apu/register_interface/src/reg_intf.sv + +// ${LX_CVA6_CORE_DIR}/cva6_wrapper/ariane_pkg.sv +${LX_CVA6_CORE_DIR}/cva6_wrapper/cva6_wrapper_pkg.sv +${LX_CVA6_CORE_DIR}/cva6_wrapper/cva6_wrapper.sv + diff --git a/litex/soc/cores/cpu/cva6/cva6_wrapper/ariane_pkg.sv b/litex/soc/cores/cpu/cva6/cva6_wrapper/ariane_pkg.sv new file mode 100644 index 000000000..3c8d0c325 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/cva6_wrapper/ariane_pkg.sv @@ -0,0 +1,886 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the “License”); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this 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. + * + * File: ariane_pkg.sv + * Author: Florian Zaruba + * Date: 8.4.2017 + * + * Description: Contains all the necessary defines for Ariane + * in one package. + */ + +// this is needed to propagate the +// configuration in case Ariane is +// instantiated in OpenPiton +`ifdef PITON_ARIANE + `include "l15.tmp.h" +`endif + +package ariane_pkg; + +`define WT_DCACHE + + // --------------- + // Global Config + // --------------- + // This is the new user config interface system. If you need to parameterize something + // within Ariane add a field here and assign a default value to the config. Please make + // sure to add a propper parameter check to the `check_cfg` function. + localparam NrMaxRules = 16; + + typedef struct packed { + int RASDepth; + int BTBEntries; + int BHTEntries; + // PMAs + int unsigned NrNonIdempotentRules; // Number of non idempotent rules + logic [NrMaxRules-1:0][63:0] NonIdempotentAddrBase; // base which needs to match + logic [NrMaxRules-1:0][63:0] NonIdempotentLength; // bit mask which bits to consider when matching the rule + int unsigned NrExecuteRegionRules; // Number of regions which have execute property + logic [NrMaxRules-1:0][63:0] ExecuteRegionAddrBase; // base which needs to match + logic [NrMaxRules-1:0][63:0] ExecuteRegionLength; // bit mask which bits to consider when matching the rule + int unsigned NrCachedRegionRules; // Number of regions which have cached property + logic [NrMaxRules-1:0][63:0] CachedRegionAddrBase; // base which needs to match + logic [NrMaxRules-1:0][63:0] CachedRegionLength; // bit mask which bits to consider when matching the rule + // cache config + bit Axi64BitCompliant; // set to 1 when using in conjunction with 64bit AXI bus adapter + bit SwapEndianess; // set to 1 to swap endianess inside L1.5 openpiton adapter + // + logic [63:0] DmBaseAddress; // offset of the debug module + int unsigned NrPMPEntries; // Number of PMP entries + } ariane_cfg_t; + + localparam ariane_cfg_t ArianeDefaultConfig = '{ + RASDepth: 2, + BTBEntries: 32, + BHTEntries: 128, + // idempotent region + NrNonIdempotentRules: 2, + NonIdempotentAddrBase: {64'b0, 64'b0}, + NonIdempotentLength: {64'b0, 64'b0}, + NrExecuteRegionRules: 3, + // DRAM, Boot ROM, Debug Module + ExecuteRegionAddrBase: {64'h8000_0000, 64'h1_0000, 64'h0}, + ExecuteRegionLength: {64'h40000000, 64'h10000, 64'h1000}, + // cached region + NrCachedRegionRules: 1, + CachedRegionAddrBase: {64'h8000_0000}, + CachedRegionLength: {64'h40000000}, + // cache config + Axi64BitCompliant: 1'b1, + SwapEndianess: 1'b0, + // debug + DmBaseAddress: 64'h0, + NrPMPEntries: 8 + }; + + // Function being called to check parameters + function automatic void check_cfg (ariane_cfg_t Cfg); + // pragma translate_off + `ifndef VERILATOR + assert(Cfg.RASDepth > 0); + assert(2**$clog2(Cfg.BTBEntries) == Cfg.BTBEntries); + assert(2**$clog2(Cfg.BHTEntries) == Cfg.BHTEntries); + assert(Cfg.NrNonIdempotentRules <= NrMaxRules); + assert(Cfg.NrExecuteRegionRules <= NrMaxRules); + assert(Cfg.NrCachedRegionRules <= NrMaxRules); + assert(Cfg.NrPMPEntries <= 16); + `endif + // pragma translate_on + endfunction + + function automatic logic range_check(logic[63:0] base, logic[63:0] len, logic[63:0] address); + // if len is a power of two, and base is properly aligned, this check could be simplified + return (address >= base) && (address < (65'(base)+len)); + endfunction : range_check + + function automatic logic is_inside_nonidempotent_regions (ariane_cfg_t Cfg, logic[63:0] address); + logic[NrMaxRules-1:0] pass; + pass = '0; + for (int unsigned k = 0; k < Cfg.NrNonIdempotentRules; k++) begin + pass[k] = range_check(Cfg.NonIdempotentAddrBase[k], Cfg.NonIdempotentLength[k], address); + end + return |pass; + endfunction : is_inside_nonidempotent_regions + + function automatic logic is_inside_execute_regions (ariane_cfg_t Cfg, logic[63:0] address); + // if we don't specify any region we assume everything is accessible + logic[NrMaxRules-1:0] pass; + pass = '0; + for (int unsigned k = 0; k < Cfg.NrExecuteRegionRules; k++) begin + pass[k] = range_check(Cfg.ExecuteRegionAddrBase[k], Cfg.ExecuteRegionLength[k], address); + end + return |pass; + endfunction : is_inside_execute_regions + + function automatic logic is_inside_cacheable_regions (ariane_cfg_t Cfg, logic[63:0] address); + automatic logic[NrMaxRules-1:0] pass; + pass = '0; + for (int unsigned k = 0; k < Cfg.NrCachedRegionRules; k++) begin + pass[k] = range_check(Cfg.CachedRegionAddrBase[k], Cfg.CachedRegionLength[k], address); + end + return |pass; + endfunction : is_inside_cacheable_regions + + // TODO: Slowly move those parameters to the new system. + localparam NR_SB_ENTRIES = 8; // number of scoreboard entries + localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits + // to uniquely identify the entry in the scoreboard + localparam ASID_WIDTH = (riscv::XLEN == 64) ? 16 : 1; + localparam BITS_SATURATION_COUNTER = 2; + localparam NR_COMMIT_PORTS = 2; + + localparam ENABLE_RENAME = 1'b0; + + localparam ISSUE_WIDTH = 1; + // amount of pipeline registers inserted for load/store return path + // this can be tuned to trade-off IPC vs. cycle time + localparam int unsigned NR_LOAD_PIPE_REGS = 1; + localparam int unsigned NR_STORE_PIPE_REGS = 0; + + // depth of store-buffers, this needs to be a power of two + localparam int unsigned DEPTH_SPEC = 4; + +`ifdef WT_DCACHE + // in this case we can use a small commit queue since we have a write buffer in the dcache + // we could in principle do without the commit queue in this case, but the timing degrades if we do that due + // to longer paths into the commit stage + localparam int unsigned DEPTH_COMMIT = 4; +`else + // allocate more space for the commit buffer to be on the save side, this needs to be a power of two + localparam int unsigned DEPTH_COMMIT = 8; +`endif + localparam bit RVC = cva6_config_pkg::CVA6ConfigCExtEn; // Is C extension configuration + +`ifdef PITON_ARIANE + // Floating-point extensions configuration + localparam bit RVF = riscv::IS_XLEN64; // Is F extension enabled + localparam bit RVD = riscv::IS_XLEN64; // Is D extension enabled +`else + // Floating-point extensions configuration + localparam bit RVF = (riscv::IS_XLEN64 | riscv::IS_XLEN32) & riscv::FPU_EN; // Is F extension enabled for both 32 Bit and 64 bit CPU + localparam bit RVD = (riscv::IS_XLEN64 ? 1:0) & riscv::FPU_EN; // Is D extension enabled for only 64 bit CPU +`endif + localparam bit RVA = 1'b1; // Is A extension enabled + + // Transprecision floating-point extensions configuration + localparam bit XF16 = 1'b0; // Is half-precision float extension (Xf16) enabled + localparam bit XF16ALT = 1'b0; // Is alternative half-precision float extension (Xf16alt) enabled + localparam bit XF8 = 1'b0; // Is quarter-precision float extension (Xf8) enabled + localparam bit XFVEC = 1'b0; // Is vectorial float extension (Xfvec) enabled + + // Transprecision float unit + localparam int unsigned LAT_COMP_FP32 = 'd2; + localparam int unsigned LAT_COMP_FP64 = 'd3; + localparam int unsigned LAT_COMP_FP16 = 'd1; + localparam int unsigned LAT_COMP_FP16ALT = 'd1; + localparam int unsigned LAT_COMP_FP8 = 'd1; + localparam int unsigned LAT_DIVSQRT = 'd2; + localparam int unsigned LAT_NONCOMP = 'd1; + localparam int unsigned LAT_CONV = 'd2; + + // -------------------------------------- + // vvvv Don't change these by hand! vvvv + localparam bit FP_PRESENT = RVF | RVD | XF16 | XF16ALT | XF8; + + // Length of widest floating-point format + localparam FLEN = RVD ? 64 : // D ext. + RVF ? 32 : // F ext. + XF16 ? 16 : // Xf16 ext. + XF16ALT ? 16 : // Xf16alt ext. + XF8 ? 8 : // Xf8 ext. + 1; // Unused in case of no FP + + localparam bit NSX = XF16 | XF16ALT | XF8 | XFVEC; // Are non-standard extensions present? + + localparam bit RVFVEC = RVF & XFVEC & FLEN>32; // FP32 vectors available if vectors and larger fmt enabled + localparam bit XF16VEC = XF16 & XFVEC & FLEN>16; // FP16 vectors available if vectors and larger fmt enabled + localparam bit XF16ALTVEC = XF16ALT & XFVEC & FLEN>16; // FP16ALT vectors available if vectors and larger fmt enabled + localparam bit XF8VEC = XF8 & XFVEC & FLEN>8; // FP8 vectors available if vectors and larger fmt enabled + // ^^^^ until here ^^^^ + // --------------------- + + localparam riscv::xlen_t ARIANE_MARCHID = {{riscv::XLEN-32{1'b0}}, 32'd3}; + + localparam riscv::xlen_t ISA_CODE = (RVA << 0) // A - Atomic Instructions extension + | (RVC << 2) // C - Compressed extension + | (RVD << 3) // D - Double precsision floating-point extension + | (RVF << 5) // F - Single precsision floating-point extension + | (1 << 8) // I - RV32I/64I/128I base ISA + | (1 << 12) // M - Integer Multiply/Divide extension + | (0 << 13) // N - User level interrupts supported + | (1 << 18) // S - Supervisor mode implemented + | (1 << 20) // U - User mode implemented + | (NSX << 23) // X - Non-standard extensions present + | ((riscv::XLEN == 64 ? 2 : 1) << riscv::XLEN-2); // MXL + + // 32 registers + 1 bit for re-naming = 6 + localparam REG_ADDR_SIZE = 6; + localparam NR_WB_PORTS = 5; + + // Read ports for general purpose register files + localparam NR_RGPR_PORTS = 2; + typedef logic [(NR_RGPR_PORTS == 3 ? riscv::XLEN : FLEN)-1:0] rs3_len_t; + + // static debug hartinfo + localparam dm::hartinfo_t DebugHartInfo = '{ + zero1: '0, + nscratch: 2, // Debug module needs at least two scratch regs + zero0: '0, + dataaccess: 1'b1, // data registers are memory mapped in the debugger + datasize: dm::DataCount, + dataaddr: dm::DataAddr + }; + + // enables a commit log which matches spikes commit log format for easier trace comparison + localparam bit ENABLE_SPIKE_COMMIT_LOG = 1'b1; + + // ------------- Dangerouse ------------- + // if set to zero a flush will not invalidate the cache-lines, in a single core environment + // where coherence is not necessary this can improve performance. This needs to be switched on + // when more than one core is in a system + localparam logic INVALIDATE_ON_FLUSH = 1'b1; +`ifdef SPIKE_TANDEM + // enable performance cycle counter, if set to zero mcycle will be incremented + // with instret (non RISC-V conformal) + localparam bit ENABLE_CYCLE_COUNT = 1'b0; + // mark WIF as nop + localparam bit ENABLE_WFI = 1'b0; + // Spike zeros tval on all exception except memory faults + localparam bit ZERO_TVAL = 1'b1; +`else + localparam bit ENABLE_CYCLE_COUNT = 1'b1; + localparam bit ENABLE_WFI = 1'b1; + localparam bit ZERO_TVAL = 1'b0; +`endif + // read mask for SSTATUS over MMSTATUS + localparam logic [63:0] SMODE_STATUS_READ_MASK = riscv::SSTATUS_UIE + | riscv::SSTATUS_SIE + | riscv::SSTATUS_SPIE + | riscv::SSTATUS_SPP + | riscv::SSTATUS_FS + | riscv::SSTATUS_XS + | riscv::SSTATUS_SUM + | riscv::SSTATUS_MXR + | riscv::SSTATUS_UPIE + | riscv::SSTATUS_SPIE + | riscv::SSTATUS_UXL + | riscv::SSTATUS_SD; + + localparam logic [63:0] SMODE_STATUS_WRITE_MASK = riscv::SSTATUS_SIE + | riscv::SSTATUS_SPIE + | riscv::SSTATUS_SPP + | riscv::SSTATUS_FS + | riscv::SSTATUS_SUM + | riscv::SSTATUS_MXR; + // --------------- + // Fetch Stage + // --------------- + + // leave as is (fails with >8 entries and wider fetch width) + localparam int unsigned FETCH_FIFO_DEPTH = 4; + localparam int unsigned FETCH_WIDTH = 32; + // maximum instructions we can fetch on one request (we support compressed instructions) + localparam int unsigned INSTR_PER_FETCH = RVC == 1'b1 ? (FETCH_WIDTH / 16) : 1; + localparam int unsigned LOG2_INSTR_PER_FETCH = RVC == 1'b1 ? 1 : $clog2(ariane_pkg::INSTR_PER_FETCH); + + // Only use struct when signals have same direction + // exception + typedef struct packed { + riscv::xlen_t cause; // cause of exception + riscv::xlen_t tval; // additional information of causing exception (e.g.: instruction causing it), + // address of LD/ST fault + logic valid; + } exception_t; + + typedef enum logic [2:0] { + NoCF, // No control flow prediction + Branch, // Branch + Jump, // Jump to address from immediate + JumpR, // Jump to address from registers + Return // Return Address Prediction + } cf_t; + + // branch-predict + // this is the struct we get back from ex stage and we will use it to update + // all the necessary data structures + // bp_resolve_t + typedef struct packed { + logic valid; // prediction with all its values is valid + logic [riscv::VLEN-1:0] pc; // PC of predict or mis-predict + logic [riscv::VLEN-1:0] target_address; // target address at which to jump, or not + logic is_mispredict; // set if this was a mis-predict + logic is_taken; // branch is taken + cf_t cf_type; // Type of control flow change + } bp_resolve_t; + + // branchpredict scoreboard entry + // this is the struct which we will inject into the pipeline to guide the various + // units towards the correct branch decision and resolve + typedef struct packed { + cf_t cf; // type of control flow prediction + logic [riscv::VLEN-1:0] predict_address; // target address at which to jump, or not + } branchpredict_sbe_t; + + typedef struct packed { + logic valid; + logic [riscv::VLEN-1:0] pc; // update at PC + logic [riscv::VLEN-1:0] target_address; + } btb_update_t; + + typedef struct packed { + logic valid; + logic [riscv::VLEN-1:0] target_address; + } btb_prediction_t; + + typedef struct packed { + logic valid; + logic [riscv::VLEN-1:0] ra; + } ras_t; + + typedef struct packed { + logic valid; + logic [riscv::VLEN-1:0] pc; // update at PC + logic taken; + } bht_update_t; + + typedef struct packed { + logic valid; + logic taken; + } bht_prediction_t; + + typedef enum logic[3:0] { + NONE, // 0 + LOAD, // 1 + STORE, // 2 + ALU, // 3 + CTRL_FLOW, // 4 + MULT, // 5 + CSR, // 6 + FPU, // 7 + FPU_VEC, // 8 + CVXIF // 9 + } fu_t; + + localparam EXC_OFF_RST = 8'h80; + + localparam SupervisorIrq = 1; + localparam MachineIrq = 0; + + // All information needed to determine whether we need to associate an interrupt + // with the corresponding instruction or not. + typedef struct packed { + riscv::xlen_t mie; + riscv::xlen_t mip; + riscv::xlen_t mideleg; + logic sie; + logic global_enable; + } irq_ctrl_t; + + // --------------- + // Cache config + // --------------- + +// for usage in OpenPiton we have to propagate the openpiton L15 configuration from l15.h +`ifdef PITON_ARIANE + +`ifndef CONFIG_L1I_CACHELINE_WIDTH + `define CONFIG_L1I_CACHELINE_WIDTH 128 +`endif + +`ifndef CONFIG_L1I_ASSOCIATIVITY + `define CONFIG_L1I_ASSOCIATIVITY 4 +`endif + +`ifndef CONFIG_L1I_SIZE + `define CONFIG_L1I_SIZE 16*1024 +`endif + +`ifndef CONFIG_L1D_CACHELINE_WIDTH + `define CONFIG_L1D_CACHELINE_WIDTH 128 +`endif + +`ifndef CONFIG_L1D_ASSOCIATIVITY + `define CONFIG_L1D_ASSOCIATIVITY 8 +`endif + +`ifndef CONFIG_L1D_SIZE + `define CONFIG_L1D_SIZE 32*1024 +`endif + + // I$ + localparam int unsigned ICACHE_LINE_WIDTH = `CONFIG_L1I_CACHELINE_WIDTH; + localparam int unsigned ICACHE_SET_ASSOC = `CONFIG_L1I_ASSOCIATIVITY; + localparam int unsigned ICACHE_INDEX_WIDTH = $clog2(`CONFIG_L1I_SIZE / ICACHE_SET_ASSOC); + localparam int unsigned ICACHE_TAG_WIDTH = riscv::PLEN - ICACHE_INDEX_WIDTH; + // D$ + localparam int unsigned DCACHE_LINE_WIDTH = `CONFIG_L1D_CACHELINE_WIDTH; + localparam int unsigned DCACHE_SET_ASSOC = `CONFIG_L1D_ASSOCIATIVITY; + localparam int unsigned DCACHE_INDEX_WIDTH = $clog2(`CONFIG_L1D_SIZE / DCACHE_SET_ASSOC); + localparam int unsigned DCACHE_TAG_WIDTH = riscv::PLEN - DCACHE_INDEX_WIDTH; +`else + // I$ + localparam int unsigned CONFIG_L1I_SIZE = 16*1024; + localparam int unsigned ICACHE_SET_ASSOC = 4; // Must be between 4 to 64 + localparam int unsigned ICACHE_INDEX_WIDTH = $clog2(CONFIG_L1I_SIZE / ICACHE_SET_ASSOC); // in bit, contains also offset width + localparam int unsigned ICACHE_TAG_WIDTH = riscv::PLEN-ICACHE_INDEX_WIDTH; // in bit + localparam int unsigned ICACHE_LINE_WIDTH = 128; // in bit + // D$ + localparam int unsigned CONFIG_L1D_SIZE = 32*1024; + localparam int unsigned DCACHE_SET_ASSOC = 8; // Must be between 4 to 64 + localparam int unsigned DCACHE_INDEX_WIDTH = $clog2(CONFIG_L1D_SIZE / DCACHE_SET_ASSOC); // in bit, contains also offset width + localparam int unsigned DCACHE_TAG_WIDTH = riscv::PLEN-DCACHE_INDEX_WIDTH; // in bit + localparam int unsigned DCACHE_LINE_WIDTH = 128; // in bit +`endif + + localparam bit CVXIF_PRESENT = cva6_config_pkg::CVA6ConfigCvxifEn; + // --------------- + // EX Stage + // --------------- + typedef enum logic [6:0] { // basic ALU op + ADD, SUB, ADDW, SUBW, + // logic operations + XORL, ORL, ANDL, + // shifts + SRA, SRL, SLL, SRLW, SLLW, SRAW, + // comparisons + LTS, LTU, GES, GEU, EQ, NE, + // jumps + JALR, BRANCH, + // set lower than operations + SLTS, SLTU, + // CSR functions + MRET, SRET, DRET, ECALL, WFI, FENCE, FENCE_I, SFENCE_VMA, CSR_WRITE, CSR_READ, CSR_SET, CSR_CLEAR, + // LSU functions + LD, SD, LW, LWU, SW, LH, LHU, SH, LB, SB, LBU, + // Atomic Memory Operations + AMO_LRW, AMO_LRD, AMO_SCW, AMO_SCD, + AMO_SWAPW, AMO_ADDW, AMO_ANDW, AMO_ORW, AMO_XORW, AMO_MAXW, AMO_MAXWU, AMO_MINW, AMO_MINWU, + AMO_SWAPD, AMO_ADDD, AMO_ANDD, AMO_ORD, AMO_XORD, AMO_MAXD, AMO_MAXDU, AMO_MIND, AMO_MINDU, + // Multiplications + MUL, MULH, MULHU, MULHSU, MULW, + // Divisions + DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW, + // Floating-Point Load and Store Instructions + FLD, FLW, FLH, FLB, FSD, FSW, FSH, FSB, + // Floating-Point Computational Instructions + FADD, FSUB, FMUL, FDIV, FMIN_MAX, FSQRT, FMADD, FMSUB, FNMSUB, FNMADD, + // Floating-Point Conversion and Move Instructions + FCVT_F2I, FCVT_I2F, FCVT_F2F, FSGNJ, FMV_F2X, FMV_X2F, + // Floating-Point Compare Instructions + FCMP, + // Floating-Point Classify Instruction + FCLASS, + // Vectorial Floating-Point Instructions that don't directly map onto the scalar ones + VFMIN, VFMAX, VFSGNJ, VFSGNJN, VFSGNJX, VFEQ, VFNE, VFLT, VFGE, VFLE, VFGT, VFCPKAB_S, VFCPKCD_S, VFCPKAB_D, VFCPKCD_D, + // Offload Instructions to be directed into cv_x_if + OFFLOAD + } fu_op; + + typedef struct packed { + fu_t fu; + fu_op operator; + riscv::xlen_t operand_a; + riscv::xlen_t operand_b; + riscv::xlen_t imm; + logic [TRANS_ID_BITS-1:0] trans_id; + } fu_data_t; + + function automatic logic op_is_branch (input fu_op op); + unique case (op) inside + EQ, NE, LTS, GES, LTU, GEU: return 1'b1; + default : return 1'b0; // all other ops + endcase + endfunction + + // ------------------------------- + // Extract Src/Dst FP Reg from Op + // ------------------------------- + function automatic logic is_rs1_fpr (input fu_op op); + if (FP_PRESENT) begin // makes function static for non-fp case + unique case (op) inside + [FMUL:FNMADD], // Computational Operations (except ADD/SUB) + FCVT_F2I, // Float-Int Casts + FCVT_F2F, // Float-Float Casts + FSGNJ, // Sign Injections + FMV_F2X, // FPR-GPR Moves + FCMP, // Comparisons + FCLASS, // Classifications + [VFMIN:VFCPKCD_D] : return 1'b1; // Additional Vectorial FP ops + default : return 1'b0; // all other ops + endcase + end else + return 1'b0; + endfunction + + function automatic logic is_rs2_fpr (input fu_op op); + if (FP_PRESENT) begin // makes function static for non-fp case + unique case (op) inside + [FSD:FSB], // FP Stores + [FADD:FMIN_MAX], // Computational Operations (no sqrt) + [FMADD:FNMADD], // Fused Computational Operations + FCVT_F2F, // Vectorial F2F Conversions requrie target + [FSGNJ:FMV_F2X], // Sign Injections and moves mapped to SGNJ + FCMP, // Comparisons + [VFMIN:VFCPKCD_D] : return 1'b1; // Additional Vectorial FP ops + default : return 1'b0; // all other ops + endcase + end else + return 1'b0; + endfunction + + // ternary operations encode the rs3 address in the imm field, also add/sub + function automatic logic is_imm_fpr (input fu_op op); + if (FP_PRESENT) begin // makes function static for non-fp case + unique case (op) inside + [FADD:FSUB], // ADD/SUB need inputs as Operand B/C + [FMADD:FNMADD], // Fused Computational Operations + [VFCPKAB_S:VFCPKCD_D] : return 1'b1; // Vectorial FP cast and pack ops + default : return 1'b0; // all other ops + endcase + end else + return 1'b0; + endfunction + + function automatic logic is_rd_fpr (input fu_op op); + if (FP_PRESENT) begin // makes function static for non-fp case + unique case (op) inside + [FLD:FLB], // FP Loads + [FADD:FNMADD], // Computational Operations + FCVT_I2F, // Int-Float Casts + FCVT_F2F, // Float-Float Casts + FSGNJ, // Sign Injections + FMV_X2F, // GPR-FPR Moves + [VFMIN:VFSGNJX], // Vectorial MIN/MAX and SGNJ + [VFCPKAB_S:VFCPKCD_D] : return 1'b1; // Vectorial FP cast and pack ops + default : return 1'b0; // all other ops + endcase + end else + return 1'b0; + endfunction + + function automatic logic is_amo (fu_op op); + case (op) inside + [AMO_LRW:AMO_MINDU]: begin + return 1'b1; + end + default: return 1'b0; + endcase + endfunction + + typedef struct packed { + logic valid; + logic [riscv::VLEN-1:0] vaddr; + logic overflow; + riscv::xlen_t data; + logic [(riscv::XLEN/8)-1:0] be; + fu_t fu; + fu_op operator; + logic [TRANS_ID_BITS-1:0] trans_id; + } lsu_ctrl_t; + + // --------------- + // IF/ID Stage + // --------------- + // store the decompressed instruction + typedef struct packed { + logic [riscv::VLEN-1:0] address; // the address of the instructions from below + logic [31:0] instruction; // instruction word + branchpredict_sbe_t branch_predict; // this field contains branch prediction information regarding the forward branch path + exception_t ex; // this field contains exceptions which might have happened earlier, e.g.: fetch exceptions + } fetch_entry_t; + + // --------------- + // ID/EX/WB Stage + // --------------- + typedef struct packed { + logic [riscv::VLEN-1:0] pc; // PC of instruction + logic [TRANS_ID_BITS-1:0] trans_id; // this can potentially be simplified, we could index the scoreboard entry + // with the transaction id in any case make the width more generic + fu_t fu; // functional unit to use + fu_op op; // operation to perform in each functional unit + logic [REG_ADDR_SIZE-1:0] rs1; // register source address 1 + logic [REG_ADDR_SIZE-1:0] rs2; // register source address 2 + logic [REG_ADDR_SIZE-1:0] rd; // register destination address + riscv::xlen_t result; // for unfinished instructions this field also holds the immediate, + // for unfinished floating-point that are partly encoded in rs2, this field also holds rs2 + // for unfinished floating-point fused operations (FMADD, FMSUB, FNMADD, FNMSUB) + // this field holds the address of the third operand from the floating-point register file + logic valid; // is the result valid + logic use_imm; // should we use the immediate as operand b? + logic use_zimm; // use zimm as operand a + logic use_pc; // set if we need to use the PC as operand a, PC from exception + exception_t ex; // exception has occurred + branchpredict_sbe_t bp; // branch predict scoreboard data structure + logic is_compressed; // signals a compressed instructions, we need this information at the commit stage if + // we want jump accordingly e.g.: +4, +2 + } scoreboard_entry_t; + + // --------------- + // MMU instanciation + // --------------- + localparam bit MMU_PRESENT = 1'b1; // MMU is present + + // -------------------- + // Atomics + // -------------------- + typedef enum logic [3:0] { + AMO_NONE =4'b0000, + AMO_LR =4'b0001, + AMO_SC =4'b0010, + AMO_SWAP =4'b0011, + AMO_ADD =4'b0100, + AMO_AND =4'b0101, + AMO_OR =4'b0110, + AMO_XOR =4'b0111, + AMO_MAX =4'b1000, + AMO_MAXU =4'b1001, + AMO_MIN =4'b1010, + AMO_MINU =4'b1011, + AMO_CAS1 =4'b1100, // unused, not part of riscv spec, but provided in OpenPiton + AMO_CAS2 =4'b1101 // unused, not part of riscv spec, but provided in OpenPiton + } amo_t; + + typedef struct packed { + logic valid; // valid flag + logic is_2M; // + logic is_1G; // + logic [27-1:0] vpn; // VPN (39bits) = 27bits + 12bits offset + logic [ASID_WIDTH-1:0] asid; + riscv::pte_t content; + } tlb_update_t; + + // Bits required for representation of physical address space as 4K pages + // (e.g. 27*4K == 39bit address space). + localparam PPN4K_WIDTH = 38; + + typedef struct packed { + logic valid; // valid flag + logic is_4M; // + logic [20-1:0] vpn; //VPN (32bits) = 20bits + 12bits offset + logic [9-1:0] asid; //ASID length = 9 for Sv32 mmu + riscv::pte_sv32_t content; + } tlb_update_sv32_t; + + typedef enum logic [1:0] { + FE_NONE, + FE_INSTR_ACCESS_FAULT, + FE_INSTR_PAGE_FAULT + } frontend_exception_t; + + // ---------------------- + // cache request ports + // ---------------------- + // I$ address translation requests + typedef struct packed { + logic fetch_valid; // address translation valid + logic [riscv::PLEN-1:0] fetch_paddr; // physical address in + exception_t fetch_exception; // exception occurred during fetch + } icache_areq_i_t; + + typedef struct packed { + logic fetch_req; // address translation request + logic [riscv::VLEN-1:0] fetch_vaddr; // virtual address out + } icache_areq_o_t; + + // I$ data requests + typedef struct packed { + logic req; // we request a new word + logic kill_s1; // kill the current request + logic kill_s2; // kill the last request + logic spec; // request is speculative + logic [riscv::VLEN-1:0] vaddr; // 1st cycle: 12 bit index is taken for lookup + } icache_dreq_i_t; + + typedef struct packed { + logic ready; // icache is ready + logic valid; // signals a valid read + logic [FETCH_WIDTH-1:0] data; // 2+ cycle out: tag + logic [riscv::VLEN-1:0] vaddr; // virtual address out + exception_t ex; // we've encountered an exception + } icache_dreq_o_t; + + // AMO request going to cache. this request is unconditionally valid as soon + // as request goes high. + // Furthermore, those signals are kept stable until the response indicates + // completion by asserting ack. + typedef struct packed { + logic req; // this request is valid + amo_t amo_op; // atomic memory operation to perform + logic [1:0] size; // 2'b10 --> word operation, 2'b11 --> double word operation + logic [63:0] operand_a; // address + logic [63:0] operand_b; // data as layouted in the register + } amo_req_t; + + // AMO response coming from cache. + typedef struct packed { + logic ack; // response is valid + logic [63:0] result; // sign-extended, result + } amo_resp_t; + + // D$ data requests + typedef struct packed { + logic [DCACHE_INDEX_WIDTH-1:0] address_index; + logic [DCACHE_TAG_WIDTH-1:0] address_tag; + riscv::xlen_t data_wdata; + logic data_req; + logic data_we; + logic [(riscv::XLEN/8)-1:0] data_be; + logic [1:0] data_size; + logic kill_req; + logic tag_valid; + } dcache_req_i_t; + + typedef struct packed { + logic data_gnt; + logic data_rvalid; + riscv::xlen_t data_rdata; + } dcache_req_o_t; + + // ---------------------- + // Arithmetic Functions + // ---------------------- + function automatic riscv::xlen_t sext32 (logic [31:0] operand); + return {{riscv::XLEN-32{operand[31]}}, operand[31:0]}; + endfunction + + // ---------------------- + // Immediate functions + // ---------------------- + function automatic logic [riscv::VLEN-1:0] uj_imm (logic [31:0] instruction_i); + return { {44+riscv::VLEN-64 {instruction_i[31]}}, instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 }; + endfunction + + function automatic logic [riscv::VLEN-1:0] i_imm (logic [31:0] instruction_i); + return { {52+riscv::VLEN-64 {instruction_i[31]}}, instruction_i[31:20] }; + endfunction + + function automatic logic [riscv::VLEN-1:0] sb_imm (logic [31:0] instruction_i); + return { {51+riscv::VLEN-64 {instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 }; + endfunction + + // ---------------------- + // LSU Functions + // ---------------------- + // align data to address e.g.: shift data to be naturally 64 + function automatic riscv::xlen_t data_align (logic [2:0] addr, logic [63:0] data); + // Set addr[2] to 1'b0 when 32bits + logic [2:0] addr_tmp = {(addr[2] && riscv::IS_XLEN64), addr[1:0]}; + logic [63:0] data_tmp = {64{1'b0}}; + case (addr_tmp) + 3'b000: data_tmp[riscv::XLEN-1:0] = {data[riscv::XLEN-1:0]}; + 3'b001: data_tmp[riscv::XLEN-1:0] = {data[riscv::XLEN-9:0], data[riscv::XLEN-1:riscv::XLEN-8]}; + 3'b010: data_tmp[riscv::XLEN-1:0] = {data[riscv::XLEN-17:0], data[riscv::XLEN-1:riscv::XLEN-16]}; + 3'b011: data_tmp[riscv::XLEN-1:0] = {data[riscv::XLEN-25:0], data[riscv::XLEN-1:riscv::XLEN-24]}; + 3'b100: data_tmp = {data[31:0], data[63:32]}; + 3'b101: data_tmp = {data[23:0], data[63:24]}; + 3'b110: data_tmp = {data[15:0], data[63:16]}; + 3'b111: data_tmp = {data[7:0], data[63:8]}; + endcase + return data_tmp[riscv::XLEN-1:0]; + endfunction + + // generate byte enable mask + function automatic logic [7:0] be_gen(logic [2:0] addr, logic [1:0] size); + case (size) + 2'b11: begin + return 8'b1111_1111; + end + 2'b10: begin + case (addr[2:0]) + 3'b000: return 8'b0000_1111; + 3'b001: return 8'b0001_1110; + 3'b010: return 8'b0011_1100; + 3'b011: return 8'b0111_1000; + 3'b100: return 8'b1111_0000; + endcase + end + 2'b01: begin + case (addr[2:0]) + 3'b000: return 8'b0000_0011; + 3'b001: return 8'b0000_0110; + 3'b010: return 8'b0000_1100; + 3'b011: return 8'b0001_1000; + 3'b100: return 8'b0011_0000; + 3'b101: return 8'b0110_0000; + 3'b110: return 8'b1100_0000; + endcase + end + 2'b00: begin + case (addr[2:0]) + 3'b000: return 8'b0000_0001; + 3'b001: return 8'b0000_0010; + 3'b010: return 8'b0000_0100; + 3'b011: return 8'b0000_1000; + 3'b100: return 8'b0001_0000; + 3'b101: return 8'b0010_0000; + 3'b110: return 8'b0100_0000; + 3'b111: return 8'b1000_0000; + endcase + end + endcase + return 8'b0; + endfunction + + function automatic logic [3:0] be_gen_32(logic [1:0] addr, logic [1:0] size); + case (size) + 2'b10: begin + return 4'b1111; + end + 2'b01: begin + case (addr[1:0]) + 2'b00: return 4'b0011; + 2'b01: return 4'b0110; + 2'b10: return 4'b1100; + + endcase + end + 2'b00: begin + case (addr[1:0]) + 2'b00: return 4'b0001; + 2'b01: return 4'b0010; + 2'b10: return 4'b0100; + 2'b11: return 4'b1000; + endcase + end + default: return 4'b0; + endcase + return 4'b0; + endfunction + + // ---------------------- + // Extract Bytes from Op + // ---------------------- + function automatic logic [1:0] extract_transfer_size(fu_op op); + case (op) + LD, SD, FLD, FSD, + AMO_LRD, AMO_SCD, + AMO_SWAPD, AMO_ADDD, + AMO_ANDD, AMO_ORD, + AMO_XORD, AMO_MAXD, + AMO_MAXDU, AMO_MIND, + AMO_MINDU: begin + return 2'b11; + end + LW, LWU, SW, FLW, FSW, + AMO_LRW, AMO_SCW, + AMO_SWAPW, AMO_ADDW, + AMO_ANDW, AMO_ORW, + AMO_XORW, AMO_MAXW, + AMO_MAXWU, AMO_MINW, + AMO_MINWU: begin + return 2'b10; + end + LH, LHU, SH, FLH, FSH: return 2'b01; + LB, LBU, SB, FLB, FSB: return 2'b00; + default: return 2'b11; + endcase + endfunction +endpackage diff --git a/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_defines.sv b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_defines.sv new file mode 100644 index 000000000..66b5005d8 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_defines.sv @@ -0,0 +1 @@ +`define WT_DCACHE diff --git a/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper.sv b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper.sv new file mode 100644 index 000000000..5f4c19e22 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper.sv @@ -0,0 +1,791 @@ +`include "axi/typedef.svh" +`include "axi/assign.svh" +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + +import cva6_wrapper_pkg::*; + +module cva6_wrapper ( + input logic clk_i , + input logic rst_n , + + input logic [31:0] irq_sources, + + // AXI i/f + + //AXI write address bus ------------------------------------ + output logic [AxiIdWidthSlaves-1:0] AWID_o , + output logic [AxiAddrWidth-1:0] AWADDR_o , + output logic [ 7:0] AWLEN_o , + output logic [ 2:0] AWSIZE_o , + output logic [ 1:0] AWBURST_o , + output logic AWLOCK_o , + output logic [ 3:0] AWCACHE_o , + output logic [ 2:0] AWPROT_o , + output logic [ 3:0] AWREGION_o , + output logic [ AxiUserWidth-1:0] AWUSER_o , + output logic [ 3:0] AWQOS_o , + output logic AWVALID_o , + input logic AWREADY_i , + // --------------------------------------------------------- + + //AXI write data bus --------------------------------------- + output logic [AxiDataWidth-1:0] WDATA_o , + output logic [AxiDataWidth/8-1:0] WSTRB_o , + output logic WLAST_o , + output logic [AxiUserWidth-1:0] WUSER_o , + output logic WVALID_o , + input logic WREADY_i , + // --------------------------------------------------------- + + //AXI write response bus ----------------------------------- + input logic [AxiIdWidthSlaves-1:0] BID_i , + input logic [ 1:0] BRESP_i , + input logic BVALID_i , + input logic [AxiUserWidth-1:0] BUSER_i , + output logic BREADY_o , + // --------------------------------------------------------- + + //AXI read address bus ------------------------------------- + output logic [AxiIdWidthSlaves-1:0] ARID_o , + output logic [AxiAddrWidth-1:0] ARADDR_o , + output logic [ 7:0] ARLEN_o , + output logic [ 2:0] ARSIZE_o , + output logic [ 1:0] ARBURST_o , + output logic ARLOCK_o , + output logic [ 3:0] ARCACHE_o , + output logic [ 2:0] ARPROT_o , + output logic [ 3:0] ARREGION_o , + output logic [ AxiUserWidth-1:0] ARUSER_o , + output logic [ 3:0] ARQOS_o , + output logic ARVALID_o , + input logic ARREADY_i , + // --------------------------------------------------------- + + //AXI read data bus ---------------------------------------- + input logic [AxiIdWidthSlaves-1:0] RID_i , + input logic [AxiDataWidth-1:0] RDATA_i , + input logic [ 1:0] RRESP_i , + input logic RLAST_i , + input logic [AxiUserWidth-1:0] RUSER_i , + input logic RVALID_i , + output logic RREADY_o , + + // common part + input logic trst_n , + input logic tck , + input logic tms , + input logic tdi , + output wire tdo , + output wire tdo_oe +); + +`AXI_TYPEDEF_ALL(axi_slave, + logic [ AxiAddrWidth-1:0], + logic [AxiIdWidthSlaves-1:0], + logic [ AxiDataWidth-1:0], + logic [(AxiDataWidth/8)-1:0], + logic [ AxiUserWidth-1:0]) + +AXI_BUS #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthMaster ), + .AXI_USER_WIDTH ( AxiUserWidth ) +) slave[NBSlave-1:0](); + +AXI_BUS #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI_USER_WIDTH ( AxiUserWidth ) +) master[NBMaster-1:0](); + +AXI_BUS #( + .AXI_ADDR_WIDTH ( riscv::XLEN ), + .AXI_DATA_WIDTH ( riscv::XLEN ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI_USER_WIDTH ( AxiUserWidth ) +) master_to_dm[0:0](); + +// disable test-enable +logic test_en; +logic ndmreset; +logic ndmreset_n; +logic debug_req_irq; +logic timer_irq; +logic ipi; + +logic rtc; + +// Debug +logic debug_req_valid; +logic debug_req_ready; +dm::dmi_req_t debug_req; +logic debug_resp_valid; +logic debug_resp_ready; +dm::dmi_resp_t debug_resp; + +logic dmactive; + +// IRQ +logic [1:0] irq; +assign test_en = 1'b0; + +assign ndmreset_n = ~ndmreset; + +// --------------- +// AXI Xbar +// --------------- + +axi_pkg::xbar_rule_64_t [NBMaster-1:0] addr_map; + +assign addr_map = '{ + '{ idx: cva6_wrapper_pkg::Debug, start_addr: cva6_wrapper_pkg::DebugBase, end_addr: cva6_wrapper_pkg::DebugBase + cva6_wrapper_pkg::DebugLength }, + '{ idx: cva6_wrapper_pkg::CLINT, start_addr: cva6_wrapper_pkg::CLINTBase, end_addr: cva6_wrapper_pkg::CLINTBase + cva6_wrapper_pkg::CLINTLength }, + '{ idx: cva6_wrapper_pkg::PLIC, start_addr: cva6_wrapper_pkg::PLICBase, end_addr: cva6_wrapper_pkg::PLICBase + cva6_wrapper_pkg::PLICLength }, + '{ idx: cva6_wrapper_pkg::External, start_addr: cva6_wrapper_pkg::ExternalBase, end_addr: cva6_wrapper_pkg::ExternalBase + cva6_wrapper_pkg::ExternalLength } +}; + +localparam axi_pkg::xbar_cfg_t AXI_XBAR_CFG = '{ + NoSlvPorts: NBSlave, + NoMstPorts: NBMaster, + MaxMstTrans: 1, // Probably requires update + MaxSlvTrans: 1, // Probably requires update + FallThrough: 1'b0, + LatencyMode: axi_pkg::CUT_ALL_PORTS, + AxiIdWidthSlvPorts: AxiIdWidthMaster, + AxiIdUsedSlvPorts: AxiIdWidthMaster, + UniqueIds: 1'b0, + AxiAddrWidth: AxiAddrWidth, + AxiDataWidth: AxiDataWidth, + NoAddrRules: NBSlave +}; + +axi_xbar_intf #( + .AXI_USER_WIDTH ( AxiUserWidth ), + .Cfg ( AXI_XBAR_CFG ), + .rule_t ( axi_pkg::xbar_rule_64_t ) +) i_axi_xbar ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + .test_i ( test_en ), + .slv_ports ( slave ), + .mst_ports ( master ), + .addr_map_i ( addr_map ), + .en_default_mst_port_i ( '0 ), + .default_mst_port_i ( '0 ) +); + +// --------------- +// Debug Module +// --------------- +dmi_jtag i_dmi_jtag ( + .clk_i ( clk_i ), + .rst_ni ( rst_n ), + .dmi_rst_no ( ), // keep open + .testmode_i ( test_en ), + .dmi_req_valid_o ( debug_req_valid ), + .dmi_req_ready_i ( debug_req_ready ), + .dmi_req_o ( debug_req ), + .dmi_resp_valid_i ( debug_resp_valid ), + .dmi_resp_ready_o ( debug_resp_ready ), + .dmi_resp_i ( debug_resp ), + .tck_i ( tck ), + .tms_i ( tms ), + .trst_ni ( trst_n ), + .td_i ( tdi ), + .td_o ( tdo ), + .tdo_oe_o ( tdo_oe ) +); + +ariane_axi::req_t dm_axi_m_req; +ariane_axi::resp_t dm_axi_m_resp; + +logic dm_slave_req; +logic dm_slave_we; +logic [riscv::XLEN-1:0] dm_slave_addr; +logic [riscv::XLEN/8-1:0] dm_slave_be; +logic [riscv::XLEN-1:0] dm_slave_wdata; +logic [riscv::XLEN-1:0] dm_slave_rdata; + +logic dm_master_req; +logic [riscv::XLEN-1:0] dm_master_add; +logic dm_master_we; +logic [riscv::XLEN-1:0] dm_master_wdata; +logic [riscv::XLEN/8-1:0] dm_master_be; +logic dm_master_gnt; +logic dm_master_r_valid; +logic [riscv::XLEN-1:0] dm_master_r_rdata; + +// debug module +dm_top #( + .NrHarts ( 1 ), + .BusWidth ( riscv::XLEN ), + .SelectableHarts ( 1'b1 ) +) i_dm_top ( + .clk_i ( clk_i ), + .rst_ni ( rst_n ), // PoR + .testmode_i ( test_en ), + .ndmreset_o ( ndmreset ), + .dmactive_o ( dmactive ), // active debug session + .debug_req_o ( debug_req_irq ), + .unavailable_i ( '0 ), + .hartinfo_i ( {ariane_pkg::DebugHartInfo} ), + .slave_req_i ( dm_slave_req ), + .slave_we_i ( dm_slave_we ), + .slave_addr_i ( dm_slave_addr ), + .slave_be_i ( dm_slave_be ), + .slave_wdata_i ( dm_slave_wdata ), + .slave_rdata_o ( dm_slave_rdata ), + .master_req_o ( dm_master_req ), + .master_add_o ( dm_master_add ), + .master_we_o ( dm_master_we ), + .master_wdata_o ( dm_master_wdata ), + .master_be_o ( dm_master_be ), + .master_gnt_i ( dm_master_gnt ), + .master_r_valid_i ( dm_master_r_valid ), + .master_r_rdata_i ( dm_master_r_rdata ), + .dmi_rst_ni ( rst_n ), + .dmi_req_valid_i ( debug_req_valid ), + .dmi_req_ready_o ( debug_req_ready ), + .dmi_req_i ( debug_req ), + .dmi_resp_valid_o ( debug_resp_valid ), + .dmi_resp_ready_i ( debug_resp_ready ), + .dmi_resp_o ( debug_resp ) +); + +axi2mem #( + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI_ADDR_WIDTH ( riscv::XLEN ), + .AXI_DATA_WIDTH ( riscv::XLEN ), + .AXI_USER_WIDTH ( AxiUserWidth ) +) i_dm_axi2mem ( + .clk_i ( clk_i ), + .rst_ni ( rst_n ), + .slave ( master_to_dm[0] ), + .req_o ( dm_slave_req ), + .we_o ( dm_slave_we ), + .addr_o ( dm_slave_addr ), + .be_o ( dm_slave_be ), + .data_o ( dm_slave_wdata ), + .data_i ( dm_slave_rdata ) +); + +if (riscv::XLEN==32 ) begin + + assign master_to_dm[0].aw_user = '0; + assign master_to_dm[0].w_user = '0; + assign master_to_dm[0].ar_user = '0; + + assign master_to_dm[0].aw_id = dm_axi_m_req.aw.id; + assign master_to_dm[0].ar_id = dm_axi_m_req.ar.id; + + assign master[cva6_wrapper_pkg::Debug].r_user ='0; + assign master[cva6_wrapper_pkg::Debug].b_user ='0; + + xlnx_axi_dwidth_converter_dm_slave i_axi_dwidth_converter_dm_slave( + .s_axi_aclk(clk_i), + .s_axi_aresetn(ndmreset_n), + .s_axi_awid(master[cva6_wrapper_pkg::Debug].aw_id), + .s_axi_awaddr(master[cva6_wrapper_pkg::Debug].aw_addr[31:0]), + .s_axi_awlen(master[cva6_wrapper_pkg::Debug].aw_len), + .s_axi_awsize(master[cva6_wrapper_pkg::Debug].aw_size), + .s_axi_awburst(master[cva6_wrapper_pkg::Debug].aw_burst), + .s_axi_awlock(master[cva6_wrapper_pkg::Debug].aw_lock), + .s_axi_awcache(master[cva6_wrapper_pkg::Debug].aw_cache), + .s_axi_awprot(master[cva6_wrapper_pkg::Debug].aw_prot), + .s_axi_awregion(master[cva6_wrapper_pkg::Debug].aw_region), + .s_axi_awqos(master[cva6_wrapper_pkg::Debug].aw_qos), + .s_axi_awvalid(master[cva6_wrapper_pkg::Debug].aw_valid), + .s_axi_awready(master[cva6_wrapper_pkg::Debug].aw_ready), + .s_axi_wdata(master[cva6_wrapper_pkg::Debug].w_data), + .s_axi_wstrb(master[cva6_wrapper_pkg::Debug].w_strb), + .s_axi_wlast(master[cva6_wrapper_pkg::Debug].w_last), + .s_axi_wvalid(master[cva6_wrapper_pkg::Debug].w_valid), + .s_axi_wready(master[cva6_wrapper_pkg::Debug].w_ready), + .s_axi_bid(master[cva6_wrapper_pkg::Debug].b_id), + .s_axi_bresp(master[cva6_wrapper_pkg::Debug].b_resp), + .s_axi_bvalid(master[cva6_wrapper_pkg::Debug].b_valid), + .s_axi_bready(master[cva6_wrapper_pkg::Debug].b_ready), + .s_axi_arid(master[cva6_wrapper_pkg::Debug].ar_id), + .s_axi_araddr(master[cva6_wrapper_pkg::Debug].ar_addr[31:0]), + .s_axi_arlen(master[cva6_wrapper_pkg::Debug].ar_len), + .s_axi_arsize(master[cva6_wrapper_pkg::Debug].ar_size), + .s_axi_arburst(master[cva6_wrapper_pkg::Debug].ar_burst), + .s_axi_arlock(master[cva6_wrapper_pkg::Debug].ar_lock), + .s_axi_arcache(master[cva6_wrapper_pkg::Debug].ar_cache), + .s_axi_arprot(master[cva6_wrapper_pkg::Debug].ar_prot), + .s_axi_arregion(master[cva6_wrapper_pkg::Debug].ar_region), + .s_axi_arqos(master[cva6_wrapper_pkg::Debug].ar_qos), + .s_axi_arvalid(master[cva6_wrapper_pkg::Debug].ar_valid), + .s_axi_arready(master[cva6_wrapper_pkg::Debug].ar_ready), + .s_axi_rid(master[cva6_wrapper_pkg::Debug].r_id), + .s_axi_rdata(master[cva6_wrapper_pkg::Debug].r_data), + .s_axi_rresp(master[cva6_wrapper_pkg::Debug].r_resp), + .s_axi_rlast(master[cva6_wrapper_pkg::Debug].r_last), + .s_axi_rvalid(master[cva6_wrapper_pkg::Debug].r_valid), + .s_axi_rready(master[cva6_wrapper_pkg::Debug].r_ready), + .m_axi_awaddr(master_to_dm[0].aw_addr), + .m_axi_awlen(master_to_dm[0].aw_len), + .m_axi_awsize(master_to_dm[0].aw_size), + .m_axi_awburst(master_to_dm[0].aw_burst), + .m_axi_awlock(master_to_dm[0].aw_lock), + .m_axi_awcache(master_to_dm[0].aw_cache), + .m_axi_awprot(master_to_dm[0].aw_prot), + .m_axi_awregion(master_to_dm[0].aw_region), + .m_axi_awqos(master_to_dm[0].aw_qos), + .m_axi_awvalid(master_to_dm[0].aw_valid), + .m_axi_awready(master_to_dm[0].aw_ready), + .m_axi_wdata(master_to_dm[0].w_data ), + .m_axi_wstrb(master_to_dm[0].w_strb), + .m_axi_wlast(master_to_dm[0].w_last), + .m_axi_wvalid(master_to_dm[0].w_valid), + .m_axi_wready(master_to_dm[0].w_ready), + .m_axi_bresp(master_to_dm[0].b_resp), + .m_axi_bvalid(master_to_dm[0].b_valid), + .m_axi_bready(master_to_dm[0].b_ready), + .m_axi_araddr(master_to_dm[0].ar_addr), + .m_axi_arlen(master_to_dm[0].ar_len), + .m_axi_arsize(master_to_dm[0].ar_size), + .m_axi_arburst(master_to_dm[0].ar_burst), + .m_axi_arlock(master_to_dm[0].ar_lock), + .m_axi_arcache(master_to_dm[0].ar_cache), + .m_axi_arprot(master_to_dm[0].ar_prot), + .m_axi_arregion(master_to_dm[0].ar_region), + .m_axi_arqos(master_to_dm[0].ar_qos), + .m_axi_arvalid(master_to_dm[0].ar_valid), + .m_axi_arready(master_to_dm[0].ar_ready), + .m_axi_rdata(master_to_dm[0].r_data), + .m_axi_rresp(master_to_dm[0].r_resp), + .m_axi_rlast(master_to_dm[0].r_last), + .m_axi_rvalid(master_to_dm[0].r_valid), + .m_axi_rready(master_to_dm[0].r_ready) + ); + +end else begin + + assign master[cva6_wrapper_pkg::Debug].aw_id = master_to_dm[0].aw_id; + assign master[cva6_wrapper_pkg::Debug].aw_addr = master_to_dm[0].aw_addr; + assign master[cva6_wrapper_pkg::Debug].aw_len = master_to_dm[0].aw_len; + assign master[cva6_wrapper_pkg::Debug].aw_size = master_to_dm[0].aw_size; + assign master[cva6_wrapper_pkg::Debug].aw_burst = master_to_dm[0].aw_burst; + assign master[cva6_wrapper_pkg::Debug].aw_lock = master_to_dm[0].aw_lock; + assign master[cva6_wrapper_pkg::Debug].aw_cache = master_to_dm[0].aw_cache; + assign master[cva6_wrapper_pkg::Debug].aw_prot = master_to_dm[0].aw_prot; + assign master[cva6_wrapper_pkg::Debug].aw_qos = master_to_dm[0].aw_qos; + assign master[cva6_wrapper_pkg::Debug].aw_atop = master_to_dm[0].aw_atop; + assign master[cva6_wrapper_pkg::Debug].aw_region = master_to_dm[0].aw_region; + assign master[cva6_wrapper_pkg::Debug].aw_user = master_to_dm[0].aw_user; + assign master[cva6_wrapper_pkg::Debug].aw_valid = master_to_dm[0].aw_valid; + + assign master_to_dm[0].aw_ready =master[cva6_wrapper_pkg::Debug].aw_ready; + + assign master[cva6_wrapper_pkg::Debug].w_data = master_to_dm[0].w_data; + assign master[cva6_wrapper_pkg::Debug].w_strb = master_to_dm[0].w_strb; + assign master[cva6_wrapper_pkg::Debug].w_last = master_to_dm[0].w_last; + assign master[cva6_wrapper_pkg::Debug].w_user = master_to_dm[0].w_user; + assign master[cva6_wrapper_pkg::Debug].w_valid = master_to_dm[0].w_valid; + + assign master_to_dm[0].w_ready =master[cva6_wrapper_pkg::Debug].w_ready; + + assign master_to_dm[0].b_id =master[cva6_wrapper_pkg::Debug].b_id; + assign master_to_dm[0].b_resp =master[cva6_wrapper_pkg::Debug].b_resp; + assign master_to_dm[0].b_user =master[cva6_wrapper_pkg::Debug].b_user; + assign master_to_dm[0].b_valid =master[cva6_wrapper_pkg::Debug].b_valid; + + assign master[cva6_wrapper_pkg::Debug].b_ready = master_to_dm[0].b_ready; + + assign master[cva6_wrapper_pkg::Debug].ar_id = master_to_dm[0].ar_id; + assign master[cva6_wrapper_pkg::Debug].ar_addr = master_to_dm[0].ar_addr; + assign master[cva6_wrapper_pkg::Debug].ar_len = master_to_dm[0].ar_len; + assign master[cva6_wrapper_pkg::Debug].ar_size = master_to_dm[0].ar_size; + assign master[cva6_wrapper_pkg::Debug].ar_burst = master_to_dm[0].ar_burst; + assign master[cva6_wrapper_pkg::Debug].ar_lock = master_to_dm[0].ar_lock; + assign master[cva6_wrapper_pkg::Debug].ar_cache = master_to_dm[0].ar_cache; + assign master[cva6_wrapper_pkg::Debug].ar_prot = master_to_dm[0].ar_prot; + assign master[cva6_wrapper_pkg::Debug].ar_qos = master_to_dm[0].ar_qos; + assign master[cva6_wrapper_pkg::Debug].ar_region = master_to_dm[0].ar_region; + assign master[cva6_wrapper_pkg::Debug].ar_user = master_to_dm[0].ar_user; + assign master[cva6_wrapper_pkg::Debug].ar_valid = master_to_dm[0].ar_valid; + + assign master_to_dm[0].ar_ready =master[cva6_wrapper_pkg::Debug].ar_ready; + + assign master_to_dm[0].r_id =master[cva6_wrapper_pkg::Debug].r_id; + assign master_to_dm[0].r_data =master[cva6_wrapper_pkg::Debug].r_data; + assign master_to_dm[0].r_resp =master[cva6_wrapper_pkg::Debug].r_resp; + assign master_to_dm[0].r_last =master[cva6_wrapper_pkg::Debug].r_last; + assign master_to_dm[0].r_user =master[cva6_wrapper_pkg::Debug].r_user; + assign master_to_dm[0].r_valid =master[cva6_wrapper_pkg::Debug].r_valid; + + assign master[cva6_wrapper_pkg::Debug].r_ready = master_to_dm[0].r_ready; + +end + +logic [1:0] axi_adapter_size; + +assign axi_adapter_size = (riscv::XLEN == 64) ? 2'b11 : 2'b10; + + +axi_adapter #( + .DATA_WIDTH ( riscv::XLEN ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .axi_req_t ( axi_slave_req_t ), + .axi_rsp_t ( axi_slave_resp_t ) +) i_dm_axi_master ( + .clk_i ( clk_i ), + .rst_ni ( rst_n ), + .req_i ( dm_master_req ), + .type_i ( ariane_axi::SINGLE_REQ ), + .amo_i ( ariane_pkg::AMO_NONE ), + .gnt_o ( dm_master_gnt ), + .addr_i ( dm_master_add ), + .we_i ( dm_master_we ), + .wdata_i ( dm_master_wdata ), + .be_i ( dm_master_be ), + .size_i ( axi_adapter_size ), + .id_i ( '0 ), + .valid_o ( dm_master_r_valid ), + .rdata_o ( dm_master_r_rdata ), + .id_o ( ), + .critical_word_o ( ), + .critical_word_valid_o ( ), + .axi_req_o ( dm_axi_m_req ), + .axi_resp_i ( dm_axi_m_resp ) +); + +if (riscv::XLEN==32 ) begin + logic [31 : 0] dm_master_m_awaddr; + logic [31 : 0] dm_master_m_araddr; + + assign slave[1].aw_addr = {32'h0000_0000, dm_master_m_awaddr}; + assign slave[1].ar_addr = {32'h0000_0000, dm_master_m_araddr}; + + logic [31 : 0] dm_master_s_rdata; + + assign dm_axi_m_resp.r.data = {32'h0000_0000, dm_master_s_rdata}; + + assign slave[1].aw_user = '0; + assign slave[1].w_user = '0; + assign slave[1].ar_user = '0; + + assign slave[1].aw_id = dm_axi_m_req.aw.id; + assign slave[1].ar_id = dm_axi_m_req.ar.id; + assign slave[1].aw_atop = dm_axi_m_req.aw.atop; + + xlnx_axi_dwidth_converter_dm_master i_axi_dwidth_converter_dm_master( + .s_axi_aclk(clk_i), + .s_axi_aresetn(ndmreset_n), + .s_axi_awid(dm_axi_m_req.aw.id), + .s_axi_awaddr(dm_axi_m_req.aw.addr[31:0]), + .s_axi_awlen(dm_axi_m_req.aw.len), + .s_axi_awsize(dm_axi_m_req.aw.size), + .s_axi_awburst(dm_axi_m_req.aw.burst), + .s_axi_awlock(dm_axi_m_req.aw.lock), + .s_axi_awcache(dm_axi_m_req.aw.cache), + .s_axi_awprot(dm_axi_m_req.aw.prot), + .s_axi_awregion(dm_axi_m_req.aw.region), + .s_axi_awqos(dm_axi_m_req.aw.qos), + .s_axi_awvalid(dm_axi_m_req.aw_valid), + .s_axi_awready(dm_axi_m_resp.aw_ready), + .s_axi_wdata(dm_axi_m_req.w.data[31:0]), + .s_axi_wstrb(dm_axi_m_req.w.strb[3:0]), + .s_axi_wlast(dm_axi_m_req.w.last), + .s_axi_wvalid(dm_axi_m_req.w_valid), + .s_axi_wready(dm_axi_m_resp.w_ready), + .s_axi_bid(dm_axi_m_resp.b.id), + .s_axi_bresp(dm_axi_m_resp.b.resp), + .s_axi_bvalid(dm_axi_m_resp.b_valid), + .s_axi_bready(dm_axi_m_req.b_ready), + .s_axi_arid(dm_axi_m_req.ar.id), + .s_axi_araddr(dm_axi_m_req.ar.addr[31:0]), + .s_axi_arlen(dm_axi_m_req.ar.len), + .s_axi_arsize(dm_axi_m_req.ar.size), + .s_axi_arburst(dm_axi_m_req.ar.burst), + .s_axi_arlock(dm_axi_m_req.ar.lock), + .s_axi_arcache(dm_axi_m_req.ar.cache), + .s_axi_arprot(dm_axi_m_req.ar.prot), + .s_axi_arregion(dm_axi_m_req.ar.region), + .s_axi_arqos(dm_axi_m_req.ar.qos), + .s_axi_arvalid(dm_axi_m_req.ar_valid), + .s_axi_arready(dm_axi_m_resp.ar_ready), + .s_axi_rid(dm_axi_m_resp.r.id), + .s_axi_rdata(dm_master_s_rdata), + .s_axi_rresp(dm_axi_m_resp.r.resp), + .s_axi_rlast(dm_axi_m_resp.r.last), + .s_axi_rvalid(dm_axi_m_resp.r_valid), + .s_axi_rready(dm_axi_m_req.r_ready), + .m_axi_awaddr(dm_master_m_awaddr), + .m_axi_awlen(slave[1].aw_len), + .m_axi_awsize(slave[1].aw_size), + .m_axi_awburst(slave[1].aw_burst), + .m_axi_awlock(slave[1].aw_lock), + .m_axi_awcache(slave[1].aw_cache), + .m_axi_awprot(slave[1].aw_prot), + .m_axi_awregion(slave[1].aw_region), + .m_axi_awqos(slave[1].aw_qos), + .m_axi_awvalid(slave[1].aw_valid), + .m_axi_awready(slave[1].aw_ready), + .m_axi_wdata(slave[1].w_data ), + .m_axi_wstrb(slave[1].w_strb), + .m_axi_wlast(slave[1].w_last), + .m_axi_wvalid(slave[1].w_valid), + .m_axi_wready(slave[1].w_ready), + .m_axi_bresp(slave[1].b_resp), + .m_axi_bvalid(slave[1].b_valid), + .m_axi_bready(slave[1].b_ready), + .m_axi_araddr(dm_master_m_araddr), + .m_axi_arlen(slave[1].ar_len), + .m_axi_arsize(slave[1].ar_size), + .m_axi_arburst(slave[1].ar_burst), + .m_axi_arlock(slave[1].ar_lock), + .m_axi_arcache(slave[1].ar_cache), + .m_axi_arprot(slave[1].ar_prot), + .m_axi_arregion(slave[1].ar_region), + .m_axi_arqos(slave[1].ar_qos), + .m_axi_arvalid(slave[1].ar_valid), + .m_axi_arready(slave[1].ar_ready), + .m_axi_rdata(slave[1].r_data), + .m_axi_rresp(slave[1].r_resp), + .m_axi_rlast(slave[1].r_last), + .m_axi_rvalid(slave[1].r_valid), + .m_axi_rready(slave[1].r_ready) + ); +end else begin + `AXI_ASSIGN_FROM_REQ(slave[1], dm_axi_m_req) + `AXI_ASSIGN_TO_RESP(dm_axi_m_resp, slave[1]) +end + + +// --------------- +// Core +// --------------- +ariane_axi::req_t axi_ariane_req; +ariane_axi::resp_t axi_ariane_resp; + +ariane #( + .ArianeCfg ( cva6_wrapper_pkg::CVA6Cfg ) +) i_ariane ( + .clk_i ( clk_i ), + .rst_ni ( rst_n /*ndmreset_n*/ ), + .boot_addr_i ( cva6_wrapper_pkg::ExternalBase ), + .hart_id_i ( '0 ), + .irq_i ( irq ), + .ipi_i ( ipi ), + .time_irq_i ( timer_irq ), + .debug_req_i ( debug_req_irq ), + .axi_req_o ( axi_ariane_req ), + .axi_resp_i ( axi_ariane_resp ) +); + +`AXI_ASSIGN_FROM_REQ(slave[0], axi_ariane_req) +`AXI_ASSIGN_TO_RESP(axi_ariane_resp, slave[0]) + +// --------------- +// CLINT +// --------------- +// divide clock by two +always_ff @(posedge clk_i or negedge ndmreset_n) begin + if (~ndmreset_n) begin + rtc <= 0; + end else begin + rtc <= rtc ^ 1'b1; + end +end + +axi_slave_req_t axi_clint_req; +axi_slave_resp_t axi_clint_resp; + +clint #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .NR_CORES ( 1 ), + .axi_req_t ( axi_slave_req_t ), + .axi_resp_t ( axi_slave_resp_t ) +) i_clint ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + .testmode_i ( test_en ), + .axi_req_i ( axi_clint_req ), + .axi_resp_o ( axi_clint_resp ), + .rtc_i ( rtc ), + .timer_irq_o ( timer_irq ), + .ipi_o ( ipi ) +); + +`AXI_ASSIGN_TO_REQ(axi_clint_req, master[cva6_wrapper_pkg::CLINT]) +`AXI_ASSIGN_FROM_RESP(master[cva6_wrapper_pkg::CLINT], axi_clint_resp) + + // --------------- + // PLIC + // --------------- + + REG_BUS #( + .ADDR_WIDTH ( 32 ), + .DATA_WIDTH ( 32 ) + ) reg_bus (clk_i); + + logic plic_penable; + logic plic_pwrite; + logic [31:0] plic_paddr; + logic plic_psel; + logic [31:0] plic_pwdata; + logic [31:0] plic_prdata; + logic plic_pready; + logic plic_pslverr; + + axi2apb_64_32 #( + .AXI4_ADDRESS_WIDTH ( AxiAddrWidth ), + .AXI4_RDATA_WIDTH ( AxiDataWidth ), + .AXI4_WDATA_WIDTH ( AxiDataWidth ), + .AXI4_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI4_USER_WIDTH ( AxiUserWidth ), + .BUFF_DEPTH_SLAVE ( 2 ), + .APB_ADDR_WIDTH ( 32 ) + ) i_axi2apb_64_32_plic ( + .ACLK ( clk_i ), + .ARESETn ( ndmreset_n ), + .test_en_i ( 1'b0 ), + .AWID_i ( master[cva6_wrapper_pkg::PLIC].aw_id ), + .AWADDR_i ( master[cva6_wrapper_pkg::PLIC].aw_addr ), + .AWLEN_i ( master[cva6_wrapper_pkg::PLIC].aw_len ), + .AWSIZE_i ( master[cva6_wrapper_pkg::PLIC].aw_size ), + .AWBURST_i ( master[cva6_wrapper_pkg::PLIC].aw_burst ), + .AWLOCK_i ( master[cva6_wrapper_pkg::PLIC].aw_lock ), + .AWCACHE_i ( master[cva6_wrapper_pkg::PLIC].aw_cache ), + .AWPROT_i ( master[cva6_wrapper_pkg::PLIC].aw_prot ), + .AWREGION_i( master[cva6_wrapper_pkg::PLIC].aw_region ), + .AWUSER_i ( master[cva6_wrapper_pkg::PLIC].aw_user ), + .AWQOS_i ( master[cva6_wrapper_pkg::PLIC].aw_qos ), + .AWVALID_i ( master[cva6_wrapper_pkg::PLIC].aw_valid ), + .AWREADY_o ( master[cva6_wrapper_pkg::PLIC].aw_ready ), + .WDATA_i ( master[cva6_wrapper_pkg::PLIC].w_data ), + .WSTRB_i ( master[cva6_wrapper_pkg::PLIC].w_strb ), + .WLAST_i ( master[cva6_wrapper_pkg::PLIC].w_last ), + .WUSER_i ( master[cva6_wrapper_pkg::PLIC].w_user ), + .WVALID_i ( master[cva6_wrapper_pkg::PLIC].w_valid ), + .WREADY_o ( master[cva6_wrapper_pkg::PLIC].w_ready ), + .BID_o ( master[cva6_wrapper_pkg::PLIC].b_id ), + .BRESP_o ( master[cva6_wrapper_pkg::PLIC].b_resp ), + .BVALID_o ( master[cva6_wrapper_pkg::PLIC].b_valid ), + .BUSER_o ( master[cva6_wrapper_pkg::PLIC].b_user ), + .BREADY_i ( master[cva6_wrapper_pkg::PLIC].b_ready ), + .ARID_i ( master[cva6_wrapper_pkg::PLIC].ar_id ), + .ARADDR_i ( master[cva6_wrapper_pkg::PLIC].ar_addr ), + .ARLEN_i ( master[cva6_wrapper_pkg::PLIC].ar_len ), + .ARSIZE_i ( master[cva6_wrapper_pkg::PLIC].ar_size ), + .ARBURST_i ( master[cva6_wrapper_pkg::PLIC].ar_burst ), + .ARLOCK_i ( master[cva6_wrapper_pkg::PLIC].ar_lock ), + .ARCACHE_i ( master[cva6_wrapper_pkg::PLIC].ar_cache ), + .ARPROT_i ( master[cva6_wrapper_pkg::PLIC].ar_prot ), + .ARREGION_i( master[cva6_wrapper_pkg::PLIC].ar_region ), + .ARUSER_i ( master[cva6_wrapper_pkg::PLIC].ar_user ), + .ARQOS_i ( master[cva6_wrapper_pkg::PLIC].ar_qos ), + .ARVALID_i ( master[cva6_wrapper_pkg::PLIC].ar_valid ), + .ARREADY_o ( master[cva6_wrapper_pkg::PLIC].ar_ready ), + .RID_o ( master[cva6_wrapper_pkg::PLIC].r_id ), + .RDATA_o ( master[cva6_wrapper_pkg::PLIC].r_data ), + .RRESP_o ( master[cva6_wrapper_pkg::PLIC].r_resp ), + .RLAST_o ( master[cva6_wrapper_pkg::PLIC].r_last ), + .RUSER_o ( master[cva6_wrapper_pkg::PLIC].r_user ), + .RVALID_o ( master[cva6_wrapper_pkg::PLIC].r_valid ), + .RREADY_i ( master[cva6_wrapper_pkg::PLIC].r_ready ), + .PENABLE ( plic_penable ), + .PWRITE ( plic_pwrite ), + .PADDR ( plic_paddr ), + .PSEL ( plic_psel ), + .PWDATA ( plic_pwdata ), + .PRDATA ( plic_prdata ), + .PREADY ( plic_pready ), + .PSLVERR ( plic_pslverr ) + ); + + apb_to_reg i_apb_to_reg ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + .penable_i ( plic_penable ), + .pwrite_i ( plic_pwrite ), + .paddr_i ( plic_paddr ), + .psel_i ( plic_psel ), + .pwdata_i ( plic_pwdata ), + .prdata_o ( plic_prdata ), + .pready_o ( plic_pready ), + .pslverr_o ( plic_pslverr ), + .reg_o ( reg_bus ) + ); + + // define reg type according to REG_BUS above + `REG_BUS_TYPEDEF_ALL(plic, logic[31:0], logic[31:0], logic[3:0]) + plic_req_t plic_req; + plic_rsp_t plic_rsp; + + // assign REG_BUS.out to (req_t, rsp_t) pair + `REG_BUS_ASSIGN_TO_REQ(plic_req, reg_bus) + `REG_BUS_ASSIGN_FROM_RSP(reg_bus, plic_rsp) + + plic_top #( + .N_SOURCE ( cva6_wrapper_pkg::NumSources ), + .N_TARGET ( cva6_wrapper_pkg::NumTargets ), + .MAX_PRIO ( cva6_wrapper_pkg::MaxPriority ), + .reg_req_t ( plic_req_t ), + .reg_rsp_t ( plic_rsp_t ) + ) i_plic ( + .clk_i, + .rst_ni (ndmreset_n), + .req_i ( plic_req ), + .resp_o ( plic_rsp ), + .le_i ( '0 ), // 0:level 1:edge + .irq_sources_i ( irq_sources ), + .eip_targets_o ( irq ) + ); + +// --------------- +// AXI to the outside world +// --------------- + + assign AWID_o = master[cva6_wrapper_pkg::External].aw_id; + assign AWADDR_o = master[cva6_wrapper_pkg::External].aw_addr; + assign AWLEN_o = master[cva6_wrapper_pkg::External].aw_len; + assign AWSIZE_o = master[cva6_wrapper_pkg::External].aw_size; + assign AWBURST_o = master[cva6_wrapper_pkg::External].aw_burst; + assign AWLOCK_o = master[cva6_wrapper_pkg::External].aw_lock; + assign AWCACHE_o = master[cva6_wrapper_pkg::External].aw_cache; + assign AWPROT_o = master[cva6_wrapper_pkg::External].aw_prot; + assign AWREGION_o = master[cva6_wrapper_pkg::External].aw_region; + assign AWUSER_o = '0; + assign AWQOS_o = master[cva6_wrapper_pkg::External].aw_qos; + assign AWVALID_o = master[cva6_wrapper_pkg::External].aw_valid; + assign master[cva6_wrapper_pkg::External].aw_ready = AWREADY_i; + assign WDATA_o = master[cva6_wrapper_pkg::External].w_data; + assign WSTRB_o = master[cva6_wrapper_pkg::External].w_strb; + assign WLAST_o = master[cva6_wrapper_pkg::External].w_last; + assign WUSER_o = '0; + assign WVALID_o = master[cva6_wrapper_pkg::External].w_valid; + assign master[cva6_wrapper_pkg::External].w_ready = WREADY_i; + assign master[cva6_wrapper_pkg::External].b_id = BID_i; + assign master[cva6_wrapper_pkg::External].b_resp = BRESP_i; + assign master[cva6_wrapper_pkg::External].b_valid = BVALID_i; + assign BREADY_o = master[cva6_wrapper_pkg::External].b_ready; + assign ARID_o = master[cva6_wrapper_pkg::External].ar_id; + assign ARADDR_o = master[cva6_wrapper_pkg::External].ar_addr; + assign ARLEN_o = master[cva6_wrapper_pkg::External].ar_len; + assign ARSIZE_o = master[cva6_wrapper_pkg::External].ar_size; + assign ARBURST_o = master[cva6_wrapper_pkg::External].ar_burst; + assign ARLOCK_o = master[cva6_wrapper_pkg::External].ar_lock; + assign ARCACHE_o = master[cva6_wrapper_pkg::External].ar_cache; + assign ARPROT_o = master[cva6_wrapper_pkg::External].ar_prot; + assign ARREGION_o = master[cva6_wrapper_pkg::External].ar_region; + assign ARUSER_o = '0; + assign ARQOS_o = master[cva6_wrapper_pkg::External].ar_qos; + assign ARVALID_o = master[cva6_wrapper_pkg::External].ar_valid; + assign master[cva6_wrapper_pkg::External].ar_ready = ARREADY_i; + assign master[cva6_wrapper_pkg::External].r_id = RID_i; + assign master[cva6_wrapper_pkg::External].r_data = RDATA_i; + assign master[cva6_wrapper_pkg::External].r_resp = RRESP_i; + assign master[cva6_wrapper_pkg::External].r_last = RLAST_i; + assign master[cva6_wrapper_pkg::External].r_valid = RVALID_i; + assign RREADY_o = master[cva6_wrapper_pkg::External].r_ready; + +endmodule diff --git a/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper_pkg.sv b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper_pkg.sv new file mode 100644 index 000000000..d435de560 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/cva6_wrapper/cva6_wrapper_pkg.sv @@ -0,0 +1,74 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + +package cva6_wrapper_pkg; + // M-Mode Hart, S-Mode Hart + localparam int unsigned NumTargets = 2; + // Uart, SPI, Ethernet, reserved + localparam int unsigned NumSources = 32; + localparam int unsigned MaxPriority = 7; + + // 24 MByte in 8 byte words + localparam NBSlave = 2; // debug, cva6 + localparam NBMaster = 4; // debug, plic, clint, external + localparam AxiAddrWidth = 64; + localparam AxiDataWidth = 64; + localparam AxiIdWidthMaster = $clog2(NBMaster); + localparam AxiIdWidthSlaves = AxiIdWidthMaster + $clog2(NBSlave); + localparam AxiUserWidth = 1; + + typedef enum int unsigned { + External = 0, + PLIC = 1, + CLINT = 2, + Debug = 3 + } axi_slaves_t; + + localparam logic[63:0] DebugLength = 64'h1000; + localparam logic[63:0] CLINTLength = 64'hC0000; + localparam logic[63:0] PLICLength = 64'h3FF_FFFF; + localparam logic[63:0] ExternalLength = 64'hEFFF_FFFF; + + // Instantiate AXI protocol checkers + localparam bit GenProtocolChecker = 1'b0; + + typedef enum logic [63:0] { + DebugBase = 64'h0000_0000, + CLINTBase = 64'h0200_0000, + PLICBase = 64'h0C00_0000, + ExternalBase = 64'h1000_0000 + } soc_bus_start_t; + + localparam NrRegion = 1; + + localparam ariane_pkg::ariane_cfg_t CVA6Cfg = '{ + RASDepth: 2, + BTBEntries: 32, + BHTEntries: 128, + // idempotent region + NrNonIdempotentRules: 1, + NonIdempotentAddrBase: {64'b0}, + NonIdempotentLength: {ExternalBase}, + NrExecuteRegionRules: 2, + ExecuteRegionAddrBase: {DebugBase, ExternalBase}, + ExecuteRegionLength: {DebugLength, ExternalLength}, + // cached region + NrCachedRegionRules: 1, + CachedRegionAddrBase: {ExternalBase}, + CachedRegionLength: {64'h7000_0000}, + // cache config + AxiCompliant: 1'b1, + SwapEndianess: 1'b0, + // debug + DmBaseAddress: DebugBase, + NrPMPEntries: 8 + }; + +endpackage