source: sources/src/sc_trace.cc

Last change on this file was 59, checked in by meunier, 7 years ago
  • Fixed memory leaks
  • Fixed indentation in some files
File size: 16.8 KB
Line 
1/*------------------------------------------------------------\
2|                                                             |
3| Tool    :                  systemcass                       |
4|                                                             |
5| File    :                   sc_trace.cc                     |
6|                                                             |
7| Author  :                 Kingbo Paul-Jerome                |
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#include <cassert>
38#include <list>
39#include <cstdio>
40#include <iostream>
41#include <cstring> //strlen
42//#include <stdint.h>
43
44#include "sc_port.h"
45#include "sc_clock.h"
46#include "sc_trace.h"
47#include "sc_interface.h"
48#include "bit2string.h"
49#include "hex2string.h"
50
51#ifdef HAVE_CONFIG_H
52#include "config.h"
53#endif
54
55
56//-----------------------------------------
57
58using namespace std;
59
60//-----------------------------------------
61#ifdef CONFIG_PAT_TRACE_FORMAT
62
63extern "C" {
64#include "genpat.h"
65}
66
67#include <cstdlib>
68#include <cstdio>
69
70#endif // CONFIG_PAT_TRACE_FORMAT
71//-----------------------------------------
72
73
74namespace sc_core {
75
76vector<sc_trace_file *>  trace_file_list;
77uint64 cpt = 0;
78uint64 trace_start = 0;
79
80
81static void init(sc_trace_file & tf) {
82    if (dump_stage) {
83        cerr << "Initializing trace functions : Looking for clocks...";
84    }
85
86    vector<signal2trace>::iterator i;
87    i = (tf.sig_list).begin();
88    while (i != (tf.sig_list).end()) {
89        if (is_clock(*(i->inter))) {
90            tf.clk_list.push_back(*i);
91            i = tf.sig_list.erase(i);
92        } 
93        else {
94            ++i;
95        }
96    }
97    if (dump_stage) {
98        cerr << "Done\n";
99    }
100}
101
102
103static void vcd_print_cycle_number(FILE * f,long long unsigned int num) {
104    string cycle;
105
106    // affichage des cycles (#500 ou #2500 etc...)
107    fprintf(f,"\n#%llu00\n", num * 5);//cycle de simulation
108}
109
110
111
112//--------------------------------------------------------------------------------------
113// trace function
114// Called each end of cycle to dump in trace files
115void trace_all(bool part) {
116    if (trace_file_list.empty()) {
117        return;
118    }
119
120    if (cpt >= trace_start) {
121        vector<sc_trace_file *>::const_iterator ptf;
122        for (ptf = trace_file_list.begin(); ptf != trace_file_list.end(); ++ptf) {
123            sc_trace_file * tf = *ptf;
124            assert(tf != NULL);
125            trace(*tf, part);
126        }
127    }
128
129    cpt++;
130}
131
132
133#ifdef CONFIG_PAT_TRACE_FORMAT
134static void pat_set_value(char * buf, const signal2trace & s) {
135    if ((s.bit_size % 4) == 0) {
136        buf[1] = 'x';
137        hex2string(buf + 2, s.inter->get_pointer(), s.bit_size);
138    }
139    else {
140        buf[1] = 'b';
141        bit2string(buf + 2, s.inter->get_pointer(), s.bit_size);
142    }
143}
144
145
146inline static void affect(const char * cur, const char * nomSig, const char * buf) {
147    AFFECT ((char*)cur, (char*)nomSig, (char*)buf );
148}
149
150
151
152inline static void pat_trace(
153        sc_trace_file       & tf, 
154        const signal2trace  & s2t, 
155        const ostringstream & cur1,
156        const ostringstream & cur2) {
157    static char buf[50] = "0\0";
158    //cout << "Nom du signal: " << s->nomSig;
159    pat_set_value(buf, s2t);
160    affect(cur1.str().c_str(), s2t.nomSig.c_str(), buf);
161    affect(cur2.str().c_str(), s2t.nomSig.c_str(), buf);
162}
163
164
165inline static void pat_trace_clocks(
166        sc_trace_file       & tf,
167        const ostringstream & cur1,
168        const ostringstream & cur2) {
169    vector<signal2trace>::const_iterator s;
170    for (s = (tf.clk_list).begin(); s != (tf.clk_list).end(); s++) {
171        const signal2trace & s2t = *s;
172        char * name = (char *) ((s2t.nomSig).c_str());
173        const sc_interface * inter = s2t.inter;
174        const sc_clock * clk = (const sc_clock *) inter;
175        bool  posedge_first = clk->posedge_first;
176        char * a, * b;
177        if (posedge_first) {
178            a = "0B1";
179            b = "0B0";
180        }
181        else {
182            a = "0B0";
183            b = "0B1"; 
184        }
185        affect(cur1.str().c_str(), name, a);
186        affect(cur2.str().c_str(), name, b);
187    }
188}
189
190
191static void pat_trace_init(sc_trace_file & tf) {
192    init(tf);
193}
194
195
196static void pat_trace(sc_trace_file & tf, bool part) { 
197    if (part) {
198        return;
199    }
200   
201    if (cpt == trace_start) {
202        pat_trace_init(tf);
203    }
204
205    // time counters
206    ostringstream cur1, cur2;
207    long long unsigned int buf = cpt * 5;
208    cur1 << buf << "00";
209    cur2 << buf + 5 << "00";
210
211    // affect each signal
212    vector<signal2trace>::iterator s;
213    for (s = (tf.sig_list).begin(); s != (tf.sig_list).end(); s++) {
214        pat_trace(tf, *s, cur1, cur2);
215    }
216    pat_trace_clocks(tf, cur1, cur2);
217}
218
219#else
220void pat_trace (sc_trace_file & tf, bool part) {}
221#endif // CONFIG_PAT_TRACE_FORMAT
222
223
224static bool is_modified(const signal2trace & s2t) {
225    unsigned int bit_size = s2t.bit_size;
226    if (bit_size > 32) {
227        const uint64 * const pointer_saved = (const uint64 *) s2t.pointer;
228        const uint64 * const pointer_current = (const uint64 *) s2t.inter->get_pointer();
229        return (*pointer_saved != *pointer_current);
230    }
231    else if (bit_size > 16) {
232        const uint32 * const pointer_saved = (const uint32 *) s2t.pointer;
233        const uint32 * const pointer_current = (const uint32 *) s2t.inter->get_pointer();
234        return (*pointer_saved != *pointer_current);
235    }
236    else {
237        const uint16 * const pointer_saved = (const uint16 *) s2t.pointer;
238        const uint16 * const pointer_current = (const uint16 *) s2t.inter->get_pointer();
239        return (*pointer_saved != *pointer_current);
240    }
241}
242
243
244static bool save_modification(signal2trace & s2t) {
245    *(s2t.pointer) = *(s2t.inter->get_pointer());
246}
247
248
249static inline void print(sc_trace_file & tf, signal2trace & s2t) {
250    char buf[100];
251    bit2string(buf + 1, s2t.inter->get_pointer() , s2t.bit_size);
252
253    char * buf2 = strip(buf + 1);
254    int len = strlen(buf2);
255    if (s2t.bit_size != 1) {
256        --buf2;
257        buf2[0] = 'b';
258        sprintf(buf2 + len + 1, " %s\n", s2t.alias);
259    }
260    else {
261        sprintf(buf2 + len, "%s\n", s2t.alias);
262    }
263   
264    // ecriture liste[i] dans le fichier VCD:
265    if ((fprintf(tf.pfic,buf2)) == 0) {
266        cerr << "erreur ecriture du couple Valeur/Nom du signal dans le VCD\n";
267        exit(16);
268    }
269}
270
271
272static inline void vcd_trace(sc_trace_file & tf, signal2trace  & s2t, bool skip = true) {
273    if ((skip) && (!is_modified(s2t))) {
274        return;
275    }
276    save_modification(s2t);
277    print(tf, s2t);
278}
279
280
281static void vcd_trace_clocks(const sc_trace_file & tf, bool v) {
282    vector<signal2trace>::const_iterator i;
283    for (i = (tf.clk_list).begin(); i != (tf.clk_list).end(); i++) {
284        const signal2trace & s2t   = *i;
285        const sc_interface * inter = s2t.inter;
286        const sc_clock * clk = (const sc_clock *) inter;
287        bool posedge_first = clk->posedge_first;
288        fprintf(tf.pfic, "%c%s\n",(v^posedge_first)?'0':'1', i->alias);
289    }
290}
291
292
293static tab_t * vcd_signal_table = NULL;
294
295
296static int vcd_get_size(const signal2trace & s2t) {
297#if 0
298    cerr << "alias     : " << s2t.alias    << "\n";
299    cerr << "bit_size  : " << s2t.bit_size << "\n";
300    cerr << "=> #tab_t : " << ((s2t.bit_size - 1) / (sizeof (tab_t)*8)) + 1 << "\n";
301#endif
302    return ((s2t.bit_size - 1) / (sizeof(tab_t) * 8)) + 1;
303}
304
305
306static int vcd_get_signal_table_size(const sc_trace_file & tf) {
307    int total_size = 0;
308    vector<signal2trace>::const_iterator i;
309    for (i = (tf.sig_list).begin(); i != (tf.sig_list).end(); i++) {
310        const signal2trace & s2t = *i;
311        total_size += vcd_get_size(s2t);
312    }
313    return total_size;
314}
315
316
317static void vcd_alloc_signal_table(int size) {
318    if (size == 0) {
319        vcd_signal_table = NULL;
320    }
321    else {
322        vcd_signal_table = (tab_t *) malloc(sizeof(tab_t) * size);
323    }
324#ifdef CONFIG_DEBUG
325    if (vcd_signal_table == NULL) {
326        cerr << "Internal error : Unable to allocate memory for signal table to trace.\n";
327        exit(24032005);
328    }
329#endif
330}
331
332
333static void vcd_bind_to_signal_table(sc_trace_file & tf) {
334    tab_t * cur = vcd_signal_table;
335    vector<signal2trace>::iterator i;
336    for (i = (tf.sig_list).begin(); i != (tf.sig_list).end(); i++) {
337        signal2trace & s2t = *i;
338        s2t.pointer = cur;
339        cur += vcd_get_size(s2t);
340#if 0
341        std::cout << s2t
342            << "\nget_pointer () => " << hex << s2t.inter->get_pointer ()
343            << "\nvcd pointer () => " << hex << s2t.pointer
344            << "\nvcd_get_size () => " << vcd_get_size (s2t)
345            << "\n";
346#endif
347    }
348}
349
350
351static void vcd_build_signal_table(sc_trace_file & tf) {
352    int s = vcd_get_signal_table_size(tf);
353    vcd_alloc_signal_table(s);
354    vcd_bind_to_signal_table(tf);
355}
356
357
358static void vcd_trace_init(sc_trace_file & tf) {
359    init(tf);
360    fprintf(tf.pfic,"$upscope $end\n$enddefinitions  $end\n\n$comment\nAll initial values are dumped below at time 0 sec = 0 timescale units.\n$end\n\n$dumpvars\n");
361    vcd_build_signal_table(tf);
362
363    // dump all var
364    vector<signal2trace>::iterator i;
365    for(i = (tf.sig_list).begin() ; i != (tf.sig_list).end(); i++) {
366        vcd_trace(tf, *i, false);
367    }//fin de la liste des signal2trace
368
369    // clocks to trace
370    vcd_trace_clocks(tf, true);
371
372    if (cpt == trace_start) {
373        fprintf(tf.pfic, "$end\n"); //fin du $dumpvars
374    }
375}
376
377
378static void vcd_trace(sc_trace_file & tf, bool part) {
379    if (sc_core::cpt == sc_core::trace_start) {
380        if (part == false) {
381            vcd_trace_init (tf);
382        }
383    }
384    else {
385#if defined(CONFIG_DEBUG)
386        if (vcd_signal_table == NULL) {
387            cerr << "Internal Error : VCD signal table is not yet allocated.\n";
388            exit(1042005);
389        }
390#endif
391        vcd_print_cycle_number(tf.pfic,sc_core::cpt);
392        // signals to trace
393        if (part == false) {
394            vector<signal2trace>::iterator i;
395            for (i = tf.sig_list.begin(); i != tf.sig_list.end(); i++) {
396                vcd_trace(tf, *i);
397            }//fin de la liste des signal2trace
398        }
399        // clocks to trace
400        vcd_trace_clocks(tf, !part);
401    }
402}
403
404
405void trace(sc_trace_file & tf, bool part) {
406    switch (tf.flag) {
407        // fonction trace() pour VCD:
408        case VCD_FORMAT:
409            vcd_trace(tf, part);
410            break;
411            //fin de la fonction trace() pour VCD
412
413            /*------------------------------------------------------------------------------------*/
414
415            // fonction trace() pour PAT:
416        case PAT_FORMAT:
417            pat_trace(tf, part);
418            break;
419            //fin de la fonction trace() pour PAT
420    }
421    // fin du switch format pour trace()
422
423}
424
425
426/*------------------------------------------------------------------------------------*/
427
428
429static void vcd_sc_trace(sc_trace_file * tf, const signal2trace & t, const std::string & name) {
430    //déclaration du signal dans l'en-tête du fichier VCD:
431    // exemple de déclarations :
432    // $var wire    1  aaa  clk       $end
433    // $var wire    1  aab  resetn       $end
434    // $var wire    1  aac  _mips0_IT_5       $end
435
436    std::string declaration;
437    std::ostringstream buf;
438    // begin
439    declaration = "$var wire ";
440    buf.width(4);
441    buf << t.bit_size;
442    declaration += buf.str();
443    declaration += "  ";
444    declaration += t.alias;
445    declaration += "  ";
446    declaration += name;
447    // bit range
448    if (t.bit_size != 1) {
449        declaration += " [";
450        std::ostringstream bit_size;
451        bit_size << t.bit_size - 1;
452        declaration += bit_size.str();
453        declaration += ":0]";
454    }
455    // end
456    declaration += "       $end\n";
457
458    if ((fprintf(tf->pfic,declaration.c_str())) == 0) {
459        cerr << "erreur ecriture de declaration du signal sc_signal\n";
460        exit(3);
461    }
462}
463
464
465static void pat_sc_trace(sc_trace_file * tf, const signal2trace & t, const std::string & name) {
466#ifdef CONFIG_PAT_TRACE_FORMAT
467    //exemple:
468    //DECLAR ("a", ":2", "X", IN, "3  downto 0", "" );
469    //DECLAR ("b", ":2", "X", IN, "3  downto 0", "" );
470    //DECLAR ("vdd", ":2", "B", IN, "", "" );
471
472    std::string downto;
473    const sc_object * obj = (const sc_object *) t.inter;
474    const char * obj_kind = obj->kind();
475    char * format;
476    char * dir;
477
478    if (strstr(obj_kind, "inout"))
479        dir = OUT; // Direction is OUT instead of INOUT
480    // because port behavior is only seen as an output port.
481    else if (strstr (obj_kind, "in")) {
482        dir = IN;
483    }
484    else if (strstr (obj_kind, "out")) {
485        dir = OUT;
486    }
487    else if (obj_kind == sc_clock::kind_string) {
488        dir = SIGNAL;
489    }
490    else if (obj_kind == sc_signal_base::kind_string) {
491        dir = REGISTER;
492    }
493    // to do : dir = REGISTER;
494    //         dir = SIGNAL;
495
496    if (t.bit_size % 4 == 0) {
497        format = "x";
498    }
499    else {
500        format = "b";
501    }
502
503    if (t.bit_size == 1) {
504        downto = "";
505    }
506    else { 
507        std::ostringstream nbits;
508        nbits << t.bit_size - 1;
509        downto = nbits.str();
510        downto += " downto 0";
511    }
512
513#if 0
514    printf ("DECLAR (\"%s\", \":1\", \"%s\", %s, \"%s\", \"\" );\n",
515            name.c_str (),
516            format,
517            dir,
518            downto.c_str());
519#endif
520    DECLAR ((char *) (name.c_str()), ":1", format, dir, (char *) downto.c_str(), "");
521#endif // CONFIG_PAT_TRACE_FORMAT
522}
523
524
525void sc_trace(sc_trace_file * tf, const signal2trace & t, const std::string & name) {
526    if (tf == NULL) {
527        return;
528    }
529    if (t.bit_size > 64) {
530        cerr << "Warning : tracing functions do not support data types larger than 64 bits.\n";
531    }
532    if (already_initialized) {
533        cerr << "Warning : please call tracing functions BEFORE sc_initialize.\n";
534    }
535    //ajout du signal dans la liste des signaux à tracer:
536    (tf->sig_list).push_back(t);
537
538    switch (tf->flag) {
539        case VCD_FORMAT : 
540            vcd_sc_trace(tf, t, name);
541            break;
542
543        case PAT_FORMAT :
544            pat_sc_trace(tf, t, name);
545            break;
546        default :
547            {
548                cerr << "Unknown trace format.\n";
549                exit(1);
550            }
551    }// fin switch format pour sc_trace
552
553}
554
555//----------------------------------------------------------------------------
556
557#define DEF_SC_TRACE(T) /*inline \*/                                        \
558    void                                                                    \
559    sc_trace (sc_trace_file* tf, const T& object, const std::string & name) \
560    {                                                                       \
561        signal2trace t;                                                     \
562        sc_interface * inter = new sc_localvar< T > (object);               \
563        t.inter = inter;                                                    \
564        t.alias = alias();                                                  \
565        t.bit_size = get_bits_number(object);                               \
566        t.nomSig = name;                                                    \
567        sc_trace (tf, t, name);                                             \
568    }
569
570
571    DEF_SC_TRACE(bool)
572    DEF_SC_TRACE(float)
573    DEF_SC_TRACE(double)
574    DEF_SC_TRACE(unsigned char)
575    DEF_SC_TRACE(unsigned short)
576    DEF_SC_TRACE(unsigned int)
577    DEF_SC_TRACE(unsigned long)
578    DEF_SC_TRACE(char)
579    DEF_SC_TRACE(short)
580    DEF_SC_TRACE(int)
581    DEF_SC_TRACE(long)
582    DEF_SC_TRACE(uint64)
583    DEF_SC_TRACE(int64)
584
585#undef DEF_SC_TRACE
586
587//---------------------------------------------------------------------------
588
589} // end of sc_core namespace
590
591
592/*
593# Local Variables:
594# tab-width: 4;
595# c-basic-offset: 4;
596# c-file-offsets:((innamespace . 0)(inline-open . 0));
597# indent-tabs-mode: nil;
598# End:
599#
600# vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
601*/
602
Note: See TracBrowser for help on using the repository browser.