OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [common/] [cgen-trace.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/* Tracing support for CGEN-based simulators.
2
   Copyright (C) 1996, 1997, 1998, 1999, 2007, 2008
3
   Free Software Foundation, Inc.
4
   Contributed by Cygnus Support.
5
 
6
This file is part of GDB, the GNU debugger.
7
 
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
12
 
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#include <errno.h>
22
#include "dis-asm.h"
23
#include "bfd.h"
24
#include "sim-main.h"
25
#include "sim-fpu.h"
26
 
27
#undef min
28
#define min(a,b) ((a) < (b) ? (a) : (b))
29
 
30
#ifndef SIZE_INSTRUCTION
31
#define SIZE_INSTRUCTION 16
32
#endif
33
 
34
#ifndef SIZE_LOCATION
35
#define SIZE_LOCATION 20
36
#endif
37
 
38
#ifndef SIZE_PC
39
#define SIZE_PC 6
40
#endif
41
 
42
#ifndef SIZE_LINE_NUMBER
43
#define SIZE_LINE_NUMBER 4
44
#endif
45
 
46
#ifndef SIZE_CYCLE_COUNT
47
#define SIZE_CYCLE_COUNT 2
48
#endif
49
 
50
#ifndef SIZE_TOTAL_CYCLE_COUNT
51
#define SIZE_TOTAL_CYCLE_COUNT 9
52
#endif
53
 
54
#ifndef SIZE_TRACE_BUF
55
#define SIZE_TRACE_BUF 1024
56
#endif
57
 
58
/* Text is queued in TRACE_BUF because we want to output the insn's cycle
59
   count first but that isn't known until after the insn has executed.
60
   This also handles the queueing of trace results, TRACE_RESULT may be
61
   called multiple times for one insn.  */
62
static char trace_buf[SIZE_TRACE_BUF];
63
/* If NULL, output to stdout directly.  */
64
static char *bufptr;
65
 
66
/* Non-zero if this is the first insn in a set of parallel insns.  */
67
static int first_insn_p;
68
 
69
/* For communication between trace_insn and trace_result.  */
70
static int printed_result_p;
71
 
72
/* Insn and its extracted fields.
73
   Set by trace_insn, used by trace_insn_fini.
74
   ??? Move to SIM_CPU to support heterogeneous multi-cpu case.  */
75
static const struct cgen_insn *current_insn;
76
static const struct argbuf *current_abuf;
77
 
78
void
79
trace_insn_init (SIM_CPU *cpu, int first_p)
80
{
81
  bufptr = trace_buf;
82
  *bufptr = 0;
83
  first_insn_p = first_p;
84
 
85
  /* Set to NULL so trace_insn_fini can know if trace_insn was called.  */
86
  current_insn = NULL;
87
  current_abuf = NULL;
88
}
89
 
90
void
91
trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
92
{
93
  SIM_DESC sd = CPU_STATE (cpu);
94
 
95
  /* Was insn traced?  It might not be if trace ranges are in effect.  */
96
  if (current_insn == NULL)
97
    return;
98
 
99
  /* The first thing printed is current and total cycle counts.  */
100
 
101
  if (PROFILE_MODEL_P (cpu)
102
      && ARGBUF_PROFILE_P (current_abuf))
103
    {
104
      unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
105
      unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
106
 
107
      if (last_p)
108
        {
109
          trace_printf (sd, cpu, "%-*ld %-*ld ",
110
                        SIZE_CYCLE_COUNT, this_insn,
111
                        SIZE_TOTAL_CYCLE_COUNT, total);
112
        }
113
      else
114
        {
115
          trace_printf (sd, cpu, "%-*ld %-*s ",
116
                        SIZE_CYCLE_COUNT, this_insn,
117
                        SIZE_TOTAL_CYCLE_COUNT, "---");
118
        }
119
    }
120
 
121
  /* Print the disassembled insn.  */
122
 
123
  trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
124
 
125
#if 0
126
  /* Print insn results.  */
127
  {
128
    const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn);
129
 
130
    if (opinst)
131
      {
132
        int i;
133
        int indices[MAX_OPERAND_INSTANCES];
134
 
135
        /* Fetch the operands used by the insn.  */
136
        /* FIXME: Add fn ptr to CGEN_CPU_DESC.  */
137
        CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn,
138
                                      0, CGEN_FIELDS_BITSIZE (&insn_fields),
139
                                      indices);
140
 
141
        for (i = 0;
142
             CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END;
143
             ++i, ++opinst)
144
          {
145
            if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT)
146
              trace_result (cpu, current_insn, opinst, indices[i]);
147
          }
148
      }
149
  }
150
#endif
151
 
152
  /* Print anything else requested.  */
153
 
154
  if (*trace_buf)
155
    trace_printf (sd, cpu, " %s\n", trace_buf);
156
  else
157
    trace_printf (sd, cpu, "\n");
158
}
159
 
160
void
161
trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
162
            const struct argbuf *abuf, IADDR pc)
163
{
164
  char disasm_buf[50];
165
 
166
  printed_result_p = 0;
167
  current_insn = opcode;
168
  current_abuf = abuf;
169
 
170
  if (CGEN_INSN_VIRTUAL_P (opcode))
171
    {
172
      trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, 0,
173
                    NULL, 0, CGEN_INSN_NAME (opcode));
174
      return;
175
    }
176
 
177
  CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf);
178
  trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
179
                NULL, 0,
180
                "%s%-*s",
181
                first_insn_p ? " " : "|",
182
                SIZE_INSTRUCTION, disasm_buf);
183
}
184
 
185
void
186
trace_extract (SIM_CPU *cpu, IADDR pc, char *name, ...)
187
{
188
  va_list args;
189
  int printed_one_p = 0;
190
  char *fmt;
191
 
192
  va_start (args, name);
193
 
194
  trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
195
                SIZE_PC, pc, name);
196
 
197
  do {
198
    int type,ival;
199
 
200
    fmt = va_arg (args, char *);
201
 
202
    if (fmt)
203
      {
204
        if (printed_one_p)
205
          trace_printf (CPU_STATE (cpu), cpu, ", ");
206
        printed_one_p = 1;
207
        type = va_arg (args, int);
208
        switch (type)
209
          {
210
          case 'x' :
211
            ival = va_arg (args, int);
212
            trace_printf (CPU_STATE (cpu), cpu, fmt, ival);
213
            break;
214
          default :
215
            abort ();
216
          }
217
      }
218
  } while (fmt);
219
 
220
  va_end (args);
221
  trace_printf (CPU_STATE (cpu), cpu, "\n");
222
}
223
 
224
void
225
trace_result (SIM_CPU *cpu, char *name, int type, ...)
226
{
227
  va_list args;
228
 
229
  va_start (args, type);
230
  if (printed_result_p)
231
    cgen_trace_printf (cpu, ", ");
232
 
233
  switch (type)
234
    {
235
    case 'x' :
236
    default :
237
      cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
238
      break;
239
    case 'f':
240
      {
241
        DI di;
242
        sim_fpu f;
243
 
244
        /* this is separated from previous line for sunos cc */
245
        di = va_arg (args, DI);
246
        sim_fpu_64to (&f, di);
247
 
248
        cgen_trace_printf (cpu, "%s <- ", name);
249
        sim_fpu_printn_fpu (&f, (sim_fpu_print_func *) cgen_trace_printf, 4, cpu);
250
        break;
251
      }
252
    case 'D' :
253
      {
254
        DI di;
255
        /* this is separated from previous line for sunos cc */
256
        di = va_arg (args, DI);
257
        cgen_trace_printf (cpu, "%s <- 0x%x%08x", name,
258
                           GETHIDI(di), GETLODI (di));
259
        break;
260
      }
261
    }
262
 
263
  printed_result_p = 1;
264
  va_end (args);
265
}
266
 
267
/* Print trace output to BUFPTR if active, otherwise print normally.
268
   This is only for tracing semantic code.  */
269
 
270
void
271
cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
272
{
273
  va_list args;
274
 
275
  va_start (args, fmt);
276
 
277
  if (bufptr == NULL)
278
    {
279
      if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL)
280
        (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
281
          (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args);
282
      else
283
        vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args);
284
    }
285
  else
286
    {
287
      vsprintf (bufptr, fmt, args);
288
      bufptr += strlen (bufptr);
289
      /* ??? Need version of SIM_ASSERT that is always enabled.  */
290
      if (bufptr - trace_buf > SIZE_TRACE_BUF)
291
        abort ();
292
    }
293
 
294
  va_end (args);
295
}
296
 
297
/* Disassembly support.  */
298
 
299
/* sprintf to a "stream" */
300
 
301
int
302
sim_disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...))
303
{
304
#ifndef __STDC__
305
  SFILE *f;
306
  const char *format;
307
#endif
308
  int n;
309
  va_list args;
310
 
311
  VA_START (args, format);
312
#ifndef __STDC__
313
  f = va_arg (args, SFILE *);
314
  format = va_arg (args, char *);
315
#endif
316
  vsprintf (f->current, format, args);
317
  f->current += n = strlen (f->current);
318
  va_end (args);
319
  return n;
320
}
321
 
322
/* Memory read support for an opcodes disassembler.  */
323
 
324
int
325
sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
326
                        struct disassemble_info *info)
327
{
328
  SIM_CPU *cpu = (SIM_CPU *) info->application_data;
329
  SIM_DESC sd = CPU_STATE (cpu);
330
  unsigned length_read;
331
 
332
  length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr,
333
                                      length);
334
  if (length_read != length)
335
    return EIO;
336
  return 0;
337
}
338
 
339
/* Memory error support for an opcodes disassembler.  */
340
 
341
void
342
sim_disasm_perror_memory (int status, bfd_vma memaddr,
343
                          struct disassemble_info *info)
344
{
345
  if (status != EIO)
346
    /* Can't happen.  */
347
    info->fprintf_func (info->stream, "Unknown error %d.", status);
348
  else
349
    /* Actually, address between memaddr and memaddr + len was
350
       out of bounds.  */
351
    info->fprintf_func (info->stream,
352
                        "Address 0x%x is out of bounds.",
353
                        (int) memaddr);
354
}
355
 
356
/* Disassemble using the CGEN opcode table.
357
   ??? While executing an instruction, the insn has been decoded and all its
358
   fields have been extracted.  It is certainly possible to do the disassembly
359
   with that data.  This seems simpler, but maybe in the future the already
360
   extracted fields will be used.  */
361
 
362
void
363
sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn,
364
                           const ARGBUF *abuf, IADDR pc, char *buf)
365
{
366
  unsigned int length;
367
  unsigned int base_length;
368
  unsigned long insn_value;
369
  struct disassemble_info disasm_info;
370
  SFILE sfile;
371
  union {
372
    unsigned8 bytes[CGEN_MAX_INSN_SIZE];
373
    unsigned16 shorts[8];
374
    unsigned32 words[4];
375
  } insn_buf;
376
  SIM_DESC sd = CPU_STATE (cpu);
377
  CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu);
378
  CGEN_EXTRACT_INFO ex_info;
379
  CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
380
  int insn_bit_length = CGEN_INSN_BITSIZE (insn);
381
  int insn_length = insn_bit_length / 8;
382
 
383
  sfile.buffer = sfile.current = buf;
384
  INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
385
                         (fprintf_ftype) sim_disasm_sprintf);
386
  disasm_info.endian =
387
    (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
388
     : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
389
     : BFD_ENDIAN_UNKNOWN);
390
 
391
  length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc,
392
                                 insn_length);
393
 
394
  if (length != insn_length)
395
  {
396
    sim_io_error (sd, "unable to read address %x", pc);
397
  }
398
 
399
  /* If the entire insn will fit into an integer, then do it. Otherwise, just
400
     use the bits of the base_insn.  */
401
  if (insn_bit_length <= 32)
402
    base_length = insn_bit_length;
403
  else
404
    base_length = min (cd->base_insn_bitsize, insn_bit_length);
405
  switch (base_length)
406
    {
407
    case 0 : return; /* fake insn, typically "compile" (aka "invalid") */
408
    case 8 : insn_value = insn_buf.bytes[0]; break;
409
    case 16 : insn_value = T2H_2 (insn_buf.shorts[0]); break;
410
    case 32 : insn_value = T2H_4 (insn_buf.words[0]); break;
411
    default: abort ();
412
    }
413
 
414
  disasm_info.buffer_vma = pc;
415
  disasm_info.buffer = insn_buf.bytes;
416
  disasm_info.buffer_length = length;
417
 
418
  ex_info.dis_info = (PTR) &disasm_info;
419
  ex_info.valid = (1 << length) - 1;
420
  ex_info.insn_bytes = insn_buf.bytes;
421
 
422
  length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc);
423
  /* Result of extract fn is in bits.  */
424
  /* ??? This assumes that each instruction has a fixed length (and thus
425
     for insns with multiple versions of variable lengths they would each
426
     have their own table entry).  */
427
  if (length == insn_bit_length)
428
    {
429
      (*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length);
430
    }
431
  else
432
    {
433
      /* This shouldn't happen, but aborting is too drastic.  */
434
      strcpy (buf, "***unknown***");
435
    }
436
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.