sy_wrappers.hpp
Go to the documentation of this file.
1 /**********************************************************************
2  * sy_wrappers.hpp -- Co-simulation wrappers for the SY MOC *
3  * *
4  * Author: Hosein Attarzadeh (shan2@kth.se) *
5  * *
6  * Purpose: Providing co-simulation wrappers for integration of *
7  * foreign models into ForSyDe *
8  * *
9  * Usage: This file is included automatically *
10  * *
11  * License: BSD3 *
12  *******************************************************************/
13 
14 #ifndef SY_WRAPPERS_HPP
15 #define SY_WRAPPERS_HPP
16 
24 #include <functional>
25 #include <tuple>
26 #include <iostream>
27 
28 #include "mi_gdb.h"
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 #include <unistd.h>
34 #include <errno.h>
35 
36 #include "abst_ext.hpp"
37 #include "sy_process.hpp"
38 
39 namespace ForSyDe
40 {
41 
42 namespace SY
43 {
44 
45 using namespace sc_core;
46 
48 
53 template <typename T0, typename T1>
54 class gdbwrap : public sy_process
55 {
56 public:
59 
61 
66  gdbwrap(const sc_module_name& _name,
67  const std::string& exec_name
68  ) : sy_process(_name), iport1("iport1"), oport1("oport1"),
69  exec_name(exec_name)
70  {
71 #ifdef FORSYDE_INTROSPECTION
72  arg_vec.push_back(std::make_tuple("exec_name",exec_name));
73 #endif
74  }
75 
77  std::string forsyde_kind() const {return "SY::gdbwrap";}
78 
79 private:
80  // Inputs and output variables
81  T0* oval;
82  abst_ext<T1>* ival1;
83  std::istringstream oval_str;
84  std::ostringstream ival1_str;
85 
87  std::string exec_name;
88 
89  // Debugger-specific definitions
90  MIDebugger d;
91  mi_bkpt *bk_in1, *bk_out;
92 
93  //Implementing the abstract semantics
94  void init()
95  {
96  oval = new T0;
97  ival1 = new abst_ext<T1>;
98  // Connect to gdb child.
99  if (!d.Connect())
100  SC_REPORT_ERROR(name(),"Connection to child GDB instance failed.");
101 
102  // Set the name of the child and the command line aguments.
103  // It also opens the xterm.
104  if (!d.SelectTargetX11(exec_name.c_str()))
105  SC_REPORT_ERROR(name(),"Error executing the external model");
106 
107  /* Set the breakpoints */
108  bk_in1=d.Breakpoint("forsyde_read_in1");
109  bk_out=d.Breakpoint("forsyde_write_out");
110  if (!bk_in1 || !bk_out)
111  SC_REPORT_ERROR(name(),"Error Setting the breakpoints");
112  mi_free_bkpt(bk_in1);
113  mi_free_bkpt(bk_out);
114 
115  // Start the executation of the external model
116  async_run(d.RunOrContinue());
117 
118  /* disabling the async mode */
119  //~ d.Send("-gdb-set mi-async off");
120  }
121 
122  void prep()
123  {
124  *ival1 = iport1.read();
125  ival1_str<<unsafe_from_abst_ext(*ival1);
126  async_run(d.StepOver());
127  d.ModifyExpression("forsyde_in1",const_cast<char*>(ival1_str.str().c_str()));
128  ival1_str.str(std::string());
129  }
130 
131  void exec()
132  {
133  // Resume execution
134  async_run(d.Continue());
135  }
136 
137  void prod()
138  {
139  async_run(d.StepOver());
140  oval_str.str(d.EvalExpression("forsyde_out"));
141  oval_str >> *oval;
142  oval_str.clear();
143  WRITE_MULTIPORT(oport1, abst_ext<T0>(*oval))
144 
145  // Resume execution
146  async_run(d.Continue());
147  }
148 
149  void clean()
150  {
151  d.TargetUnselect();
152  d.Disconnect();
153  delete ival1;
154  delete oval;
155  }
156 
157  inline void async_run(int res)
158  {
159  if (!res)
160  SC_REPORT_ERROR(name(),"Error in GDB command execution!");
161 
162  mi_stop *sr;
163  while (!d.Poll(sr)) wait(SC_ZERO_TIME);
164  if (sr)
165  mi_free_stop(sr);
166  else
167  SC_REPORT_ERROR(name(),mi_error_from_gdb);
168  }
169 
170 #ifdef FORSYDE_INTROSPECTION
171  void bindInfo()
172  {
173  boundInChans.resize(1); // only one input port
174  boundInChans[0].port = &iport1;
175  boundOutChans.resize(1); // only one output port
176  boundOutChans[0].port = &oport1;
177  }
178 #endif
179 };
180 
182 
187 template <typename T0, typename T1>
188 class pipewrap : public sy_process
189 {
190 public:
193 
195 
199  pipewrap(const sc_module_name& _name,
200  const int& offset,
201  const std::string& pipe_path
202  ) : sy_process(_name), iport1("iport1"), oport1("oport1"),
203  offset(offset), pipe_path(pipe_path)
204  {
205 #ifdef FORSYDE_INTROSPECTION
206  arg_vec.push_back(std::make_tuple("pipe_path",pipe_path));
207 #endif
208  }
209 
211  std::string forsyde_kind() const {return "SY::pipewrap";}
212 
213 private:
214  // Inputs and output variables
215  T0* oval;
216  abst_ext<T1>* ival1;
217  std::istringstream oval_str;
218  std::ostringstream ival_str;
219 
221  int offset;
223  std::string pipe_path;
224 
225  // Communication pipes
226  FILE* inp_pipe; // Input (to the external model) pipe
227  FILE* out_pipe; // Output (from the external model) pipe
228  int inp_pipe_fd, out_pipe_fd;
229  bool initiated;
230 
231  //Implementing the abstract semantics
232  void init()
233  {
234  oval = new T0;
235  ival1 = new abst_ext<T1>;
236 
237  initiated =false;
238  inp_pipe_fd = out_pipe_fd = 0;
239 
240  // Open the pipes. They might be opened in any order
241  ival_str.str(pipe_path + "/" + basename() + "_inp");
242  oval_str.str(pipe_path + "/" + basename() + "_out");
243 
244  // TODO: improve error detection for openning the pipes
245  while (inp_pipe_fd<=0 || out_pipe_fd<=0) // both pipes are not open
246  {
247  if (inp_pipe_fd<=0)
248  {
249  inp_pipe_fd = open(ival_str.str().c_str(), O_WRONLY|O_NONBLOCK);
250  if (inp_pipe_fd > 0)
251  inp_pipe = fdopen(inp_pipe_fd, "w");
252  }
253  if (out_pipe_fd<=0)
254  {
255  out_pipe_fd = open(oval_str.str().c_str(), O_RDONLY|O_NONBLOCK);
256  if (out_pipe_fd > 0)
257  out_pipe = fdopen(out_pipe_fd, "r");
258  }
259  wait(SC_ZERO_TIME);
260  }
261  ival_str.str(std::string());
262  oval_str.str(std::string());
263  }
264 
265  void prep()
266  {
267  *ival1 = iport1.read();
268  ival_str<<unsafe_from_abst_ext(*ival1);
269 
270  while(fprintf(inp_pipe,"%s\n",ival_str.str().c_str())==0)
271  {
272  if (ferror(inp_pipe) && errno==EAGAIN)
273  {
274  clearerr(inp_pipe);
275  wait(SC_ZERO_TIME);
276  }
277  else
278  SC_REPORT_ERROR(name(),"Error writing to the input pipe.");
279  }
280  ival_str.str(std::string());
281  }
282 
283  void exec() {}
284 
285  void prod()
286  {
287  // FIXME: generalize over the hard coded value 10
288  char buf[80];
289  while(fgets(buf,80,out_pipe)==NULL)
290  {
291  //if (errno==ENXIO) printf("ENXIO\n");
292  if (feof(out_pipe))
293  {
294  if (initiated) // Input exhausted!
295  wait();
296  else
297  {
298  clearerr(out_pipe);
299  wait(SC_ZERO_TIME);
300  }
301  }
302  else if (ferror(out_pipe) && errno==EAGAIN)
303  wait(SC_ZERO_TIME);
304  else
305  SC_REPORT_ERROR(name(),"Error reading from the output pipe.");
306  }
307  initiated = true;
308 
309  oval_str.str(std::string(buf));
310  oval_str >> *oval;
311  oval_str.clear();
312  WRITE_MULTIPORT(oport1, abst_ext<T0>(*oval))
313  }
314 
315  void clean()
316  {
317  fclose(inp_pipe);
318  fclose(out_pipe);
319  delete ival1;
320  delete oval;
321  }
322 
323 #ifdef FORSYDE_INTROSPECTION
324  void bindInfo()
325  {
326  boundInChans.resize(1); // only one input port
327  boundInChans[0].port = &iport1;
328  boundOutChans.resize(1); // only one output port
329  boundOutChans[0].port = &oport1;
330  }
331 #endif
332 };
333 
335 
340 template <typename T0, typename T1, typename T2>
341 class pipewrap2 : public sy_process
342 {
343 public:
347 
349 
353  pipewrap2(const sc_module_name& _name,
354  const int& offset,
355  const std::string& pipe_path
356  ) : sy_process(_name), iport1("iport1"), iport2("iport2"),
357  oport1("oport1"), offset(offset), pipe_path(pipe_path)
358  {
359 #ifdef FORSYDE_INTROSPECTION
360  arg_vec.push_back(std::make_tuple("pipe_path",pipe_path));
361 #endif
362  }
363 
365  std::string forsyde_kind() const {return "SY::pipewrap2";}
366 
367 private:
368  // Inputs and output variables
369  T0* oval;
370  abst_ext<T1>* ival1;
371  abst_ext<T2>* ival2;
372  std::istringstream oval_str;
373  std::ostringstream ival_str;
374 
376  int offset;
378  std::string pipe_path;
379 
380  // Communication pipes
381  FILE* inp_pipe; // Input (to the external model) pipe
382  FILE* out_pipe; // Output (from the external model) pipe
383  int inp_pipe_fd, out_pipe_fd;
384  bool initiated;
385 
386  //Implementing the abstract semantics
387  void init()
388  {
389  oval = new T0;
390  ival1 = new abst_ext<T1>;
391  ival2 = new abst_ext<T2>;
392 
393  initiated =false;
394  inp_pipe_fd = out_pipe_fd = 0;
395 
396  // Open the pipes. They might be opened in any order
397  ival_str.str(pipe_path + "/" + basename() + "_inp");
398  oval_str.str(pipe_path + "/" + basename() + "_out");
399 
400  // TODO: improve error detection for openning the pipes
401  while (inp_pipe_fd<=0 || out_pipe_fd<=0) // both pipes are not open
402  {
403  if (inp_pipe_fd<=0)
404  {
405  inp_pipe_fd = open(ival_str.str().c_str(), O_WRONLY|O_NONBLOCK);
406  if (inp_pipe_fd > 0)
407  inp_pipe = fdopen(inp_pipe_fd, "w");
408  }
409  if (out_pipe_fd<=0)
410  {
411  out_pipe_fd = open(oval_str.str().c_str(), O_RDONLY|O_NONBLOCK);
412  if (out_pipe_fd > 0)
413  out_pipe = fdopen(out_pipe_fd, "r");
414  }
415  wait(SC_ZERO_TIME);
416  }
417  ival_str.str(std::string());
418  oval_str.str(std::string());
419  }
420 
421  void prep()
422  {
423  if (offset<=0)
424  {
425  *ival1 = iport1.read();
426  *ival2 = iport2.read();
427  ival_str<<unsafe_from_abst_ext(*ival1)<<" "<<unsafe_from_abst_ext(*ival2);
428 
429  while(fprintf(inp_pipe,"%s\n",ival_str.str().c_str())==0)
430  {
431  if (ferror(inp_pipe) && errno==EAGAIN)
432  {
433  clearerr(inp_pipe);
434  wait(SC_ZERO_TIME);
435  }
436  else
437  SC_REPORT_ERROR(name(),"Error writing to the input pipe.");
438  }
439  fflush(inp_pipe);
440  ival_str.str(std::string());
441  }
442  }
443 
444  void exec() {}
445 
446  void prod()
447  {
448  if (offset>=0)
449  {
450  // FIXME: generalize over the hard coded value 80
451  char buf[80];
452  while(fgets(buf,80,out_pipe)==NULL)
453  {
454  //if (errno==ENXIO) printf("ENXIO\n");
455  if (feof(out_pipe))
456  {
457  if (initiated) // Input exhausted!
458  wait();
459  else
460  {
461  clearerr(out_pipe);
462  wait(SC_ZERO_TIME);
463  }
464  }
465  else if (ferror(out_pipe) && errno==EAGAIN)
466  wait(SC_ZERO_TIME);
467  else
468  SC_REPORT_ERROR(name(),"Error reading from the output pipe.");
469  }
470  initiated = true;
471 
472  oval_str.str(std::string(buf));
473  oval_str >> *oval;
474  oval_str.clear();
475  WRITE_MULTIPORT(oport1, abst_ext<T0>(*oval))
476  }
477  if (offset<0) offset++;
478  else if (offset>0) offset--;
479  }
480 
481  void clean()
482  {
483  fclose(inp_pipe);
484  fclose(out_pipe);
485  delete ival1;
486  delete ival2;
487  delete oval;
488  }
489 
490 #ifdef FORSYDE_INTROSPECTION
491  void bindInfo()
492  {
493  boundInChans.resize(2); // only one input port
494  boundInChans[0].port = &iport1;
495  boundInChans[1].port = &iport2;
496  boundOutChans.resize(1); // only one output port
497  boundOutChans[0].port = &oport1;
498  }
499 #endif
500 };
501 
502 
504 
510 template <class T0, template <class> class OIf,
511  class T1, template <class> class I1If>
512 inline gdbwrap<T0,T1>* make_gdbwrap(const std::string& pName,
513  const std::string& exec_name,
514  OIf<T0>& outS,
515  I1If<T1>& inp1S
516  )
517 {
518  auto p = new gdbwrap<T0,T1>(pName.c_str(), exec_name);
519 
520  (*p).iport1(inp1S);
521  (*p).oport1(outS);
522 
523  return p;
524 }
525 
527 
533 template <class T0, template <class> class OIf,
534  class T1, template <class> class I1If>
535 inline pipewrap<T0,T1>* make_pipewrap(const std::string& pName,
536  const int& offset,
537  const std::string& path_name,
538  OIf<T0>& outS,
539  I1If<T1>& inp1S
540  )
541 {
542  auto p = new pipewrap<T0,T1>(pName.c_str(), offset, path_name);
543 
544  (*p).iport1(inp1S);
545  (*p).oport1(outS);
546 
547  return p;
548 }
549 
551 
557 template <class T0, template <class> class OIf,
558  class T1, template <class> class I1If,
559  class T2, template <class> class I2If>
560 inline pipewrap2<T0,T1,T2>* make_pipewrap2(const std::string& pName,
561  const int& offset,
562  const std::string& path_name,
563  OIf<T0>& outS,
564  I1If<T1>& inp1S,
565  I2If<T2>& inp2S
566  )
567 {
568  auto p = new pipewrap2<T0,T1,T2>(pName.c_str(), offset, path_name);
569 
570  (*p).iport1(inp1S);
571  (*p).iport2(inp2S);
572  (*p).oport1(outS);
573 
574  return p;
575 }
576 
577 }
578 }
579 
580 #endif
Process constructor for a pipe wrapper with one input and one output.
Definition: sy_wrappers.hpp:188
SY_in< T1 > iport1
port for the input channel
Definition: sy_wrappers.hpp:191
Process constructor for a GDB wrapper with one input and one output.
Definition: sy_wrappers.hpp:54
pipewrap(const sc_module_name &_name, const int &offset, const std::string &pipe_path)
The constructor requires the module name.
Definition: sy_wrappers.hpp:199
The namespace for ForSyDe.
Definition: abssemantics.hpp:30
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: sy_wrappers.hpp:211
Implements the Absent-extended values.
SY_in< T2 > iport2
port for the second channel
Definition: sy_wrappers.hpp:345
SY_out< T0 > oport1
port for the output channel
Definition: sy_wrappers.hpp:58
Implements the abstract process in the synchronous Model of Computation.
pipewrap< T0, T1 > * make_pipewrap(const std::string &pName, const int &offset, const std::string &path_name, OIf< T0 > &outS, I1If< T1 > &inp1S)
Helper function to construct a pipewrap process.
Definition: sy_wrappers.hpp:535
SY_out< T0 > oport1
port for the output channel
Definition: sy_wrappers.hpp:346
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: sy_wrappers.hpp:77
SY_in< T1 > iport1
port for the input channel
Definition: sy_wrappers.hpp:57
SY_in< T1 > iport1
port for the input channel
Definition: sy_wrappers.hpp:344
gdbwrap(const sc_module_name &_name, const std::string &exec_name)
The constructor requires the module name.
Definition: sy_wrappers.hpp:66
The process constructor which defines the abstract semantics of execution.
Definition: abssemantics.hpp:212
Process constructor for a pipe wrapper with one input and one output.
Definition: sy_wrappers.hpp:341
pipewrap2< T0, T1, T2 > * make_pipewrap2(const std::string &pName, const int &offset, const std::string &path_name, OIf< T0 > &outS, I1If< T1 > &inp1S, I2If< T2 > &inp2S)
Helper function to construct a pipewrap process.
Definition: sy_wrappers.hpp:560
SY_out< T0 > oport1
port for the output channel
Definition: sy_wrappers.hpp:192
pipewrap2(const sc_module_name &_name, const int &offset, const std::string &pipe_path)
The constructor requires the module name.
Definition: sy_wrappers.hpp:353
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: sy_wrappers.hpp:365
gdbwrap< T0, T1 > * make_gdbwrap(const std::string &pName, const std::string &exec_name, OIf< T0 > &outS, I1If< T1 > &inp1S)
Helper function to construct a gdbwrap process.
Definition: sy_wrappers.hpp:512