source: sources/src/gen_code.cc @ 41

Last change on this file since 41 was 41, checked in by buchmann, 15 years ago

Add:

  • openmp support:
    • add flags to test_regression makefile
    • configure.ac now checks for openmp
    • Makefile.am add openmp flags
    • a new testbench to check benefits due to openmp
File size: 18.7 KB
Line 
1/*------------------------------------------------------------\
2|                                                             |
3| Tool    :                  systemcass                       |
4|                                                             |
5| File    :                 gen_code.cc                       |
6|                                                             |
7| Author  :                 Taktak Sami                       |
8|                           Buchmann Richard                  |
9|                                                             |
10| Date    :                   09_07_2004                      |
11|                                                             |
12\------------------------------------------------------------*/
13
14/*
15 * This file is part of the Disydent Project
16 * Copyright (C) Laboratoire LIP6 - Département ASIM
17 * Universite Pierre et Marie Curie
18 *
19 * Home page          : http://www-asim.lip6.fr/disydent
20 * E-mail             : mailto:richard.buchmann@lip6.fr
21 *
22 * This library is free software; you  can redistribute it and/or modify it
23 * under the terms  of the GNU Library General Public  License as published
24 * by the Free Software Foundation; either version 2 of the License, or (at
25 * your option) any later version.
26 *
27 * Disydent is distributed  in the hope  that it  will be
28 * useful, but WITHOUT  ANY WARRANTY; without even the  implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
30 * Public License for more details.
31 *
32 * You should have received a copy  of the GNU General Public License along
33 * with the GNU C Library; see the  file COPYING. If not, write to the Free
34 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 */
36#if defined(__linux__)
37#include <linux/limits.h>
38#elif defined(WIN32)
39#include <windows.h>
40#endif
41#include <cstring>
42#include <cstdio>
43#include <cstdlib>
44#include <iostream>
45#include <fstream>
46
47#include "internal.h"
48#include "gen_code.h"
49#include "sc_module.h"
50#include "sc_ver.h"
51#include "process_dependency.h"
52#ifdef HAVE_CONFIG_H
53#include "config.h"
54#endif
55
56#ifdef _OPENMP
57#include <omp.h>
58#endif
59
60#ifdef CONFIG_CHECK_FSM_RULES
61#include "fsm_rules.h"
62#define fsm_check_flag "-DCONFIG_CHECK_FSM_RULES"
63#else
64#define fsm_check_flag
65#endif
66
67#define casc_cflags GENERATED_MODULE_CFLAGS " " fsm_check_flag
68
69// Enable CPP call, this is useful for typeinfo-enabled classes
70#define CPP_CALL
71
72using namespace std;
73
74namespace sc_core {
75
76static void PrintCall(std::ostream&, const method_process_t &);
77static void open_temp(std::ofstream&, char *);
78typedef void (*CASC_ENTRY_FUNC) (void *);
79typedef union { unsigned long long int integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;
80
81const char *
82get_pmf_type ()
83{
84  switch (sizeof (SC_ENTRY_FUNC)) {
85  case 4:
86    // G4 pointer-to-member-function style
87    return "unsigned long int";
88  case 8:
89    // PC pointer-to-member-function style
90    return "unsigned long long int";
91  default:
92    cerr << "Internal Error : Unsupported pointer-to-member-function"
93            "(size: " << sizeof (SC_ENTRY_FUNC) << ").\n"
94            "Please try --nodynamiclink option.\n";
95    exit(21072009);
96  };
97}
98
99static
100ostream& operator << (ostream &o, const SC_ENTRY_FUNC &f)
101{
102  register fct p;
103  p.integer = 0;
104  p.pmf = f;
105  return o << "0x" << hex << p.integer << "ULL";
106}
107
108static 
109void
110PrintCall         (std::ostream           &o,
111                   const method_process_t &m)
112{
113  SC_ENTRY_FUNC func  = m.func;
114  if (print_schedule)
115    o << "    fprintf(stderr,\"evaluation de "
116      << m.module->name() << "->" << m.name << "()\\n\");\n";
117  o << " p.integer = " << func << ";\n";
118#ifdef CPP_CALL
119  o << " (((sc_module*)(" << m.module << "))->*(p.pmf)) (); /* " 
120    << m.module->name () << "->" << m.name << "() */\n";
121#else
122  o << " p.pf((void *)" 
123    << m.module << "); /* " 
124    << m.module->name () << "->" << m.name << "() */\n";
125#endif
126}
127
128static
129bool
130is_exist (const char *temp)
131{
132#if 0
133  cerr << "testing " << temp << "\n";
134#endif
135  ifstream o;
136  o.open (temp,ios::in);
137  if (o.is_open () == false)
138    return false;
139#if 0
140  cerr << "opened\n";
141  cerr << "peek : " << (int) o.peek() << endl;
142#endif
143  if (o.peek () == -1)
144    return false;
145  return true;
146}
147
148static 
149void
150open_temp          (ofstream &o,
151                    char     *temp)
152{
153/*
154  srand (time (NULL));
155    int r = rand () % 1000;
156*/
157  pid_t pid = getpid();
158  int r = -1;
159  do {
160    sprintf (temp, "%s/scheduling-%d-%x.cc", temporary_dir, pid, ++r);
161  } while (is_exist (temp));
162
163  o.open (temp,ios::out);
164  if (o.is_open () == false)
165  {
166    cerr << "Error : Unable to open a file to write scheduling code.\n";
167    exit (30032005);
168  }
169
170#ifdef CONFIG_DEBUG
171  cerr << "opened temporary filename : " << temp << "\n";
172#endif
173 
174  sprintf (temp, "scheduling-%d-%x", pid, r++);
175}
176
177static
178char *
179gen_transition (ofstream              &o,
180                method_process_list_t &transition_func_list)
181{
182  // transitions
183  o << "\ninline void transition(void)\n{\n";
184  if (transition_func_list.empty () == false) {
185    o << " /* fonctions de transition */\n"
186      << " register fct p;\n";
187    method_process_list_t::iterator mm;
188    for( mm = transition_func_list.begin(); mm != transition_func_list.end(); ++mm)
189    {
190      PrintCall (o, **mm);
191    }
192  }
193  o << "}\n";
194}
195
196static
197char *
198gen_moore (ofstream              &o,
199           method_process_list_t &moore_func_list)
200{
201  // Moore generations (sequential functions)
202  o << "\ninline void moore_generation (void)\n{\n";
203  if (moore_func_list.empty () == false) {
204    o << "  /* fonctions de generation de Moore */\n"
205      << " register fct p;\n";
206    method_process_list_t::reverse_iterator mm;
207    for( mm = moore_func_list.rbegin(); mm != moore_func_list.rend(); ++mm)
208    {
209      PrintCall (o, **mm);
210    }
211  }
212  o << " \n}\n";
213}
214
215static
216char *
217gen_mealy (ofstream                &o,
218           strong_component_list_t &strongcomponents)
219{
220  // Mealy generations (combinational functions only)
221  o << "\nextern void mealy_generation (void)\n{\n";
222  if (strongcomponents.empty ())
223    return NULL;
224   o << "  register fct p;\n"
225    << "\n\n  /* fonctions de mealy */\n";
226#ifdef NO_STATIC_SCHEDULE
227  o << "\n  do {\n    unstable = 0;\n";
228#endif
229  strong_component_list_t::iterator ss;
230  for ( ss = strongcomponents.begin(); ss != strongcomponents.end(); ++ss) {
231    if ( (*ss)->size() == 1) {
232      /* un seul element dans le strong component */
233      method_process_t *m = (method_process_t*)(*((*ss)->begin ()));
234      PrintCall (o, *m);
235      continue;
236    } else {
237      /* plusieurs elements dans le strong component */
238#ifndef NO_STATIC_SCHEDULE
239      o << "\n  do {\n    unstable = 0;\n";
240#endif
241      component_list_t::reverse_iterator rev_mm;
242      for( rev_mm = (*ss)->rbegin(); rev_mm != (*ss)->rend(); ++rev_mm) {
243        method_process_t *m = (method_process_t*) *rev_mm;
244        PrintCall (o, *m);
245      }
246#ifndef NO_STATIC_SCHEDULE
247      o << "  } while ( unstable );\n\n";
248#endif
249    }
250  }
251#ifdef NO_STATIC_SCHEDULE
252  o << "  } while ( unstable );\n\n";
253#else
254  o << "\tunstable = 0;\n";
255#endif
256}
257
258static
259char *
260gen_mealy (ofstream                &o,
261           ProcessDependencyList   &mealy_func_list)
262{
263  // Mealy generations (combinational functions only)
264  o << "\nextern void mealy_generation (void)\n{\n";
265  o << "  register fct p;\n"
266    << "\n\n  /* fonctions de mealy */\n";
267  ProcessDependencyList::iterator it;
268  for (it = mealy_func_list.begin(); it != mealy_func_list.end(); ++it)
269  {
270    const method_process_t *m = *it;
271    PrintCall (o, *m);
272  }
273}
274
275char *
276gen_scheduling_code_for_dynamic_link (
277               method_process_list_t           &transition_func_list,
278               method_process_list_t           &moore_func_list,
279               strong_component_list_t         &strongcomponents)
280{
281  if (dump_stage)
282    cerr << "Generating C code for scheduling...\n";
283
284  // open temporary file
285  ofstream o;
286  char base_name[PATH_MAX];
287  open_temp (o, base_name);
288 
289  if (! o.good ()) {
290    perror("scheduling: open file\n");
291    exit(-1);
292  }
293
294  o << "// generated by " << sc_version () << endl
295    << "#include <casc.h>\n\n"
296    << "#include <cstdio>\n\n"
297//  << "#include <iostream>\n\n"
298    << "namespace sc_core {\n"
299    << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
300    << " typedef void (*CASC_ENTRY_FUNC)(void *);\n";
301
302  const char *pmf_type = get_pmf_type ();
303
304  o << " typedef union { " 
305    << pmf_type
306    << " integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n"; 
307 
308  gen_transition (o, transition_func_list); 
309  gen_moore      (o, moore_func_list); 
310  gen_mealy      (o, strongcomponents);
311
312  o << " \n}\n";
313  o << "\n} // end of sc_core namespace\n";
314 
315  o.flush ();
316  o.close ();
317
318  // add "cc" extension
319  char file_name[PATH_MAX];
320  strncpy(file_name, base_name, PATH_MAX);
321  file_name[strlen (base_name)] = '\0';
322  strcat(file_name, ".cc");
323  rename (base_name, file_name);
324 
325  if (edit_schedule)
326    run_schedule_editor (file_name);
327 
328  if (dump_stage)
329    cerr << "Generating C code for scheduling done.\n";
330
331  return strdup(base_name);
332}
333
334char *
335gen_scheduling_code_for_dynamic_link   (
336            method_process_list_t &transition_func_list,
337            method_process_list_t &moore_func_list,
338            ProcessDependencyList &mealy_func_list)
339{
340  if (dump_stage)
341    cerr << "Generating C code for scheduling...\n";
342
343  // open temporary file
344  ofstream o;
345  char base_name[PATH_MAX];
346  open_temp (o, base_name);
347 
348  if (! o.good ()) {
349    perror("scheduling: open file\n");
350    exit(-1);
351  }
352
353  o << "// generated by " << sc_version () << endl
354    << "#include <casc.h>\n\n"
355    << "#include <cstdio>\n\n"
356//    << "#include <iostream>\n\n"
357    << "namespace sc_core {\n"
358    << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
359    << " typedef void (*CASC_ENTRY_FUNC)(void *);\n"
360    << " typedef union { unsigned long long int integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n"; 
361 
362  gen_transition (o, transition_func_list); 
363  gen_moore      (o, moore_func_list); 
364  gen_mealy      (o, mealy_func_list);
365
366  o << "\n}\n";
367  o << "\n} // end of sc_core namespace\n";
368 
369  o.flush ();
370  o.close ();
371 
372  // add "cc" extension
373  char file_name[PATH_MAX];
374  strncpy(file_name, base_name, PATH_MAX);
375  file_name[strlen (base_name)] = '\0';
376  strcat(file_name, ".cc");
377  rename (base_name, file_name);
378
379  if (edit_schedule)
380    run_schedule_editor (file_name);
381
382  if (dump_stage)
383    cerr << "Generating C code for scheduling done.\n";
384 
385  return strdup(base_name);
386}
387
388/* base_name est la base du nom du fichier C++
389 * casc_cflags est une string qui correspond à $(INCLUDE) d'un Makefile
390 */
391void 
392compile_code          (const char *base_name, 
393                       const char *casc_cflags2) 
394{
395  if (dump_stage) 
396    cerr << "Compiling C/C++ code for scheduling...\n";
397  char compil_str[512];
398  const char *compiler = getenv ("CXX");
399  const char *systemc_dir = getenv ("SYSTEMCASS");
400//  const char *target_arch = getenv ("TARGET_ARCH");
401  const char *default_compiler =
402#ifdef CPP_CALL
403    "g++";
404#else
405    "gcc";
406#endif
407
408  compiler = (compiler == NULL)?default_compiler:compiler;
409  if (systemc_dir == NULL) {
410    systemc_dir = getenv ("SYSTEMC");
411    if (systemc_dir == NULL) {
412      cerr << "Error : set SYSTEMCASS or SYSTEMC environnement variable "
413              "to the SYSTEMCASS directory.\n";
414      exit (-1);
415    }
416  }
417  //target_arch = (target_arch == NULL)?"":target_arch;
418 
419  char target_name[128];
420  char source_name[128];
421  sprintf (target_name, "%s.lo", base_name);
422  sprintf (source_name, "%s.cc", base_name);
423 
424  if (keep_generated_code)
425  { 
426    char lg_cde[256];
427    sprintf (lg_cde, "mkdir -p %s", generated_files_dir);
428    system(lg_cde);
429    sprintf(lg_cde, "cp %s/%s %s/", 
430            temporary_dir, source_name, generated_files_dir);
431    if (dump_stage) 
432      cerr << "$ " << lg_cde << "\n";
433    system(lg_cde);
434    sprintf(lg_cde, "(cd %s ; indent %s)", 
435            generated_files_dir, source_name);
436    if (dump_stage) 
437      cerr << "$ " << lg_cde << "\n";
438    system(lg_cde);
439  }
440  /* ******* */
441  /* COMPILE */
442  /* ******* */
443  const char *commandline_template =
444#if defined(CONFIG_OS_DARWIN)
445    "(cd %s ;"                     " %s %s -DSCHEDULING_BY_CASC -I%s/include -fno-common -dynamic -o %s -c %s)"
446#elif defined(CONFIG_OS_LINUX)
447    "(cd %s ; libtool --mode=compile %s %s -DSCHEDULING_BY_CASC -I%s/include -shared -o %s -c %s)"
448#else
449    "(cd %s ;"                     " %s %s -DSCHEDULING_BY_CASC -I%s/include -dynamiclib -o %s -c %s)"
450#endif
451    ;
452
453  string cflags = casc_cflags;
454  if (use_openmp)
455    cflags += " -fopenmp";
456
457  sprintf(compil_str, 
458      commandline_template,
459      temporary_dir,
460      compiler, 
461      cflags.c_str(), 
462      systemc_dir, 
463      target_name,
464      source_name);
465
466  if (dump_stage) 
467    cerr << "Executing command : " << compil_str << "\n";
468 
469  if (system(compil_str)) {
470    perror("compil : system");
471    exit(-1);
472  }
473
474  /* **** */
475  /* LINK */
476  /* **** */
477  sprintf (target_name, "%s.la", base_name);
478
479#ifdef CONFIG_OS_LINUX
480  sprintf (source_name, "%s.lo", base_name);
481  sprintf(compil_str, "(cd %s ; pwd ; libtool --mode=link %s %s -module -shared -o %s %s -rpath /tmp)", /* -L. -L%s/lib-%s */ 
482     temporary_dir, compiler, casc_cflags, /*systemc_dir, target_arch,*/ 
483     target_name, source_name);
484#else
485  sprintf (source_name, "%s.o", base_name);
486  sprintf(compil_str, "(cd %s ; pwd ; libtool -dynamic -o %s %s)", 
487     temporary_dir, target_name, source_name);
488#endif
489
490  if (dump_stage) 
491    cerr << "Executing command : " << compil_str << "\n";
492
493  if (system(compil_str)) {
494    perror("compil : system");
495    exit(-1);
496  }
497
498 /*
499  sprintf(compil_str, "(cd %s ; rm -f %s.o %s.lo)",
500          temporary_dir, base_name, base_name);
501  if (dump_stage)
502    cerr << "$ " << compil_str << "\n";
503*/
504
505  system(compil_str);
506  if (dump_stage) 
507    cerr << "Compiling done.\n";
508}
509
510/* ********************************
511 * Function for static scheduling
512 */
513struct function_call {
514  fct      *function;
515  void    **instance;
516  int       func_number;
517};
518static function_call pf[3];
519
520void
521get_function_call (function_call         &pf, 
522                   method_process_list_t &func_list)
523{
524  pf.func_number = func_list.size ();
525  pf.function = (fct*)   malloc (sizeof (fct)   * pf.func_number);
526  pf.instance = (void**) malloc (sizeof (void*) * pf.func_number);
527  method_process_list_t::iterator mm;
528  int i;
529  for (mm = func_list.begin(), i = 0; mm != func_list.end(); ++mm, ++i)
530  {
531    const method_process_t *mp = *mm;
532    pf.function[i].pmf = (mp->func);
533    pf.instance[i] = (void*)(mp->module);
534  }
535}
536
537void
538get_function_call (function_call &pf, 
539                   ProcessDependencyList &func_list)
540{
541  pf.func_number = func_list.size ();
542  pf.function = (fct*)   malloc (sizeof (fct)   * pf.func_number);
543  pf.instance = (void**) malloc (sizeof (void*) * pf.func_number);
544  ProcessDependencyList::iterator it;
545  int i;
546  for (i = 0, it = func_list.begin(); it != func_list.end(); ++it, ++i)
547  {
548    const method_process_t *mp = *it;
549    pf.function[i].pmf = (mp->func);
550    pf.instance[i] = (void*)(mp->module);
551  }
552}
553
554void
555gen_scheduling_code_for_static_func (
556            method_process_list_t &transition_func_list,
557            method_process_list_t &moore_func_list,
558            ProcessDependencyList &mealy_func_list)
559{
560  if (dump_stage)
561    cerr << "Generating scheduling...\n";
562
563  get_function_call (pf[0], transition_func_list);
564  get_function_call (pf[1], moore_func_list);
565  get_function_call (pf[2], mealy_func_list);
566
567  if (dump_stage)
568    cerr << "Generating scheduling done.\n";
569}
570
571void
572call_functions (function_call &fc)
573{
574  int n = fc.func_number;
575  int i;
576  for (i = 0; i < n; ++i)
577  {
578#if 0 //defined(CONFIG_DEBUG)
579    sc_module *m = (sc_module*)(fc.instance[i]);
580    cerr << m->name () << endl;
581#endif
582    fc.function[i].pf (fc.instance[i]);
583  }
584}
585
586void
587call_functions_in_parallel (function_call &fc)
588{
589  int n = fc.func_number;
590  int i;
591  #pragma omp parallel for
592  for (i = 0; i < n; ++i)
593  {
594#if 0 //defined(CONFIG_DEBUG)
595    sc_module *m = (sc_module*)(fc.instance[i]);
596    cerr << m->name () << endl;
597    cerr << "thread #" << omp_get_thread_num () << endl;
598#endif
599    fc.function[i].pf (fc.instance[i]);
600  }
601}
602
603void static_mealy_generation ()
604{
605  call_functions (pf[2]);
606}
607
608void static_simulate_1_cycle (void) 
609{
610#ifdef CONFIG_CHECK_FSM_RULES
611  casc_fsm_step = TRANSITION;
612#endif
613  call_functions (pf[0]); // transition
614  update     ();
615#ifdef CONFIG_CHECK_FSM_RULES
616  casc_fsm_step = GEN_MOORE;
617#endif
618  call_functions_in_parallel (pf[1]); // moore generation
619#ifdef CONFIG_CHECK_FSM_RULES
620  casc_fsm_step = GEN_MEALY;
621#endif
622  call_functions (pf[2]); // mealy generation
623#ifdef CONFIG_CHECK_FSM_RULES
624  casc_fsm_step = STIMULI;
625#endif
626}
627
628/* ***************************************
629 * Function for quasi static scheduling
630 */
631
632static method_process_list_t   func_list[2];
633static strong_component_list_t quasistatic_list;
634
635static 
636void
637Call         (const method_process_t &m)
638{
639  sc_module        *mod  = m.module;
640  SC_ENTRY_FUNC     func = m.func;
641//  CASC_ENTRY_FUNC   func = reinterpret_cast<CASC_ENTRY_FUNC> (m.func);
642  (mod->*func) ();
643}
644
645void quasistatic_mealy_generation ()
646{
647  strong_component_list_t::iterator ss;
648  for ( ss = quasistatic_list.begin(); ss != quasistatic_list.end(); ++ss) {
649    if ( (*ss)->size() == 1) {
650      /* un seul element dans le strong component */
651      method_process_t *m = (method_process_t*)(*((*ss)->begin ()));
652      Call (*m);
653      continue;
654    } else {
655      /* plusieurs elements dans le strong component */
656      do {
657        unstable = 0;
658        component_list_t::reverse_iterator rev_mm;
659        for( rev_mm = (*ss)->rbegin(); rev_mm != (*ss)->rend(); ++rev_mm) {
660          method_process_t *m = (method_process_t*) *rev_mm;
661          Call (*m);
662        }
663      } while ( unstable );
664    }
665  }
666}
667
668void quasistatic_simulate_1_cycle (void) 
669{
670#ifdef CONFIG_CHECK_FSM_RULES
671  casc_fsm_step = TRANSITION;
672#endif
673  method_process_list_t::iterator mm;
674  for( mm = func_list[0].begin(); mm != func_list[0].end(); ++mm)
675  {
676    method_process_t &m    = **mm;
677    Call (m);
678  }
679  update     ();
680#ifdef CONFIG_CHECK_FSM_RULES
681  casc_fsm_step = GEN_MOORE;
682#endif
683  for( mm = func_list[1].begin(); mm != func_list[1].end(); ++mm)
684  {
685    method_process_t &m    = **mm;
686    Call (m);
687  }
688#ifdef CONFIG_CHECK_FSM_RULES
689  casc_fsm_step = GEN_MEALY;
690#endif
691  quasistatic_mealy_generation ();
692#ifdef CONFIG_CHECK_FSM_RULES
693  casc_fsm_step = STIMULI;
694#endif
695}
696
697void
698gen_scheduling_code_for_quasistatic_func (
699            method_process_list_t   &transition_func_list,
700            method_process_list_t   &moore_func_list,
701            strong_component_list_t &mealy_func_list)
702{
703  if (dump_stage)
704    cerr << "Generating quasi static scheduling...\n";
705
706  func_list[0]     = transition_func_list;
707  func_list[1]     = moore_func_list;
708  quasistatic_list = mealy_func_list;
709
710  if (dump_stage)
711    cerr << "Generating quasi static scheduling done.\n";
712}
713} // end of sc_core namespace
714
715
Note: See TracBrowser for help on using the repository browser.