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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [hal/] [frv/] [arch/] [v2_0/] [src/] [frv_stub.c] - Blame information for rev 1773

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

Line No. Rev Author Line
1 1254 phoenix
//========================================================================
2
//
3
//      frv_stub.c
4
//
5
//      Helper functions for stub, generic to all FUJITSU 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 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, gthomas
44
// Contributors:  Red Hat, gthomas, jskov, msalter
45
// Date:          2001-09-16
46
// Purpose:       
47
// Description:   Helper functions for stub, generic to all FUJITSU processors
48
// Usage:         
49
//
50
//####DESCRIPTIONEND####
51
//
52
//========================================================================
53
 
54
#include <pkgconf/hal.h>
55
 
56
#ifdef CYGPKG_REDBOOT
57
#include <pkgconf/redboot.h>
58
#endif
59
 
60
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
61
 
62
#include <cyg/hal/hal_stub.h>
63
#include <cyg/hal/hal_arch.h>
64
#include <cyg/hal/hal_intr.h>
65
#include <cyg/hal/hal_cache.h>
66
 
67
#ifndef FALSE
68
#define FALSE 0
69
#define TRUE  1
70
#endif
71
 
72
#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
73
#include <cyg/hal/dbg-threads-api.h>    // dbg_currthread_id
74
#endif
75
 
76
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
77
cyg_uint32 __frv_breakinst = HAL_BREAKINST;
78
#endif
79
 
80
// Sadly, this doesn't seem to work on the FRV400 either
81
//#define USE_HW_STEP  
82
 
83
#ifdef CYGSEM_HAL_FRV_HW_DEBUG
84
static inline unsigned __get_dcr(void)
85
{
86
    unsigned retval;
87
 
88
    asm volatile (
89
        "movsg   dcr,%0\n"
90
        : "=r" (retval)
91
        : /* no inputs */  );
92
 
93
    return retval;
94
}
95
 
96
static inline void __set_dcr(unsigned val)
97
{
98
    asm volatile (
99
        "movgs   %0,dcr\n"
100
        : /* no outputs */
101
        : "r" (val) );
102
}
103
 
104
#endif
105
 
106
/* Given a trap value TRAP, return the corresponding signal. */
107
 
108
int __computeSignal (unsigned int trap_number)
109
{
110
    // should also catch CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION here but we
111
    // can't tell the different between a real one and a breakpoint :-(
112
    switch (trap_number) {
113
      // Interrupts
114
    case CYGNUM_HAL_VECTOR_EXTERNAL_INTERRUPT_LEVEL_1 ... CYGNUM_HAL_VECTOR_EXTERNAL_INTERRUPT_LEVEL_15:
115
        return SIGINT;
116
    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_MMU_MISS:
117
    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_ERROR:
118
    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_EXCEPTION:
119
    case CYGNUM_HAL_VECTOR_MEMORY_ADDRESS_NOT_ALIGNED:
120
    case CYGNUM_HAL_VECTOR_DATA_ACCESS_ERROR:
121
    case CYGNUM_HAL_VECTOR_DATA_ACCESS_MMU_MISS:
122
    case CYGNUM_HAL_VECTOR_DATA_ACCESS_EXCEPTION:
123
    case CYGNUM_HAL_VECTOR_DATA_STORE_ERROR:
124
        return SIGBUS;
125
    case CYGNUM_HAL_VECTOR_PRIVELEDGED_INSTRUCTION:
126
    case CYGNUM_HAL_VECTOR_ILLEGAL_INSTRUCTION:
127
    case CYGNUM_HAL_VECTOR_REGISTER_EXCEPTION:
128
    case CYGNUM_HAL_VECTOR_FP_DISABLED:
129
    case CYGNUM_HAL_VECTOR_MP_DISABLED:
130
    case CYGNUM_HAL_VECTOR_FP_EXCEPTION:
131
    case CYGNUM_HAL_VECTOR_MP_EXCEPTION:
132
    case CYGNUM_HAL_VECTOR_DIVISION_EXCEPTION:
133
    case CYGNUM_HAL_VECTOR_COMMIT_EXCEPTION:
134
    case CYGNUM_HAL_VECTOR_COMPOUND_EXCEPTION:
135
      return SIGILL;
136
    default:
137
        return SIGTRAP;
138
    }
139
}
140
 
141
 
142
/* Return the trap number corresponding to the last-taken trap. */
143
int __get_trap_number (void)
144
{
145
    // The vector is not not part of the GDB register set so get it
146
    // directly from the save context.
147
    return _hal_registers->vector;
148
}
149
 
150
 
151
#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
152
int __is_bsp_syscall(void)
153
{
154
  // Might want to be more specific here
155
  return (_hal_registers->vector == CYGNUM_HAL_VECTOR_SYSCALL);
156
}
157
#endif // defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
158
 
159
/* Set the currently-saved pc register value to PC. */
160
 
161
void set_pc (target_register_t pc)
162
{
163
    put_register (PC, pc);
164
}
165
 
166
 
167
/*----------------------------------------------------------------------
168
 * Single-step support
169
 */
170
 
171
/* Set things up so that the next user resume will execute one instruction.
172
   This may be done by setting breakpoints or setting a single step flag
173
   in the saved user registers, for example. */
174
 
175
#ifndef CYGSEM_HAL_FRV_HW_DEBUG
176
#if CYGINT_HAL_FRV_ARCH_FR400 == 1
177
#define VLIW_DEPTH 2
178
#endif
179
#if CYGINT_HAL_FRV_ARCH_FR500 == 1
180
#define VLIW_DEPTH 4
181
#endif
182
/*
183
 * Structure to hold opcodes hoisted when breakpoints are
184
 * set for single-stepping or async interruption.
185
 */
186
struct _bp_save {
187
    unsigned long  *addr;
188
    unsigned long   opcode;
189
};
190
 
191
/*
192
 * We single-step by setting breakpoints.
193
 *
194
 * This is where we save the original instructions.
195
 */
196
static struct _bp_save step_bp[VLIW_DEPTH+1];
197
 
198
//**************************************************************
199
//************ CAUTION!! ***************************************
200
//**************************************************************
201
//
202
// Attempt to analyze the current instruction.  This code is not
203
// perfect in the case of VLIW sequences, although it's close.
204
// Consider these sequences:
205
//
206
//      ldi.p   @(gr5,0),gr4
207
//      jmpl    @(gr4,gr0)
208
// and 
209
//
210
//      ldi.p   @(gr5,0),gr4
211
//      add.p   gr6,gr7,gr8
212
//      jmpl    @(gr4,gr0)
213
//
214
// In these cases, the only way to effectively calculate the 
215
// target address (of the jump) would be to simulate the actions
216
// of the pipelined instructions which come beforehand.
217
//
218
// Of course, this only affects single stepping through a VLIW
219
// sequence which contains such pipelined effects and a branch.
220
// Hopefully this is rare.
221
//
222
// Note: testing of the above sequence on the FR400 yielded an
223
// illegal instruction (invalid VLIW sequence), so this may not
224
// turn out to be a problem in practice, just theory.
225
//
226
//**************************************************************
227
//**************************************************************
228
 
229
static int
230
_analyze_instr(unsigned long pc, unsigned long *targ,
231
               unsigned long *next, int *is_vliw)
232
{
233
    unsigned long opcode;
234
    int n, is_branch = 0;
235
 
236
    opcode = *(unsigned long *)pc;
237
    switch ((opcode >> 18) & 0x7f) {
238
    case 6:
239
    case 7:
240
        /* bcc, fbcc */
241
        is_branch = 1;
242
        n = (int)(opcode << 16);
243
        n >>= 16;
244
        *targ = pc + n*4;
245
        pc += 4;
246
        break;
247
    case 12:
248
        /* jmpl */
249
        n = (int)(get_register((opcode>>12)&63));
250
        n += (int)(get_register(opcode&63));
251
        pc = n;
252
        break;
253
    case 13:
254
        /* jmpil */
255
        n = (int)(get_register((opcode>>12)&63));
256
        n += (((int)(opcode << 20)) >> 20);
257
        pc = n;
258
        break;
259
    case 15:
260
        /* call */
261
        n = (opcode >> 25) << 18;
262
        n |= (opcode & 0x3ffff);
263
        n <<= 8;
264
        n >>= 8;
265
        pc += n*4;
266
        break;
267
    case 14:
268
        /* ret */
269
        is_branch = 1;
270
        *targ = get_register(LR);
271
        pc += 4;
272
        break;
273
    default:
274
        pc += 4;
275
        break;
276
    }
277
    *next = pc;
278
    *is_vliw = (opcode & 0x80000000) == 0;
279
    return is_branch;
280
}
281
#endif
282
 
283
void __single_step (void)
284
{
285
#ifdef CYGSEM_HAL_FRV_HW_DEBUG
286
    __set_dcr(__get_dcr() | _DCR_SE);
287
    diag_printf("Setting single step - DCR: %x\n", __get_dcr());
288
#else
289
    unsigned long pc, targ, next_pc;
290
    int i, is_branch = 0;
291
    int is_vliw;
292
 
293
    for (i = 0;  i < VLIW_DEPTH+1;  i++) {
294
        step_bp[i].addr = NULL;
295
    }
296
 
297
    pc = get_register(PC);
298
    i = 1;
299
    while (i < (VLIW_DEPTH+1)) {
300
        is_branch = _analyze_instr(pc, &targ, &next_pc, &is_vliw);
301
        if (is_branch && next_pc != targ) {
302
            step_bp[i].addr = (unsigned long *)targ;
303
            step_bp[i].opcode = *(unsigned long *)targ;
304
            *(unsigned long *)targ = HAL_BREAKINST;
305
            HAL_DCACHE_STORE(targ, 4);
306
            HAL_ICACHE_INVALIDATE(targ, 4);
307
        }
308
        if (is_vliw) {
309
            pc += 4;
310
            i++;
311
        } else {
312
            break;
313
        }
314
    }
315
    step_bp[0].addr = (unsigned long *)next_pc;
316
    step_bp[0].opcode = *(unsigned long *)next_pc;
317
    *(unsigned long *)next_pc = HAL_BREAKINST;
318
    HAL_DCACHE_STORE(next_pc, 4);
319
    HAL_ICACHE_INVALIDATE(next_pc, 4);
320
#endif
321
}
322
 
323
/* Clear the single-step state. */
324
 
325
void __clear_single_step (void)
326
{
327
#ifdef CYGSEM_HAL_FRV_HW_DEBUG
328
    __set_dcr(__get_dcr() & ~_DCR_SE);
329
#else
330
    struct _bp_save *p;
331
    int i;
332
 
333
    for (i = 0;  i < VLIW_DEPTH+1;  i++) {
334
        p = &step_bp[i];
335
        if (p->addr) {
336
            *(p->addr) = p->opcode;
337
            HAL_DCACHE_STORE((cyg_uint32)p->addr, 4);
338
            HAL_ICACHE_INVALIDATE((cyg_uint32)p->addr, 4);
339
            p->addr = NULL;
340
        }
341
    }
342
#endif
343
}
344
 
345
void __install_breakpoints (void)
346
{
347
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
348
    /* Install the breakpoints in the breakpoint list */
349
    __install_breakpoint_list();
350
#endif
351
}
352
 
353
void __clear_breakpoints (void)
354
{
355
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
356
    __clear_breakpoint_list();
357
#endif
358
}
359
 
360
/* If the breakpoint we hit is in the breakpoint() instruction, return a
361
   non-zero value. */
362
 
363
int
364
__is_breakpoint_function ()
365
{
366
    return get_register (PC) == (target_register_t)&_breakinst;
367
}
368
 
369
 
370
/* Skip the current instruction.  Since this is only called by the
371
   stub when the PC points to a breakpoint or trap instruction,
372
   we can safely just skip 4. */
373
 
374
void __skipinst (void)
375
{
376
    unsigned long pc = get_register(PC);
377
 
378
    pc += 4;
379
    put_register(PC, pc);
380
}
381
 
382
#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.