|
| 1 | +// SPDX-License-Identifier: Apache-2.0 |
| 2 | +// |
| 3 | +// Bedrock-RTL Address-Decoding APB Demux |
| 4 | +// |
| 5 | +// Routes APB transfers to the correct downstream interface based on PADDR. |
| 6 | +// Address ranges, optional masking, normalization, and default routing use the |
| 7 | +// protocol-neutral br_demux_addr_decode helper. APB fanout, timing, and |
| 8 | +// response handling use br_apb_demux_select_onehot. |
| 9 | + |
| 10 | +`include "br_asserts_internal.svh" |
| 11 | +`include "br_unused.svh" |
| 12 | + |
| 13 | +module br_apb_demux #( |
| 14 | + parameter int AddrWidth = 12, // Must be at least 12 |
| 15 | + parameter int NumDownstreams = 1, // Must be at least 1 |
| 16 | + // ri lint_check_waive ARRAY_LENGTH_ONE |
| 17 | + parameter int NumRetimeStages[NumDownstreams] = '{default: 0}, |
| 18 | + // When set, the final downstream receives every address that misses the |
| 19 | + // explicit ranges. Otherwise, misses complete with PSLVERR. |
| 20 | + parameter bit HasDefaultDownstream = 0, |
| 21 | + localparam int NumAddressRanges = HasDefaultDownstream ? NumDownstreams - 1 : NumDownstreams, |
| 22 | + // Require enabled ranges to be power-of-two sized and naturally aligned. |
| 23 | + // ri lint_check_waive ARRAY_LENGTH_ONE |
| 24 | + parameter bit RequirePowerOfTwoAlignedRanges[NumAddressRanges] = '{default: 1}, |
| 25 | + // Rebase each explicit downstream address before applying its output mask. |
| 26 | + // ri lint_check_waive ARRAY_LENGTH_ONE |
| 27 | + parameter bit NormalizeDownstreamAddress[NumAddressRanges] = '{default: 0}, |
| 28 | + // Mask used only for address decode; forwarded addresses remain unmasked. |
| 29 | + parameter logic [AddrWidth-1:0] UpstreamAddrMask = '1, |
| 30 | + // Mask applied to each forwarded address after optional normalization. |
| 31 | + parameter logic [NumDownstreams-1:0][AddrWidth-1:0] DownstreamAddrMask = '1 |
| 32 | +) ( |
| 33 | + input logic clk, |
| 34 | + input logic rst, |
| 35 | + |
| 36 | + input logic [AddrWidth-1:0] upstream_paddr, |
| 37 | + input logic upstream_psel, |
| 38 | + input logic upstream_penable, |
| 39 | + input logic [br_amba::ApbProtWidth-1:0] upstream_pprot, |
| 40 | + input logic [3:0] upstream_pstrb, |
| 41 | + input logic upstream_pwrite, |
| 42 | + // TODO(twabbott): Parameterize APB data/strobe widths once br_amba_apb_timing_slice supports it. |
| 43 | + input logic [31:0] upstream_pwdata, |
| 44 | + output logic [31:0] upstream_prdata, |
| 45 | + output logic upstream_pready, |
| 46 | + output logic upstream_pslverr, |
| 47 | + |
| 48 | + // Configurable ranges must remain stable while an APB transfer is pending. |
| 49 | + input logic [NumAddressRanges-1:0][AddrWidth-1:0] downstream_addr_base, |
| 50 | + input logic [NumAddressRanges-1:0][AddrWidth-1:0] downstream_addr_size, |
| 51 | + |
| 52 | + output logic [NumDownstreams-1:0][AddrWidth-1:0] downstream_paddr, |
| 53 | + output logic [NumDownstreams-1:0] downstream_psel, |
| 54 | + output logic [NumDownstreams-1:0] downstream_penable, |
| 55 | + output logic [NumDownstreams-1:0][br_amba::ApbProtWidth-1:0] downstream_pprot, |
| 56 | + output logic [NumDownstreams-1:0][3:0] downstream_pstrb, |
| 57 | + output logic [NumDownstreams-1:0] downstream_pwrite, |
| 58 | + output logic [NumDownstreams-1:0][31:0] downstream_pwdata, |
| 59 | + input logic [NumDownstreams-1:0][31:0] downstream_prdata, |
| 60 | + input logic [NumDownstreams-1:0] downstream_pready, |
| 61 | + input logic [NumDownstreams-1:0] downstream_pslverr |
| 62 | +); |
| 63 | + // Integration Checks |
| 64 | + |
| 65 | + logic upstream_request_pending; |
| 66 | + |
| 67 | + assign upstream_request_pending = upstream_psel && (!upstream_penable || !upstream_pready); |
| 68 | + |
| 69 | + `BR_ASSERT_STATIC(legal_num_downstreams_a, NumDownstreams >= 1 + HasDefaultDownstream) |
| 70 | + `BR_ASSERT_STATIC(legal_addr_width_a, AddrWidth >= 12) |
| 71 | + `BR_ASSERT_INTG(addr_map_stable_while_pending_a, upstream_request_pending |=> $stable |
| 72 | + ({downstream_addr_base, downstream_addr_size})) |
| 73 | + `BR_UNUSED(upstream_request_pending) |
| 74 | + |
| 75 | + // Implementation |
| 76 | + |
| 77 | + logic [NumDownstreams-1:0] select_onehot; |
| 78 | + logic [NumDownstreams-1:0][AddrWidth-1:0] downstream_paddr_unmasked; |
| 79 | + |
| 80 | + br_demux_addr_decode #( |
| 81 | + .AddrWidth(AddrWidth), |
| 82 | + .NumDownstreams(NumDownstreams), |
| 83 | + .HasDefaultDownstream(HasDefaultDownstream), |
| 84 | + .RequirePowerOfTwoAlignedRanges(RequirePowerOfTwoAlignedRanges), |
| 85 | + .NormalizeDownstreamAddress(NormalizeDownstreamAddress), |
| 86 | + .UpstreamAddrMask(UpstreamAddrMask), |
| 87 | + .DownstreamAddrMask(DownstreamAddrMask) |
| 88 | + ) br_demux_addr_decode ( |
| 89 | + .clk, |
| 90 | + .rst, |
| 91 | + .addr_valid(upstream_psel), |
| 92 | + .upstream_addr(upstream_paddr), |
| 93 | + .downstream_addr_base, |
| 94 | + .downstream_addr_size, |
| 95 | + .downstream_addr_in(downstream_paddr_unmasked), |
| 96 | + .select_onehot, |
| 97 | + .downstream_addr_out(downstream_paddr) |
| 98 | + ); |
| 99 | + |
| 100 | + br_apb_demux_select_onehot #( |
| 101 | + .AddrWidth(AddrWidth), |
| 102 | + .NumDownstreams(NumDownstreams), |
| 103 | + .EnableDecodeError(!HasDefaultDownstream), |
| 104 | + .NumRetimeStages(NumRetimeStages) |
| 105 | + ) br_apb_demux_select_onehot ( |
| 106 | + .clk, |
| 107 | + .rst, |
| 108 | + .select_onehot, |
| 109 | + .upstream_paddr, |
| 110 | + .upstream_psel, |
| 111 | + .upstream_penable, |
| 112 | + .upstream_pprot, |
| 113 | + .upstream_pstrb, |
| 114 | + .upstream_pwrite, |
| 115 | + .upstream_pwdata, |
| 116 | + .upstream_prdata, |
| 117 | + .upstream_pready, |
| 118 | + .upstream_pslverr, |
| 119 | + .downstream_paddr(downstream_paddr_unmasked), |
| 120 | + .downstream_psel, |
| 121 | + .downstream_penable, |
| 122 | + .downstream_pprot, |
| 123 | + .downstream_pstrb, |
| 124 | + .downstream_pwrite, |
| 125 | + .downstream_pwdata, |
| 126 | + .downstream_prdata, |
| 127 | + .downstream_pready, |
| 128 | + .downstream_pslverr |
| 129 | + ); |
| 130 | + |
| 131 | +endmodule : br_apb_demux |
0 commit comments