cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
simu_udp_shell_if_env.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016 -- 2021 IBM Corporation
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 
48 
49 using namespace hls;
50 using namespace std;
51 
52 
55 extern unsigned int gSimCycCnt;
56 extern bool gTraceEvent;
57 extern bool gFatalError;
58 extern unsigned int gMaxSimCycles;
59 
60 //---------------------------------------------------------
61 // HELPERS FOR THE DEBUGGING TRACES
62 // .e.g: DEBUG_LEVEL = (MDL_TRACE | IPS_TRACE)
63 //---------------------------------------------------------
64 #define THIS_NAME "SIM"
65 
66 #define TRACE_OFF 0x0000
67 #define TRACE_UOE 1 << 1
68 #define TRACE_UAF 1 << 2
69 #define TRACE_MMIO 1 << 3
70 #define TRACE_ALL 0xFFFF
71 
72 #define DEBUG_LEVEL (TRACE_UOE)
73 
74 
77 void stepSim() {
78  gSimCycCnt++;
79  if (gTraceEvent || ((gSimCycCnt % 1000) == 0)) {
80  printInfo(THIS_NAME, "-- [@%4.4d] -----------------------------\n", gSimCycCnt);
81  gTraceEvent = false;
82  }
83  else if (0) {
84  printInfo(THIS_NAME, "------------------- [@%d] ------------\n", gSimCycCnt);
85  }
86 }
87 
88 
93 void increaseSimTime(unsigned int cycles) {
94  gMaxSimCycles += cycles;
95 }
96 
97 
111 void pUAF(
112  //-- USIF / Rx Data Interface
113  stream<UdpAppData> &siUSIF_Data,
114  stream<UdpAppMeta> &siUSIF_Meta,
115  //-- USIF / Tx Data Interface
116  stream<UdpAppData> &soUSIF_Data,
117  stream<UdpAppMeta> &soUSIF_Meta,
118  stream<UdpAppDLen> &soUSIF_DLen)
119 {
120 
121  const char *myRxName = concat3(THIS_NAME, "/", "UAF-Rx");
122  const char *myTxName = concat3(THIS_NAME, "/", "UAF-Tx");
123 
124  static enum RxFsmStates { RX_IDLE=0, RX_STREAM } uaf_rxFsmState=RX_IDLE;
125 
126  UdpAppData appData;
127  UdpAppMeta appMeta;
128 
129  switch (uaf_rxFsmState ) {
130  case RX_IDLE:
131  if (!siUSIF_Meta.empty() and !soUSIF_Meta.full()) {
132  siUSIF_Meta.read(appMeta);
133  // Swap IP_SA/IP_DA and update UPD_SP/UDP_DP
134  UdpAppMeta swappedMeta(appMeta.ip4DstAddr, DEFAULT_FPGA_SND_PORT,
136  soUSIF_Meta.write(swappedMeta);
137  soUSIF_DLen.write(0);
138  uaf_rxFsmState = RX_STREAM;
139  }
140  break;
141  case RX_STREAM:
142  if (!siUSIF_Data.empty() and !soUSIF_Data.full()) {
143  siUSIF_Data.read(appData);
144  if (DEBUG_LEVEL & TRACE_UAF) {
145  printAxisRaw(myRxName, "Received data: ", appData);
146  }
147  soUSIF_Data.write(appData);
148  if (appData.getTLast()) {
149  uaf_rxFsmState = RX_IDLE;
150  }
151  }
152  break;
153  }
154 }
155 
156 
163 void pMMIO(
164  //-- SHELL / Ready Signal
165  StsBit *piSHL_Ready,
166  //-- MMIO / Enable Layer-7 (.i.e APP alias ROLE)
167  CmdBit *poUSIF_Enable)
168 {
169  const char *myName = concat3(THIS_NAME, "/", "MMIO");
170 
171  static bool mmio_printOnce = true;
172 
173  if (*piSHL_Ready) {
174  *poUSIF_Enable = 1;
175  if (mmio_printOnce) {
176  printInfo(myName, "[SHELL/NTS/UOE] is ready -> Enabling operation of the UDP Shell Interface (USIF).\n");
177  mmio_printOnce = false;
178  }
179  }
180  else {
181  *poUSIF_Enable = 0;
182  }
183 }
184 
185 
206 void pUOE(
207  int &nrErr,
208  ofstream &dataGoldFile,
209  ofstream &dataFile,
210  ofstream &metaGoldFile,
211  ofstream &metaFile,
212  int echoDgrmLen,
213  SockAddr testSock,
214  int testDgrmLen,
215  //-- MMIO / Ready Signal
216  StsBit *poMMIO_Ready,
217  //-- UOE->USIF / UDP Rx Data Interfaces
218  stream<UdpAppData> &soUSIF_Data,
219  stream<UdpAppMeta> &soUSIF_Meta,
220  stream<UdpAppDLen> &soUSIF_DLen,
221  //-- USIF->UOE / UDP Tx Data Interfaces
222  stream<UdpAppData> &siUSIF_Data,
223  stream<UdpAppMeta> &siUSIF_Meta,
224  stream<UdpAppDLen> &siUSIF_DLen,
225  //-- USIF<->UOE / Listen Interfaces
226  stream<UdpPort> &siUSIF_LsnReq,
227  stream<StsBool> &soUSIF_LsnRep,
228  //-- USIF<->UOE / Close Interfaces
229  stream<UdpPort> &siUSIF_ClsReq)
230 {
231 
232  static enum LsnStates { LSN_WAIT_REQ, LSN_SEND_REP } uoe_lsnState = LSN_WAIT_REQ;
233  static enum RxpStates { RXP_SEND_META, RXP_SEND_DATA, \
234  RXP_SEND_8801, RXP_DONE } uoe_rxpState = RXP_SEND_META;
235  static enum TxpStates { TXP_WAIT_META, TXP_RECV_DATA } uoe_txpState = TXP_WAIT_META;
236 
237  static int uoe_startupDelay = cUoeInitCycles;
238  static int uoe_rxpStartupDelay = 50; // Wait until all the listen port are opened
239  static int uoe_txpStartupDelay = 0;
240  static bool uoe_isReady = false;
241  static bool uoe_rxpIsReady = false;
242  static bool uoe_txpIsReady = false;
243 
244  const char *myLsnName = concat3(THIS_NAME, "/", "UOE/Listen");
245  const char *myRxpName = concat3(THIS_NAME, "/", "UOE/RxPath");
246  const char *myTxpName = concat3(THIS_NAME, "/", "UOE/TxPath");
247 
248  //------------------------------------------------------
249  //-- FSM #0 - STARTUP DELAYS
250  //------------------------------------------------------
251  if (uoe_startupDelay) {
252  *poMMIO_Ready = 0;
253  uoe_startupDelay--;
254  }
255  else {
256  *poMMIO_Ready = 1;
257  if (uoe_rxpStartupDelay)
258  uoe_rxpStartupDelay--;
259  else
260  uoe_rxpIsReady = true;
261  if (uoe_txpStartupDelay)
262  uoe_txpStartupDelay--;
263  else
264  uoe_txpIsReady = true;
265  }
266 
267  //------------------------------------------------------
268  //-- FSM #1 - LISTENING
269  //------------------------------------------------------
270  static UdpPort uoe_lsnPortReq;
271  switch (uoe_lsnState) {
272  case LSN_WAIT_REQ: // CHECK IF A LISTENING REQUEST IS PENDING
273  if (!siUSIF_LsnReq.empty()) {
274  siUSIF_LsnReq.read(uoe_lsnPortReq);
275  printInfo(myLsnName, "Received a listen port request #%d from [USIF].\n",
276  uoe_lsnPortReq.to_int());
277  uoe_lsnState = LSN_SEND_REP;
278  }
279  break;
280  case LSN_SEND_REP: // SEND REPLY BACK TO [USIF]
281  if (!soUSIF_LsnRep.full()) {
282  soUSIF_LsnRep.write(OK);
283  uoe_lsnState = LSN_WAIT_REQ;
284  }
285  else {
286  printWarn(myLsnName, "Cannot send listen reply back to [USIF] because stream is full.\n");
287  }
288  break;
289  } // End-of: switch (uoe_lsnState) {
290 
291  //------------------------------------------------------
292  //-- FSM #2 - RX DATA PATH
293  //------------------------------------------------------
294  UdpAppData appData;
295  static UdpAppMeta uoe_rxMeta;
296  static int uoe_rxByteCnt;
297  static Ly4Len uoe_txByteCnt;
298  static int uoe_dgmCnt=0;
299  static int uoe_waitEndOfTxTest=0;
300  const int nrDgmToSend=7;
301  if (uoe_rxpIsReady) {
302  switch (uoe_rxpState) {
303  case RXP_SEND_META: // SEND METADATA TO [USIF]
304  if (!soUSIF_Meta.full() and !soUSIF_DLen.full()) {
305  if (uoe_waitEndOfTxTest) {
306  // Give USIF the time to finish sending all the requested bytes
307  uoe_waitEndOfTxTest--;
308  }
309  else if (uoe_dgmCnt == nrDgmToSend) {
310  uoe_rxpState = RXP_DONE;
311  }
312  else {
313  uoe_rxMeta.ip4SrcAddr = DEFAULT_HOST_IP4_ADDR;
314  uoe_rxMeta.udpSrcPort = DEFAULT_HOST_SND_PORT;
315  uoe_rxMeta.ip4DstAddr = DEFAULT_FPGA_IP4_ADDR;
316  switch (uoe_dgmCnt) {
317  case 1:
318  case 3:
319  uoe_rxMeta.udpDstPort = RECV_MODE_LSN_PORT;
320  uoe_rxByteCnt = echoDgrmLen;
321  gMaxSimCycles += (echoDgrmLen / 8);
322  uoe_waitEndOfTxTest = 0;
323  uoe_rxpState = RXP_SEND_DATA;
324  break;
325  case 2:
326  case 4:
327  uoe_rxMeta.udpDstPort = XMIT_MODE_LSN_PORT;
328  uoe_txByteCnt = testDgrmLen;
329  gMaxSimCycles += (testDgrmLen / 8);
330  uoe_waitEndOfTxTest = (testDgrmLen / 8) + 1;
331  uoe_rxpState = RXP_SEND_8801;
332  break;
333  default:
334  uoe_rxMeta.udpDstPort = ECHO_MODE_LSN_PORT;
335  uoe_rxByteCnt = echoDgrmLen;
336  gMaxSimCycles += (echoDgrmLen / 8);
337  uoe_waitEndOfTxTest = 0;
338  uoe_rxpState = RXP_SEND_DATA;
339  // Swap IP_SA/IP_DA and update UPD_SP/UDP_DP
340  SocketPair udpGldMeta(SockAddr(uoe_rxMeta.ip4DstAddr, DEFAULT_FPGA_SND_PORT),
342  // Dump this socket pair to a gold file
343  writeSocketPairToFile(udpGldMeta, metaGoldFile);
344  break;
345  }
346  soUSIF_Meta.write(uoe_rxMeta);
347  soUSIF_DLen.write(uoe_rxByteCnt);
348  if (DEBUG_LEVEL & TRACE_UOE) {
349  printInfo(myRxpName, "Sending metadata to [USIF].\n");
350  SocketPair udpRxMeta(SockAddr(uoe_rxMeta.ip4SrcAddr, uoe_rxMeta.udpSrcPort),
351  SockAddr(uoe_rxMeta.ip4DstAddr, uoe_rxMeta.udpDstPort));
352  printSockPair(myRxpName, udpRxMeta);
353  }
354  uoe_dgmCnt += 1;
355  }
356  }
357  break;
358  case RXP_SEND_DATA: // FORWARD DATA TO [USIF]
359  if (!soUSIF_Data.full()) {
360  appData.setTData((random() << 32) | random()) ;
361  if (uoe_rxByteCnt > 8) {
362  appData.setTKeep(0xFF);
363  appData.setTLast(0);
364  uoe_rxByteCnt -= 8;
365  }
366  else {
367  appData.setTKeep(lenTotKeep(uoe_rxByteCnt));
368  appData.setTLast(TLAST);
369  uoe_rxpState = RXP_SEND_META;
370  }
371  soUSIF_Data.write(appData);
372  if (DEBUG_LEVEL & TRACE_UOE) {
373  printAxisRaw(myRxpName, "Sending data chunk to [USIF]: ", appData);
374  }
375  if (uoe_rxMeta.udpDstPort != RECV_MODE_LSN_PORT) {
376  writeAxisRawToFile(appData, dataGoldFile);
377  }
378  }
379  break;
380  case RXP_SEND_8801: // FORWARD TX DATA LENGTH REQUEST TO [USIF]
381  if (!soUSIF_Data.full()) {
382  printInfo(myRxpName, "Requesting Tx test mode to generate a datagram of length=%d and to send it to socket: \n",
383  uoe_txByteCnt.to_uint());
384  printSockAddr(myRxpName, testSock);
385  appData.setLE_TData(byteSwap32(testSock.addr), 31, 0);
386  appData.setLE_TData(byteSwap16(testSock.port), 47, 32);
387  appData.setLE_TData(byteSwap16(uoe_txByteCnt), 63, 48);
388  appData.setLE_TKeep(0xFF);
389  appData.setLE_TLast(TLAST);
390  soUSIF_Data.write(appData);
391  if (DEBUG_LEVEL & TRACE_UOE) {
392  printAxisRaw(myRxpName, "Sending Tx data length request to [USIF]: ", appData);
393  }
394  //-- Update the Meta-Gold File
395  SocketPair udpGldMeta(SockAddr(DEFAULT_FPGA_IP4_ADDR, uoe_rxMeta.udpDstPort),
396  SockAddr(testSock.addr, testSock.port));
397  // Dump this socket pair to a gold file
398  writeSocketPairToFile(udpGldMeta, metaGoldFile);
399  //-- Update the Data-Gold File
400  bool firstChunk=true;
401  int txByteReq = uoe_txByteCnt;
402  while (txByteReq) {
403  UdpAppData goldChunk(0,0,0);
404  if (firstChunk) {
405  for (int i=0; i<8; i++) {
406  if (txByteReq) {
407  unsigned char byte = (GEN_CHK0 >> ((7-i)*8)) & 0xFF;
408  goldChunk.setLE_TData(byte, (i*8)+7, (i*8)+0);
409  goldChunk.setLE_TKeep(1, i, i);
410  txByteReq--;
411  }
412  }
413  firstChunk = !firstChunk;
414  }
415  else { // Second Chunk
416  for (int i=0; i<8; i++) {
417  if (txByteReq) {
418  unsigned char byte = (GEN_CHK1 >> ((7-i)*8)) & 0xFF;
419  goldChunk.setLE_TData(byte, (i*8)+7, (i*8)+0);
420  goldChunk.setLE_TKeep(1, i, i);
421  txByteReq--;
422  }
423  }
424  firstChunk = !firstChunk;
425  }
426  if (txByteReq == 0) {
427  goldChunk.setLE_TLast(TLAST);
428  }
429  writeAxisRawToFile(goldChunk, dataGoldFile);
430  }
431  uoe_rxpState = RXP_SEND_META;
432  }
433  break;
434  case RXP_DONE: // END OF THE RX PATH SEQUENCE
435  // ALL DATAGRAMS HAVE BEEN SENT
436  uoe_rxpState = RXP_DONE;
437  break;
438  } // End-of: switch())
439  }
440 
441  //------------------------------------------------------
442  //-- FSM #3 - TX DATA PATH
443  //-- (Always drain the data coming from [USIF])
444  //------------------------------------------------------
445  static UdpAppDLen uoe_appDLen;
446  if (uoe_txpIsReady) {
447  switch (uoe_txpState) {
448  case TXP_WAIT_META:
449  if (!siUSIF_Meta.empty() and !siUSIF_DLen.empty()) {
450  UdpAppMeta appMeta;
451  UdpAppDLen appDLen;
452  siUSIF_Meta.read(appMeta);
453  siUSIF_DLen.read(uoe_appDLen);
454  if (DEBUG_LEVEL & TRACE_UOE) {
455  if (uoe_appDLen == 0) {
456  printInfo(myTxpName, "This UDP Tx datagram is forwarded in streaming mode (DLen=0).\n");
457  }
458  else {
459  printInfo(myTxpName, "Receiving %d bytes of data from [USIF].\n", uoe_appDLen.to_int());
460  }
462  SockAddr(appMeta.ip4DstAddr, appMeta.udpDstPort)));
463  }
464  SocketPair appTxMeta(SockAddr(appMeta.ip4SrcAddr, appMeta.udpSrcPort),
465  SockAddr(appMeta.ip4DstAddr, appMeta.udpDstPort));
466  writeSocketPairToFile(appTxMeta, metaFile);
467  uoe_txpState = TXP_RECV_DATA;
468  }
469  break;
470  case TXP_RECV_DATA:
471  if (!siUSIF_Data.empty()) {
472  UdpAppData appData;
473  siUSIF_Data.read(appData);
474  writeAxisRawToFile(appData, dataFile);
475  if (uoe_appDLen != 0) {
476  uoe_appDLen -= appData.getLen();
477  }
478  if (DEBUG_LEVEL & TRACE_UOE) {
479  printAxisRaw(myTxpName, "Received data chunk from [USIF] ", appData);
480  }
481  if (appData.getTLast()) {
482  uoe_txpState = TXP_WAIT_META;
483  if (uoe_appDLen != 0) {
484  printWarn(myTxpName, "TLAST is set but DLen != 0.\n");
485  }
486  }
487  }
488  break;
489  }
490  }
491 }
492 
void setTLast(tLast last)
Definition: AxisRaw.hpp:246
tLast getTLast() const
Definition: AxisRaw.hpp:219
void setLE_TLast(LE_tLast last)
Definition: AxisRaw.hpp:280
void setLE_TData(LE_tData data, int leHi=64 -1, int leLo=0)
Definition: AxisRaw.hpp:272
void setTKeep(tKeep keep)
Definition: AxisRaw.hpp:239
int getLen() const
Definition: AxisRaw.hpp:411
void setTData(tData data)
Definition: AxisRaw.hpp:228
void setLE_TKeep(LE_tKeep keep, int leHi=64/8-1, int leLo=0)
Definition: AxisRaw.hpp:276
Ip4Addr addr
Definition: nts_types.hpp:209
Ly4Port port
Definition: nts_types.hpp:210
Ly4Port udpDstPort
Definition: nts.hpp:229
Ly4Port udpSrcPort
Definition: nts.hpp:227
Ip4Addr ip4SrcAddr
Definition: nts.hpp:226
Ip4Addr ip4DstAddr
Definition: nts.hpp:228
const char * myRxpName
Definition: tb_nal.cpp:837
#define DEFAULT_HOST_LSN_PORT
Definition: tb_nal.cpp:73
UdpLen UdpAppDLen
Definition: nal.hpp:255
const char * myTxpName
Definition: tb_nal.cpp:838
RxpStates
Definition: tb_nal.cpp:818
TxpStates
Definition: tb_nal.cpp:819
const char * myLsnName
Definition: tb_nal.cpp:835
#define DEFAULT_HOST_IP4_ADDR
Definition: tb_nal.cpp:72
LsnStates
Definition: tb_nal.cpp:816
RxFsmStates
Definition: tb_nal.cpp:681
ap_uint< 16 > UdpPort
Definition: nal.hpp:249
#define DEFAULT_FPGA_IP4_ADDR
Definition: tb_nal.cpp:70
@ RXP_SEND_DATA
Definition: tb_nal.cpp:818
@ RXP_SEND_META
Definition: tb_nal.cpp:818
@ RXP_DONE
Definition: tb_nal.cpp:818
@ TXP_RECV_DATA
Definition: tb_nal.cpp:819
@ LSN_WAIT_REQ
Definition: tb_nal.cpp:816
@ RX_STREAM
Definition: tb_nal.cpp:681
bool writeAxisRawToFile(AxisRaw &axisRaw, ofstream &outFileStream)
Dump an Axis raw data chunk to a file.
bool writeSocketPairToFile(SocketPair &socketPair, ofstream &outFileStream)
Dump a SocketPair to a file.
#define DEFAULT_FPGA_SND_PORT
#define DEFAULT_HOST_SND_PORT
ap_uint< 1 > StsBit
Definition: nts_types.hpp:116
void printAxisRaw(const char *callerName, AxisRaw chunk)
Prints an Axis raw data chunk (used for debugging).
Definition: nts_utils.cpp:46
ap_uint< 16 > Ly4Len
Definition: nts_types.hpp:202
void printSockAddr(const char *callerName, SockAddr sockAddr)
Print a socket address.
Definition: nts_utils.cpp:174
tKeep lenTotKeep(ap_uint< 4 > noValidBytes)
A function to set a number of '1' in an 8-bit field. It is used here to set the number of valid bytes...
Definition: nts_utils.cpp:328
#define printInfo(callerName, format,...)
A macro to print an information message.
Definition: nts_utils.hpp:169
#define OK
Definition: nts_types.hpp:57
ap_uint< 1 > CmdBit
Definition: nts_types.hpp:108
#define printWarn(callerName, format,...)
A macro to print a warning message.
Definition: nts_utils.hpp:182
#define concat3(firstCharConst, secondCharConst, thirdCharConst)
Definition: nts_utils.hpp:161
void printSockPair(const char *callerName, SocketPair sockPair)
Print a socket pair association.
Definition: nts_utils.cpp:114
#define TLAST
Definition: AxisRaw.hpp:116
#define GEN_CHK0
#define GEN_CHK1
#define RECV_MODE_LSN_PORT
#define XMIT_MODE_LSN_PORT
#define ECHO_MODE_LSN_PORT
#define TRACE_UAF
void stepSim()
Increment the simulation counter.
void pUAF(stream< UdpAppData > &siUSIF_Data, stream< UdpAppMeta > &siUSIF_Meta, stream< UdpAppData > &soUSIF_Data, stream< UdpAppMeta > &soUSIF_Meta, stream< UdpAppDLen > &soUSIF_DLen)
Emulate the behavior of the ROLE/UdpAppFlash (UAF).
unsigned int gMaxSimCycles
Definition: test_arp.hpp:69
unsigned int gSimCycCnt
Definition: tb_nal.cpp:150
const int cUoeInitCycles
bool gTraceEvent
Definition: tb_nal.cpp:151
#define THIS_NAME
void increaseSimTime(unsigned int cycles)
Increase the simulation time of the testbench.
void pMMIO(StsBit *piSHL_Ready, CmdBit *poUSIF_Enable)
Emulate the behavior of the SHELL & MMIO.
bool gFatalError
Definition: tb_nal.cpp:152
#define DEBUG_LEVEL
#define TRACE_UOE
void pUOE(int &nrErr, ofstream &dataGoldFile, ofstream &dataFile, ofstream &metaGoldFile, ofstream &metaFile, int echoDgrmLen, SockAddr testSock, int testDgrmLen, StsBit *poMMIO_Ready, stream< UdpAppData > &soUSIF_Data, stream< UdpAppMeta > &soUSIF_Meta, stream< UdpAppDLen > &soUSIF_DLen, stream< UdpAppData > &siUSIF_Data, stream< UdpAppMeta > &siUSIF_Meta, stream< UdpAppDLen > &siUSIF_DLen, stream< UdpPort > &siUSIF_LsnReq, stream< StsBool > &soUSIF_LsnRep, stream< UdpPort > &siUSIF_ClsReq)
Emulate behavior of the SHELL/NTS/UDP Offload Engine (UOE).
: Simulation environment for the UDP Shell Interface (USIF).
ap_uint< 32 > byteSwap32(ap_uint< 32 > inputVector)
Definition: udp.cpp:78
ap_uint< 16 > byteSwap16(ap_uint< 16 > inputVector)
Definition: udp.cpp:82