dde_process_constructors.hpp
Go to the documentation of this file.
1 /**********************************************************************
2  * dde_process_constructors.hpp -- Process constructors in the DDE *
3  * MOC *
4  * *
5  * Author: Hosein Attarzadeh (shan2@kth.se) *
6  * *
7  * Purpose: Providing basic process constructors for modeling *
8  * distributed discrete-event systems in ForSyDe-SystemC *
9  * *
10  * Usage: This file is included automatically *
11  * *
12  * License: BSD3 *
13  *******************************************************************/
14 
15 #ifndef DDE_PROCESS_CONSTRUCTORS_HPP
16 #define DDE_PROCESS_CONSTRUCTORS_HPP
17 
25 #include <functional>
26 #include <algorithm>
27 #include <tuple>
28 #include <deque>
29 #include <boost/numeric/ublas/matrix.hpp>
30 
31 #include "tt_event.hpp"
32 #include "dde_process.hpp"
33 
34 namespace ForSyDe
35 {
36 
37 namespace DDE
38 {
39 
40 using namespace sc_core;
41 using namespace boost::numeric::ublas;
42 
44 
48 template <typename T0, typename T1>
49 class comb : public dde_process
50 {
51 public:
54 
56  typedef std::function<void(abst_ext<T0>&, const T1&)> functype;
57 
59 
63  comb(sc_module_name _name,
64  functype _func
65  ) : dde_process(_name), iport1("iport1"), oport1("oport1"),
66  _func(_func)
67  {
68 #ifdef FORSYDE_INTROSPECTION
69  std::string func_name = std::string(basename());
70  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
71  arg_vec.push_back(std::make_tuple("_func",func_name+std::string("_func")));
72 #endif
73  }
74 
76  std::string forsyde_kind() const {return "DDE::comb";}
77 
78 private:
79  // Inputs and output variables
80  abst_ext<T0>* oval;
81  ttn_event<T1>* iev1;
82 
84  functype _func;
85 
86  //Implementing the abstract semantics
87  void init()
88  {
89  oval = new abst_ext<T0>;
90  iev1 = new ttn_event<T1>;
91  }
92 
93  void prep()
94  {
95  *iev1 = iport1.read();
96  }
97 
98  void exec()
99  {
100  if (is_present(get_value(*iev1)))
101  _func(*oval, unsafe_from_abst_ext(get_value(*iev1)));
102  else
103  *oval = abst_ext<T0>();
104  }
105 
106  void prod()
107  {
108  auto oev = ttn_event<T0>(*oval, get_time(*iev1));
109  WRITE_MULTIPORT(oport1, oev)
110  // synchronization with kernel time
111  wait(get_time(oev) - sc_time_stamp());
112  }
113 
114  void clean()
115  {
116  delete iev1;
117  delete oval;
118  }
119 
120 #ifdef FORSYDE_INTROSPECTION
121  void bindInfo()
122  {
123  boundInChans.resize(1); // only one input port
124  boundInChans[0].port = &iport1;
125  boundOutChans.resize(1); // only one output port
126  boundOutChans[0].port = &oport1;
127  }
128 #endif
129 };
130 
132 
134 template <typename T0, typename T1, typename T2>
135 class comb2 : public dde_process
136 {
137 public:
141 
143  typedef std::function<void(abst_ext<T0>&, const abst_ext<T1>&, const abst_ext<T2>&)> functype;
144 
146 
150  comb2(sc_module_name _name,
151  functype _func
152  ) : dde_process(_name), iport1("iport1"), iport2("iport2"), oport1("oport1"),
153  _func(_func)
154  {
155 #ifdef FORSYDE_INTROSPECTION
156  std::string func_name = std::string(basename());
157  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
158  arg_vec.push_back(std::make_tuple("_func",func_name+std::string("_func")));
159 #endif
160  }
161 
163  std::string forsyde_kind() const {return "DDE::comb2";}
164 private:
165  // Inputs and output variables
166  abst_ext<T0>* oval;
167  ttn_event<T1> *next_iev1;
168  ttn_event<T2> *next_iev2;
169  abst_ext<T1> *cur_ival1;
170  abst_ext<T2> *cur_ival2;
171 
172  // the current time (local time)
173  sc_time tl;
174 
175  // clocks of the input ports (channel times)
176  sc_time in1T, in2T;
177 
179  functype _func;
180 
181  //Implementing the abstract semantics
182  void init()
183  {
184  oval = new abst_ext<T0>;
185  next_iev1 = new ttn_event<T1>;
186  next_iev2 = new ttn_event<T2>;
187  cur_ival1 = new abst_ext<T1>;
188  cur_ival2 = new abst_ext<T2>;
189  in1T = in2T = tl = SC_ZERO_TIME;
190  }
191 
192  void prep()
193  {
194  if (in1T == tl)
195  {
196  *next_iev1 = iport1.read();
197  in1T = get_time(*next_iev1);
198  }
199  if (in2T == tl)
200  {
201  *next_iev2 = iport2.read();
202  in2T = get_time(*next_iev2);
203  }
204 
205  // update channel clocks and the local clock
206  tl = std::min(in1T, in2T);
207 
208  // update current values
209  if (get_time(*next_iev1) == tl)
210  *cur_ival1 = get_value(*next_iev1);
211  else
212  *cur_ival1 = abst_ext<T1>();
213  if (get_time(*next_iev2) == tl)
214  *cur_ival2 = get_value(*next_iev2);
215  else
216  *cur_ival2 = abst_ext<T2>();
217  }
218 
219  void exec()
220  {
221  if (is_absent(*cur_ival1) && is_absent(*cur_ival2))
222  *oval = abst_ext<T0>();
223  else
224  _func(*oval, *cur_ival1, *cur_ival2);
225  }
226 
227  void prod()
228  {
229  WRITE_MULTIPORT(oport1, ttn_event<T0>(*oval,tl))
230  wait(tl - sc_time_stamp());
231  }
232 
233  void clean()
234  {
235  delete oval;
236  delete next_iev1;
237  delete next_iev2;
238  delete cur_ival1;
239  delete cur_ival2;
240  }
241 
242 #ifdef FORSYDE_INTROSPECTION
243  void bindInfo()
244  {
245  boundInChans.resize(2); // only one input port
246  boundInChans[0].port = &iport1;
247  boundInChans[1].port = &iport2;
248  boundOutChans.resize(1); // only one output port
249  boundOutChans[0].port = &oport1;
250  }
251 #endif
252 };
253 
255 
263 template <class T>
264 class delay : public dde_process
265 {
266 public:
269 
271 
275  delay(sc_module_name _name,
276  abst_ext<T> init_val,
277  sc_time delay_time
278  ) : dde_process(_name), iport1("iport1"), oport1("oport1"),
279  init_val(init_val), delay_time(delay_time)
280  {
281 #ifdef FORSYDE_INTROSPECTION
282  std::stringstream ss;
283  ss << init_val;
284  arg_vec.push_back(std::make_tuple("init_val", ss.str()));
285  ss.str("");
286  ss << delay_time;
287  arg_vec.push_back(std::make_tuple("delay_time", ss.str()));
288 #endif
289  }
290 
292  std::string forsyde_kind() const {return "DDE::delay";}
293 
294 private:
295  // Initial value and the delay time
296  abst_ext<T> init_val;
297  sc_time delay_time;
298 
299  // Inputs and output variables
300  ttn_event<T>* ev;
301 
302  //Implementing the abstract semantics
303  void init()
304  {
305  ev = new ttn_event<T>;
306  auto oev = ttn_event<T>(init_val, SC_ZERO_TIME);
307  WRITE_MULTIPORT(oport1, oev)
308  wait(SC_ZERO_TIME);
309  }
310 
311  void prep()
312  {
313  *ev = iport1.read();
314  }
315 
316  void exec()
317  {
318  set_time(*ev, get_time(*ev)+delay_time);
319  }
320 
321  void prod()
322  {
323  WRITE_MULTIPORT(oport1, *ev)
324  wait(get_time(*ev) - sc_time_stamp());
325  }
326 
327  void clean()
328  {
329  delete ev;
330  }
331 #ifdef FORSYDE_INTROSPECTION
332  void bindInfo()
333  {
334  boundInChans.resize(1); // only one input port
335  boundInChans[0].port = &iport1;
336  boundOutChans.resize(1); // only one output port
337  boundOutChans[0].port = &oport1;
338  }
339 #endif
340 };
341 
343 
347 template <typename IT, typename ST, typename OT>
348 class mealy : public dde_process
349 {
350 public:
353 
355  typedef std::function<void(ST&, const ST&, const ttn_event<IT>&)> ns_functype;
356 
358  typedef std::function<void(abst_ext<OT>&, const ST&, const ttn_event<IT>&)> od_functype;
359 
361 
365  mealy(const sc_module_name& _name,
366  const ns_functype& _ns_func,
367  const od_functype& _od_func,
368  const ST& init_st,
369  const sc_time& delay_time
370  ) : dde_process(_name), _ns_func(_ns_func), _od_func(_od_func),
371  init_st(init_st), delay_time(delay_time)
372  {
373 #ifdef FORSYDE_INTROSPECTION
374  std::string func_name = std::string(basename());
375  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
376  arg_vec.push_back(std::make_tuple("_ns_func",func_name+std::string("_ns_func")));
377  arg_vec.push_back(std::make_tuple("_od_func",func_name+std::string("_od_func")));
378  std::stringstream ss;
379  ss << init_st;
380  arg_vec.push_back(std::make_tuple("init_st",ss.str()));
381  ss.str("");
382  ss << delay_time;
383  arg_vec.push_back(std::make_tuple("delay_time",ss.str()));
384 #endif
385  }
386 
388  std::string forsyde_kind() const{return "DDE::mealy";}
389 
390 private:
392  ns_functype _ns_func;
393  od_functype _od_func;
394 
395  // Initial value
396  ST init_st;
397 
398  sc_time delay_time;
399 
400  // Input, output, current state, and next state variables
401  ttn_event<IT>* itok;
402  ST* stval;
403  ST* nsval;
404  abst_ext<OT>* oval;
405 
406  //Implementing the abstract semantics
407  void init()
408  {
409  itok = new ttn_event<IT>;
410  stval = new ST;
411  *stval = init_st;
412  nsval = new ST;
413  oval = new abst_ext<OT>;
414  }
415 
416  void prep()
417  {
418  *itok = iport1.read();
419  }
420 
421  void exec()
422  {
423  _ns_func(*nsval, *stval, *itok);
424  _od_func(*oval, *stval, *itok);
425  *stval = *nsval;
426  }
427 
428  void prod()
429  {
430  WRITE_MULTIPORT(oport1, ttn_event<OT>(*oval,get_time(*itok)+delay_time))
431  }
432 
433  void clean()
434  {
435  delete itok;
436  delete stval;
437  delete nsval;
438  delete oval;
439  }
440 #ifdef FORSYDE_INTROSPECTION
441  void bindInfo()
442  {
443  boundInChans.resize(1); // only one input port
444  boundInChans[0].port = &iport1;
445  boundOutChans.resize(1); // only one output port
446  boundOutChans[0].port = &oport1;
447  }
448 #endif
449 };
450 
452 
456 template <typename IT1, typename IT2, typename ST, typename OT>
457 class mealy2 : public dde_process
458 {
459 public:
463 
465  typedef std::function<void(ST&, const ST&, const ttn_event<IT1>&, const ttn_event<IT2>&)> ns_functype;
466 
468  typedef std::function<void(abst_ext<OT>&, const ST&, const ttn_event<IT1>&, const ttn_event<IT2>&)> od_functype;
469 
471 
475  mealy2(const sc_module_name& _name,
476  const ns_functype& _ns_func,
477  const od_functype& _od_func,
478  const ST& init_st,
479  const sc_time& delay_time
480  ) : dde_process(_name), _ns_func(_ns_func), _od_func(_od_func),
481  init_st(init_st), delay_time(delay_time)
482  {
483 #ifdef FORSYDE_INTROSPECTION
484  std::string func_name = std::string(basename());
485  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
486  arg_vec.push_back(std::make_tuple("_ns_func",func_name+std::string("_ns_func")));
487  arg_vec.push_back(std::make_tuple("_od_func",func_name+std::string("_od_func")));
488  std::stringstream ss;
489  ss << init_st;
490  arg_vec.push_back(std::make_tuple("init_st",ss.str()));
491  ss.str("");
492  ss << delay_time;
493  arg_vec.push_back(std::make_tuple("delay_time",ss.str()));
494 #endif
495  }
496 
498  std::string forsyde_kind() const{return "DDE::mealy2";}
499 
500 private:
502  ns_functype _ns_func;
503  od_functype _od_func;
504 
505  // Initial value
506  ST init_st;
507 
508  sc_time delay_time;
509 
510  // Input, output, current state, and next state variables
511  ttn_event<IT1> *next_iev1;
512  ttn_event<IT2> *next_iev2;
513  abst_ext<IT1> *cur_ival1;
514  abst_ext<IT2> *cur_ival2;
515  ST* stval;
516  ST* nsval;
517  abst_ext<OT>* oval;
518 
519  // the current time (local time)
520  sc_time tl;
521 
522  // clocks of the input ports (channel times)
523  sc_time in1T, in2T;
524 
525  //Implementing the abstract semantics
526  void init()
527  {
528  next_iev1 = new ttn_event<IT1>;
529  next_iev2 = new ttn_event<IT2>;
530  cur_ival1 = new abst_ext<IT1>;
531  cur_ival2 = new abst_ext<IT2>;
532  stval = new ST;
533  *stval = init_st;
534  nsval = new ST;
535  oval = new abst_ext<OT>;
536  in1T = in2T = tl = SC_ZERO_TIME;
537  }
538 
539  void prep()
540  {
541  if (in1T == tl)
542  {
543  *next_iev1 = iport1.read();
544  in1T = get_time(*next_iev1);
545  }
546  if (in2T == tl)
547  {
548  *next_iev2 = iport2.read();
549  in2T = get_time(*next_iev2);
550  }
551 
552  // update channel clocks and the local clock
553  tl = std::min(in1T, in2T);
554 
555  // update current values
556  if (get_time(*next_iev1) == tl)
557  *cur_ival1 = get_value(*next_iev1);
558  else
559  *cur_ival1 = abst_ext<IT1>();
560  if (get_time(*next_iev2) == tl)
561  *cur_ival2 = get_value(*next_iev2);
562  else
563  *cur_ival2 = abst_ext<IT2>();
564  }
565 
566  void exec()
567  {
568  if (is_absent(*cur_ival1) && is_absent(*cur_ival2))
569  *oval = abst_ext<OT>();
570  else
571  {
572  _ns_func(*nsval, *stval, ttn_event<IT1>(*cur_ival1,tl), ttn_event<IT2>(*cur_ival2,tl));
573  _od_func(*oval, *stval, ttn_event<IT1>(*cur_ival1,tl), ttn_event<IT2>(*cur_ival2,tl));
574  *stval = *nsval;
575  }
576  }
577 
578  void prod()
579  {
580  WRITE_MULTIPORT(oport1, ttn_event<OT>(*oval,tl+delay_time))
581  wait(tl - sc_time_stamp());
582  }
583 
584  void clean()
585  {
586  delete next_iev1;
587  delete next_iev2;
588  delete cur_ival1;
589  delete cur_ival2;
590  delete stval;
591  delete nsval;
592  delete oval;
593  }
594 #ifdef FORSYDE_INTROSPECTION
595  void bindInfo()
596  {
597  boundInChans.resize(2); // only one input port
598  boundInChans[0].port = &iport1;
599  boundInChans[1].port = &iport2;
600  boundOutChans.resize(1); // only one output port
601  boundOutChans[0].port = &oport1;
602  }
603 #endif
604 };
605 
607 
610 template <class T>
611 class filter : public dde_process
612 {
613 public:
617 
618  typedef matrix<T> MatrixDouble;
619 
621 
625  filter(sc_module_name _name,
626  std::vector<T> numerators,
627  std::vector<T> denominators,
628  sc_time max_step,
629  sc_time min_step=sc_time(0.05,SC_NS),
630  T tol_error=1e-5
631  ) : dde_process(_name), iport1("iport1"), oport1("oport1"),
632  numerators(numerators), denominators(denominators),
633  max_step(max_step), min_step(min_step), tol_error(tol_error)
634  {
635 #ifdef FORSYDE_INTROSPECTION
636  std::stringstream ss;
637  ss << numerators;
638  arg_vec.push_back(std::make_tuple("numerators", ss.str()));
639  ss.str("");
640  ss << denominators;
641  arg_vec.push_back(std::make_tuple("denominators", ss.str()));
642  ss.str("");
643  ss << max_step;
644  arg_vec.push_back(std::make_tuple("max_step", ss.str()));
645  ss.str("");
646  ss << min_step;
647  arg_vec.push_back(std::make_tuple("min_step", ss.str()));
648  ss.str("");
649  ss << tol_error;
650  arg_vec.push_back(std::make_tuple("tol_error", ss.str()));
651 #endif
652  }
653 
655  std::string forsyde_kind() const {return "DDE::filter";}
656 
657 private:
658  // Constructor parameters
659  std::vector<T> numerators, denominators;
660  sc_time max_step, min_step;
661  T tol_error;
662 
663  // Internal variables
664  sc_time step;
665  sc_time samplingTimeTag;
666  MatrixDouble a, b, c, d;
667  // states
668  MatrixDouble x, x0, x1, x2;
669  // current and previous input/time.
670  MatrixDouble u, u0, u1, u_1;
671  sc_time t, t_1, t2, h;
672  // output
673  MatrixDouble y0, y1, y2;
674  // Some helper matrices used in RK solver
675  MatrixDouble k1,k2,k3,k4;
676  // to prevent rounding error
677  double roundingFactor;
678 
679  // Output event
680  ttn_event<T>* out_ev;
681 
682  //Implementing the abstract semantics
683  void init()
684  {
685  out_ev = new ttn_event<T>;
686 
687  step = max_step;
688  int /*nn = nums.size(),*/ nd = denominators.size();
689  a = MatrixDouble(nd-1,nd-1);
690  b = MatrixDouble(nd-1,1);
691  c = MatrixDouble(1,nd-1);
692  d = MatrixDouble(1,1);
693 
694  tf2ss(numerators,denominators,a,b,c,d);
695 
696  // State number
697  int numState = a.size1();
698  assert(a.size1() == a.size2());
699  samplingTimeTag = SC_ZERO_TIME;
700  x = zero_matrix<T>(numState,1);
701  u = MatrixDouble(1,1), u_1 = MatrixDouble(1,1);
702  u0 = u1 = MatrixDouble(1,1);
703  y1 = MatrixDouble(1,1);
704  k1 = MatrixDouble(numState,1);
705  k2 = MatrixDouble(numState,1);
706  k3 = MatrixDouble(numState,1);
707  k4 = MatrixDouble(numState,1);
708 
709  // initial sampling time tag
710  WRITE_MULTIPORT(oport2,ttn_event<unsigned int>(0, samplingTimeTag))
711  // read initial input
712  auto in_ev = iport1.read();
713  u(0,0) = unsafe_from_abst_ext(get_value(in_ev)); // FIXME: assumes non-null inputs
714  t = get_time(in_ev);
715  // calculate and write initial output
716  y1 = boost::numeric::ublas::prod(c,x) + boost::numeric::ublas::prod(d,u);
717  *out_ev = ttn_event<T>(y1(0,0), t);
718  WRITE_MULTIPORT(oport1, *out_ev)
719  // step signal
720  WRITE_MULTIPORT(oport2, ttn_event<unsigned int>(0, samplingTimeTag+step/2))
721  WRITE_MULTIPORT(oport2, ttn_event<unsigned int>(0, samplingTimeTag+step))
722  u_1(0,0) = u(0,0);
723  t_1 = t;
724  roundingFactor = 1.0001;
725  }
726 
727  void prep()
728  {
729  auto in_ev = iport1.read();
730  u1(0,0) = unsafe_from_abst_ext(get_value(in_ev)); // FIXME: assumes non-null inputs
731  t = get_time(in_ev);
732 
733  in_ev = iport1.read();
734  u0(0,0) = unsafe_from_abst_ext(get_value(in_ev)); // FIXME: assumes non-null inputs
735  t2 = get_time(in_ev);
736  }
737 
738  void exec()
739  {
740  // 1st step error estimation
741  h = t - t_1;
742  rkSolver(a, b, c, d, u1, u_1, x, h.to_seconds(), x1, y1);
743 
744  // regular RK
745  h = t2 - t_1;
746  rkSolver(a, b, c, d, u0, u_1, x, h.to_seconds(), x0, y0);
747 
748  // 2nd step error estimation
749  rkSolver(a, b, c, d, u0, u1, x1, (h/2).to_seconds(), x2, y2);
750 
751  // error estimation
752  double err_est = (double) std::abs(y2(0,0)-y0(0,0))/(h.to_seconds());
753  if( (err_est < tol_error) || (h<=roundingFactor*min_step)) {
754  x = x0;
755  samplingTimeTag = t;
756  // TODO: move the following line to the prod stage
757  WRITE_MULTIPORT(oport2, ttn_event<unsigned int>(1, samplingTimeTag)) // commitment
758  *out_ev = ttn_event<T>(y0(0,0), t);
759  WRITE_MULTIPORT(oport1, *out_ev)
760  u(0,0) = u0(0,0);
761  u_1(0,0) = u(0,0);
762  t_1 = t;
763  if(h==min_step)
764  std::cout << "Step accepted due to minimum step size. "
765  << "However, err_tol is not met." << std::endl;
766  }
767  }
768 
769  void prod()
770  {
771  WRITE_MULTIPORT(oport2, ttn_event<unsigned int>(0, samplingTimeTag+step/2))
772  WRITE_MULTIPORT(oport2, ttn_event<unsigned int>(0, samplingTimeTag+step))
773  }
774 
775  void clean()
776  {
777  delete out_ev;
778  }
779 
780  // To obtain state space matrices from transfer function.
781  // We assume there are non-zero leading coefficients in num and denom.
782  int tf2ss(std::vector<T> & num_, std::vector<T> & den_, MatrixDouble & a,
783  MatrixDouble & b, MatrixDouble & c, MatrixDouble & d)
784  {
785  std::vector<T> num, den;
786  // sizes checking
787  int nn = num_.size(), nd = den_.size();
788  if(nn >= nd)
789  {
790  std::cerr << "ERROR: " << "degree(num) = " << nn
791  << " >= degree(denom) = " << nd << std::endl;
792  abort();
793  }
794  T dCoef1 = den_.at(0);
795  if(nd==1)
796  {
797  //~ a = NULL, b = NULL, c = NULL;
798  d = MatrixDouble(1,1);
799  d(0,0) = num_.at(0)/dCoef1;
800  }
801  else
802  {
803  if ((nd - nn) > 0)
804  {
805  // Pad num so that degree(num) == degree(denom)
806  for(int i=0; i<nd; i++)
807  {
808  if(i<(nd-nn))
809  num.push_back(0.0);
810  else
811  num.push_back(num_.at(i-nd+nn));
812  }
813  }
814 
815  // Normalizing w.r.t the leading coefficient of denominator
816  for(unsigned int i=0; i<num.size(); i++)
817  num.at(i) /= dCoef1;
818  for(unsigned int i=0; i<den_.size(); i++)
819  den_.at(i) /= dCoef1;
820  for(unsigned int i=0; i<(den_.size()-1); i++)
821  den.push_back(den_.at(i+1));
822 
823  // Form A (nd-1)*(nd-1)
824  a = zero_matrix<T> (a.size1(), a.size2());
825  if(nd > 2)
826  {
827  // The eyes (up-right corner) are set to '1'
828  for(int i=0; i<(nd-2); i++)
829  for(int j=0; j<(nd-1); j++)
830  if((j-i)==1) a(i,j) = 1.0;
831  // The lower row(s)
832  for(int j=0; j<(nd-1); j++)
833  a(nd-2,j) = 0-den.at(nd-2-j);
834  }
835  else
836  a(0,0) = 0-den.at(0);
837  //
838  // Form B (nd-1)*1
839  b = zero_matrix<T> (b.size1(), b.size2());
840  b(nd-2,0) = 1.0;
841  //
842  // Form C 1*(nd-1)
843  for(int j=0; j< nd-1; j++)
844  c(0,nd-2-j) = num.at(j+1) - num.at(0)*den.at(j);
845  //
846  // Form D 1*1
847  d(0,0) = num.at(0);
848  }
849 
850  return 0;
851  }
852 
853  void rkSolver(MatrixDouble a, MatrixDouble b, MatrixDouble c,
854  MatrixDouble d, MatrixDouble u_k, MatrixDouble u_k_1,
855  MatrixDouble x, T h, MatrixDouble &x_, MatrixDouble &y)
856  {
857  // Some helper matrices used in RK solver
858  MatrixDouble k1,k2,k3,k4;
859  k1 = boost::numeric::ublas::prod(a,x) + boost::numeric::ublas::prod(b,u_k_1);
860  k2 = boost::numeric::ublas::prod(a,(x+k1*(h/2.0))) + boost::numeric::ublas::prod(b,(u_k_1 + u_k)) * 0.5;
861  k3 = boost::numeric::ublas::prod(a,(x+k2*(h/2.0))) + boost::numeric::ublas::prod(b,(u_k_1 + u_k)) * 0.5;
862  k4 = boost::numeric::ublas::prod(a,(x+k3*h)) + boost::numeric::ublas::prod(b,u_k);
863  x_ = x + (k1 + 2.0*k2 + 2.0*k3 + k4) * (h/6.0);
864  y = boost::numeric::ublas::prod(c,x_) + boost::numeric::ublas::prod(d,u_k);
865  }
866 
867 #ifdef FORSYDE_INTROSPECTION
868  void bindInfo()
869  {
870  boundInChans.resize(1); // only one input port
871  boundInChans[0].port = &iport1;
872  boundOutChans.resize(2); // two output ports
873  boundOutChans[0].port = &oport1;
874  boundOutChans[1].port = &oport2;
875  }
876 #endif
877 };
878 
880 
883 template <class T>
884 class filterf : public dde_process
885 {
886 public:
889 
890  typedef matrix<T> MatrixDouble;
891 
893 
897  filterf(sc_module_name _name,
898  std::vector<T> numerators,
899  std::vector<T> denominators
900  ) : dde_process(_name), iport1("iport1"), oport1("oport1"),
901  numerators(numerators), denominators(denominators)
902  {
903 #ifdef FORSYDE_INTROSPECTION
904  std::stringstream ss;
905  ss << numerators;
906  arg_vec.push_back(std::make_tuple("numerators", ss.str()));
907  ss.str("");
908  ss << denominators;
909  arg_vec.push_back(std::make_tuple("denominators", ss.str()));
910 #endif
911  }
912 
914  std::string forsyde_kind() const {return "DDE::filterf";}
915 
916 private:
917  // Constructor parameters
918  std::vector<T> numerators, denominators;
919 
920  // Internal variables
921  MatrixDouble a, b, c, d;
922  // states
923  MatrixDouble x, x_1;
924  // current and previous input/time.
925  MatrixDouble u, u_1;
926  sc_time t, t_1, h;
927  // output
928  MatrixDouble y;
929  // Some helper matrices used in RK solver
930  MatrixDouble k1,k2,k3,k4;
931 
932  // Output event
933  ttn_event<T>* out_ev;
934 
935  //Implementing the abstract semantics
936  void init()
937  {
938  out_ev = new ttn_event<T>;
939 
940  int /*nn = nums.size(),*/ nd = denominators.size();
941  a = MatrixDouble(nd-1,nd-1);
942  b = MatrixDouble(nd-1,1);
943  c = MatrixDouble(1,nd-1);
944  d = MatrixDouble(1,1);
945 
946  tf2ss(numerators,denominators,a,b,c,d);
947 
948  // State number
949  int numState = a.size1();
950  assert(a.size1() == a.size2());
951  x = zero_matrix<T>(numState,1), x_1 = zero_matrix<T>(numState,1);
952  u = MatrixDouble(1,1), u_1 = MatrixDouble(1,1);
953  y = MatrixDouble(1,1);
954  k1 = MatrixDouble(numState,1);
955  k2 = MatrixDouble(numState,1);
956  k3 = MatrixDouble(numState,1);
957  k4 = MatrixDouble(numState,1);
958 
959  // read initial input
960  auto in_ev = iport1.read();
961  u(0,0) = unsafe_from_abst_ext(get_value(in_ev)); // FIXME: assumes non-absent inputs
962  t = get_time(in_ev);
963  // calculate and write initial output
964  y = boost::numeric::ublas::prod(c,x) + boost::numeric::ublas::prod(d,u);
965  *out_ev = ttn_event<T>(y(0,0), t);
966  WRITE_MULTIPORT(oport1, *out_ev)
967  wait(t - sc_time_stamp());
968  u_1(0,0) = u(0,0);
969  t_1 = t;
970  }
971 
972  void prep()
973  {
974  auto in_ev = iport1.read();
975  u(0,0) = unsafe_from_abst_ext(get_value(in_ev)); // FIXME: assumes non-absent inputs
976  t = get_time(in_ev);
977  }
978 
979  void exec()
980  {
981  // 1st step error estimation
982  h = t - t_1;
983  rkSolver(a, b, c, d, u, u_1, x_1, h.to_seconds(), x, y);
984  *out_ev = ttn_event<T>(y(0,0), t);
985  }
986 
987  void prod()
988  {
989  WRITE_MULTIPORT(oport1, *out_ev)
990  wait(t - sc_time_stamp());
991  x_1 = x;
992  u_1(0,0) = u(0,0);
993  t_1 = t;
994  }
995 
996  void clean()
997  {
998  delete out_ev;
999  }
1000 
1001  // To obtain state space matrices from transfer function.
1002  // We assume there are non-zero leading coefficients in num and denom.
1003  int tf2ss(std::vector<T> & num_, std::vector<T> & den_, MatrixDouble & a,
1004  MatrixDouble & b, MatrixDouble & c, MatrixDouble & d)
1005  {
1006  std::vector<T> num, den;
1007  // sizes checking
1008  int nn = num_.size(), nd = den_.size();
1009  if(nn >= nd)
1010  {
1011  std::cerr << "ERROR: " << "degree(num) = " << nn
1012  << " >= degree(denom) = " << nd << std::endl;
1013  abort();
1014  }
1015  T dCoef1 = den_.at(0);
1016  if(nd==1)
1017  {
1018  //~ a = NULL, b = NULL, c = NULL;
1019  d = MatrixDouble(1,1);
1020  d(0,0) = num_.at(0)/dCoef1;
1021  }
1022  else
1023  {
1024  if ((nd - nn) > 0)
1025  {
1026  // Pad num so that degree(num) == degree(denom)
1027  for(int i=0; i<nd; i++)
1028  {
1029  if(i<(nd-nn))
1030  num.push_back(0.0);
1031  else
1032  num.push_back(num_.at(i-nd+nn));
1033  }
1034  }
1035 
1036  // Normalizing w.r.t the leading coefficient of denominator
1037  for(unsigned int i=0; i<num.size(); i++)
1038  num.at(i) /= dCoef1;
1039  for(unsigned int i=0; i<den_.size(); i++)
1040  den_.at(i) /= dCoef1;
1041  for(unsigned int i=0; i<(den_.size()-1); i++)
1042  den.push_back(den_.at(i+1));
1043 
1044  // Form A (nd-1)*(nd-1)
1045  a = zero_matrix<T> (a.size1(), a.size2());
1046  if(nd > 2)
1047  {
1048  // The eyes (up-right corner) are set to '1'
1049  for(int i=0; i<(nd-2); i++)
1050  for(int j=0; j<(nd-1); j++)
1051  if((j-i)==1) a(i,j) = 1.0;
1052  // The lower row(s)
1053  for(int j=0; j<(nd-1); j++)
1054  a(nd-2,j) = 0-den.at(nd-2-j);
1055  }
1056  else
1057  a(0,0) = 0-den.at(0);
1058  //
1059  // Form B (nd-1)*1
1060  b = zero_matrix<T> (b.size1(), b.size2());
1061  b(nd-2,0) = 1.0;
1062  //
1063  // Form C 1*(nd-1)
1064  for(int j=0; j< nd-1; j++)
1065  c(0,nd-2-j) = num.at(j+1) - num.at(0)*den.at(j);
1066  //
1067  // Form D 1*1
1068  d(0,0) = num.at(0);
1069  }
1070 
1071  return 0;
1072  }
1073 
1074  void rkSolver(MatrixDouble a, MatrixDouble b, MatrixDouble c,
1075  MatrixDouble d, MatrixDouble u_k, MatrixDouble u_k_1,
1076  MatrixDouble x, T h, MatrixDouble &x_, MatrixDouble &y)
1077  {
1078  // Some helper matrices used in RK solver
1079  MatrixDouble k1,k2,k3,k4;
1080  k1 = boost::numeric::ublas::prod(a,x) + boost::numeric::ublas::prod(b,u_k_1);
1081  k2 = boost::numeric::ublas::prod(a,(x+k1*(h/2.0))) + boost::numeric::ublas::prod(b,(u_k_1 + u_k)) * 0.5;
1082  k3 = boost::numeric::ublas::prod(a,(x+k2*(h/2.0))) + boost::numeric::ublas::prod(b,(u_k_1 + u_k)) * 0.5;
1083  k4 = boost::numeric::ublas::prod(a,(x+k3*h)) + boost::numeric::ublas::prod(b,u_k);
1084  x_ = x + (k1 + 2.0*k2 + 2.0*k3 + k4) * (h/6.0);
1085  y = boost::numeric::ublas::prod(c,x_) + boost::numeric::ublas::prod(d,u_k);
1086  }
1087 
1088 #ifdef FORSYDE_INTROSPECTION
1089  void bindInfo()
1090  {
1091  boundInChans.resize(1); // only one input port
1092  boundInChans[0].port = &iport1;
1093  boundOutChans.resize(1); // two output ports
1094  boundOutChans[0].port = &oport1;
1095  }
1096 #endif
1097 };
1098 
1100 
1105 template <class T>
1106 class source : public dde_process
1107 {
1108 public:
1110 
1112  typedef std::function<void(ttn_event<T>&, const ttn_event<T>&)> functype;
1113 
1115 
1118  source(sc_module_name _name,
1119  functype _func,
1120  ttn_event<T> init_st,
1121  unsigned long long take=0
1122  ) : dde_process(_name), oport1("oport1"),
1123  init_st(init_st), take(take), _func(_func)
1124  {
1125 #ifdef FORSYDE_INTROSPECTION
1126  std::string func_name = std::string(basename());
1127  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
1128  arg_vec.push_back(std::make_tuple("_func",func_name+std::string("_func")));
1129  std::stringstream ss;
1130  ss << init_st;
1131  arg_vec.push_back(std::make_tuple("init_st", ss.str()));
1132  ss.str("");
1133  ss << take;
1134  arg_vec.push_back(std::make_tuple("take", ss.str()));
1135 #endif
1136  }
1137 
1139  std::string forsyde_kind() const {return "DDE::source";}
1140 
1141 private:
1142  ttn_event<T> init_st; // The current state
1143  unsigned long long take; // Number of tokens produced
1144 
1145  ttn_event<T>* cur_st; // The current state of the process
1146  unsigned long long tok_cnt;
1147  bool infinite;
1148 
1150  functype _func;
1151 
1152  //Implementing the abstract semantics
1153  void init()
1154  {
1155  cur_st = new ttn_event<T>;
1156  *cur_st = init_st;
1157  WRITE_MULTIPORT(oport1, *cur_st)
1158  wait(get_time(*cur_st) - sc_time_stamp());
1159  if (take==0) infinite = true;
1160  tok_cnt = 1;
1161  }
1162 
1163  void prep() {}
1164 
1165  void exec()
1166  {
1167  _func(*cur_st, *cur_st);
1168  }
1169 
1170  void prod()
1171  {
1172  if (tok_cnt++ < take || infinite)
1173  {
1174  WRITE_MULTIPORT(oport1, *cur_st)
1175  wait(get_time(*cur_st) - sc_time_stamp());
1176  }
1177  else wait();
1178  }
1179 
1180  void clean()
1181  {
1182  delete cur_st;
1183  }
1184 
1185 #ifdef FORSYDE_INTROSPECTION
1186  void bindInfo()
1187  {
1188  boundOutChans.resize(1); // only one output port
1189  boundOutChans[0].port = &oport1;
1190  boundOutChans[0].portType = typeid(T).name();
1191  }
1192 #endif
1193 };
1194 
1196 
1200 template <class T>
1201 class vsource : public dde_process
1202 {
1203 public:
1205 
1207 
1210  vsource(sc_module_name _name,
1211  const std::vector<T>& values,
1212  const std::vector<sc_time>& offsets
1213  ) : dde_process(_name), oport1("oport1"),
1214  values(values), offsets(offsets)
1215  {
1216  if (values.size()<offsets.size())
1217  SC_REPORT_ERROR(name(),"Error matching values and offsets vectors!");
1218 #ifdef FORSYDE_INTROSPECTION
1219  std::stringstream ss;
1220  ss << values;
1221  arg_vec.push_back(std::make_tuple("values", ss.str()));
1222  ss.str("");
1223  ss << offsets;
1224  arg_vec.push_back(std::make_tuple("offsets", ss.str()));
1225 #endif
1226  }
1227 
1229  std::string forsyde_kind() const {return "DDE::vsource";}
1230 private:
1231  std::vector<T> values;
1232  std::vector<sc_time> offsets;
1233  size_t iter;
1234 
1235  //Implementing the abstract semantics
1236  void init()
1237  {
1238  iter = 0;
1239  }
1240 
1241  void prep() {}
1242 
1243  void exec() {}
1244 
1245  void prod()
1246  {
1247  WRITE_MULTIPORT(oport1, ttn_event<T>(abst_ext<T>(values[iter]), offsets[iter]))
1248  wait(offsets[iter] - sc_time_stamp());
1249  iter++;
1250  if (iter == values.size())
1251  {
1252  // Promise no more values
1253  WRITE_MULTIPORT(oport1, ttn_event<T>(abst_ext<T>(), sc_max_time()))
1254  wait();
1255  }
1256  }
1257 
1258  void clean() {}
1259 
1260 #ifdef FORSYDE_INTROSPECTION
1261  void bindInfo()
1262  {
1263  boundOutChans.resize(1); // only one output port
1264  boundOutChans[0].port = &oport1;
1265  boundOutChans[0].portType = typeid(T).name();
1266  }
1267 #endif
1268 };
1269 
1271 
1275 template <class T>
1276 class sink : public dde_process
1277 {
1278 public:
1280 
1282  typedef std::function<void(const ttn_event<T>&)> functype;
1283 
1285 
1288  sink(sc_module_name _name,
1289  functype _func
1290  ) : dde_process(_name), iport1("iport1"), _func(_func)
1291 
1292  {
1293 #ifdef FORSYDE_INTROSPECTION
1294  std::string func_name = std::string(basename());
1295  func_name = func_name.substr(0, func_name.find_last_not_of("0123456789")+1);
1296  arg_vec.push_back(std::make_tuple("_func",func_name+std::string("_func")));
1297 #endif
1298  }
1299 
1301  std::string forsyde_kind() const {return "DDE::sink";}
1302 
1303 private:
1304  ttn_event<T>* val; // The current state of the process
1305 
1307  functype _func;
1308 
1309  //Implementing the abstract semantics
1310  void init()
1311  {
1312  val = new ttn_event<T>;
1313  }
1314 
1315  void prep()
1316  {
1317  *val = iport1.read();
1318  }
1319 
1320  void exec()
1321  {
1322  _func(*val);
1323  }
1324 
1325  void prod() {}
1326 
1327  void clean()
1328  {
1329  delete val;
1330  }
1331 
1332 #ifdef FORSYDE_INTROSPECTION
1333  void bindInfo()
1334  {
1335  boundInChans.resize(1); // only one output port
1336  boundInChans[0].port = &iport1;
1337  }
1338 #endif
1339 };
1340 
1342 
1344 template <class T1, class T2>
1345 class zip : public dde_process
1346 {
1347 public:
1351 
1353 
1356  zip(sc_module_name _name)
1357  :dde_process(_name), iport1("iport1"), iport2("iport2"), oport1("oport1")
1358  { }
1359 
1361  std::string forsyde_kind() const {return "DDE::zip";}
1362 
1363 private:
1364  // inputs and output variables
1365  ttn_event<T1> *next_iev1;
1366  ttn_event<T2> *next_iev2;
1367  abst_ext<T1> *cur_ival1;
1368  abst_ext<T2> *cur_ival2;
1370 
1371  // the current time (local time)
1372  sc_time tl;
1373 
1374  // clocks of the input ports (channel times)
1375  sc_time in1T, in2T;
1376 
1377  void init()
1378  {
1379  next_iev1 = new ttn_event<T1>;
1380  next_iev2 = new ttn_event<T2>;
1381  cur_ival1 = new abst_ext<T1>;
1382  cur_ival2 = new abst_ext<T2>;
1383  in1T = in2T = tl = SC_ZERO_TIME;
1385  }
1386 
1387  void prep()
1388  {
1389  if (in1T == tl)
1390  {
1391  *next_iev1 = iport1.read();
1392  in1T = get_time(*next_iev1);
1393  }
1394  if (in2T == tl)
1395  {
1396  *next_iev2 = iport2.read();
1397  in2T = get_time(*next_iev2);
1398  }
1399 
1400  // update channel clocks and the local clock
1401  tl = std::min(in1T, in2T);
1402 
1403  // update current values
1404  if (get_time(*next_iev1) == tl)
1405  *cur_ival1 = get_value(*next_iev1);
1406  else
1407  *cur_ival1 = abst_ext<T1>();
1408  if (get_time(*next_iev2) == tl)
1409  *cur_ival2 = get_value(*next_iev2);
1410  else
1411  *cur_ival2 = abst_ext<T1>();
1412  }
1413 
1414  void exec()
1415  {
1416  if (is_absent(*cur_ival1) && is_absent(*cur_ival2))
1417  oval->set_abst();
1418  else
1420  std::make_tuple(*cur_ival1,*cur_ival2)
1421  );
1422  }
1423 
1424  void prod()
1425  {
1426  auto temp_event = ttn_event<std::tuple<abst_ext<T1>,abst_ext<T2>>>(*oval,tl);
1427  WRITE_MULTIPORT(oport1,temp_event)
1428  wait(tl - sc_time_stamp());
1429  }
1430 
1431  void clean()
1432  {
1433  delete next_iev1;
1434  delete next_iev2;
1435  delete cur_ival1;
1436  delete cur_ival2;
1437  delete oval;
1438  }
1439 
1440 #ifdef FORSYDE_INTROSPECTION
1441  void bindInfo()
1442  {
1443  boundInChans.resize(2); // two input ports
1444  boundInChans[0].port = &iport1;
1445  boundInChans[0].portType = typeid(T1).name();
1446  boundInChans[1].port = &iport2;
1447  boundInChans[1].portType = typeid(T2).name();
1448  boundOutChans.resize(1); // only one output port
1449  boundOutChans[0].port = &oport1;
1450  boundOutChans[0].portType = typeid(std::tuple<T1,T2>).name(); // FIXME: shouldn't be abst_ext<Tx> instead of Tx?
1451  }
1452 #endif
1453 };
1454 
1456 
1459 template <class T1, std::size_t N>
1460 class zipX : public dde_process
1461 {
1462 public:
1463  std::array<DDE_in<T1>,N> iport;
1465 
1467 
1470  zipX(sc_module_name _name)
1471  :dde_process(_name), oport1("oport1")
1472  { }
1473 
1475  std::string forsyde_kind() const {return "DDE::zipX";}
1476 
1477 private:
1478  // inputs and output variables
1479  std::array<ttn_event<T1>,N> next_ievs;
1480  std::array<abst_ext<T1>,N> cur_ivals;
1482 
1483  // the current time (local time)
1484  sc_time tl;
1485 
1486  // clocks of the input ports (channel times)
1487  std::array<sc_time,N> insT;
1488 
1489  void init()
1490  {
1491  insT.fill(SC_ZERO_TIME);
1492  tl = SC_ZERO_TIME;
1493  oval = new abst_ext< std::array<abst_ext<T1>,N> >();
1494  }
1495 
1496  void prep()
1497  {
1498  for (size_t i=0;i<N;i++)
1499  if (insT[i] == tl)
1500  {
1501  next_ievs[i] = iport[i].read();
1502  insT[i] = get_time(next_ievs[i]);
1503  }
1504 
1505  // update channel clocks and the local clock
1506  tl = *std::min_element(insT.begin(), insT.end());
1507 
1508  // update current values
1509  for (size_t i=0;i<N;i++)
1510  if (get_time(next_ievs[i]) == tl)
1511  cur_ivals[i] = get_value(next_ievs[i]);
1512  else
1513  cur_ivals[i] = abst_ext<T1>();
1514  }
1515 
1516  void exec()
1517  {
1518  if (std::all_of(cur_ivals.begin(), cur_ivals.end(), [](abst_ext<T1> el){
1519  return is_absent(el);
1520  }))
1521  oval->set_abst();
1522  else
1523  *oval = abst_ext< std::array<abst_ext<T1>,N> >(cur_ivals);
1524  }
1525 
1526  void prod()
1527  {
1528  auto temp_event = ttn_event<std::array<abst_ext<T1>,N>>(*oval,tl);
1529  WRITE_MULTIPORT(oport1,temp_event)
1530  wait(tl - sc_time_stamp());
1531  }
1532 
1533  void clean()
1534  {
1535  delete oval;
1536  }
1537 
1538 #ifdef FORSYDE_INTROSPECTION
1539  void bindInfo()
1540  {
1541  boundInChans.resize(N); // N input ports
1542  for (size_t i=0;i<N;i++)
1543  boundInChans[i].port = &iport[i];
1544  boundOutChans.resize(1); // only one output port
1545  boundOutChans[0].port = &oport1;
1546  }
1547 #endif
1548 };
1549 
1551 
1553 template <class T1, class T2>
1554 class unzip : public dde_process
1555 {
1556 public:
1560 
1562 
1565  unzip(sc_module_name _name)
1566  :dde_process(_name), iport1("iport1"), oport1("oport1"), oport2("oport2")
1567  {}
1568 
1570  std::string forsyde_kind() const {return "DDE::unzip";}
1571 private:
1572  // intermediate values
1574  abst_ext<T1>* out_val1;
1575  abst_ext<T2>* out_val2;
1576 
1577  void init()
1578  {
1580  out_val1 = new abst_ext<T1>;
1581  out_val2 = new abst_ext<T2>;
1582  }
1583 
1584  void prep()
1585  {
1586  *in_ev = iport1.read();
1587  }
1588 
1589  void exec()
1590  {
1591  if (is_absent(get_value(*in_ev)))
1592  {
1593  *out_val1 = abst_ext<T1>();
1594  *out_val2 = abst_ext<T2>();
1595  }
1596  else
1597  {
1598  *out_val1 = std::get<0>(unsafe_from_abst_ext(get_value(*in_ev)));
1599  *out_val2 = std::get<1>(unsafe_from_abst_ext(get_value(*in_ev)));
1600  }
1601  }
1602 
1603  void prod()
1604  {
1605  sc_time te(get_time(*in_ev));
1606  WRITE_MULTIPORT(oport1,ttn_event<T1>(*out_val1,te)) // write to the output 1
1607  WRITE_MULTIPORT(oport2,ttn_event<T2>(*out_val2,te)) // write to the output 2
1608  }
1609 
1610  void clean()
1611  {
1612  delete in_ev;
1613  delete out_val1;
1614  delete out_val2;
1615  }
1616 
1617 #ifdef FORSYDE_INTROSPECTION
1618  void bindInfo()
1619  {
1620  boundInChans.resize(1); // only one input port
1621  boundInChans[0].port = &iport1;
1622  boundInChans[0].portType = typeid(std::tuple<T1,T2>).name(); // FIXME: shouldn't be abst_ext<Tx> instead of Tx?
1623  boundOutChans.resize(2); // two output ports
1624  boundOutChans[0].port = &oport1;
1625  boundOutChans[0].portType = typeid(T1).name();
1626  boundOutChans[1].port = &oport2;
1627  boundOutChans[1].portType = typeid(T2).name();
1628  }
1629 #endif
1630 };
1631 
1633 
1636 template <class T1, std::size_t N>
1637 class unzipX : public dde_process
1638 {
1639 public:
1641  std::array<DDE_out<T1>,N> oport;
1642 
1644 
1647  unzipX(sc_module_name _name)
1648  :dde_process(_name), iport1("iport1")
1649  { }
1650 
1652  std::string forsyde_kind() const {return "DDE::unzipX";}
1653 
1654 private:
1655  // intermediate values
1657 
1658  // output events
1659  std::array<ttn_event<T1>,N> oevs;
1660 
1661  sc_time tl;
1662 
1663  void init()
1664  {
1665  in_ev = new ttn_event<std::array<abst_ext<T1>,N>>;
1666  tl = SC_ZERO_TIME;
1667  }
1668 
1669  void prep()
1670  {
1671  *in_ev = iport1.read();
1672  }
1673 
1674  void exec()
1675  {
1676  if (is_absent(*in_ev))
1677  {
1678  for (size_t i=0; i<N; i++)
1679  oevs[i] = ttn_event<T1>(abst_ext<T1>(),tl);
1680  }
1681  else
1682  {
1683  for (size_t i=0; i<N; i++)
1684  oevs[i] = ttn_event<T1>(unsafe_from_abst_ext(*in_ev)[i]);
1685  }
1686  tl = get_time(*in_ev);
1687  }
1688 
1689  void prod()
1690  {
1691  for (size_t i=0; i<N; i++)
1692  WRITE_MULTIPORT(oport[i],oevs[i]) // write to the output i
1693  wait(tl - sc_time_stamp());
1694  }
1695 
1696  void clean()
1697  {
1698  delete in_ev;
1699  }
1700 
1701 #ifdef FORSYDE_INTROSPECTION
1702  void bindInfo()
1703  {
1704  boundInChans.resize(1); // only one input port
1705  boundInChans[0].port = &iport1;
1706  boundOutChans.resize(N); // output ports
1707  for (size_t i=0;i<N;i++)
1708  boundOutChans[i].port = &oport[i];
1709  }
1710 #endif
1711 };
1712 
1713 
1715 
1724 template <class T>
1725 class fanout : public dde_process
1726 {
1727 public:
1730 
1732 
1735  fanout(sc_module_name _name) // module name
1736  : dde_process(_name) { }
1737 
1739  std::string forsyde_kind() const {return "DDE::fanout";}
1740 
1741 private:
1742  // Inputs and output variables
1743  ttn_event<T>* val;
1744 
1745  //Implementing the abstract semantics
1746  void init()
1747  {
1748  val = new ttn_event<T>;
1749  }
1750 
1751  void prep()
1752  {
1753  *val = iport1.read();
1754  }
1755 
1756  void exec() {}
1757 
1758  void prod()
1759  {
1760  WRITE_MULTIPORT(oport1, *val)
1761  }
1762 
1763  void clean()
1764  {
1765  delete val;
1766  }
1767 #ifdef FORSYDE_INTROSPECTION
1768  void bindInfo()
1769  {
1770  boundInChans.resize(1); // only one input port
1771  boundInChans[0].port = &iport1;
1772  boundInChans[0].portType = typeid(T).name();
1773  boundOutChans.resize(1); // only one output port
1774  boundOutChans[0].port = &oport1;
1775  boundOutChans[0].portType = typeid(T).name();
1776  }
1777 #endif
1778 };
1779 
1780 }
1781 }
1782 
1783 #endif
std::function< void(ST &, const ST &, const ttn_event< IT > &)> ns_functype
Type of the next-state function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:355
delay(sc_module_name _name, abst_ext< T > init_val, sc_time delay_time)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:275
Process constructor for a combinational process with two inputs and one output.
Definition: dde_process_constructors.hpp:135
Time-tagged data types.
Definition: tt_event.hpp:32
DDE_in< IT1 > iport1
port for the input channel
Definition: dde_process_constructors.hpp:460
DDE_out< OT > oport1
port for the output channel
Definition: dde_process_constructors.hpp:352
DDE_out< T0 > oport1
port for the output channel
Definition: dde_process_constructors.hpp:53
filterf(sc_module_name _name, std::vector< T > numerators, std::vector< T > denominators)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:897
std::array< DDE_in< T1 >, N > iport
port array for the input channels
Definition: dde_process_constructors.hpp:1463
Process constructor for a delay element.
Definition: dde_process_constructors.hpp:264
std::function< void(ttn_event< T > &, const ttn_event< T > &)> functype
Type of the function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:1112
DDE_in< T > iport1
port for the input channel
Definition: dde_process_constructors.hpp:887
std::function< void(abst_ext< OT > &, const ST &, const ttn_event< IT1 > &, const ttn_event< IT2 > &)> od_functype
Type of the output-decoding function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:468
The namespace for ForSyDe.
Definition: abssemantics.hpp:30
DDE_in< std::array< abst_ext< T1 >, N > > iport1
port for the input channel
Definition: dde_process_constructors.hpp:1640
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1301
fanout(sc_module_name _name)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1735
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:292
The zip process with two inputs and one output.
Definition: dde_process_constructors.hpp:1345
DDE_in< std::tuple< abst_ext< T1 >, abst_ext< T2 > > > iport1
port for the input channel
Definition: dde_process_constructors.hpp:1557
DDE_in< T > iport1
port for the input channel
Definition: dde_process_constructors.hpp:614
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:888
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1229
zip(sc_module_name _name)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1356
DDE_out< OT > oport1
port for the output channel
Definition: dde_process_constructors.hpp:462
DDE_in< T > iport1
port for the input channel
Definition: dde_process_constructors.hpp:1279
DDE_out< std::tuple< abst_ext< T1 >, abst_ext< T2 > > > oport1
port for the output channel
Definition: dde_process_constructors.hpp:1350
mealy2(const sc_module_name &_name, const ns_functype &_ns_func, const od_functype &_od_func, const ST &init_st, const sc_time &delay_time)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:475
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1652
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:388
std::function< void(abst_ext< T0 > &, const abst_ext< T1 > &, const abst_ext< T2 > &)> functype
Type of the function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:143
DDE_in< T2 > iport2
port for the input channel 2
Definition: dde_process_constructors.hpp:139
The unzipX process with a vector of outputs and one input.
Definition: dde_process_constructors.hpp:1637
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:268
Process constructor for implementing a linear filter with fixed step size.
Definition: dde_process_constructors.hpp:884
filter(sc_module_name _name, std::vector< T > numerators, std::vector< T > denominators, sc_time max_step, sc_time min_step=sc_time(0.05, SC_NS), T tol_error=1e-5)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:625
The zipX process with a vector of inputs and one output.
Definition: dde_process_constructors.hpp:1460
vsource(sc_module_name _name, const std::vector< T > &values, const std::vector< sc_time > &offsets)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1210
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1739
zipX(sc_module_name _name)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1470
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:1204
The unzip process with one input and two outputs.
Definition: dde_process_constructors.hpp:1554
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1139
mealy(const sc_module_name &_name, const ns_functype &_ns_func, const od_functype &_od_func, const ST &init_st, const sc_time &delay_time)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:365
unzip(sc_module_name _name)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1565
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:1729
sink(sc_module_name _name, functype _func)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1288
std::function< void(const ttn_event< T > &)> functype
Type of the function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:1282
comb2(sc_module_name _name, functype _func)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:150
The process constructor which defines the abstract semantics of execution.
Definition: abssemantics.hpp:212
DDE_in< T > iport1
port for the input channel
Definition: dde_process_constructors.hpp:267
source(sc_module_name _name, functype _func, ttn_event< T > init_st, unsigned long long take=0)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1118
std::function< void(ST &, const ST &, const ttn_event< IT1 > &, const ttn_event< IT2 > &)> ns_functype
Type of the next-state function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:465
DDE_in< T1 > iport1
port for the input channel 1
Definition: dde_process_constructors.hpp:1348
DDE_in< T > iport1
port for the input channel
Definition: dde_process_constructors.hpp:1728
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1361
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1570
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:76
Process constructor for a source process.
Definition: dde_process_constructors.hpp:1106
DDE_in< T2 > iport2
port for the input channel 2
Definition: dde_process_constructors.hpp:1349
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:615
Process constructor for a Mealy machine with two inputs.
Definition: dde_process_constructors.hpp:457
Process constructor for a sink process.
Definition: dde_process_constructors.hpp:1276
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:498
Process constructor for a source process with vector input.
Definition: dde_process_constructors.hpp:1201
std::function< void(abst_ext< T0 > &, const T1 &)> functype
Type of the function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:56
std::function< void(abst_ext< OT > &, const ST &, const ttn_event< IT > &)> od_functype
Type of the output-decoding function to be passed to the process constructor.
Definition: dde_process_constructors.hpp:358
DDE_out< T2 > oport2
port for the output channel 2
Definition: dde_process_constructors.hpp:1559
DDE_out< T > oport1
port for the output channel
Definition: dde_process_constructors.hpp:1109
Process constructor for a fan-out process with one input and one output.
Definition: dde_process_constructors.hpp:1725
Implements the abstract process in the DDE Model of Computation.
Implements the time-tagged events.
Process constructor for a Mealy machine.
Definition: dde_process_constructors.hpp:348
unzipX(sc_module_name _name)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:1647
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:655
DDE_out< std::array< abst_ext< T1 >, N > > oport1
port for the output channel
Definition: dde_process_constructors.hpp:1464
DDE_out< T0 > oport1
port for the output channel
Definition: dde_process_constructors.hpp:140
DDE_in< T1 > iport1
port for the input channel 1
Definition: dde_process_constructors.hpp:138
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:914
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:163
comb(sc_module_name _name, functype _func)
The constructor requires the module name.
Definition: dde_process_constructors.hpp:63
DDE_in< IT > iport1
port for the input channel
Definition: dde_process_constructors.hpp:351
void set_abst()
Sets absent.
Definition: abst_ext.hpp:63
DDE_in< T1 > iport1
port for the input channel
Definition: dde_process_constructors.hpp:52
DDE_in< IT2 > iport2
port for the input channel
Definition: dde_process_constructors.hpp:461
DDE_out< T1 > oport1
port for the output channel 1
Definition: dde_process_constructors.hpp:1558
std::array< DDE_out< T1 >, N > oport
port array for the output channels
Definition: dde_process_constructors.hpp:1641
Process constructor for a combinational process with one input and one output.
Definition: dde_process_constructors.hpp:49
DDE_out< unsigned int > oport2
port for the sampling signal
Definition: dde_process_constructors.hpp:616
Process constructor for implementing a linear filter.
Definition: dde_process_constructors.hpp:611
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: dde_process_constructors.hpp:1475