* Make-common.in (CGEN_INCLUDE_DEPS): Add cgen-defs.h, cgen-engine.h.
[external/binutils.git] / sim / common / cgen-trace.c
1 /* Tracing support for CGEN-based simulators.
2    Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.
4
5 This file is part of GDB, the GNU debugger.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "sim-main.h"
22 #include "bfd.h"
23 #include "cpu-opc.h"
24
25 #ifndef SIZE_INSTRUCTION
26 #define SIZE_INSTRUCTION 16
27 #endif
28
29 #ifndef SIZE_LOCATION
30 #define SIZE_LOCATION 20
31 #endif
32
33 #ifndef SIZE_PC
34 #define SIZE_PC 6
35 #endif
36
37 #ifndef SIZE_LINE_NUMBER
38 #define SIZE_LINE_NUMBER 4
39 #endif
40
41 #ifndef SIZE_CYCLE_COUNT
42 #define SIZE_CYCLE_COUNT 2
43 #endif
44
45 #ifndef SIZE_TOTAL_CYCLE_COUNT
46 #define SIZE_TOTAL_CYCLE_COUNT 9
47 #endif
48
49 #ifndef SIZE_TRACE_BUF
50 #define SIZE_TRACE_BUF 256
51 #endif
52
53 /* Text is queued in TRACE_BUF because we want to output the insn's cycle
54    count first but that isn't known until after the insn has executed.
55    This also handles the queueing of trace results, TRACE_RESULT may be
56    called multiple times for one insn.  */
57 static char trace_buf[SIZE_TRACE_BUF];
58 /* If NULL, output to stdout directly.  */
59 static char *bufptr;
60
61 /* Non-zero if this is the first insn in a set of parallel insns.  */
62 static int first_insn_p;
63
64 /* For communication between trace_insn and trace_result.  */
65 static int printed_result_p;
66
67 /* Insn and its extracted fields.
68    Set by trace_insn, used by trace_insn_fini.
69    ??? Move to SIM_CPU to support heterogeneous multi-cpu case.  */
70 static const struct cgen_insn *current_insn;
71 static CGEN_FIELDS insn_fields;
72 static const struct argbuf *current_abuf;
73
74 void
75 trace_insn_init (SIM_CPU *cpu, int first_p)
76 {
77   bufptr = trace_buf;
78   *bufptr = 0;
79   first_insn_p = first_p;
80
81   /* Set to NULL so trace_insn_fini can know if trace_insn was called.  */
82   current_insn = NULL;
83   current_abuf = NULL;
84 }
85
86 void
87 trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
88 {
89   SIM_DESC sd = CPU_STATE (cpu);
90
91   /* Was insn traced?  It might not be if trace ranges are in effect.  */
92   if (current_insn == NULL)
93     return;
94
95   /* The first thing printed is current and total cycle counts.  */
96
97   if (PROFILE_MODEL_P (cpu)
98       && ARGBUF_PROFILE_P (current_abuf))
99     {
100       unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
101       unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
102
103       if (last_p)
104         {
105           trace_printf (sd, cpu, "%-*ld %-*ld ",
106                         SIZE_CYCLE_COUNT, this_insn,
107                         SIZE_TOTAL_CYCLE_COUNT, total);
108         }
109       else
110         {
111           trace_printf (sd, cpu, "%-*ld %-*s ",
112                         SIZE_CYCLE_COUNT, this_insn,
113                         SIZE_TOTAL_CYCLE_COUNT, "---");
114         }
115     }
116
117   /* Print the disassembled insn.  */
118
119   trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
120
121 #if 0
122   /* Print insn results.  */
123   {
124     const CGEN_OPERAND_INSTANCE *opinst = CGEN_INSN_OPERANDS (current_insn);
125
126     if (opinst)
127       {
128         int i;
129         int indices[MAX_OPERAND_INSTANCES];
130
131         /* Fetch the operands used by the insn.  */
132         /* FIXME: Add fn ptr to CGEN_OPCODE_DESC.  */
133         CGEN_SYM (get_insn_operands) (STATE_OPCODE_TABLE (sd), current_insn,
134                                       0, CGEN_FIELDS_BITSIZE (&insn_fields),
135                                       indices);
136
137         for (i = 0;
138              CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
139              ++i, ++opinst)
140           {
141             if (CGEN_OPERAND_INSTANCE_TYPE (opinst) == CGEN_OPERAND_INSTANCE_OUTPUT)
142               trace_result (cpu, current_insn, opinst, indices[i]);
143           }
144       }
145   }
146 #endif
147
148   /* Print anything else requested.  */
149
150   if (*trace_buf)
151     trace_printf (sd, cpu, " %s\n", trace_buf);
152   else
153     trace_printf (sd, cpu, "\n");
154 }
155
156 void
157 trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
158             const struct argbuf *abuf, PCADDR pc)
159 {
160   char disasm_buf[50];
161
162   printed_result_p = 0;
163   current_insn = opcode;
164   current_abuf = abuf;
165
166   if (CGEN_INSN_VIRTUAL_P (opcode))
167     {
168       trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, (address_word) 0, 0,
169                     NULL, 0, CGEN_INSN_NAME (opcode));
170       return;
171     }
172
173   sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf, &insn_fields);
174   trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
175                 NULL, 0,
176                 "%s%-*s",
177                 first_insn_p ? " " : "|",
178                 SIZE_INSTRUCTION, disasm_buf);
179 }
180
181 void
182 trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...)
183 {
184   va_list args;
185   int printed_one_p = 0;
186   char *fmt;
187
188   va_start (args, name);
189
190   trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
191                 SIZE_PC, pc, name);
192
193   do {
194     int type,ival;
195
196     fmt = va_arg (args, char *);
197
198     if (fmt)
199       {
200         if (printed_one_p)
201           trace_printf (CPU_STATE (cpu), cpu, ", ");
202         printed_one_p = 1;
203         type = va_arg (args, int);
204         switch (type)
205           {
206           case 'x' :
207             ival = va_arg (args, int);
208             trace_printf (CPU_STATE (cpu), cpu, fmt, ival);
209             break;
210           default :
211             abort ();
212           }
213       }
214   } while (fmt);
215
216   va_end (args);
217   trace_printf (CPU_STATE (cpu), cpu, "\n");
218 }
219
220 void
221 trace_result (SIM_CPU *cpu, char *name, int type, ...)
222 {
223   va_list args;
224
225   va_start (args, type);
226   if (printed_result_p)
227     cgen_trace_printf (cpu, ", ");
228
229   switch (type)
230     {
231     case 'x' :
232     default :
233       cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
234       break;
235     case 'D' :
236       {
237         DI di;
238         /* this is separated from previous line for sunos cc */
239         di = va_arg (args, DI);
240         cgen_trace_printf (cpu, "%s <- 0x%x%08x", name,
241                            GETHIDI(di), GETLODI (di));
242         break;
243       }
244     }
245
246   printed_result_p = 1;
247   va_end (args);
248 }
249
250 /* Print trace output to BUFPTR if active, otherwise print normally.
251    This is only for tracing semantic code.  */
252
253 void
254 cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
255 {
256   va_list args;
257
258   va_start (args, fmt);
259
260   if (bufptr == NULL)
261     {
262       if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL)
263         (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
264           (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args);
265       else
266         vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args);
267     }
268   else
269     {
270       vsprintf (bufptr, fmt, args);
271       bufptr += strlen (bufptr);
272       /* ??? Need version of SIM_ASSERT that is always enabled.  */
273       if (bufptr - trace_buf > SIZE_TRACE_BUF)
274         abort ();
275     }
276
277   va_end (args);
278 }