/*------------------------------------------------------------\ | | | Tool : systemcass | | | | File : sc_trace.cc | | | | Author : Kingbo Paul-Jerome | | Buchmann Richard | | | | Date : 09_07_2004 | | | \------------------------------------------------------------*/ /* * This file is part of the Disydent Project * Copyright (C) Laboratoire LIP6 - Département ASIM * Universite Pierre et Marie Curie * * Home page : http://www-asim.lip6.fr/disydent * E-mail : mailto:richard.buchmann@lip6.fr * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * Disydent is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along * with the GNU C Library; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "sc_port.h" #include "sc_clock.h" #include "sc_trace.h" #include "sc_interface.h" #include "bit2string.h" #include "hex2string.h" #include "assert.h" #include #include #include //----------------------------------------- using namespace std; //----------------------------------------- #ifdef PAT_TRACE_FORMAT extern "C" { #include "genpat.h" } //#include "malloc.h" // NO LONGER SUPPORTED #include #include #endif // PAT_TRACE_FORMAT //----------------------------------------- namespace sc_core { vector trace_file_list; uint64 cpt = 0; uint64 trace_start = 0; //----------------------------------------- #if 0 static ostream& operator << (ostream &, const signal2trace &); #endif //----------------------------------------- /* typedef list signal2trace_list; template static void make_list_from_vector (const vector& v, list& l) { l.clear (); typename vector::const_iterator i; for (i = v.begin (); i != v.end (); ++i) l.push_back (*i); } template static void make_vector_from_list (const list& l, vector& v) { v.clear (); typename list::const_iterator i; for (i = l.begin (); i != l.end (); ++i) v.push_back (*i); } static int operator<(const signal2trace &e1, const signal2trace &e2) { return (e1.bit_size < e2.bit_size); } static void init (sc_trace_file *tf) { signal2trace_list lsig; make_list_from_vector (tf->sig_list, lsig); lsig.reverse(); //sort (); make_vector_from_list (lsig, tf->sig_list); } */ static void init (sc_trace_file &tf) { if (dump_stage) cerr << "Initializing trace functions : Looking for clocks..."; vector::iterator i; i = (tf.sig_list).begin(); while (i!=(tf.sig_list).end()) { if (is_clock( *(i->inter) ) ) { tf.clk_list.push_back(*i); i = tf.sig_list.erase(i); } else ++i; } if (dump_stage) cerr << "Done\n"; } static void vcd_print_cycle_number (FILE *f,long long unsigned int num) { string cycle; //------------------------------------------------------------------------------------ // affichage des cycles (#500 ou #2500 etc...) fprintf(f,"\n#%llu00\n", num * 5);//cycle de simulation } //-------------------------------------------------------------------------------------- // trace function // Called each end of cycle to dump in trace files void trace_all (bool part) { if (trace_file_list.empty ()) return; if (cpt >= trace_start) { vector::const_iterator ptf; for (ptf = trace_file_list.begin (); ptf != trace_file_list.end(); ++ptf) { sc_trace_file *tf = *ptf; ASSERT(tf != NULL); trace (*tf, part); } } cpt++; } #if PAT_TRACE_FORMAT static void pat_set_value (char *buf, const signal2trace &s) { if ( ( s.bit_size % 4 ) == 0 ) { buf[1] = 'x'; hex2string( buf+2, s.inter->get_pointer() , s.bit_size ); } else { buf[1] = 'b'; bit2string( buf+2, s.inter->get_pointer() , s.bit_size ); } } inline static void affect (const char *cur, const char *nomSig, const char *buf) { #if 0 printf ("AFFECT (\"%s\", \"%s\", \"%s\");\n", cur, nomSig, buf); #endif AFFECT ((char*)cur, (char*)nomSig, (char*)buf ); } inline static void pat_trace (sc_trace_file &tf, const signal2trace &s2t, const ostringstream &cur1, const ostringstream &cur2) { static char buf[50] = "0\0"; //cout << "Nom du signal: " << s->nomSig; pat_set_value (buf, s2t); affect (cur1.str().c_str(), s2t.nomSig.c_str(), buf); affect (cur2.str().c_str(), s2t.nomSig.c_str(), buf); } inline static void pat_trace_clocks (sc_trace_file &tf, const ostringstream &cur1, const ostringstream &cur2) { vector::const_iterator s; for(s=(tf.clk_list).begin();s!=(tf.clk_list).end();s++) { const signal2trace &s2t = *s; char *name = (char*)((s2t.nomSig).c_str()); const sc_interface *inter = s2t.inter; const sc_clock *clk = (const sc_clock *) inter; bool posedge_first = clk->posedge_first; char *a, *b; if (posedge_first) { a = "0B1"; b = "0B0"; } else { a = "0B0"; b = "0B1"; } affect (cur1.str().c_str(), name, a); affect (cur2.str().c_str(), name, b); } } static void pat_trace_init (sc_trace_file &tf) { init (tf); } static void pat_trace (sc_trace_file &tf, bool part) { if (part) return; if (cpt==trace_start) { pat_trace_init (tf); } // time counters ostringstream cur1,cur2; long long unsigned int buf = cpt * 5; cur1 << buf << "00"; cur2 << buf + 5 << "00"; // affect each signal vector::iterator s; for(s=(tf.sig_list).begin();s!=(tf.sig_list).end();s++) { pat_trace (tf, *s, cur1, cur2); } pat_trace_clocks (tf, cur1, cur2); } #else void pat_trace (sc_trace_file &tf, bool part) { } #endif // PAT_TRACE_FORMAT static bool is_modified (const signal2trace &s2t) { unsigned int bit_size = s2t.bit_size; if (bit_size > 32) { const uint64 *const pointer_saved = (const uint64 *)s2t.pointer; const uint64 *const pointer_current = (const uint64 *)s2t.inter->get_pointer (); return (*pointer_saved != *pointer_current); } else if (bit_size > 16) { const uint32 *const pointer_saved = s2t.pointer; const uint32 *const pointer_current = s2t.inter->get_pointer (); return (*pointer_saved != *pointer_current); } else { const uint16 *const pointer_saved = (const uint16 *)s2t.pointer; const uint16 *const pointer_current = (const uint16 *)s2t.inter->get_pointer (); return (*pointer_saved != *pointer_current); } } static bool save_modification (signal2trace &s2t) { *(s2t.pointer) = *(s2t.inter->get_pointer ()); } static inline void print (sc_trace_file &tf, signal2trace &s2t) { char buf[100]; bit2string( buf+1, s2t.inter->get_pointer() , s2t.bit_size ); char *buf2 = strip(buf+1); int len = strlen (buf2); if (s2t.bit_size != 1) { --buf2; buf2[0] = 'b'; sprintf (buf2 + len + 1, " %s\n", s2t.alias); } else { sprintf (buf2 + len, "%s\n", s2t.alias); } /* char *buf2 = strip(buf); char buf3[128]; if (s2t.bit_size != 1) sprintf (buf3, "b%s %s\n", buf2, s2t.alias); else sprintf (buf3, "%s%s\n", buf2, s2t.alias); */ // ecriture liste[i] dans le fichier VCD: if ((fprintf(tf.pfic,buf2))==0) { cerr << "erreur ecriture du couple Valeur/Nom du signal dans le VCD\n"; exit(16); } } static inline void vcd_trace (sc_trace_file &tf, signal2trace &s2t, bool skip = true) { if ((skip) && (!is_modified (s2t))) return; save_modification (s2t); print (tf, s2t); } static void vcd_trace_clocks (const sc_trace_file &tf, bool v) { vector::const_iterator i; for(i=(tf.clk_list).begin();i!=(tf.clk_list).end();i++) { const signal2trace &s2t = *i; const sc_interface *inter = s2t.inter; const sc_clock *clk = (const sc_clock *) inter; bool posedge_first = clk->posedge_first; fprintf(tf.pfic, "%c%s\n",(v^posedge_first)?'0':'1', i->alias); } } static tab_t *vcd_signal_table = NULL; static int vcd_get_size (const signal2trace &s2t) { #if 0 cerr << "alias : " << s2t.alias << "\n"; cerr << "bit_size : " << s2t.bit_size << "\n"; cerr << "=> #tab_t : " << ((s2t.bit_size - 1) / (sizeof (tab_t)*8)) + 1 << "\n"; #endif return ((s2t.bit_size - 1) / (sizeof (tab_t)*8)) + 1; } static int vcd_get_signal_table_size (const sc_trace_file &tf) { int total_size = 0; vector::const_iterator i; for(i=(tf.sig_list).begin();i!=(tf.sig_list).end();i++) { const signal2trace &s2t = *i; total_size += vcd_get_size (s2t); } return total_size; } static void vcd_alloc_signal_table (int size) { if (size == 0) vcd_signal_table = NULL; else vcd_signal_table = (tab_t*) malloc (sizeof (tab_t) * size); #if DEBUG if (vcd_signal_table == NULL) { cerr << "Internal error : Unable to allocate memory for signal table to trace.\n"; exit (24032005); } #endif } static void vcd_bind_to_signal_table (sc_trace_file &tf) { tab_t *cur = vcd_signal_table; vector::iterator i; for(i=(tf.sig_list).begin();i!=(tf.sig_list).end();i++) { signal2trace &s2t = *i; s2t.pointer = cur; cur += vcd_get_size (s2t); #if 0 std::cout << s2t << "\nget_pointer () => " << hex << s2t.inter->get_pointer () << "\nvcd pointer () => " << hex << s2t.pointer << "\nvcd_get_size () => " << vcd_get_size (s2t) << "\n"; #endif } } static void vcd_build_signal_table (sc_trace_file &tf) { int s = vcd_get_signal_table_size (tf); vcd_alloc_signal_table (s); vcd_bind_to_signal_table (tf); } static void vcd_trace_init (sc_trace_file &tf) { init (tf); 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"); vcd_build_signal_table (tf); // dump all var vector::iterator i; for(i=(tf.sig_list).begin();i!=(tf.sig_list).end();i++) { vcd_trace (tf, *i, false); }//fin de la liste des signal2trace // clocks to trace vcd_trace_clocks (tf, true); if (cpt==trace_start) fprintf(tf.pfic,"$end\n"); //fin du $dumpvars } static void vcd_trace (sc_trace_file &tf, bool part) { if (sc_core::cpt==sc_core::trace_start) { if (part == false) vcd_trace_init (tf); } else { #if defined(DEBUG) if (vcd_signal_table == NULL) { cerr << "Internal Error : VCD signal table is not yet allocated.\n"; exit (1042005); } #endif vcd_print_cycle_number (tf.pfic,sc_core::cpt); // signals to trace if (part == false) { // vector &sig_list = (part == false)?to_update_on_pos:to_update_on_neg; vector::iterator i; for(i=tf.sig_list.begin();i!=tf.sig_list.end();i++) { vcd_trace (tf, *i); }//fin de la liste des signal2trace } // clocks to trace vcd_trace_clocks (tf, !part); } } void trace (sc_trace_file &tf, bool part) { /*------------------------------------------------------------------------------------*/ switch (tf.flag){ // fonction trace() pour VCD: case VCD_FORMAT: vcd_trace (tf, part); break;//fin de la fonction trace() pour VCD /*------------------------------------------------------------------------------------*/ // fonction trace() pour PAT: case PAT_FORMAT : pat_trace (tf, part); break;//fin de la fonction trace() pour PAT }// fin du switch format pour trace() } /*------------------------------------------------------------------------------------*/ static void vcd_sc_trace (sc_trace_file *tf, const signal2trace &t, const std::string &name) { //déclaration du signal dans l'en-tête du fichier VCD: // exemple de déclarations : // $var wire 1 aaa clk $end // $var wire 1 aab resetn $end // $var wire 1 aac _mips0_IT_5 $end std::string declaration; std::ostringstream buf; // begin declaration = "$var wire "; buf.width (4); buf << t.bit_size; declaration += buf.str(); declaration += " "; declaration += t.alias; declaration += " "; declaration += name; // bit range if (t.bit_size != 1) { declaration += " ["; std::ostringstream bit_size; bit_size << t.bit_size - 1; declaration += bit_size.str(); declaration += ":0]"; } // end declaration += " $end\n"; //declaration += " $end\n"; if ((fprintf(tf->pfic,declaration.c_str()))==0) { cerr << "erreur ecriture de declaration du signal sc_signal\n"; exit(3); } } static void pat_sc_trace (sc_trace_file *tf, const signal2trace &t, const std::string &name) { #ifdef PAT_TRACE_FORMAT //exemple: //DECLAR ("a", ":2", "X", IN, "3 downto 0", "" ); //DECLAR ("b", ":2", "X", IN, "3 downto 0", "" ); //DECLAR ("vdd", ":2", "B", IN, "", "" ); std::string downto; const sc_object *obj = (const sc_object *) t.inter; const char *obj_kind = obj->kind (); char *format; char *dir; if (strstr (obj_kind,"inout")) dir = OUT; // Direction is OUT instead of INOUT // because port behavior is only seen as an output port. else if (strstr (obj_kind,"in")) dir = IN; else if (strstr (obj_kind,"out")) dir = OUT; else if (obj_kind == sc_clock::kind_string) dir = SIGNAL; else if (obj_kind == sc_signal_base::kind_string) dir = REGISTER; // to do : dir = REGISTER; // dir = SIGNAL; if ( t.bit_size % 4 == 0) format = "x"; else format = "b"; if ( t.bit_size == 1) { downto = ""; } else { std::ostringstream nbits; nbits << t.bit_size-1; downto = nbits.str(); downto += " downto 0"; } #if 0 printf ("DECLAR (\"%s\", \":1\", \"%s\", %s, \"%s\", \"\" );\n", name.c_str (), format, dir, downto.c_str()); #endif DECLAR ((char*)(name.c_str ()), ":1", format, dir,(char *) downto.c_str(), "" ); #endif // PAT_TRACE_FORMAT } void sc_trace( sc_trace_file* tf, const signal2trace &t, const std::string &name ) { if (tf == NULL) return; if (t.bit_size > 64) cerr << "Warning : tracing functions do not support data types larger than 64 bits.\n"; if (already_initialized) cerr << "Warning : please call tracing functions BEFORE sc_initialize.\n"; //ajout du signal dans la liste des signaux à tracer: (tf->sig_list).push_back (t); switch (tf->flag) { case VCD_FORMAT : vcd_sc_trace (tf, t, name); break; case PAT_FORMAT : pat_sc_trace (tf, t, name); break; default : { cerr << "Unknown trace format.\n"; exit (1); } }// fin switch format pour sc_trace } //--------------------------------------------------------------------------- #if 0 static ostream& operator << (ostream &o, const signal2trace &s2t) { o << "signal2trace {" << "inter = " << hex << s2t.inter << ",alias = '" << s2t.alias << "'" << ",bitsize = " << dec << s2t.bit_size << ",pointer = " << hex << s2t.pointer << ",nomSig = " << s2t.nomSig << "}"; return o; } #endif //---------------------------------------------------------------------------- #define DEF_SC_TRACE(T) /*inline \*/ \ void \ sc_trace (sc_trace_file* tf, const T& object, const std::string &name) \ { \ signal2trace t; \ sc_interface *inter = new sc_localvar (object); \ t.inter = inter; \ t.alias = alias(); \ t.bit_size = get_bits_number(object); \ t.nomSig = name; \ sc_trace (tf, t, name); \ } \ DEF_SC_TRACE(bool) DEF_SC_TRACE(float) DEF_SC_TRACE(double) DEF_SC_TRACE(unsigned char) DEF_SC_TRACE(unsigned short) DEF_SC_TRACE(unsigned int) DEF_SC_TRACE(unsigned long) DEF_SC_TRACE(char) DEF_SC_TRACE(short) DEF_SC_TRACE(int) DEF_SC_TRACE(long) DEF_SC_TRACE(uint64) DEF_SC_TRACE(int64) #undef DEF_SC_TRACE //--------------------------------------------------------------------------- } // end of sc_core namespace