cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
simu_tcp_app_flash_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 
44 
45 using namespace hls;
46 using namespace std;
47 
48 
51 extern unsigned int gSimCycCnt;
52 extern bool gTraceEvent;
53 extern bool gFatalError;
54 extern unsigned int gMaxSimCycles; // = MAX_SIM_CYCLES + TB_GRACE_TIME;
55 
56 
60 #define THIS_NAME "SIM"
61 
62 #define TRACE_OFF 0x0000
63 #define TRACE_TSs 1 << 1
64 #define TRACE_TSr 1 << 2
65 #define TRACE_TAF 1 << 3
66 #define TRACE_MMIO 1 << 4
67 #define TRACE_ALL 0xFFFF
68 #define DEBUG_LEVEL (TRACE_OFF)
69 
70 
73 void stepSim() {
74  gSimCycCnt++;
75  if (gTraceEvent || ((gSimCycCnt % 1000) == 0)) {
76  printInfo(THIS_NAME, "-- [@%4.4d] -----------------------------\n", gSimCycCnt);
77  gTraceEvent = false;
78  }
79  else if (0) {
80  printInfo(THIS_NAME, "------------------- [@%d] ------------\n", gSimCycCnt);
81  }
82 }
83 
84 
89 void increaseSimTime(unsigned int cycles) {
90  gMaxSimCycles += cycles;
91 }
92 
93 
107  int &nrErr,
108  stream<TcpAppData> &siTAF_Data,
109  stream<TcpSessId> &siTAF_SessId,
110  stream<TcpDatLen> &siTAF_DatLen,
111  ofstream &rawFileStream,
112  ofstream &tcpFileStream,
113  int &nrSegments)
114 {
115  const char *myName = concat3(THIS_NAME, "/", "TSr");
116 
117  static int tsr_startOfSegCount = 0;
118 
119  TcpAppData currChunk;
120  TcpSessId tcpSessId;
121  TcpDatLen tcpDatLen;
122 
123  // Read and drain the metadata
124  if (!siTAF_SessId.empty() and !siTAF_DatLen.empty()) {
125  siTAF_SessId.read(tcpSessId);
126  siTAF_DatLen.read(tcpDatLen);
127  tsr_startOfSegCount++;
128  if (tsr_startOfSegCount > 1) {
129  printWarn(myName, "Metadata and data streams did not arrive in expected order!\n");
130  }
131  if (DEBUG_LEVEL & TRACE_TSr) {
132  printInfo(myName, "Received SessId=%d and DatLen=%d\n",
133  tcpSessId.to_uint(), tcpDatLen.to_uint());
134  }
135  }
136  // Read and drain data stream
137  if (!siTAF_Data.empty()) {
138  siTAF_Data.read(currChunk);
139  if (DEBUG_LEVEL & TRACE_TSr) { printAxisRaw(myName, "siTAF_Data=", currChunk); }
140  if (currChunk.getTLast()) {
141  tsr_startOfSegCount--;
142  nrSegments++;
143  }
144  //-- Write data to file
145  if (!writeAxisRawToFile(currChunk, rawFileStream) or \
146  !writeAxisAppToFile(currChunk, tcpFileStream)) {
147  return KO;
148  }
149  }
150  return OK;
151 }
152 
153 
167  int &nrError,
168  stream<TcpAppData> &soTAF_Data,
169  stream<TcpSessId> &soTAF_SessId,
170  stream<TcpDatLen> &soTAF_DatLen,
171  ifstream &inpFileStream,
172  ofstream &outGoldStream,
173  int &nrSegments)
174 {
175  const char *myName = concat3(THIS_NAME, "/", "TSs");
176 
177  //-- STATIC VARIABLES ------------------------------------------------------
178  static bool tss_startOfTcpSeg = true;
179  static bool tss_idlingReq = false; // Request to idle (i.e., do not feed TAF's input stream)
180  static unsigned int tss_idleCycReq = 0; // The requested number of idle cycles
181  static unsigned int tss_idleCycCnt = 0; // The count of idle cycles
182  static SimAppData tss_simAppData;
183  static TcpSessId tss_tcpSessId = DEFAULT_SESS_ID;
184 
185  //-- DYNAMIC VARIABLES -----------------------------------------------------
186  string strLine;
187  vector<string> stringVector;
188  TcpAppData currChunk;
189  char *pEnd;
190 
191  //-----------------------------------------------------
192  //-- RETURN IF IDLING IS REQUESTED
193  //-----------------------------------------------------
194  if (tss_idlingReq == true) {
195  if (tss_idleCycCnt >= tss_idleCycReq) {
196  tss_idleCycCnt = 0;
197  tss_idlingReq = false;
198  if (DEBUG_LEVEL & TRACE_TSs) {
199  printInfo(myName, "End of Tx idling phase. \n");
200  }
201  }
202  else {
203  tss_idleCycCnt++;
204  }
205  return true;
206  }
207 
208  //------------------------------------------------------
209  //-- FEED DATA STREAM
210  //------------------------------------------------------
211  if (tss_simAppData.size() != 0) {
212  if (!soTAF_Data.full()) {
213  //-- Feed TAF with a new data chunk
214  AxisApp appChunk = tss_simAppData.pullChunk();
215  soTAF_Data.write(appChunk);
216  if (DEBUG_LEVEL & TRACE_TSs) { printAxisRaw(myName, "soTAF_Data=", appChunk); }
217  increaseSimTime(1);
218  }
219  }
220  else {
221  //------------------------------------------------------
222  //-- BUILD a new DATA STREAM from FILE
223  //------------------------------------------------------
224  while (!inpFileStream.eof()) {
225  //-- Read a line from input vector file -----------
226  getline(inpFileStream, strLine);
227  if (DEBUG_LEVEL & TRACE_TSs) { printf("%s \n", strLine.c_str()); fflush(stdout); }
228  stringVector = myTokenizer(strLine, ' ');
229  if (!strLine.empty()) {
230  //-- Build a new tss_simAppData from file
231  if (stringVector[0].length() == 1) {
232  //------------------------------------------------------
233  //-- Process the command and comment lines
234  //-- FYI: A command or a comment start with a single
235  //-- character followed by a space character.
236  //------------------------------------------------------
237  if (stringVector[0] == "#") {
238  // This is a comment line.
239  continue;
240  }
241  else if (stringVector[0] == ">") {
242  // The test vector is issuing a command
243  // FYI, don't forget to return at the end of command execution.
244  if (stringVector[1] == "IDLE") {
245  // COMMAND = Request to idle for <NUM> cycles.
246  tss_idleCycReq = strtol(stringVector[2].c_str(), &pEnd, 10);
247  tss_idlingReq = true;
248  if (DEBUG_LEVEL & TRACE_TSs) {
249  printInfo(myName, "Request to idle for %d cycles. \n", tss_idleCycReq);
250  }
251  increaseSimTime(tss_idleCycReq);
252  return true;
253  }
254  if (stringVector[1] == "SET") {
255  printWarn(myName, "The 'SET' command is not yet implemented...");
256  }
257  }
258  else {
259  printFatal(myName, "Read unknown command \"%s\" from TSIF.\n", stringVector[0].c_str());
260  }
261  }
262  else {
263  AxisApp currChunk;
264  bool firstChunkFlag = true; // Axis chunk is first data chunk
265  int writtenBytes = 0;
266  do {
267  if (firstChunkFlag == false) {
268  getline(inpFileStream, strLine);
269  if (DEBUG_LEVEL & TRACE_TSs) { printf("%s \n", strLine.c_str()); fflush(stdout); }
270  stringVector = myTokenizer(strLine, ' ');
271  // Skip lines that might be commented out
272  if (stringVector[0] == "#") {
273  // This is a comment line.
274  if (DEBUG_LEVEL & TRACE_TSs) { printf("%s ", strLine.c_str()); fflush(stdout); }
275  continue;
276  }
277  }
278  firstChunkFlag = false;
279  bool rc = readAxisRawFromLine(currChunk, strLine);
280  if (rc) {
281  tss_simAppData.pushChunk(currChunk);
282  }
283  // Write current chunk to the gold file
284  rc = writeAxisRawToFile(currChunk, outGoldStream);
285  if (currChunk.getTLast()) {
286  // Send metadata to [TAF]
287  soTAF_SessId.write(TcpSessId(tss_tcpSessId));
288  soTAF_DatLen.write(TcpDatLen(tss_simAppData.length()));
289  tss_tcpSessId++;
290  return OK;
291  }
292  } while (not currChunk.getTLast());
293  }
294  }
295  }
296  }
297  return OK;
298 }
299 
300 
313 void pTSIF(
314  int &nrErr,
315  //-- MMIO/ Configuration Interfaces
316  #if defined TAF_USE_NON_FIFO_IO
317  ap_uint<2> poTAF_EchoCtrl,
318  #endif
319  //-- TAF / TCP Data Interfaces
320  stream<TcpAppData> &soTAF_Data,
321  stream<TcpSessId> &soTAF_SessId,
322  stream<TcpDatLen> &soTAF_DatLen,
323  //-- TAF / TCP Data Interface
324  stream<TcpAppData> &siTAF_Data,
325  stream<TcpSessId> &siTAF_SessId,
326  stream<TcpDatLen> &siTAF_DatLen)
327 {
328  const char *myName = concat3(THIS_NAME, "/", "TSIF");
329 
330  //-- STATIC VARIABLES ------------------------------------------------------
331  static bool tsif_doneWithPassThroughTest1 = false;
332  static int tsif_txSegCnt = 0;
333  static int tsif_rxSegCnt = 0;
334  static int tsif_graceTime1 = 25; // Give TEST #1 some grace time to finish
335 
336  static ifstream ifSHL_Data;
337  static ofstream ofRawFile1;
338  static ofstream ofRawGold1;
339  static ofstream ofTcpFile1;
340  static ofstream ofRawFile2;
341  static ofstream ofTcpFile2;
342 
343  //-- DYNAMIC VARIABLES -----------------------------------------------------
344  bool rcSend;
345  bool rcRecv;
346  string ifSHL_DataName = "../../../../test/testVectors/siTSIF_Data.dat";
347  string ofRawFileName1 = "../../../../test/simOutFiles/soTAF_Shl_Echo_Path_Thru_Data.dat";
348  string ofRawGoldName1 = "../../../../test/simOutFiles/soTAF_Shl_Echo_Path_Thru_Data_Gold.dat";
349  string ofTcpFileName1 = "../../../../test/simOutFiles/soTAF_Shl_Echo_Path_Thru_Data.tcp";
350  string ofRawFileName2 = "../../../../test/simOutFiles/soTAF_Shl_Echo_Off_Data.dat";
351  string ofTcpFileName2 = "../../../../test/simOutFiles/soTAF_Shl_Echo_Off_Data.tcp";
352 
353  //------------------------------------------------------
354  //-- STEP-1 : RETURN IF DONE or STARTUP TIME
355  //------------------------------------------------------
356  if (tsif_doneWithPassThroughTest1) {
357  return;
358  }
359  if (gSimCycCnt < STARTUP_DELAY) {
360  return;
361  }
362 
363  //------------------------------------------------------
364  //-- STEP-2 : TEST THE PASS-THROUGH MODE
365  //------------------------------------------------------
366  if (gSimCycCnt == STARTUP_DELAY) {
367  printf("\n## PART-1 : TEST OF THE PASS-THROUGH MODE ####################\n");
368  tsif_rxSegCnt = 0;
369 
370  //-- STEP-2.0 : REMOVE PREVIOUS OUTPUT FILES
371  std::remove(ofRawFileName1.c_str());
372  std::remove(ofRawGoldName1.c_str());
373  std::remove(ofRawFileName2.c_str());
374  std::remove(ofTcpFileName1.c_str());
375  std::remove(ofTcpFileName2.c_str());
376 
377  //-- STEP-2.1 : OPEN INPUT TEST FILE #1
378  if (!ifSHL_Data.is_open()) {
379  ifSHL_Data.open (ifSHL_DataName.c_str(), ifstream::in);
380  if (!ifSHL_Data) {
381  printFatal(myName, "Could not open the input data file \'%s\'. \n", ifSHL_DataName.c_str());
382  nrErr++;
383  tsif_doneWithPassThroughTest1 = true;
384  return;
385  }
386  }
387  //-- STEP-2.2 : OPEN TWO OUTPUT DATA FILES #1
388  if (!ofRawFile1.is_open()) {
389  ofRawFile1.open (ofRawFileName1.c_str(), ofstream::out);
390  if (!ofRawFile1) {
391  printFatal(myName, "Could not open the output Raw data file \'%s\'. \n", ofRawFileName1.c_str());
392  nrErr++;
393  tsif_doneWithPassThroughTest1 = true;
394  return;
395  }
396  }
397  if (!ofRawGold1.is_open()) {
398  ofRawGold1.open (ofRawGoldName1.c_str(), ofstream::out);
399  if (!ofRawGold1) {
400  printFatal(myName, "Could not open the output Raw gold file \'%s\'. \n", ofRawGoldName1.c_str());
401  nrErr++;
402  tsif_doneWithPassThroughTest1 = true;
403  return;
404  }
405  }
406  if (!ofTcpFile1.is_open()) {
407  ofTcpFile1.open (ofTcpFileName1.c_str(), ofstream::out);
408  if (!ofTcpFile1) {
409  printFatal(myName, "Could not open the Tcp output data file \'%s\'. \n", ofTcpFileName1.c_str());
410  nrErr++;
411  tsif_doneWithPassThroughTest1 = true;
412  return;
413  }
414  }
415  }
416  else if (tsif_graceTime1) {
417  //-- STEP-2.3 : FEED THE TAF
418  rcSend = pTSIF_Send(
419  nrErr,
420  soTAF_Data,
421  soTAF_SessId,
422  soTAF_DatLen,
423  ifSHL_Data,
424  ofRawGold1,
425  tsif_txSegCnt);
426  //-- STEP-2.4 : READ FROM THE TAF
427  rcRecv = pTSIF_Recv(
428  nrErr,
429  siTAF_Data,
430  siTAF_SessId,
431  siTAF_DatLen,
432  ofRawFile1,
433  ofTcpFile1,
434  tsif_rxSegCnt);
435  //-- STEP-2.5 : CHECK IF TEST FAILED or IS FINISHED
436  if ((rcSend != OK) or (rcRecv != OK)) {
437  tsif_graceTime1--; // Give the test some grace time to finish
438  }
439  }
440 
441  //------------------------------------------------------
442  //-- STEP-3 : VERIFY THE PASS-THROUGH MODE
443  //------------------------------------------------------
444  if (tsif_graceTime1 == 0) {
445  if (ofRawFile1.tellp() != 0) {
446  int rc1 = system(("diff --brief -w " + std::string(ofRawFileName1) + " " + std::string(ofRawGoldName1) + " ").c_str());
447  if (rc1) {
448  printError(myName, "File '%s' does not match '%s'.\n", ofRawFileName1.c_str(), ofRawGoldName1.c_str());
449  nrErr += 1;
450  }
451  tsif_doneWithPassThroughTest1 = true;
452  }
453  else {
454  printError(THIS_NAME, "File \"%s\" is empty.\n", ofRawFileName1.c_str());
455  nrErr += 1;
456  }
457  //-- Closing open files
458  ifSHL_Data.close();
459  ofRawFile1.close();
460  ofRawGold1.close();
461  ofTcpFile1.close();
462  }
463 }
464 
tLast getTLast() const
Definition: AxisRaw.hpp:219
Class App Data.
Definition: SimAppData.hpp:53
int length()
Definition: SimAppData.hpp:133
void pushChunk(AxisApp appChunk)
Definition: SimAppData.hpp:115
AxisApp pullChunk()
Definition: SimAppData.hpp:125
bool readAxisRawFromLine(AxisRaw &axisRaw, string stringBuffer)
Retrieve an AxisRaw chunk from a string.
vector< string > myTokenizer(string strBuff, char delimiter)
Brakes a string into tokens by using the 'delimiter' character.
bool writeAxisRawToFile(AxisRaw &axisRaw, ofstream &outFileStream)
Dump an Axis raw data chunk to a file.
int writeAxisAppToFile(AxisApp &axisApp, ofstream &outFile)
Dump a TCP or UDP application data chunk into a file. The data are stored as a stream of bytes which ...
#define printError(callerName, format,...)
A macro to print an error message.
Definition: nts_utils.hpp:195
void printAxisRaw(const char *callerName, AxisRaw chunk)
Prints an Axis raw data chunk (used for debugging).
Definition: nts_utils.cpp:46
ap_uint< 16 > TcpDatLen
Definition: AxisTcp.hpp:123
#define printInfo(callerName, format,...)
A macro to print an information message.
Definition: nts_utils.hpp:169
#define OK
Definition: nts_types.hpp:57
#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
#define KO
Definition: nts_types.hpp:58
#define printFatal(callerName, format,...)
A macro to print a fatal error message and exit.
Definition: nts_utils.hpp:208
ap_uint< 16 > TcpSessId
Definition: nts_types.hpp:137
void stepSim()
Increment the simulation counter.
bool pTSIF_Send(int &nrError, stream< TcpAppData > &soTAF_Data, stream< TcpSessId > &soTAF_SessId, stream< TcpDatLen > &soTAF_DatLen, ifstream &inpFileStream, ofstream &outGoldStream, int &nrSegments)
Emulate the sending part of the TSIF process.
#define TRACE_TSr
#define DEFAULT_SESS_ID
unsigned int gMaxSimCycles
Definition: test_arp.hpp:69
unsigned int gSimCycCnt
Definition: tb_nal.cpp:150
bool gTraceEvent
Definition: tb_nal.cpp:151
#define THIS_NAME
void increaseSimTime(unsigned int cycles)
Increase the simulation time of the testbench.
bool pTSIF_Recv(int &nrErr, stream< TcpAppData > &siTAF_Data, stream< TcpSessId > &siTAF_SessId, stream< TcpDatLen > &siTAF_DatLen, ofstream &rawFileStream, ofstream &tcpFileStream, int &nrSegments)
Emulate the receiving part of the TSIF process.
#define TRACE_TSs
#define STARTUP_DELAY
bool gFatalError
Definition: tb_nal.cpp:152
#define DEBUG_LEVEL
void pTSIF(int &nrErr, stream< TcpAppData > &soTAF_Data, stream< TcpSessId > &soTAF_SessId, stream< TcpDatLen > &soTAF_DatLen, stream< TcpAppData > &siTAF_Data, stream< TcpSessId > &siTAF_SessId, stream< TcpDatLen > &siTAF_DatLen)
Emulate the behavior of TSIF.
out
Definition: test.py:12
: Simulation environment for the TCP Application Flash (TAF).