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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [mips/] [arch/] [current/] [src/] [mips-stub.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//========================================================================
2
//
3
//      mips-stub.h
4
//
5
//      Helper functions for stub, generic to all MIPS processors
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 Free Software Foundation, 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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     Red Hat, nickg
43
// Contributors:  Red Hat, nickg
44
// Date:          1998-06-08
45
// Purpose:       
46
// Description:   Helper functions for stub, generic to all MIPS processors
47
// Usage:         
48
//
49
//####DESCRIPTIONEND####
50
//
51
//========================================================================
52
 
53
#include <stddef.h>
54
 
55
#include <pkgconf/hal.h>
56
 
57
#ifdef CYGPKG_REDBOOT
58
#include <pkgconf/redboot.h>
59
#endif
60
 
61
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
62
 
63
#include <cyg/hal/hal_stub.h>
64
 
65
#define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS
66
#include <cyg/hal/mips-regs.h>
67
 
68
#include <cyg/hal/hal_arch.h>
69
#include <cyg/hal/hal_intr.h>
70
#include <cyg/hal/mips_opcode.h>
71
 
72
typedef unsigned long t_inst;
73
 
74
/*----------------------------------------------------------------------
75
 * Asynchronous interrupt support
76
 */
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 *epc)
92
{
93
  long gp_save;
94
 
95
  /* This may be called from a separately linked program,
96
     so we need to save and restore the incoming gp register
97
     and setup our stub local gp register.
98
     Alternatively, we could skip this foolishness if we
99
     compiled libstub with "-G 0". */
100
 
101
  __asm__ volatile ( "move   %0,$28\n"
102
                     ".extern _gp\n"
103
                     "la     $28,_gp\n"
104
                     : "=r" (gp_save) );
105
 
106
  asyncBuffer.targetAddr = epc;
107
  asyncBuffer.savedInstr = *(t_inst *)epc;
108
  *(t_inst *)epc = *(t_inst *)_breakinst;
109
  __instruction_cache(CACHE_FLUSH);
110
  __data_cache(CACHE_FLUSH);
111
 
112
  __asm__  volatile ( "move   $28,%0\n" :: "r"(gp_save) );
113
}
114
 
115
/*--------------------------------------------------------------------*/
116
/* Given a trap value TRAP, return the corresponding signal. */
117
 
118
int __computeSignal (unsigned int trap_number)
119
{
120
  switch (trap_number)
121
    {
122
    case EXC_INT:
123
      /* External interrupt */
124
      return SIGINT;
125
 
126
    case EXC_RI:
127
      /* Reserved instruction */
128
    case EXC_CPU:
129
      /* Coprocessor unusable */
130
      return SIGILL;
131
 
132
    case EXC_BP:
133
      /* Break point */
134
      if (asyncBuffer.targetAddr != NULL)
135
        {
136
          /* BP installed by serial driver to stop running program */
137
          *asyncBuffer.targetAddr = asyncBuffer.savedInstr;
138
          __instruction_cache(CACHE_FLUSH);
139
          __data_cache(CACHE_FLUSH);
140
          asyncBuffer.targetAddr = NULL;
141
          return SIGINT;
142
        }
143
      return SIGTRAP;
144
 
145
    case EXC_OVF:
146
      /* Arithmetic overflow */
147
    case EXC_TRAP:
148
      /* Trap exception */
149
    case EXC_FPE:
150
      /* Floating Point Exception */
151
      return SIGFPE;
152
 
153
    case EXC_IBE:
154
      /* Bus error (Ifetch) */
155
    case EXC_DBE:
156
      /* Bus error (data load or store) */
157
      return SIGBUS;
158
 
159
    case EXC_MOD:
160
      /* TLB modification exception */
161
    case EXC_TLBL:
162
      /* TLB miss (Load or Ifetch) */
163
    case EXC_TLBS:
164
      /* TLB miss (Store) */
165
    case EXC_ADEL:
166
      /* Address error (Load or Ifetch) */
167
    case EXC_ADES:
168
      /* Address error (Store) */
169
      return SIGSEGV;
170
 
171
    case EXC_SYS:
172
      /* System call */
173
      return SIGSYS;
174
 
175
    default:
176
      return SIGTERM;
177
    }
178
}
179
 
180
/* Return the trap number corresponding to the last-taken trap. */
181
 
182
int __get_trap_number (void)
183
{
184
  return (get_register (CAUSE) & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
185
}
186
 
187
#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
188
int __is_bsp_syscall(void)
189
{
190
    return __get_trap_number() == EXC_SYS;
191
}
192
#endif
193
 
194
/* Set the currently-saved pc register value to PC. This also updates NPC
195
   as needed. */
196
 
197
void set_pc (target_register_t pc)
198
{
199
  put_register (PC, pc);
200
}
201
 
202
 
203
/*----------------------------------------------------------------------
204
 * Single-step support
205
 */
206
 
207
/* Saved instruction data for single step support.  */
208
 
209
static struct
210
{
211
  t_inst *targetAddr;
212
  t_inst savedInstr;
213
} instrBuffer;
214
 
215
 
216
/* Set things up so that the next user resume will execute one instruction.
217
   This may be done by setting breakpoints or setting a single step flag
218
   in the saved user registers, for example. */
219
 
220
void __single_step (void)
221
{
222
  InstFmt inst;
223
  t_inst *pc = (t_inst *) get_register (PC);
224
 
225
  instrBuffer.targetAddr = pc + 1;              /* set default */
226
 
227
  inst.word = *pc;                              /* read the next instruction  */
228
 
229
//diag_printf("pc %08x %08x\n",pc,inst.word);
230
 
231
  switch (inst.RType.op) {                    /* override default if branch */
232
    case OP_SPECIAL:
233
      switch (inst.RType.func) {
234
        case OP_JR:
235
        case OP_JALR:
236
          instrBuffer.targetAddr = (t_inst *) get_register (inst.RType.rs);
237
          break;
238
      };
239
      break;
240
 
241
    case OP_REGIMM:
242
      switch (inst.IType.rt) {
243
        case OP_BLTZ:
244
        case OP_BLTZL:
245
        case OP_BLTZAL:
246
        case OP_BLTZALL:
247
            if ((int)get_register (inst.IType.rs) < 0 )
248
            instrBuffer.targetAddr =
249
              (t_inst *)(((signed short)inst.IType.imm<<2)
250
                                        + (get_register (PC) + 4));
251
          else
252
            instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
253
          break;
254
        case OP_BGEZ:
255
        case OP_BGEZL:
256
        case OP_BGEZAL:
257
        case OP_BGEZALL:
258
            if ((int)get_register (inst.IType.rs) >= 0 )
259
            instrBuffer.targetAddr =
260
              (t_inst *)(((signed short)inst.IType.imm<<2)
261
                                        + (get_register (PC) + 4));
262
          else
263
            instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
264
          break;
265
      };
266
      break;
267
 
268
    case OP_J:
269
    case OP_JAL:
270
      instrBuffer.targetAddr =
271
        (t_inst *)((inst.JType.target<<2)
272
                   + ((get_register (PC) + 4)&0xf0000000));
273
      break;
274
 
275
    case OP_BEQ:
276
    case OP_BEQL:
277
      if (get_register (inst.IType.rs) == get_register (inst.IType.rt))
278
        instrBuffer.targetAddr =
279
          (t_inst *)(((signed short)inst.IType.imm<<2)
280
                     + (get_register (PC) + 4));
281
      else
282
        instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
283
      break;
284
    case OP_BNE:
285
    case OP_BNEL:
286
      if (get_register (inst.IType.rs) != get_register (inst.IType.rt))
287
        instrBuffer.targetAddr =
288
          (t_inst *)(((signed short)inst.IType.imm<<2)
289
                     + (get_register (PC) + 4));
290
      else
291
        instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
292
      break;
293
    case OP_BLEZ:
294
    case OP_BLEZL:
295
        if ((int)get_register (inst.IType.rs) <= 0)
296
        instrBuffer.targetAddr =
297
          (t_inst *)(((signed short)inst.IType.imm<<2) + (get_register (PC) + 4));
298
      else
299
        instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
300
      break;
301
    case OP_BGTZ:
302
    case OP_BGTZL:
303
        if ((int)get_register (inst.IType.rs) > 0)
304
        instrBuffer.targetAddr =
305
          (t_inst *)(((signed short)inst.IType.imm<<2) + (get_register (PC) + 4));
306
      else
307
        instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
308
      break;
309
 
310
#ifdef CYGHWR_HAL_MIPS_FPU
311
 
312
    case OP_COP1:
313
      if (inst.RType.rs == OP_BC)
314
          switch (inst.RType.rt) {
315
            case COPz_BCF:
316
            case COPz_BCFL:
317
                if (get_register (FCR31) & FCR31_C)
318
                instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
319
              else
320
                instrBuffer.targetAddr =
321
                  (t_inst *)(((signed short)inst.IType.imm<<2)
322
                                            + (get_register (PC) + 4));
323
              break;
324
            case COPz_BCT:
325
            case COPz_BCTL:
326
                if (get_register (FCR31) & FCR31_C)
327
                instrBuffer.targetAddr =
328
                  (t_inst *)(((signed short)inst.IType.imm<<2)
329
                                            + (get_register (PC) + 4));
330
              else
331
                instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
332
              break;
333
          };
334
      break;
335
#endif
336
 
337
  }
338
}
339
 
340
 
341
/* Clear the single-step state. */
342
 
343
void __clear_single_step (void)
344
{
345
//diag_printf("clear_ss ta %08x\n",instrBuffer.targetAddr);
346
  if (instrBuffer.targetAddr != NULL)
347
    {
348
      *instrBuffer.targetAddr = instrBuffer.savedInstr;
349
      instrBuffer.targetAddr = NULL;
350
    }
351
  instrBuffer.savedInstr = NOP_INSTR;
352
}
353
 
354
 
355
void __install_breakpoints ()
356
{
357
//diag_printf("install_bpt ta %08x\n",instrBuffer.targetAddr);
358
  if (instrBuffer.targetAddr != NULL)
359
    {
360
      instrBuffer.savedInstr = *instrBuffer.targetAddr;
361
      *instrBuffer.targetAddr = __break_opcode ();
362
//diag_printf("ta %08x si %08x *ta %08x\n",
363
//            instrBuffer.targetAddr,instrBuffer.savedInstr,*instrBuffer.targetAddr);
364
 
365
      /* Ensure that the planted breakpoint makes it out to memory and
366
         is subsequently loaded into the instruction cache.
367
      */
368
      __data_cache (CACHE_FLUSH) ;
369
      __instruction_cache (CACHE_FLUSH) ;
370
    }
371
 
372
  /* Install the breakpoints in the breakpoint list */
373
  __install_breakpoint_list();
374
}
375
 
376
void __clear_breakpoints (void)
377
{
378
  __clear_breakpoint_list();
379
}
380
 
381
 
382
/* If the breakpoint we hit is in the breakpoint() instruction, return a
383
   non-zero value. */
384
 
385
int
386
__is_breakpoint_function ()
387
{
388
    return get_register (PC) == (target_register_t)(unsigned long)&_breakinst;
389
}
390
 
391
 
392
/* Skip the current instruction.  Since this is only called by the
393
   stub when the PC points to a breakpoint or trap instruction,
394
   we can safely just skip 4. */
395
 
396
void __skipinst (void)
397
{
398
    put_register (PC, get_register (PC) + 4);
399
}
400
 
401
#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.