source: sources/src/gen_code.cc @ 54

Last change on this file since 54 was 54, checked in by becoulet, 11 years ago

added missing #include for getpid()

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