source: sources/src/gen_code.cc@ 42

Last change on this file since 42 was 41, checked in by buchmann, 17 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
RevLine 
[1]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 */
[27]36#if defined(__linux__)
[17]37#include <linux/limits.h>
[27]38#elif defined(WIN32)
[17]39#include <windows.h>
40#endif
[31]41#include <cstring>
42#include <cstdio>
43#include <cstdlib>
44#include <iostream>
45#include <fstream>
[1]46
[27]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
[1]55
[41]56#ifdef _OPENMP
57#include <omp.h>
58#endif
59
[27]60#ifdef CONFIG_CHECK_FSM_RULES
61#include "fsm_rules.h"
62#define fsm_check_flag "-DCONFIG_CHECK_FSM_RULES"
[1]63#else
64#define fsm_check_flag
65#endif
66
[27]67#define casc_cflags GENERATED_MODULE_CFLAGS " " fsm_check_flag
[1]68
[27]69// Enable CPP call, this is useful for typeinfo-enabled classes
70#define CPP_CALL
[1]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
[38]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
[1]99static
100ostream& operator << (ostream &o, const SC_ENTRY_FUNC &f)
101{
[35]102 register fct p;
103 p.integer = 0;
104 p.pmf = f;
105 return o << "0x" << hex << p.integer << "ULL";
[1]106}
107
108static
109void
110PrintCall (std::ostream &o,
111 const method_process_t &m)
112{
[41]113 SC_ENTRY_FUNC func = m.func;
[1]114 if (print_schedule)
115 o << " fprintf(stderr,\"evaluation de "
[41]116 << m.module->name() << "->" << m.name << "()\\n\");\n";
[1]117 o << " p.integer = " << func << ";\n";
[27]118#ifdef CPP_CALL
[1]119 o << " (((sc_module*)(" << m.module << "))->*(p.pmf)) (); /* "
[41]120 << m.module->name () << "->" << m.name << "() */\n";
[1]121#else
122 o << " p.pf((void *)"
[41]123 << m.module << "); /* "
124 << m.module->name () << "->" << m.name << "() */\n";
[1]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,
[41]151 char *temp)
[1]152{
153/*
[41]154 srand (time (NULL));
155 int r = rand () % 1000;
[1]156*/
157 pid_t pid = getpid();
158 int r = -1;
[41]159 do {
160 sprintf (temp, "%s/scheduling-%d-%x.cc", temporary_dir, pid, ++r);
[1]161 } while (is_exist (temp));
162
163 o.open (temp,ios::out);
[41]164 if (o.is_open () == false)
[1]165 {
[41]166 cerr << "Error : Unable to open a file to write scheduling code.\n";
[1]167 exit (30032005);
168 }
169
[27]170#ifdef CONFIG_DEBUG
[1]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{
[41]182 // transitions
[1]183 o << "\ninline void transition(void)\n{\n";
184 if (transition_func_list.empty () == false) {
185 o << " /* fonctions de transition */\n"
[41]186 << " register fct p;\n";
187 method_process_list_t::iterator mm;
[1]188 for( mm = transition_func_list.begin(); mm != transition_func_list.end(); ++mm)
189 {
190 PrintCall (o, **mm);
191 }
[41]192 }
[1]193 o << "}\n";
194}
195
196static
197char *
198gen_moore (ofstream &o,
199 method_process_list_t &moore_func_list)
200{
[41]201 // Moore generations (sequential functions)
[1]202 o << "\ninline void moore_generation (void)\n{\n";
[41]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;
[1]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{
[41]220 // Mealy generations (combinational functions only)
[1]221 o << "\nextern void mealy_generation (void)\n{\n";
[41]222 if (strongcomponents.empty ())
[1]223 return NULL;
[41]224 o << " register fct p;\n"
225 << "\n\n /* fonctions de mealy */\n";
[1]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 */
[41]233 method_process_t *m = (method_process_t*)(*((*ss)->begin ()));
[1]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) {
[41]243 method_process_t *m = (method_process_t*) *rev_mm;
[1]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{
[41]263 // Mealy generations (combinational functions only)
[1]264 o << "\nextern void mealy_generation (void)\n{\n";
265 o << " register fct p;\n"
[35]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 }
[1]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
[35]284 // open temporary file
285 ofstream o;
[1]286 char base_name[PATH_MAX];
[35]287 open_temp (o, base_name);
[1]288
[35]289 if (! o.good ()) {
[1]290 perror("scheduling: open file\n");
291 exit(-1);
292 }
293
294 o << "// generated by " << sc_version () << endl
[35]295 << "#include <casc.h>\n\n"
296 << "#include <cstdio>\n\n"
297// << "#include <iostream>\n\n"
298 << "namespace sc_core {\n"
[1]299 << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
[35]300 << " typedef void (*CASC_ENTRY_FUNC)(void *);\n";
[38]301
302 const char *pmf_type = get_pmf_type ();
303
[1]304 o << " typedef union { "
305 << pmf_type
306 << " integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
[41]307
308 gen_transition (o, transition_func_list);
309 gen_moore (o, moore_func_list);
[35]310 gen_mealy (o, strongcomponents);
[1]311
312 o << " \n}\n";
313 o << "\n} // end of sc_core namespace\n";
314
315 o.flush ();
[41]316 o.close ();
[1]317
[41]318 // add "cc" extension
[1]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
[41]343 // open temporary file
344 ofstream o;
[1]345 char base_name[PATH_MAX];
[41]346 open_temp (o, base_name);
[1]347
[41]348 if (! o.good ()) {
[1]349 perror("scheduling: open file\n");
350 exit(-1);
351 }
352
353 o << "// generated by " << sc_version () << endl
[41]354 << "#include <casc.h>\n\n"
355 << "#include <cstdio>\n\n"
356// << "#include <iostream>\n\n"
357 << "namespace sc_core {\n"
[1]358 << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
[41]359 << " typedef void (*CASC_ENTRY_FUNC)(void *);\n"
[1]360 << " typedef union { unsigned long long int integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
[41]361
362 gen_transition (o, transition_func_list);
363 gen_moore (o, moore_func_list);
[35]364 gen_mealy (o, mealy_func_list);
[1]365
366 o << "\n}\n";
367 o << "\n} // end of sc_core namespace\n";
368
369 o.flush ();
[41]370 o.close ();
[1]371
[41]372 // add "cc" extension
[1]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)
[38]396 cerr << "Compiling C/C++ code for scheduling...\n";
[1]397 char compil_str[512];
[38]398 const char *compiler = getenv ("CXX");
[1]399 const char *systemc_dir = getenv ("SYSTEMCASS");
400// const char *target_arch = getenv ("TARGET_ARCH");
[41]401 const char *default_compiler =
[27]402#ifdef CPP_CALL
[41]403 "g++";
[1]404#else
[41]405 "gcc";
[1]406#endif
407
408 compiler = (compiler == NULL)?default_compiler:compiler;
[41]409 if (systemc_dir == NULL) {
[1]410 systemc_dir = getenv ("SYSTEMC");
411 if (systemc_dir == NULL) {
[41]412 cerr << "Error : set SYSTEMCASS or SYSTEMC environnement variable "
[1]413 "to the SYSTEMCASS directory.\n";
[41]414 exit (-1);
[1]415 }
[41]416 }
[1]417 //target_arch = (target_arch == NULL)?"":target_arch;
418
419 char target_name[128];
420 char source_name[128];
[36]421 sprintf (target_name, "%s.lo", base_name);
[1]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 /* ******* */
[27]443 const char *commandline_template =
444#if defined(CONFIG_OS_DARWIN)
[41]445 "(cd %s ;" " %s %s -DSCHEDULING_BY_CASC -I%s/include -fno-common -dynamic -o %s -c %s)"
[27]446#elif defined(CONFIG_OS_LINUX)
[41]447 "(cd %s ; libtool --mode=compile %s %s -DSCHEDULING_BY_CASC -I%s/include -shared -o %s -c %s)"
[1]448#else
[41]449 "(cd %s ;" " %s %s -DSCHEDULING_BY_CASC -I%s/include -dynamiclib -o %s -c %s)"
[1]450#endif
[41]451 ;
[38]452
453 string cflags = casc_cflags;
454 if (use_openmp)
455 cflags += " -fopenmp";
456
[27]457 sprintf(compil_str,
[41]458 commandline_template,
459 temporary_dir,
460 compiler,
461 cflags.c_str(),
462 systemc_dir,
463 target_name,
464 source_name);
[1]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 /* **** */
[36]477 sprintf (target_name, "%s.la", base_name);
[1]478
[27]479#ifdef CONFIG_OS_LINUX
[1]480 sprintf (source_name, "%s.lo", base_name);
[36]481 sprintf(compil_str, "(cd %s ; pwd ; libtool --mode=link %s %s -module -shared -o %s %s -rpath /tmp)", /* -L. -L%s/lib-%s */
[41]482 temporary_dir, compiler, casc_cflags, /*systemc_dir, target_arch,*/
[1]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)",
[41]487 temporary_dir, target_name, source_name);
[1]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);
[41]544 ProcessDependencyList::iterator it;
[1]545 int i;
[41]546 for (i = 0, it = func_list.begin(); it != func_list.end(); ++it, ++i)
547 {
548 const method_process_t *mp = *it;
[1]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 {
[27]578#if 0 //defined(CONFIG_DEBUG)
[1]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
[41]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
[1]603void static_mealy_generation ()
604{
605 call_functions (pf[2]);
606}
607
608void static_simulate_1_cycle (void)
609{
[27]610#ifdef CONFIG_CHECK_FSM_RULES
[35]611 casc_fsm_step = TRANSITION;
[1]612#endif
613 call_functions (pf[0]); // transition
614 update ();
[27]615#ifdef CONFIG_CHECK_FSM_RULES
[35]616 casc_fsm_step = GEN_MOORE;
[1]617#endif
[41]618 call_functions_in_parallel (pf[1]); // moore generation
[27]619#ifdef CONFIG_CHECK_FSM_RULES
[35]620 casc_fsm_step = GEN_MEALY;
[1]621#endif
622 call_functions (pf[2]); // mealy generation
[27]623#ifdef CONFIG_CHECK_FSM_RULES
[35]624 casc_fsm_step = STIMULI;
[1]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}
[41]644
[1]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 */
[41]651 method_process_t *m = (method_process_t*)(*((*ss)->begin ()));
[1]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) {
[41]660 method_process_t *m = (method_process_t*) *rev_mm;
[1]661 Call (*m);
662 }
663 } while ( unstable );
664 }
665 }
666}
667
668void quasistatic_simulate_1_cycle (void)
669{
[27]670#ifdef CONFIG_CHECK_FSM_RULES
[35]671 casc_fsm_step = TRANSITION;
[1]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 ();
[27]680#ifdef CONFIG_CHECK_FSM_RULES
[35]681 casc_fsm_step = GEN_MOORE;
[1]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 }
[27]688#ifdef CONFIG_CHECK_FSM_RULES
[35]689 casc_fsm_step = GEN_MEALY;
[1]690#endif
691 quasistatic_mealy_generation ();
[27]692#ifdef CONFIG_CHECK_FSM_RULES
[35]693 casc_fsm_step = STIMULI;
[1]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.