1 /* Tracing support for CGEN-based simulators.
2 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
3 Contributed by Cygnus Support.
5 This file is part of GDB, the GNU debugger.
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)
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.
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. */
25 #ifndef SIZE_INSTRUCTION
26 #define SIZE_INSTRUCTION 16
30 #define SIZE_LOCATION 20
37 #ifndef SIZE_LINE_NUMBER
38 #define SIZE_LINE_NUMBER 4
41 #ifndef SIZE_CYCLE_COUNT
42 #define SIZE_CYCLE_COUNT 2
45 #ifndef SIZE_TOTAL_CYCLE_COUNT
46 #define SIZE_TOTAL_CYCLE_COUNT 9
49 #ifndef SIZE_TRACE_BUF
50 #define SIZE_TRACE_BUF 256
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. */
61 /* Non-zero if this is the first insn in a set of parallel insns. */
62 static int first_insn_p
;
64 /* For communication between trace_insn and trace_result. */
65 static int printed_result_p
;
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
;
75 trace_insn_init (SIM_CPU
*cpu
, int first_p
)
79 first_insn_p
= first_p
;
81 /* Set to NULL so trace_insn_fini can know if trace_insn was called. */
87 trace_insn_fini (SIM_CPU
*cpu
, const struct argbuf
*abuf
, int last_p
)
89 SIM_DESC sd
= CPU_STATE (cpu
);
91 /* Was insn traced? It might not be if trace ranges are in effect. */
92 if (current_insn
== NULL
)
95 /* The first thing printed is current and total cycle counts. */
97 if (PROFILE_MODEL_P (cpu
)
98 && ARGBUF_PROFILE_P (current_abuf
))
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
));
105 trace_printf (sd
, cpu
, "%-*ld %-*ld ",
106 SIZE_CYCLE_COUNT
, this_insn
,
107 SIZE_TOTAL_CYCLE_COUNT
, total
);
111 trace_printf (sd
, cpu
, "%-*ld %-*s ",
112 SIZE_CYCLE_COUNT
, this_insn
,
113 SIZE_TOTAL_CYCLE_COUNT
, "---");
117 /* Print the disassembled insn. */
119 trace_printf (sd
, cpu
, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu
)));
122 /* Print insn results. */
124 const CGEN_OPERAND_INSTANCE
*opinst
= CGEN_INSN_OPERANDS (current_insn
);
129 int indices
[MAX_OPERAND_INSTANCES
];
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
),
138 CGEN_OPERAND_INSTANCE_TYPE (opinst
) != CGEN_OPERAND_INSTANCE_END
;
141 if (CGEN_OPERAND_INSTANCE_TYPE (opinst
) == CGEN_OPERAND_INSTANCE_OUTPUT
)
142 trace_result (cpu
, current_insn
, opinst
, indices
[i
]);
148 /* Print anything else requested. */
151 trace_printf (sd
, cpu
, " %s\n", trace_buf
);
153 trace_printf (sd
, cpu
, "\n");
157 trace_insn (SIM_CPU
*cpu
, const struct cgen_insn
*opcode
,
158 const struct argbuf
*abuf
, PCADDR pc
)
162 printed_result_p
= 0;
163 current_insn
= opcode
;
166 if (CGEN_INSN_VIRTUAL_P (opcode
))
168 trace_prefix (CPU_STATE (cpu
), cpu
, NULL_CIA
, pc
, 0,
169 NULL
, 0, CGEN_INSN_NAME (opcode
));
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
),
177 first_insn_p
? " " : "|",
178 SIZE_INSTRUCTION
, disasm_buf
);
182 trace_extract (SIM_CPU
*cpu
, PCADDR pc
, char *name
, ...)
185 int printed_one_p
= 0;
188 va_start (args
, name
);
190 trace_printf (CPU_STATE (cpu
), cpu
, "Extract: 0x%.*lx: %s ",
196 fmt
= va_arg (args
, char *);
201 trace_printf (CPU_STATE (cpu
), cpu
, ", ");
203 type
= va_arg (args
, int);
207 ival
= va_arg (args
, int);
208 trace_printf (CPU_STATE (cpu
), cpu
, fmt
, ival
);
217 trace_printf (CPU_STATE (cpu
), cpu
, "\n");
221 trace_result (SIM_CPU
*cpu
, char *name
, int type
, ...)
225 va_start (args
, type
);
226 if (printed_result_p
)
227 cgen_trace_printf (cpu
, ", ");
233 cgen_trace_printf (cpu
, "%s <- 0x%x", name
, va_arg (args
, int));
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
));
246 printed_result_p
= 1;
250 /* Print trace output to BUFPTR if active, otherwise print normally.
251 This is only for tracing semantic code. */
254 cgen_trace_printf (SIM_CPU
*cpu
, char *fmt
, ...)
258 va_start (args
, fmt
);
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
);
266 vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu
)), fmt
, args
);
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
)