diff --git a/Bender.yml b/Bender.yml index 97d36c1e..3b158942 100644 --- a/Bender.yml +++ b/Bender.yml @@ -69,6 +69,7 @@ sources: - src/cdc_2phase.sv - src/cdc_4phase.sv - src/addr_decode.sv + - src/multiaddr_decode.sv - target: not(all(xilinx,vivado_ipx)) files: - src/cb_filter.sv diff --git a/README.md b/README.md index 902396a1..73e4ef8e 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Please note that cells with status *deprecated* are not to be used for new desig |----------------------------|-----------------------------------------------------------------------------------------------------------|--------------|---------------| | `addr_decode` | Address map decoder | 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 | | | `ecc_encode` | SECDED Encoder (Single Error Correction, Double Error Detection) | active | | | `binary_to_gray` | Binary to gray code converter | active | | diff --git a/src/multiaddr_decode.sv b/src/multiaddr_decode.sv new file mode 100644 index 00000000..0cbcbb1d --- /dev/null +++ b/src/multiaddr_decode.sv @@ -0,0 +1,154 @@ +// 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. + +// Author: Luca Colagrande + +/// Multi-address Decoder: Combinational module which takes an address set +/// in {addr, mask} representation and returns a bit mask `select_o` indicating which +/// address map rules in `addr_map_i` it matches. +/// +/// An address set is a set of addresses. The {addr, mask} pair is one possible way of encoding +/// an address set. Asserted bits in the mask indicate that the corresponding bit in addr can +/// be treated as a "don't care", meaning it can assume any value (0 or 1) to produce a valid +/// address in the address set. +/// +/// The address map `addr_map_i` is a packed array of rule_t structs. Each rule is itself an +/// address set. +/// +/// For each rule the decoder checks if there is an address in the {`addr_i`, `mask_i`} address +/// set which belongs to the address set of the rule. If so, the corresponding bit in `select_o` +/// is set. +/// For each rule, it also returns the subset of addresses in {`addr_i`, `mask_i`} which +/// match the rule {`addr_o[i]`, `mask_o[i]`}. +module multiaddr_decode #( + /// 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 addr; + /// addr_t mask; + /// } rule_t; + /// + /// - `idx`: index of the rule, has to be < `NoIndices`. + /// - `addr`: any address in the address space described by the rule + /// - `mask`: a bitmask of the same length as the address which transforms the address + /// above in a multi-address encoding. A '1' in this mask indicates that the + /// corresponding bit in address can take any value and it will still be part + /// of this rule's address space. + /// + /// {addr, mask} is an alternative representation to the typical interval [start, end) + /// representation for a collection of addresses. With {addr, mask} we can represent contiguous + /// intervals of the form [start, end) so long that the latter satisfies the following properties: + /// - the length of the interval (end - start) is a power of 2 (i.e. 2^N for some integer N) + /// - the offset of the interval (start) is a multiple of the length + /// (i.e. M*2^N for some integer M) + /// When these properties are satisfied we can go from the [start, end) representation + /// to the {addr, mask} representation (and viceversa) using the following equations: + /// - mask = {'0, {log2(end - start){1'b1}}} + /// - addr = start + parameter type rule_t = logic +) ( + /// Multi-address to decode. + input addr_t addr_i, + input addr_t mask_i, + /// Address map. + input rule_t [NoRules-1:0] addr_map_i, + /// Decoded indices. + output logic [NoIndices-1:0] select_o, + /// Decoded multi-address. + output addr_t [NoIndices-1:0] addr_o, + output addr_t [NoIndices-1:0] mask_o, + /// Decode is valid. + output logic dec_valid_o, + /// Decode is not valid, no matching rule found. + output logic dec_error_o +); + + 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 = 1'b1; + select_o = '0; + addr_o = '0; + mask_o = '0; + + // Match the rules + for (int unsigned i = 0; i < NoRules; i++) begin + automatic int unsigned idx = addr_map_i[i].idx; + // We have a match if at least one address of the input + // address set is a part of the rule's address set. + // We have this condition when all bits in the input address match + // all bits in `addr_map_i[i].addr`, with possible exception + // of those bits which are either masked in the input address + // or in the addrmap rule. In other words, any bit which is masked + // either in the input address or in the addrmap rule is treated as a don't care + automatic addr_t dont_care = mask_i | addr_map_i[i].mask; + automatic addr_t matching_bits = ~(addr_i ^ addr_map_i[i].addr); + automatic logic match = &(dont_care | matching_bits); + if (match) begin + matched_rules[i] = 1'b1; + dec_valid_o = 1'b1; + dec_error_o = 1'b0; + select_o[idx] |= 1'b1; + // When there is a partial match, i.e. only a subset of the input address set + // falls in the address set of the rule, we want to return this subset + // {addr_o, mask_o}. + // Bits which are masked in the input address but not in the addrmap rule + // are resolved to the value in the addrmap, and are thus unmasked in the + // output address set. All other bits remain masked or unchanged. + mask_o[idx] = mask_i & addr_map_i[i].mask; + addr_o[idx] = (~mask_i & addr_i) | (mask_i & addr_map_i[i].addr); + end + end + end + + // Assumptions and assertions + `ifndef VERILATOR + `ifndef XSIM + // pragma translate_off + initial begin : proc_check_parameters + assume (NoRules > 0) else + $fatal(1, $sformatf("At least one rule needed")); + assume ($bits(addr_i) == $bits(addr_map_i[0].addr)) else + $warning($sformatf("Input address has %d bits and address map has %d bits.", + $bits(addr_i), $bits(addr_map_i[0].addr))); + end + + // These following assumptions check the validity of the address map. + // check_idx: Enforces a valid index in the rule. + 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 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\n\ + Rule> MAX_IDX: %h\n\ + #####################################################", + i, addr_map_i[i].idx, (NoIndices-1))); + end + end + end + + // pragma translate_on + `endif + `endif +endmodule diff --git a/src_files.yml b/src_files.yml index b3741b61..8f8eefb6 100644 --- a/src_files.yml +++ b/src_files.yml @@ -22,6 +22,7 @@ common_cells_all: - src/lfsr.sv - src/lfsr_16bit.sv - src/lfsr_8bit.sv + - src/multiaddr_decode.sv - src/mv_filter.sv - src/onehot_to_bin.sv - src/plru_tree.sv