source: sources/src/gen_code.cc @ 47

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

This patch simplifies SystemCASS.

Remove:

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