source: sources/src/gen_code.cc @ 52

Last change on this file since 52 was 52, checked in by meunier, 11 years ago

Code formatting in all source files.

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