source: sources/src/gen_code.cc@ 40

Last change on this file since 40 was 38, checked in by buchmann, 17 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
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
[27]56#ifdef CONFIG_CHECK_FSM_RULES
57#include "fsm_rules.h"
58#define fsm_check_flag "-DCONFIG_CHECK_FSM_RULES"
[1]59#else
60#define fsm_check_flag
61#endif
62
[27]63#define casc_cflags GENERATED_MODULE_CFLAGS " " fsm_check_flag
[1]64
[27]65// Enable CPP call, this is useful for typeinfo-enabled classes
66#define CPP_CALL
[1]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
[38]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
[1]95static
96ostream& operator << (ostream &o, const SC_ENTRY_FUNC &f)
97{
[35]98 register fct p;
99 p.integer = 0;
100 p.pmf = f;
101 return o << "0x" << hex << p.integer << "ULL";
[1]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";
[27]114#ifdef CPP_CALL
[1]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
[27]166#ifdef CONFIG_DEBUG
[1]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"
[35]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 }
[1]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
[35]280 // open temporary file
281 ofstream o;
[1]282 char base_name[PATH_MAX];
[35]283 open_temp (o, base_name);
[1]284
[35]285 if (! o.good ()) {
[1]286 perror("scheduling: open file\n");
287 exit(-1);
288 }
289
290 o << "// generated by " << sc_version () << endl
[35]291 << "#include <casc.h>\n\n"
292 << "#include <cstdio>\n\n"
293// << "#include <iostream>\n\n"
294 << "namespace sc_core {\n"
[1]295 << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
[35]296 << " typedef void (*CASC_ENTRY_FUNC)(void *);\n";
[38]297
298 const char *pmf_type = get_pmf_type ();
299
[1]300 o << " typedef union { "
301 << pmf_type
302 << " integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
303
[35]304 gen_transition (o, transition_func_list);
305 gen_moore (o, moore_func_list);
306 gen_mealy (o, strongcomponents);
[1]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
[27]350 << "#include <casc.h>\n\n"
351 << "#include <cstdio>\n\n"
352// << "#include <iostream>\n\n"
[1]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
[35]358 gen_transition (o, transition_func_list);
359 gen_moore (o, moore_func_list);
360 gen_mealy (o, mealy_func_list);
[1]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)
[38]392 cerr << "Compiling C/C++ code for scheduling...\n";
[1]393 char compil_str[512];
[38]394 const char *compiler = getenv ("CXX");
[1]395 const char *systemc_dir = getenv ("SYSTEMCASS");
396// const char *target_arch = getenv ("TARGET_ARCH");
397 const char *default_compiler =
[27]398#ifdef CPP_CALL
[1]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];
[36]417 sprintf (target_name, "%s.lo", base_name);
[1]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 /* ******* */
[27]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)"
[1]444#else
[27]445 "(cd %s ;" " %s %s -DSCHEDULING_BY_CASC -I%s/include -dynamiclib -o %s -c %s)"
[1]446#endif
[27]447 ;
[38]448
449 string cflags = casc_cflags;
450 if (use_openmp)
451 cflags += " -fopenmp";
452
[27]453 sprintf(compil_str,
454 commandline_template,
455 temporary_dir,
456 compiler,
[38]457 cflags.c_str(),
[27]458 systemc_dir,
459 target_name,
460 source_name);
[1]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 /* **** */
[36]473 sprintf (target_name, "%s.la", base_name);
[1]474
[27]475#ifdef CONFIG_OS_LINUX
[1]476 sprintf (source_name, "%s.lo", base_name);
[36]477 sprintf(compil_str, "(cd %s ; pwd ; libtool --mode=link %s %s -module -shared -o %s %s -rpath /tmp)", /* -L. -L%s/lib-%s */
[1]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 {
[27]574#if 0 //defined(CONFIG_DEBUG)
[1]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{
[27]589#ifdef CONFIG_CHECK_FSM_RULES
[35]590 casc_fsm_step = TRANSITION;
[1]591#endif
592 call_functions (pf[0]); // transition
593 update ();
[27]594#ifdef CONFIG_CHECK_FSM_RULES
[35]595 casc_fsm_step = GEN_MOORE;
[1]596#endif
597 call_functions (pf[1]); // moore generation
[27]598#ifdef CONFIG_CHECK_FSM_RULES
[35]599 casc_fsm_step = GEN_MEALY;
[1]600#endif
601 call_functions (pf[2]); // mealy generation
[27]602#ifdef CONFIG_CHECK_FSM_RULES
[35]603 casc_fsm_step = STIMULI;
[1]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{
[27]648#ifdef CONFIG_CHECK_FSM_RULES
[35]649 casc_fsm_step = TRANSITION;
[1]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 ();
[27]658#ifdef CONFIG_CHECK_FSM_RULES
[35]659 casc_fsm_step = GEN_MOORE;
[1]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 }
[27]666#ifdef CONFIG_CHECK_FSM_RULES
[35]667 casc_fsm_step = GEN_MEALY;
[1]668#endif
669 quasistatic_mealy_generation ();
[27]670#ifdef CONFIG_CHECK_FSM_RULES
[35]671 casc_fsm_step = STIMULI;
[1]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.