]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/cgen-trace.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.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, pc, 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 }