From e503ff0aa024a2eaf56b20198a66ee386b24379f Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Tue, 26 Sep 2023 08:06:51 +0200 Subject: [PATCH] addr_decode: Add a variant suited for online configuration --- Bender.yml | 163 +++++++++++++++++---------------- README.md | 1 + common_cells.core | 6 +- src/addr_decode.sv | 111 ++++------------------- src/addr_decode_dync.sv | 191 +++++++++++++++++++++++++++++++++++++++ src/addr_decode_napot.sv | 9 +- src_files.yml | 5 +- 7 files changed, 308 insertions(+), 178 deletions(-) create mode 100644 src/addr_decode_dync.sv diff --git a/Bender.yml b/Bender.yml index 3b158942..1f93df61 100644 --- a/Bender.yml +++ b/Bender.yml @@ -8,6 +8,7 @@ package: - "Manuel Eggimann " - "Stefan Mach " - "Wolfgang Roenninger " + - "Thomas Benz " dependencies: common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.0 } @@ -20,91 +21,95 @@ sources: # Source files grouped in levels. Files in level 0 have no dependencies on files in this package. # Files in level 1 only depend on files in level 0, files in level 2 on files in levels 1 and 0, # etc. Files within a level are ordered alphabetically. + # Level 0 - src/binary_to_gray.sv + - target: not(all(xilinx,vivado_ipx)) files: - - src/cb_filter_pkg.sv - - src/cc_onehot.sv - - src/cf_math_pkg.sv - - src/clk_int_div.sv - - src/delta_counter.sv - - src/ecc_pkg.sv - - src/edge_propagator_tx.sv - - src/exp_backoff.sv - - src/fifo_v3.sv - - src/gray_to_binary.sv - - src/isochronous_4phase_handshake.sv - - src/isochronous_spill_register.sv - - src/lfsr.sv - - src/lfsr_16bit.sv - - src/lfsr_8bit.sv - - src/mv_filter.sv - - src/onehot_to_bin.sv - - src/plru_tree.sv - - src/popcount.sv - - src/rr_arb_tree.sv - - src/rstgen_bypass.sv - - src/serial_deglitch.sv - - src/shift_reg.sv - - src/shift_reg_gated.sv - - src/spill_register_flushable.sv - - src/stream_demux.sv - - src/stream_filter.sv - - src/stream_fork.sv - - src/stream_intf.sv - - src/stream_join_dynamic.sv - - src/stream_mux.sv - - src/stream_throttle.sv - - src/lossy_valid_to_stream.sv - - src/sub_per_hash.sv - - src/sync.sv - - src/sync_wedge.sv - - src/unread.sv - - src/read.sv - - src/cdc_reset_ctrlr_pkg.sv - # Level 1 - - src/clk_int_div_static.sv - - src/addr_decode_napot.sv - - src/cdc_2phase.sv - - src/cdc_4phase.sv - - src/addr_decode.sv - - src/multiaddr_decode.sv + - src/cb_filter_pkg.sv + - src/cc_onehot.sv + - src/cdc_reset_ctrlr_pkg.sv + - src/cf_math_pkg.sv + - src/clk_int_div.sv + - src/delta_counter.sv + - src/ecc_pkg.sv + - src/edge_propagator_tx.sv + - src/exp_backoff.sv + - src/fifo_v3.sv + - src/gray_to_binary.sv + - src/isochronous_4phase_handshake.sv + - src/isochronous_spill_register.sv + - src/lfsr.sv + - src/lfsr_16bit.sv + - src/lfsr_8bit.sv + - src/lossy_valid_to_stream.sv + - src/mv_filter.sv + - src/onehot_to_bin.sv + - src/plru_tree.sv + - src/popcount.sv + - src/rr_arb_tree.sv + - src/rstgen_bypass.sv + - src/serial_deglitch.sv + - src/shift_reg.sv + - src/shift_reg_gated.sv + - src/spill_register_flushable.sv + - src/stream_demux.sv + - src/stream_filter.sv + - src/stream_fork.sv + - src/stream_intf.sv + - src/stream_join_dynamic.sv + - src/stream_mux.sv + - src/stream_throttle.sv + - src/sub_per_hash.sv + - src/sync.sv + - src/sync_wedge.sv + - src/unread.sv + - src/read.sv + # Level 1 + - src/addr_decode_dync.sv + - src/cdc_2phase.sv + - src/cdc_4phase.sv + - src/clk_int_div_static.sv + # Level 2 + - src/addr_decode.sv + - src/addr_decode_napot.sv + - src/multiaddr_decode.sv - target: not(all(xilinx,vivado_ipx)) files: - - src/cb_filter.sv - - src/cdc_fifo_2phase.sv - - src/counter.sv - - src/ecc_decode.sv - - src/ecc_encode.sv - - src/edge_detect.sv - - src/lzc.sv - - src/max_counter.sv - - src/rstgen.sv - - src/spill_register.sv - - src/stream_delay.sv - - src/stream_fifo.sv - - src/stream_fork_dynamic.sv - - src/stream_join.sv - - src/clk_mux_glitch_free.sv - # Level 2 - - src/cdc_reset_ctrlr.sv - - src/cdc_fifo_gray.sv - - src/fall_through_register.sv - - src/id_queue.sv - - src/stream_to_mem.sv - - src/stream_arbiter_flushable.sv - - src/stream_fifo_optimal_wrap.sv - - src/stream_register.sv - - src/stream_xbar.sv - # Level 3 - - src/cdc_fifo_gray_clearable.sv - - src/cdc_2phase_clearable.sv - - src/mem_to_banks_detailed.sv - - src/stream_arbiter.sv - - src/stream_omega_net.sv - # Level 4 - - src/mem_to_banks.sv + - src/cb_filter.sv + - src/cdc_fifo_2phase.sv + - src/clk_mux_glitch_free.sv + - src/counter.sv + - src/ecc_decode.sv + - src/ecc_encode.sv + - src/edge_detect.sv + - src/lzc.sv + - src/max_counter.sv + - src/rstgen.sv + - src/spill_register.sv + - src/stream_delay.sv + - src/stream_fifo.sv + - src/stream_fork_dynamic.sv + - src/stream_join.sv + # Level 2 + - src/cdc_reset_ctrlr.sv + - src/cdc_fifo_gray.sv + - src/fall_through_register.sv + - src/id_queue.sv + - src/stream_to_mem.sv + - src/stream_arbiter_flushable.sv + - src/stream_fifo_optimal_wrap.sv + - src/stream_register.sv + - src/stream_xbar.sv + # Level 3 + - src/cdc_fifo_gray_clearable.sv + - src/cdc_2phase_clearable.sv + - src/mem_to_banks_detailed.sv + - src/stream_arbiter.sv + - src/stream_omega_net.sv + # Level 4 + - src/mem_to_banks.sv - target: simulation files: diff --git a/README.md b/README.md index 73e4ef8e..d22e2ca2 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Please note that cells with status *deprecated* are not to be used for new desig | Name | Description | Status | Superseded By | |----------------------------|-----------------------------------------------------------------------------------------------------------|--------------|---------------| | `addr_decode` | Address map decoder | active | | +| `addr_decode_dync` | Address map decoder extended to support dynamic online configuration | active | | | `addr_decode_napot` | Address map decoder using naturally-aligned power of two (NAPOT) regions | active | | | `multiaddr_decode` | Address map decoder using NAPOT regions and allowing for multiple address inputs | active | | | `ecc_decode` | SECDED Decoder (Single Error Correction, Double Error Detection) | active | | diff --git a/common_cells.core b/common_cells.core index 1868c428..3ba992db 100644 --- a/common_cells.core +++ b/common_cells.core @@ -10,6 +10,7 @@ filesets: # Source files grouped in levels. Files in level 0 have no dependencies on files in this package. # Files in level 1 only depend on files in level 0, files in level 2 on files in levels 1 and 0, # etc. Files within a level are ordered alphabetically. + # Level 0 - src/binary_to_gray.sv - src/cb_filter_pkg.sv - src/cc_onehot.sv @@ -50,10 +51,9 @@ filesets: - src/read.sv - src/cdc_reset_ctrlr_pkg.sv # Level 1 + - src/addr_decode_dync.sv - src/cdc_2phase.sv - src/cdc_4phase.sv - - src/addr_decode.sv - - src/addr_decode_napot.sv - src/cb_filter.sv - src/cdc_fifo_2phase.sv - src/counter.sv @@ -69,6 +69,8 @@ filesets: - src/stream_fork_dynamic.sv - src/clk_mux_glitch_free.sv # Level 2 + - src/addr_decode.sv + - src/addr_decode_napot.sv - src/cdc_reset_ctrlr.sv - src/cdc_fifo_gray.sv - src/fall_through_register.sv diff --git a/src/addr_decode.sv b/src/addr_decode.sv index e3a8eb2a..315dc2db 100644 --- a/src/addr_decode.sv +++ b/src/addr_decode.sv @@ -8,7 +8,9 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -// Author: Wolfgang Roenninger +// Authors: +// - Wolfgang Roenninger +// - Thomas Benz /// Address Decoder: Maps the input address combinatorially to an index. /// The address map `addr_map_i` is a packed array of rule_t structs. @@ -88,95 +90,22 @@ module addr_decode #( input idx_t default_idx_i ); - logic [NoRules-1:0] matched_rules; // purely for address map debugging + // wraps the dynamic configuration version of the address decoder + addr_decode_dync #( + .NoIndices ( NoIndices ), + .NoRules ( NoRules ), + .addr_t ( addr_t ), + .rule_t ( rule_t ), + .Napot ( Napot ) + ) i_addr_decode_dync ( + .addr_i, + .addr_map_i, + .idx_o, + .dec_valid_o, + .dec_error_o, + .en_default_idx_i, + .default_idx_i, + .config_ongoing_i ( 1'b0 ) + ); - always_comb begin - // default assignments - matched_rules = '0; - dec_valid_o = 1'b0; - dec_error_o = (en_default_idx_i) ? 1'b0 : 1'b1; - idx_o = (en_default_idx_i) ? default_idx_i : '0; - - // match the rules - for (int unsigned i = 0; i < NoRules; i++) begin - if ( - !Napot && (addr_i >= addr_map_i[i].start_addr) && - ((addr_i < addr_map_i[i].end_addr) || (addr_map_i[i].end_addr == '0)) || - Napot && (addr_map_i[i].start_addr & addr_map_i[i].end_addr) == - (addr_i & addr_map_i[i].end_addr) - ) begin - matched_rules[i] = 1'b1; - dec_valid_o = 1'b1; - dec_error_o = 1'b0; - idx_o = idx_t'(addr_map_i[i].idx); - end - end - end - - // Assumptions and assertions - `ifndef VERILATOR - `ifndef XSIM - // pragma translate_off - initial begin : proc_check_parameters - assume ($bits(addr_i) == $bits(addr_map_i[0].start_addr)) else - $warning($sformatf("Input address has %d bits and address map has %d bits.", - $bits(addr_i), $bits(addr_map_i[0].start_addr))); - assume (NoRules > 0) else - $fatal(1, $sformatf("At least one rule needed")); - assume (NoIndices > 0) else - $fatal(1, $sformatf("At least one index needed")); - end - - assert final ($onehot0(matched_rules)) else - $warning("More than one bit set in the one-hot signal, matched_rules"); - - // These following assumptions check the validity of the address map. - // The assumptions gets generated for each distinct pair of rules. - // Each assumption is present two times, as they rely on one rules being - // effectively ordered. Only one of the rules with the same function is - // active at a time for a given pair. - // check_start: Enforces a smaller start than end address. - // check_idx: Enforces a valid index in the rule. - // check_overlap: Warns if there are overlapping address regions. - always @(addr_map_i) #0 begin : proc_check_addr_map - if (!$isunknown(addr_map_i)) begin - for (int unsigned i = 0; i < NoRules; i++) begin - check_start : assume (Napot || addr_map_i[i].start_addr < addr_map_i[i].end_addr || - addr_map_i[i].end_addr == '0) else - $fatal(1, $sformatf("This rule has a higher start than end address!!!\n\ - Violating rule %d.\n\ - Rule> IDX: %h START: %h END: %h\n\ - #####################################################", - i ,addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr)); - // check the SLV ids - check_idx : assume (addr_map_i[i].idx < NoIndices) else - $fatal(1, $sformatf("This rule has a IDX that is not allowed!!!\n\ - Violating rule %d.\n\ - Rule> IDX: %h START: %h END: %h\n\ - Rule> MAX_IDX: %h\n\ - #####################################################", - i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr, - (NoIndices-1))); - for (int unsigned j = i + 1; j < NoRules; j++) begin - // overlap check - check_overlap : assume (Napot || - !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && - (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || - !((addr_map_i[i].end_addr == '0) && - (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || - !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && - (addr_map_i[j].end_addr == '0))) else - $warning($sformatf("Overlapping address region found!!!\n\ - Rule %d: IDX: %h START: %h END: %h\n\ - Rule %d: IDX: %h START: %h END: %h\n\ - #####################################################", - i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr, - j, addr_map_i[j].idx, addr_map_i[j].start_addr, addr_map_i[j].end_addr)); - end - end - end - end - // pragma translate_on - `endif - `endif endmodule diff --git a/src/addr_decode_dync.sv b/src/addr_decode_dync.sv new file mode 100644 index 00000000..79ba3235 --- /dev/null +++ b/src/addr_decode_dync.sv @@ -0,0 +1,191 @@ +// Copyright 2019 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. + +// Authors: +// - Wolfgang Roenninger +// - Paul Scheffler +// - Michael Rogenmoser +// - Thomas Benz + +/// Address Decoder: Maps the input address combinatorially to an index. +/// DYNamic Configuration (DYNC) version +/// The address map `addr_map_i` is a packed array of rule_t structs. +/// The ranges of any two rules may overlap. If so, the rule at the higher (more significant) +/// position in `addr_map_i` prevails. +/// +/// There can be an arbitrary number of address rules. There can be multiple +/// ranges defined for the same index. The start address has to be less than the end address. +/// +/// There is the possibility to add a default mapping: +/// `en_default_idx_i`: Driving this port to `1'b1` maps all input addresses +/// for which no rule in `addr_map_i` exists to the default index specified by +/// `default_idx_i`. In this case, `dec_error_o` is always `1'b0`. +/// +/// The `Napot` parameter allows using naturally-aligned power of two (NAPOT) regions, +/// using base addresses and masks instead of address ranges to specify rules. +/// +/// Assertions: The module checks every time there is a change in the address mapping +/// if the resulting map is valid. It fatals if `start_addr` is higher than `end_addr` (non-NAPOT +/// only) or if a mapping targets an index that is outside the number of allowed indices. +/// It issues warnings if the address regions of any two mappings overlap (non-NAPOT only). +module addr_decode_dync #( + /// Highest index which can happen in a rule. + parameter int unsigned NoIndices = 32'd0, + /// Total number of rules. + parameter int unsigned NoRules = 32'd0, + /// Address type inside the rules and to decode. + parameter type addr_t = logic, + /// Rule packed struct type. + /// The address decoder expects three fields in `rule_t`: + /// + /// typedef struct packed { + /// int unsigned idx; + /// addr_t start_addr; + /// addr_t end_addr; + /// } rule_t; + /// + /// - `idx`: index of the rule, has to be < `NoIndices` + /// - `start_addr`: start address of the range the rule describes, value is included in range + /// - `end_addr`: end address of the range the rule describes, value is NOT included in range + /// if `end_addr == '0` end of address space is assumed + /// + /// If `Napot` is 1, The field names remain the same, but the rule describes a naturally-aligned + /// power of two (NAPOT) region instead of an address range: `start_addr` becomes the base address + /// and `end_addr` the mask. See the wrapping module `addr_decode_napot` for details. + parameter type rule_t = logic, + // Whether this is a NAPOT (base and mask) or regular range decoder + parameter bit Napot = 0, + /// Dependent parameter, do **not** overwite! + /// + /// Width of the `idx_o` output port. + parameter int unsigned IdxWidth = cf_math_pkg::idx_width(NoIndices), + /// Dependent parameter, do **not** overwite! + /// + /// Type of the `idx_o` output port. + parameter type idx_t = logic [IdxWidth-1:0] +) ( + /// Address to decode. + input addr_t addr_i, + /// Address map: rule with the highest array position wins on collision + input rule_t [NoRules-1:0] addr_map_i, + /// Decoded index. + output idx_t idx_o, + /// Decode is valid. + output logic dec_valid_o, + /// Decode is not valid, no matching rule found. + output logic dec_error_o, + /// Enable default port mapping. + /// + /// When not used, tie to `0`. + input logic en_default_idx_i, + /// Default port index. + /// + /// When `en_default_idx_i` is `1`, this will be the index when no rule matches. + /// + /// When not used, tie to `0`. + input idx_t default_idx_i, + /// The module is dynamically configured, this deactivates its output and the integrated + /// assertions. + input logic config_ongoing_i +); + + logic [NoRules-1:0] matched_rules; // purely for address map debugging + + always_comb begin + // default assignments + matched_rules = '0; + dec_valid_o = 1'b0; + dec_error_o = (en_default_idx_i) ? 1'b0 : 1'b1; + idx_o = (en_default_idx_i) ? default_idx_i : '0; + + // match the rules + for (int unsigned i = 0; i < NoRules; i++) begin + if ( + !Napot && (addr_i >= addr_map_i[i].start_addr) && + ((addr_i < addr_map_i[i].end_addr) || (addr_map_i[i].end_addr == '0)) || + Napot && (addr_map_i[i].start_addr & addr_map_i[i].end_addr) == + (addr_i & addr_map_i[i].end_addr) + ) begin + matched_rules[i] = ~config_ongoing_i; + dec_valid_o = ~config_ongoing_i; + dec_error_o = 1'b0; + idx_o = config_ongoing_i ? default_idx_i : idx_t'(addr_map_i[i].idx); + end + end + end + + // Assumptions and assertions + `ifndef VERILATOR + `ifndef XSIM + // pragma translate_off + initial begin : proc_check_parameters + assume ($bits(addr_i) == $bits(addr_map_i[0].start_addr)) else + $warning($sformatf("Input address has %d bits and address map has %d bits.", + $bits(addr_i), $bits(addr_map_i[0].start_addr))); + assume (NoRules > 0) else + $fatal(1, $sformatf("At least one rule needed")); + assume (NoIndices > 0) else + $fatal(1, $sformatf("At least one index needed")); + end + + assert final ($onehot0(matched_rules) || config_ongoing_i) else + $warning("More than one bit set in the one-hot signal, matched_rules"); + + // These following assumptions check the validity of the address map. + // The assumptions gets generated for each distinct pair of rules. + // Each assumption is present two times, as they rely on one rules being + // effectively ordered. Only one of the rules with the same function is + // active at a time for a given pair. + // check_start: Enforces a smaller start than end address. + // check_idx: Enforces a valid index in the rule. + // check_overlap: Warns if there are overlapping address regions. + always @(addr_map_i or config_ongoing_i) #0 begin : proc_check_addr_map + if (!$isunknown(addr_map_i) && ~config_ongoing_i) begin + for (int unsigned i = 0; i < NoRules; i++) begin + check_start : assume (Napot || addr_map_i[i].start_addr < addr_map_i[i].end_addr || + addr_map_i[i].end_addr == '0) else + $fatal(1, $sformatf("This rule has a higher start than end address!!!\n\ + Violating rule %d.\n\ + Rule> IDX: %h START: %h END: %h\n\ + #####################################################", + i ,addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr)); + // check the SLV ids + check_idx : assume (addr_map_i[i].idx < NoIndices) else + $fatal(1, $sformatf("This rule has a IDX that is not allowed!!!\n\ + Violating rule %d.\n\ + Rule> IDX: %h START: %h END: %h\n\ + Rule> MAX_IDX: %h\n\ + #####################################################", + i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr, + (NoIndices-1))); + for (int unsigned j = i + 1; j < NoRules; j++) begin + // overlap check + check_overlap : assume (Napot || + !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && + (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || + !((addr_map_i[i].end_addr == '0) && + (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || + !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && + (addr_map_i[j].end_addr == '0))) else + $warning($sformatf("Overlapping address region found!!!\n\ + Rule %d: IDX: %h START: %h END: %h\n\ + Rule %d: IDX: %h START: %h END: %h\n\ + #####################################################", + i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr, + j, addr_map_i[j].idx, addr_map_i[j].start_addr, addr_map_i[j].end_addr)); + end + end + end + end + // pragma translate_on + `endif + `endif + +endmodule diff --git a/src/addr_decode_napot.sv b/src/addr_decode_napot.sv index 2b03af6d..eb09eb02 100644 --- a/src/addr_decode_napot.sv +++ b/src/addr_decode_napot.sv @@ -11,7 +11,7 @@ // Author: Florian Zaruba // Author: Paul Scheffler -/// This module wraps `addr_decode` in its naturally-aligned power of two (NAPOT) variant, +/// This module wraps `addr_decode_dync` in its naturally-aligned power of two (NAPOT) variant, /// alleviating the need to set the `Napot` parameter and using more descriptive `rule_t` /// field names. See the `addr_decode`documentation for details. module addr_decode_napot #( @@ -72,20 +72,21 @@ module addr_decode_napot #( addr_t end_addr; } rule_range_t; - addr_decode #( + addr_decode_dync #( .NoIndices ( NoIndices ) , .NoRules ( NoRules ), .addr_t ( addr_t ), .rule_t ( rule_range_t ), .Napot ( 1 ) - ) i_addr_decode ( + ) i_addr_decode_dync ( .addr_i, .addr_map_i, .idx_o, .dec_valid_o, .dec_error_o, .en_default_idx_i, - .default_idx_i + .default_idx_i, + .config_ongoing_i ( 1'b0 ) ); endmodule diff --git a/src_files.yml b/src_files.yml index 8f8eefb6..41b45410 100644 --- a/src_files.yml +++ b/src_files.yml @@ -48,10 +48,9 @@ common_cells_all: - src/read.sv - src/cdc_reset_ctrlr_pkg.sv # Level 1 + - src/addr_decode_dync.sv - src/cdc_2phase.sv - src/cdc_4phase.sv - - src/addr_decode.sv - - src/addr_decode_napot.sv - src/cb_filter.sv - src/cdc_fifo_2phase.sv - src/counter.sv @@ -67,6 +66,8 @@ common_cells_all: - src/stream_fork_dynamic.sv - src/clk_mux_glitch_free.sv # Level 2 + - src/addr_decode.sv + - src/addr_decode_napot.sv - src/cdc_reset_ctrlr.sv - src/cdc_fifo_gray.sv - src/fall_through_register.sv