source: sources/src/gen_code.cc @ 58

Last change on this file since 58 was 57, checked in by cfuguet, 9 years ago

Introduce missing syslimits.h header when using MacOS-X

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