diff --git a/CHANGELOG.md b/CHANGELOG.md index cf6f258c4..5af490e70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +- Chcek execute PMA on instruction frontend + ### Changed - Re-work interrupt and debug subsystem to associate requests during decode. This improves stability on for non-idempotent loads. diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 246faf6ea..4b4313fe0 100644 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -33,14 +33,21 @@ package ariane_pkg; // sure to add a propper parameter check to the `check_cfg` function. typedef struct packed { int NrNonIdempotentRules; // Number of non idempotent rules - logic [2**16-1:0][63:0] NonIdempotentAddrBase; // base which needs to match - logic [2**16-1:0][63:0] NonIdempotentAddrMaks; // bit mask which bits to consider when matching the rule + logic [15:0][63:0] NonIdempotentAddrBase; // base which needs to match + logic [15:0][63:0] NonIdempotentAddrMaks; // bit mask which bits to consider when matching the rule + int NrExecuteRegionRules; // Number of regions which have execute property + logic [15:0][63:0] ExecuteRegionAddrBase; // base which needs to match + logic [15:0][63:0] ExecuteRegionAddrMaks; // bit mask which bits to consider when matching the rule } ariane_cfg_t; localparam ariane_cfg_t ArianeDefaultConfig = '{ NrNonIdempotentRules: 2, NonIdempotentAddrBase: {64'b0, 64'b0}, - NonIdempotentAddrMaks: {64'b0, 64'b0} + NonIdempotentAddrMaks: {64'b0, 64'b0}, + NrExecuteRegionRules: 3, + // DRAM, Boot ROM, Debug Module + ExecuteRegionAddrBase: {64'h8000_0000, 64'h1_0000, 64'h0}, + ExecuteRegionAddrMaks: {mask(64'h40000000), mask(64'h10000), mask(64'h1000)} }; // Function being called to check parameters @@ -48,10 +55,22 @@ package ariane_pkg; // pragma translate_off `ifndef VERILATOR assert(Cfg.NrNonIdempotentRules <= 16); + assert(Cfg.NrExecuteRegionRules <= 16); `endif // pragma translate_on endfunction + // Generate a mask for a given power of two length + function logic [63:0] mask (input logic [63:0] len); + // pragma translate_off + `ifndef VERILATOR + // check that the region we want is actually power of two aligned + assert (2**$clog2(len) == len) else $error("Length must be a power of two"); + `endif + // pragma translate_on + return {64{1'b1}} << $clog2(len); + endfunction + // 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 diff --git a/src/ariane.sv b/src/ariane.sv index 521d47635..05851595f 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -234,7 +234,7 @@ module ariane #( .DmBaseAddress ( DmBaseAddress ) ) i_frontend ( .flush_i ( flush_ctrl_if ), // not entirely correct - .flush_bp_i ( flush_ctrl_bp ), + .flush_bp_i ( 1'b0 ), .debug_mode_i ( debug_mode ), .boot_addr_i ( boot_addr_i ), .icache_dreq_i ( icache_dreq_cache_if ), diff --git a/src/ex_stage.sv b/src/ex_stage.sv index 08225bbca..273e65d38 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -251,7 +251,9 @@ module ex_stage #( assign lsu_data = lsu_valid_i ? fu_data_i : '0; - load_store_unit lsu_i ( + load_store_unit #( + .Cfg ( Cfg ) + ) lsu_i ( .clk_i, .rst_ni, .flush_i, diff --git a/src/load_store_unit.sv b/src/load_store_unit.sv index c6da6e3e4..90819d376 100644 --- a/src/load_store_unit.sv +++ b/src/load_store_unit.sv @@ -15,7 +15,8 @@ import ariane_pkg::*; module load_store_unit #( - parameter int unsigned ASID_WIDTH = 1 + parameter int unsigned ASID_WIDTH = 1, + parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig )( input logic clk_i, input logic rst_ni, @@ -119,7 +120,8 @@ module load_store_unit #( mmu #( .INSTR_TLB_ENTRIES ( 16 ), .DATA_TLB_ENTRIES ( 16 ), - .ASID_WIDTH ( ASID_WIDTH ) + .ASID_WIDTH ( ASID_WIDTH ), + .Cfg ( Cfg ) ) i_mmu ( // misaligned bypass .misaligned_ex_i ( misaligned_exception ), diff --git a/src/mmu.sv b/src/mmu.sv index b45de2c11..dc160796f 100644 --- a/src/mmu.sv +++ b/src/mmu.sv @@ -19,8 +19,9 @@ import ariane_pkg::*; module mmu #( parameter int unsigned INSTR_TLB_ENTRIES = 4, parameter int unsigned DATA_TLB_ENTRIES = 4, - parameter int unsigned ASID_WIDTH = 1 -)( + parameter int unsigned ASID_WIDTH = 1, + parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig +) ( input logic clk_i, input logic rst_ni, input logic flush_i, @@ -178,6 +179,7 @@ module mmu #( //----------------------- // Instruction Interface //----------------------- + logic match_any_execute_region; // The instruction interface is a simple request response interface always_comb begin : instr_interface // MMU disabled: just pass through @@ -235,8 +237,21 @@ module mmu #( icache_areq_o.fetch_exception = {riscv::INSTR_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1}; end end + // if it didn't match any execute region throw an `Instruction Access Fault` + if (!match_any_execute_region) begin + icache_areq_o.fetch_exception = {riscv::INSTR_ACCESS_FAULT, icache_areq_o.fetch_paddr, 1'b1}; + end end + always_comb begin : execute_addr_check + // if we don't specify any region we assume everything is accessible + match_any_execute_region = (Cfg.NrExecuteRegionRules == 0); + // check for execute flag on memory + for (int i = 0; i < Cfg.NrExecuteRegionRules; i++) begin + match_any_execute_region |= (Cfg.ExecuteRegionAddrBase[i] & Cfg.ExecuteRegionAddrMaks[i]) + == (icache_areq_o.fetch_paddr & Cfg.ExecuteRegionAddrMaks[i]); + end + end //----------------------- // Data Interface //-----------------------