MatchLib
All Classes Namespaces Files Functions Modules Pages
AxiSplitter.h
1/*
2 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef __AXI_SPLITTER_H__
17#define __AXI_SPLITTER_H__
18
19#include <systemc.h>
20#include <nvhls_connections.h>
21#include <nvhls_serdes.h>
22#include <nvhls_packet.h>
23#include <nvhls_int.h>
24#include <nvhls_array.h>
25#include <axi/axi4.h>
26#include "Arbiter.h"
27#include "TypeToBits.h"
28
61template <typename axiCfg, int numSubordinates, int numAddrBitsToInspect = axiCfg::addrWidth, bool default_output = false, bool translate_addr = false>
62class AxiSplitter : public sc_module {
63 public:
64 static const int kDebugLevel = 5;
65 sc_in<bool> clk;
66 sc_in<bool> reset_bar;
67
68 typedef typename axi::axi4<axiCfg> axi4_;
69
70 typedef typename axi4_::read::template manager<>::ARPort axi_rd_manager_ar;
71 typedef typename axi4_::read::template manager<>::RPort axi_rd_manager_r;
72 typedef typename axi4_::write::template manager<>::AWPort axi_wr_manager_aw;
73 typedef typename axi4_::write::template manager<>::WPort axi_wr_manager_w;
74 typedef typename axi4_::write::template manager<>::BPort axi_wr_manager_b;
75
76 static const unsigned int log_numSubordinates = nvhls::log2_ceil<numSubordinates>::val + 1;
77
78 // [ben] Unfortunately HLS cannot handle an nv_array of the manager/subordinate wrapper classes.
79 // It will work fine in C but die mysteriously in Catapult 10.1b when methods of the
80 // bundled connections are accessed.
86 typename axi4_::read::template subordinate<> axi_rd_m;
87 typename axi4_::write::template subordinate<> axi_wr_m;
88
89 sc_in<NVUINTW(numAddrBitsToInspect)> addrBound[numSubordinates][2];
90
91 SC_HAS_PROCESS(AxiSplitter);
92
93 AxiSplitter(sc_module_name name)
94 : sc_module(name),
95 clk("clk"),
96 reset_bar("reset_bar"),
97 axi_rd_s_ar("axi_rd_s_ar"),
98 axi_rd_s_r("axi_rd_s_r"),
99 axi_wr_s_aw("axi_wr_s_aw"),
100 axi_wr_s_w("axi_wr_s_w"),
101 axi_wr_s_b("axi_wr_s_b"),
102 axi_rd_m("axi_rd_m"),
103 axi_wr_m("axi_wr_m")
104 {
105
106 SC_THREAD(run_r);
107 sensitive << clk.pos();
108 async_reset_signal_is(reset_bar, false);
109
110 SC_THREAD(run_w);
111 sensitive << clk.pos();
112 async_reset_signal_is(reset_bar, false);
113 }
114
115 // As an optimization, responses with different IDs could be allowed
116 // through, since it is safe to return them out of order.
117
118 void run_r() {
119#pragma hls_unroll yes
120 for (int i=0; i<numSubordinates; i++) {
121 axi_rd_s_ar[i].Reset();
122 axi_rd_s_r[i].Reset();
123 }
124 axi_rd_m.ar.Reset();
125 axi_rd_m.r.Reset();
126
127 typename axi4_::AddrPayload AR_reg;
128 typename axi4_::ReadPayload R_reg;
129
130 bool read_inFlight = 0;
131 NVUINTW(log_numSubordinates) pushedTo = numSubordinates;
132
133 #pragma hls_pipeline_init_interval 1
134 #pragma pipeline_stall_mode flush
135 while (1) {
136 wait();
137
138 switch (read_inFlight) {
139 case false:
140 if (axi_rd_m.ar.PopNB(AR_reg)) {
141 NVUINTW(numAddrBitsToInspect)
142 addr(static_cast<sc_uint<numAddrBitsToInspect> >(AR_reg.addr)); // Cast larger to smaller
143 pushedTo = numSubordinates;
144 // TODO - refactor this so it can be unrolled
145 for (int i=0; i<numSubordinates; i++) {
146 if (addr >= addrBound[i][0].read() && addr <= addrBound[i][1].read() && pushedTo == numSubordinates) {
147 pushedTo = i;
148 }
149 }
150 if (default_output && pushedTo == numSubordinates) {
151 pushedTo = numSubordinates-1;
152 }
153 // If the address did not fall in any valid range, that's bad
154 NVHLS_ASSERT_MSG(pushedTo != numSubordinates, "Read address did not fall into any output address range, and default output is not set");
155
156 if (translate_addr)
157 AR_reg.addr -= addrBound[pushedTo][0].read();
158
159 axi_rd_s_ar[pushedTo].Push(AR_reg);
160 read_inFlight = 1;
161 }
162 break;
163 case true:
164 if (axi_rd_s_r[pushedTo].PopNB(R_reg)) {
165 axi_rd_m.r.Push(R_reg);
166 if (R_reg.last == 1) read_inFlight = 0;
167 }
168 break;
169 }
170 }
171 }
172
173 void run_w() {
174#pragma hls_unroll yes
175 for (int i=0; i<numSubordinates; i++) {
176 axi_wr_s_aw[i].Reset();
177 axi_wr_s_w[i].Reset();
178 axi_wr_s_b[i].Reset();
179 }
180 axi_wr_m.aw.Reset();
181 axi_wr_m.w.Reset();
182 axi_wr_m.b.Reset();
183
184 typename axi4_::AddrPayload AW_reg;
185 typename axi4_::WritePayload W_reg;
186 typename axi4_::WRespPayload B_reg;
187
188 NVUINTW(log_numSubordinates) pushedTo = numSubordinates;
189 enum {
190 IDLE = 0,
191 WRITE_INFLIGHT = 1,
192 RESP_INFLIGHT = 2,
193 };
194 NVUINT2 s = IDLE;
195
196 #pragma hls_pipeline_init_interval 1
197 #pragma pipeline_stall_mode flush
198 while (1) {
199 wait();
200
201 switch (s) {
202 case IDLE:
203 if (axi_wr_m.aw.PopNB(AW_reg)) {
204 NVUINTW(numAddrBitsToInspect)
205 addr(static_cast<sc_uint<numAddrBitsToInspect> >(AW_reg.addr)); // Cast larger to smaller
206 pushedTo = numSubordinates;
207 // TODO - refactor this so it can be unrolled
208 for (int i=0; i<numSubordinates; i++) {
209 if (addr >= addrBound[i][0].read() && addr <= addrBound[i][1].read() && pushedTo == numSubordinates) {
210 pushedTo = i;
211 }
212 }
213 if (default_output && pushedTo == numSubordinates) {
214 pushedTo = numSubordinates-1;
215 }
216 NVHLS_ASSERT_MSG(pushedTo != numSubordinates, "Write address did not fall into any output address range, and default output is not set");
217 if (translate_addr)
218 AW_reg.addr -= addrBound[pushedTo][0].read();
219
220 axi_wr_s_aw[pushedTo].Push(AW_reg);
221 s = WRITE_INFLIGHT;
222 }
223 break;
224 case WRITE_INFLIGHT:
225 NVHLS_ASSERT_MSG(pushedTo != numSubordinates, "Write address did not fall into any output address range, and default output is not set");
226 if (axi_wr_m.w.PopNB(W_reg)) {
227 axi_wr_s_w[pushedTo].Push(W_reg);
228 if (W_reg.last == 1) {
229 if (axiCfg::useWriteResponses) {
230 s = RESP_INFLIGHT;
231 } else {
232 s = IDLE;
233 }
234 }
235 }
236 break;
237 case RESP_INFLIGHT:
238 if (axiCfg::useWriteResponses) {
239 if (axi_wr_s_b[pushedTo].PopNB(B_reg)) {
240 axi_wr_m.b.Push(B_reg);
241 s = IDLE;
242 }
243 }
244 else {
245 NVHLS_ASSERT_MSG(0, "Should never reach this state if write responses are disabled");
246 }
247 break;
248 }
249 }
250 }
251};
252
253#endif
An n-way splitter that connects a single AXI manager port to a multiple AXI subordinate ports.
Definition AxiSplitter.h:62
The base axi4 class parameterized according a valid config.
Definition axi4.h:64
An implementation of array that declares VectorLength variables for array of size VectorLength.
#define NVHLS_ASSERT_MSG(X, MSG)
#define NVUINTW(width)
Definition nvhls_types.h:35
A struct composed of the signals associated with AXI read and write requests.
Definition axi4.h:114
A struct composed of the signals associated with an AXI read response.
Definition axi4.h:157
A struct composed of the signals associated with an AXI write response.
Definition axi4.h:190
A struct composed of the signals associated with AXI write data.
Definition axi4.h:215
Compute Celing of log2 of a constant.
Definition nvhls_int.h:174