MatchLib
AxiSlaveToMem.h
1 /*
2  * Copyright (c) 2016-2020, 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 
17 #ifndef __AXISLAVETOMEM_H__
18 #define __AXISLAVETOMEM_H__
19 
20 #include <systemc.h>
21 #include <ac_reset_signal_is.h>
22 #include <hls_globals.h>
23 #include <axi/axi4.h>
24 #include <mem_array.h>
25 #include <fifo.h>
26 
56 template <typename axiCfg, int capacity, int fifoDepth = 8>
57 class AxiSlaveToMem : public sc_module {
58  private:
59  static const int capacity_in_bytes = capacity;
60  static const int banks = 1;
61 
62  typedef NVUINTW(axiCfg::dataWidth) Data;
64 
65  Memarray memarray;
66 
67  public:
68  static const int kDebugLevel = 1;
69 
70  typedef typename axi::axi4<axiCfg> axi4_;
71  static const int bytesPerWord = axiCfg::dataWidth >> 3;
72 
73  typename axi4_::read::template slave<> if_rd;
74  typename axi4_::write::template slave<> if_wr;
75 
76  sc_in<bool> reset_bar;
77  sc_in<bool> clk;
78 
83 
84  SC_CTOR(AxiSlaveToMem)
85  : if_rd("if_rd"), if_wr("if_wr"), reset_bar("reset_bar"), clk("clk") {
86  SC_THREAD(run);
87  sensitive << clk.pos();
88  async_reset_signal_is(reset_bar, false);
89  }
90 
91  protected:
92  void run() {
93  if_rd.reset();
94  if_wr.reset();
95 
96  rd_resp.reset();
97  rd_addr.reset();
98  wr_resp.reset();
99  wr_addr.reset();
100 
101  sc_uint<axi4_::ALEN_WIDTH> rd_beat_cnt = 0;
102  sc_uint<axi4_::ALEN_WIDTH> wr_beat_cnt = 0;
103 
104  #pragma hls_pipeline_init_interval 2
105  #pragma pipeline_stall_mode flush
106  while (1) {
107  wait();
108 
109  bool rd_resp_full = rd_resp.isFull();
110 
111  if (!rd_resp.isEmpty()) {
112  typename axi4_::ReadPayload data_pld;
113  data_pld = rd_resp.peek();
114  if (if_rd.nb_rwrite(data_pld)) {
115  rd_resp.incrHead();
116  }
117  }
118 
119  if (!rd_resp_full && !rd_addr.isEmpty()) {
120  typename axi4_::AddrPayload rd_addr_pld;
121  rd_addr_pld = rd_addr.peek();
122 
123  CDCOUT(sc_time_stamp() << " " << name() << " Received read request: "
124  << rd_addr_pld
125  << endl, kDebugLevel);
126 
127  typename axi4_::ReadPayload data_pld;
128  data_pld.data = memarray.read(rd_addr_pld.addr + bytesPerWord*rd_beat_cnt);
129  data_pld.resp = axi4_::Enc::XRESP::OKAY;
130  data_pld.id = rd_addr_pld.id;
131 
132  auto rd_beat_cnt_local = rd_beat_cnt;
133 
134  if (rd_beat_cnt_local == rd_addr_pld.len) {
135  rd_beat_cnt_local = 0;
136  rd_addr.incrHead();
137  data_pld.last = 1;
138  } else {
139  data_pld.last = 0;
140  ++rd_beat_cnt_local;
141  }
142 
143  rd_beat_cnt = rd_beat_cnt_local;
144  rd_resp.push(data_pld);
145  }
146 
147  if (!rd_addr.isFull()) {
148  typename axi4_::AddrPayload rd_addr_pld;
149  if (if_rd.nb_aread(rd_addr_pld)) {
150  rd_addr.push(rd_addr_pld);
151  }
152  }
153 
154  bool wr_resp_full = wr_resp.isFull();
155  bool wr_addr_full = wr_addr.isFull();
156 
157  if (!wr_resp.isEmpty()) {
158  typename axi4_::WRespPayload resp_pld;
159  resp_pld = wr_resp.peek();
160  if (if_wr.nb_bwrite(resp_pld)) {
161  wr_resp.incrHead();
162  }
163  }
164 
165  if (!wr_resp_full && !wr_addr.isEmpty()) {
166  typename axi4_::AddrPayload wr_addr_pld;
167  wr_addr_pld = wr_addr.peek();
168 
169  typename axi4_::WritePayload write_pld;
170 
171  if (if_wr.w.PopNB(write_pld)) {
172  auto wr_beat_cnt_local = wr_beat_cnt;
173  memarray.write(static_cast<typename Memarray::LocalIndex>(static_cast<sc_uint<axi4_::ADDR_WIDTH> >
174  (wr_addr_pld.addr) + bytesPerWord*wr_beat_cnt_local), 0, write_pld.data);
175  CDCOUT(sc_time_stamp() << " " << name() << " Received write request:"
176  << " addr=[" << wr_addr_pld << "]"
177  << " data=[" << write_pld << "]"
178  << " beat=" << dec << wr_beat_cnt_local
179  << endl, kDebugLevel);
180 
181  if (wr_beat_cnt_local == wr_addr_pld.len) {
182  wr_beat_cnt_local = 0;
183  NVHLS_ASSERT_MSG(write_pld.last == true, "WRLEN indicates that this should be the last beat, but WRLAST is not set");
184  wr_addr.incrHead();
185 
186  // push resp
187  typename axi4_::WRespPayload resp_pld;
188  resp_pld.resp = axi4_::Enc::XRESP::OKAY;
189  resp_pld.id = wr_addr_pld.id;
190  wr_resp.push(resp_pld);
191  } else {
192  NVHLS_ASSERT_MSG(write_pld.last == false, "WRLEN indicates that this should not be the last beat, but WRLAST is set");
193  ++wr_beat_cnt_local;
194  }
195 
196  wr_beat_cnt = wr_beat_cnt_local;
197  }
198  }
199 
200  if (!wr_addr_full) {
201  typename axi4_::AddrPayload wr_addr_pld;
202  if (if_wr.aw.PopNB(wr_addr_pld)) {
203  wr_addr.push(wr_addr_pld);
204  }
205  }
206  }
207  }
208 };
209 
210 #endif
A struct composed of the signals associated with an AXI write response.
Definition: axi4.h:236
A struct composed of the signals associated with AXI write data.
Definition: axi4.h:279
A struct composed of the signals associated with AXI read and write requests.
Definition: axi4.h:108
A struct composed of the signals associated with an AXI read response.
Definition: axi4.h:180
#define CDCOUT(x, y)
Definition: hls_globals.h:73
The base axi4 class parameterized according a valid config.
Definition: axi4.h:58
#define NVHLS_ASSERT_MSG(X, MSG)
Definition: nvhls_assert.h:116
An AXI slave SRAM.
Definition: AxiSlaveToMem.h:57
Configurable FIFO class.
Definition: fifo.h:65