source: sources/src/gen_code.cc @ 38

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

Now detects if SystemCASS correctly handles runtime compilation with the current architecture. SystemCASS exits if runtime compilation is not supported. Use --nodynamiclink options if it exits. This may occur on 64 bits machines.

Usage help is more readable.

Code cleanup.

Add some code for the coming soon openMP feature.

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