source: sources/src/gen_code.cc @ 59

Last change on this file since 59 was 59, checked in by meunier, 7 years ago
  • Fixed memory leaks
  • Fixed indentation in some files
File size: 18.7 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#elif defined(__MACH__)
42#include <sys/syslimits.h>
43#endif
44
45#include <unistd.h>
46#include <cstring>
47#include <cstdio>
48#include <cstdlib>
49#include <iostream>
50#include <fstream>
51
52#include "internal.h"
53#include "gen_code.h"
54#include "sc_module.h"
55#include "sc_ver.h"
56#include "process_dependency.h"
57
58#ifdef HAVE_CONFIG_H
59#include "config.h"
60#endif
61
62#ifdef _OPENMP
63#include <omp.h>
64#endif
65
66#define casc_cflags GENERATED_MODULE_CFLAGS
67
68// Enable CPP call, this is useful for typeinfo-enabled classes
69#define CPP_CALL
70
71using namespace std;
72
73namespace sc_core {
74
75static void PrintCall(std::ostream &, const method_process_t &);
76static void open_temp(std::ofstream &, char *);
77typedef void (*CASC_ENTRY_FUNC) (void *);
78typedef union {
79    unsigned long long int integer;
80    SC_ENTRY_FUNC pmf;
81    CASC_ENTRY_FUNC pf;
82} fct;
83
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    };
100}
101
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";
108}
109
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";
117#ifdef CPP_CALL
118    o << " (((sc_module*)(" << m.module << "))->*(p.pmf)) (); /* " << m.module->name() << "->" << m.name << "() */\n";
119#else
120    o << " p.pf((void *)" << m.module << "); /* " << m.module->name() << "->" << m.name << "() */\n";
121#endif
122}
123
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;
135}
136
137
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));
148
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    }
154#ifdef CONFIG_DEBUG
155    cerr << "opened temporary filename : " << temp << "\n";
156#endif
157    sprintf(temp, "scheduling-%d-%x", pid, r++);
158}
159
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        }
170    }
171    o << "}\n";
172}
173
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        }
186    }
187    o << " \n}\n";
188}
189
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";
198#ifdef NO_STATIC_SCHEDULE
199    o << "\n  do {\n    unstable = 0;\n";
200#endif
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 */
211#ifndef NO_STATIC_SCHEDULE
212            o << "\n  do {\n    unstable = 0;\n";
213#endif
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            }
219#ifndef NO_STATIC_SCHEDULE
220            o << "  } while ( unstable );\n\n";
221#endif
222        }
223    }
224#ifdef NO_STATIC_SCHEDULE
225    o << "  } while ( unstable );\n\n";
226#else
227    o << "\tunstable = 0;\n";
228#endif
229}
230
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    }
241}
242
243
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    }
253
254    // open temporary file
255    ofstream o;
256    char base_name[PATH_MAX];
257    open_temp(o, base_name);
258
259    if (!o.good()) {
260        perror("scheduling: open file\n");
261        exit(-1);
262    }
263
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";
270
271    const char * pmf_type = get_pmf_type();
272
273    o << " typedef union { "
274        << pmf_type
275        << " integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
276
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);
303}
304
305
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    }
315
316    // open temporary file
317    ofstream o;
318    char base_name[PATH_MAX];
319    open_temp(o, base_name);
320
321    if (!o.good()) {
322        perror("scheduling: open file\n");
323        exit(-1);
324    }
325
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";
333
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);
360}
361
362
363/* base_name est la base du nom du fichier C++
364 * casc_cflags est une string qui correspond à $(INCLUDE) d'un Makefile
365 */
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 =
374#ifdef CPP_CALL
375        "g++";
376#else
377    "gcc";
378#endif
379
380    compiler = (compiler == NULL) ? default_compiler : compiler;
381    if (systemc_dir == NULL) {
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        }
387    }
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 =
413#if defined(CONFIG_OS_DARWIN)
414        "(cd %s ;"
415        " %s %s -DSCHEDULING_BY_CASC -I%s/include -fno-common -dynamic -o %s -c %s)"
416#elif defined(CONFIG_OS_LINUX)
417        "(cd %s ; libtool --mode=compile %s %s -DSCHEDULING_BY_CASC -I%s/include -shared -o %s -c %s)"
418#else
419        "(cd %s ;"
420        " %s %s -DSCHEDULING_BY_CASC -I%s/include -dynamiclib -o %s -c %s)"
421#endif
422        ;
423
424    string cflags = casc_cflags;
425    if (use_openmp) {
426        cflags += " -fopenmp";
427    }
428
429    sprintf(compil_str, commandline_template, temporary_dir, compiler, cflags.c_str(), systemc_dir, target_name, source_name);
430
431    if (dump_stage) {
432        cerr << "Executing command : " << compil_str << "\n";
433    }
434
435    if (system(compil_str)) {
436        perror("compil : system");
437        exit(-1);
438    }
439
440    /* **** */
441    /* LINK */
442    /* **** */
443    sprintf(target_name, "%s.la", base_name);
444
445#ifdef CONFIG_OS_LINUX
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);
450#else
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);
453#endif
454
455    if (dump_stage) {
456        cerr << "Executing command : " << compil_str << "\n";
457    }
458
459    if (system(compil_str)) {
460        perror("compil : system");
461        exit(-1);
462    }
463
464    system(compil_str);
465    if (dump_stage) {
466        cerr << "Compiling done.\n";
467    }
468}
469
470
471/* ********************************
472 * Function for static scheduling
473 */
474struct function_call {
475    fct * function;
476    void ** instance;
477    int func_number;
478};
479static function_call pf[3];
480
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    }
493}
494
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    }
507}
508
509
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    }
519
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    }
527}
528
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;
538#endif
539        fc.function[i].pf(fc.instance[i]);
540    }
541}
542
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;
554#endif
555        fc.function[i].pf(fc.instance[i]);
556    }
557}
558
559
560void static_mealy_generation() {
561    call_functions(pf[2]);
562}
563
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
570}
571
572
573/* ***************************************
574 * Function for quasi static scheduling
575 */
576
577static method_process_list_t func_list[2];
578static strong_component_list_t quasistatic_list;
579
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    // QM
585    //cerr << "Exec " << mod->name() << "->" << m.name << endl;
586    (mod->*func) ();
587}
588
589
590void quasistatic_mealy_generation() {
591    strong_component_list_t::iterator ss;
592    for (ss = quasistatic_list.begin(); ss != quasistatic_list.end(); ++ss) {
593        if ((*ss)->size() == 1) {
594            /* un seul element dans le strong component */
595            method_process_t * m = (method_process_t *) (*((*ss)->begin()));
596            Call(*m);
597            continue;
598        }
599        else {
600            /* plusieurs elements dans le strong component */
601            do {
602                unstable = 0;
603                component_list_t::reverse_iterator rev_mm;
604                for (rev_mm = (*ss)->rbegin(); rev_mm != (*ss)->rend(); ++rev_mm) {
605                    method_process_t * m = (method_process_t *) * rev_mm;
606                    Call(*m);
607                }
608            } while (unstable);
609        }
610    }
611}
612
613
614void quasistatic_simulate_1_cycle(void) {
615    method_process_list_t::iterator mm;
616    for (mm = func_list[0].begin(); mm != func_list[0].end(); ++mm) {
617        method_process_t & m = **mm;
618        Call(m);
619    }
620    update();
621    for (mm = func_list[1].begin(); mm != func_list[1].end(); ++mm) {
622        method_process_t & m = **mm;
623        Call(m);
624    }
625    quasistatic_mealy_generation();
626}
627
628
629void gen_scheduling_code_for_quasistatic_func(method_process_list_t &
630        transition_func_list,
631        method_process_list_t &
632        moore_func_list,
633        strong_component_list_t &
634        mealy_func_list) {
635    if (dump_stage) {
636        cerr << "Generating quasi static scheduling...\n";
637    }
638
639    func_list[0] = transition_func_list;
640    func_list[1] = moore_func_list;
641    quasistatic_list = mealy_func_list;
642
643    if (dump_stage) {
644        cerr << "Generating quasi static scheduling done.\n";
645    }
646}
647} // end of sc_core namespace
648
649
650/*
651# Local Variables:
652# tab-width: 4;
653# c-basic-offset: 4;
654# c-file-offsets:((innamespace . 0)(inline-open . 0));
655# indent-tabs-mode: nil;
656# End:
657#
658# vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
659*/
Note: See TracBrowser for help on using the repository browser.