source: sources/src/gen_code.cc @ 35

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

Code cleanup.

Add --dynamiclink option to systemcass executable.

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