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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [hal/] [mn10300/] [arch/] [v2_0/] [src/] [mn10300_stub.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//========================================================================
2
//
3
//      mn10300_stub.c
4
//
5
//      Helper functions for mn10300 stub
6
//
7
//========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):     Red Hat, jskov
44
// Contributors:  Red Hat, jskov, dmoseley
45
// Date:          1998-11-06
46
// Purpose:       
47
// Description:   Helper functions for mn10300 stub
48
// Usage:         
49
//
50
//####DESCRIPTIONEND####
51
//
52
//========================================================================
53
 
54
#include <stddef.h>
55
 
56
#include <pkgconf/hal.h>
57
 
58
#ifdef CYGPKG_REDBOOT
59
#include <pkgconf/redboot.h>
60
#endif
61
 
62
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
63
 
64
#include <cyg/hal/hal_stub.h>
65
#include <cyg/hal/hal_arch.h>
66
#include <cyg/hal/hal_intr.h>
67
 
68
#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
69
#include <cyg/hal/dbg-threads-api.h>    // dbg_currthread_id
70
#endif
71
 
72
/*----------------------------------------------------------------------
73
 * Asynchronous interrupt support
74
 */
75
 
76
typedef unsigned char t_inst;
77
 
78
static struct
79
{
80
  t_inst *targetAddr;
81
  t_inst savedInstr;
82
} asyncBuffer;
83
 
84
/* Called to asynchronously interrupt a running program.
85
   Must be passed address of instruction interrupted.
86
   This is typically called in response to a debug port
87
   receive interrupt.
88
*/
89
 
90
void
91
install_async_breakpoint(void *pc)
92
{
93
  asyncBuffer.targetAddr = pc;
94
  asyncBuffer.savedInstr = *(t_inst *)pc;
95
  *(t_inst *)pc = (t_inst)HAL_BREAKINST;
96
  __instruction_cache(CACHE_FLUSH);
97
  __data_cache(CACHE_FLUSH);
98
}
99
 
100
/*--------------------------------------------------------------------*/
101
/* Given a trap value TRAP, return the corresponding signal. */
102
 
103
int __computeSignal (unsigned int trap_number)
104
{
105
    if (asyncBuffer.targetAddr != NULL)
106
    {
107
        /* BP installed by serial driver to stop running program */
108
        *asyncBuffer.targetAddr = asyncBuffer.savedInstr;
109
        __instruction_cache(CACHE_FLUSH);
110
        __data_cache(CACHE_FLUSH);
111
        asyncBuffer.targetAddr = NULL;
112
        return SIGINT;
113
    }
114
#ifdef SIGSYSCALL
115
    switch (trap_number)
116
      {
117
      case SIGSYSCALL:
118
        /* System call */
119
        return SIGSYSCALL;
120
      }
121
#endif
122
    return SIGTRAP;
123
}
124
 
125
/*--------------------------------------------------------------------*/
126
/* Return the trap number corresponding to the last-taken trap. */
127
 
128
int __get_trap_number (void)
129
{
130
    // The vector is not not part of the GDB register set so get it
131
    // directly from the save context.
132
    return _hal_registers->vector;
133
}
134
 
135
#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
136
int __is_bsp_syscall(void)
137
{
138
    return __get_trap_number() == SIGSYS;
139
}
140
#endif
141
 
142
/*--------------------------------------------------------------------*/
143
/* Set the currently-saved pc register value to PC. This also updates NPC
144
   as needed. */
145
 
146
void set_pc (target_register_t pc)
147
{
148
    put_register (PC, pc);
149
}
150
 
151
 
152
/*----------------------------------------------------------------------
153
 * Single-step support. Lifted from CygMon.
154
 */
155
 
156
#define NUM_SS_BPTS 2
157
static target_register_t break_mem [NUM_SS_BPTS] = {0, 0};
158
static unsigned char break_mem_data [NUM_SS_BPTS];
159
 
160
/* Set a single-step breakpoint at ADDR.  Up to two such breakpoints
161
   can be set; WHICH specifies which one to set (0 or 1).  */
162
 
163
static void
164
set_single_bp (int which, unsigned char *addr)
165
{
166
    if (0 == break_mem[which]) {
167
        break_mem[which] = (target_register_t) addr;
168
        break_mem_data[which] = *addr;
169
        *addr = HAL_BREAKINST;
170
    }
171
}
172
 
173
/* Clear any single-step breakpoint(s) that may have been set.  */
174
 
175
void __clear_single_step (void)
176
{
177
  int x;
178
  for (x = 0; x < NUM_SS_BPTS; x++)
179
    {
180
        unsigned char* addr = (unsigned char*) break_mem[x];
181
        if (addr) {
182
            *addr = break_mem_data[x];
183
            break_mem[x] = 0;
184
        }
185
    }
186
}
187
 
188
/* Read a 16-bit displacement from address 'p'. The
189
   value is stored little-endian.  */
190
 
191
static short
192
read_disp16(unsigned char *p)
193
{
194
    return (short)(p[0] | (p[1] << 8));
195
}
196
 
197
/* Read a 32-bit displacement from address 'p'. The
198
   value is stored little-endian.  */
199
 
200
static int
201
read_disp32(unsigned char *p)
202
{
203
    return (int)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
204
}
205
 
206
 
207
/* Get the contents of An register.  */
208
 
209
static unsigned int
210
get_areg (int n)
211
{
212
  switch (n)
213
    {
214
    case 0:
215
      return get_register (A0);
216
    case 1:
217
      return get_register (A1);
218
    case 2:
219
      return get_register (A2);
220
    case 3:
221
      return get_register (A3);
222
    }
223
  return 0;
224
}
225
 
226
 
227
/* Table of instruction sizes, indexed by first byte of instruction,
228
   used to determine the address of the next instruction for single stepping.
229
   If an entry is zero, special code must handle the case (for example,
230
   branches or multi-byte opcodes).  */
231
 
232
static char opcode_size[256] =
233
{
234
     /* 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
235
     /*------------------------------------------------*/
236
/* 0 */ 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3,
237
/* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
238
/* 2 */ 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
239
/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1,
240
/* 4 */ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2,
241
/* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
242
/* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
243
/* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
244
/* 8 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
245
/* 9 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
246
/* a */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
247
/* b */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
248
/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2,
249
/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250
/* e */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
251
/* f */ 0, 2, 2, 2, 2, 2, 2, 1, 0, 3, 0, 4, 0, 6, 7, 1
252
};
253
 
254
/* Set breakpoint(s) to simulate a single step from the current PC.  */
255
 
256
void __single_step (void)
257
{
258
  unsigned char *pc = (unsigned char *) get_register (PC);
259
  unsigned int opcode;
260
  int          displ;
261
 
262
  opcode = *pc;
263
 
264
  /* Check the table for the simple cases.  */
265
  displ = opcode_size[opcode];
266
  if (displ != 0)
267
    {
268
      set_single_bp (0, pc + displ);
269
      return;
270
    }
271
 
272
  /* Handle the more complicated cases.  */
273
  switch (opcode)
274
    {
275
    case 0xc0:
276
    case 0xc1:
277
    case 0xc2:
278
    case 0xc3:
279
    case 0xc4:
280
    case 0xc5:
281
    case 0xc6:
282
    case 0xc7:
283
    case 0xc8:
284
    case 0xc9:
285
    case 0xca:
286
      /*
287
       *  bxx (d8,PC)
288
       */
289
      displ = *((signed char *)pc + 1);
290
      set_single_bp (0, pc + 2);
291
      if (displ < 0 || displ > 2)
292
        set_single_bp (1, pc + displ);
293
      break;
294
 
295
    case 0xd0:
296
    case 0xd1:
297
    case 0xd2:
298
    case 0xd3:
299
    case 0xd4:
300
    case 0xd5:
301
    case 0xd6:
302
    case 0xd7:
303
    case 0xd8:
304
    case 0xd9:
305
    case 0xda:
306
      /*
307
       *  lxx (d8,PC)
308
       */
309
      if (pc != (unsigned char*) get_register (LAR))
310
        set_single_bp (0, (unsigned char *) get_register (LAR));
311
      set_single_bp (1, pc + 1);
312
      break;
313
 
314
    case 0xdb:
315
      /*
316
       * setlb requires special attention. It loads the next four instruction
317
       * bytes into the LIR register, so we can't insert a breakpoint in any
318
       * of those locations.
319
       */
320
      set_single_bp (0, pc + 5);
321
      break;
322
 
323
    case 0xcc:
324
    case 0xcd:
325
      /*
326
       * jmp (d16,PC) or call (d16,PC)
327
       */
328
      displ = read_disp16((char *)(pc + 1));
329
      set_single_bp (0, pc + displ);
330
      break;
331
 
332
    case 0xdc:
333
    case 0xdd:
334
      /*
335
       * jmp (d32,PC) or call (d32,PC)
336
       */
337
      displ = read_disp32((char *)(pc + 1));
338
      set_single_bp (0, pc + displ);
339
      break;
340
 
341
    case 0xde:
342
      /*
343
       *  retf
344
       */
345
      set_single_bp (0, (unsigned char *) get_register (MDR));
346
      break;
347
 
348
    case 0xdf:
349
      /*
350
       *  ret
351
       */
352
      displ = *((char *)pc + 2);
353
      set_single_bp (0, (unsigned char *) read_disp32 ((unsigned char *)
354
                     get_register (SP) + displ));
355
      break;
356
 
357
    case 0xf0:
358
      /*
359
       *  Some branching 2-byte instructions.
360
       */
361
      opcode = *(pc + 1);
362
      if (opcode >= 0xf0 && opcode <= 0xf7)
363
        {
364
          /* jmp (An) / calls (An) */
365
          set_single_bp (0, (unsigned char *) get_areg (opcode & 3));
366
 
367
        }
368
      else if (opcode == 0xfc)
369
        {
370
          /* rets */
371
          set_single_bp (0, (unsigned char *) read_disp32 ((unsigned char *)
372
                         get_register (SP)));
373
 
374
        }
375
      else if (opcode == 0xfd)
376
        {
377
          /* rti */
378
          set_single_bp (0, (unsigned char *) read_disp32 ((unsigned char *)
379
                         get_register (SP) + 4));
380
 
381
        }
382
      else
383
        set_single_bp (0, pc + 2);
384
 
385
      break;
386
 
387
    case 0xf8:
388
      /*
389
       *  Some branching 3-byte instructions.
390
       */
391
      opcode = *(pc + 1);
392
      if (opcode >= 0xe8 && opcode <= 0xeb)
393
        {
394
          displ = *((signed char *)pc + 2);
395
          set_single_bp (0, pc + 3);
396
          if (displ < 0 || displ > 3)
397
              set_single_bp (1, pc + displ);
398
 
399
        }
400
      else
401
        set_single_bp (0, pc + 3);
402
      break;
403
 
404
    case 0xfa:
405
      opcode = *(pc + 1);
406
      if (opcode == 0xff)
407
        {
408
          /* calls (d16,PC) */
409
          displ = read_disp16((char *)(pc + 2));
410
          set_single_bp (0, pc + displ);
411
        }
412
      else
413
        set_single_bp (0, pc + 4);
414
      break;
415
 
416
    case 0xfc:
417
      opcode = *(pc + 1);
418
      if (opcode == 0xff)
419
        {
420
          /* calls (d32,PC) */
421
          displ = read_disp32((char *)(pc + 2));
422
          set_single_bp (0, pc + displ);
423
        }
424
      else
425
        set_single_bp (0, pc + 6);
426
      break;
427
 
428
  }
429
}
430
 
431
void __install_breakpoints (void)
432
{
433
    /* NOP since single-step HW exceptions are used instead of
434
       breakpoints. */
435
 
436
  /* Install the breakpoints in the breakpoint list */
437
  __install_breakpoint_list();
438
}
439
 
440
void __clear_breakpoints (void)
441
{
442
  __clear_breakpoint_list();
443
}
444
 
445
 
446
/* If the breakpoint we hit is in the breakpoint() instruction, return a
447
   non-zero value. */
448
 
449
int
450
__is_breakpoint_function ()
451
{
452
    return get_register (PC) == (target_register_t)&CYG_LABEL_NAME(_breakinst);
453
}
454
 
455
 
456
/* Skip the current instruction. */
457
 
458
void __skipinst (void)
459
{
460
    unsigned char *pc = (char *) get_register (PC);
461
 
462
    switch (*pc)
463
    {
464
    case 0xff:                          // breakpoint instruction
465
        pc++;
466
        break;
467
    case 0xf0:                          // Assume syscall trap (0xf0, 0x20)
468
        pc += 2;
469
        break;
470
    default:
471
        pc++;                           // Assume all other instructions 
472
        break;                          // are one byte
473
    }
474
 
475
  put_register (PC, (target_register_t) pc);
476
}
477
 
478
#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

powered by: WebSVN 2.1.0

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