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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//========================================================================
2
//
3
//      arm_stub.c
4
//
5
//      Helper functions for stub, generic to all ARM 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, 2003 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, gthomas
43
// Contributors:  Red Hat, gthomas, jskov
44
// Date:          1998-11-26
45
// Purpose:       
46
// Description:   Helper functions for stub, generic to all ARM processors
47
// Usage:         
48
//
49
//####DESCRIPTIONEND####
50
//
51
//========================================================================
52
 
53
#include <stddef.h>
54
#include <string.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
#ifdef CYGPKG_HAL_ARM_SIM
65
#error "GDB Stub support not implemented for ARM SIM"
66
#endif
67
 
68
#include <cyg/hal/hal_stub.h>
69
#include <cyg/hal/hal_arch.h>
70
#include <cyg/hal/hal_intr.h>
71
 
72
#ifndef FALSE
73
#define FALSE 0
74
#define TRUE  1
75
#endif
76
 
77
// Use bit 0 as a thumb-mode flag for next address to be executed.
78
// Alternative would be to keep track of it using a C variable, but
79
// since bit 0 is used by the BX instruction, we might as well do the
80
// same thing and thus avoid checking two different flags.
81
#define IS_THUMB_ADDR(addr)     ((addr) & 1)
82
#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
83
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
84
 
85
#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
86
#include <cyg/hal/dbg-threads-api.h>    // dbg_currthread_id
87
#endif
88
 
89
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
90
cyg_uint32 __arm_breakinst = HAL_BREAKINST_ARM;
91
cyg_uint16 __thumb_breakinst = HAL_BREAKINST_THUMB;
92
#endif
93
 
94
/* Given a trap value TRAP, return the corresponding signal. */
95
 
96
int __computeSignal (unsigned int trap_number)
97
{
98
    // Check to see if we stopped because of a hw watchpoint/breakpoint.
99
#ifdef HAL_STUB_IS_STOPPED_BY_HARDWARE
100
    {
101
        void *daddr;
102
        if (HAL_STUB_IS_STOPPED_BY_HARDWARE(daddr))
103
            return SIGTRAP;
104
    }
105
#endif
106
    // should also catch CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION here but we
107
    // can't tell the different between a real one and a breakpoint :-(
108
    switch (trap_number) {
109
    case CYGNUM_HAL_VECTOR_ABORT_PREFETCH:      // Fall through
110
    case CYGNUM_HAL_VECTOR_ABORT_DATA:          // Fall through
111
    case CYGNUM_HAL_VECTOR_reserved:
112
        return SIGBUS;
113
    case CYGNUM_HAL_VECTOR_IRQ:
114
    case CYGNUM_HAL_VECTOR_FIQ:
115
        return SIGINT;
116
    default:
117
        return SIGTRAP;
118
    }
119
}
120
 
121
 
122
/* Return the trap number corresponding to the last-taken trap. */
123
int __get_trap_number (void)
124
{
125
    // The vector is not not part of the GDB register set so get it
126
    // directly from the save context.
127
    return _hal_registers->vector;
128
}
129
 
130
 
131
#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
132
int __is_bsp_syscall(void)
133
{
134
    unsigned long pc = get_register(PC);
135
    unsigned long cpsr = get_register(PS);  // condition codes
136
 
137
    if (_hal_registers->vector == CYGNUM_HAL_EXCEPTION_INTERRUPT) {
138
        if (cpsr & CPSR_THUMB_ENABLE)
139
            return *(unsigned short *)pc == 0xdf18;
140
        else
141
            return *(unsigned *)pc == 0xef180001;
142
    }
143
    return 0;
144
}
145
#endif
146
 
147
/* Set the currently-saved pc register value to PC. */
148
 
149
void set_pc (target_register_t pc)
150
{
151
    put_register (PC, pc);
152
}
153
 
154
// Calculate byte offset a given register from start of register save area.
155
static int
156
reg_offset(regnames_t reg)
157
{
158
    int base_offset;
159
 
160
    if (reg < F0)
161
        return reg * 4;
162
 
163
    base_offset = 16 * 4;
164
 
165
    if (reg < FPS)
166
        return base_offset + ((reg - F0) * 12);
167
 
168
    base_offset += (8 * 12);
169
 
170
    if (reg <= PS)
171
        return base_offset + ((reg - FPS) * 4);
172
 
173
    return -1;  // Should never happen!
174
}
175
 
176
 
177
// Return the currently-saved value corresponding to register REG of
178
// the exception context.
179
target_register_t
180
get_register (regnames_t reg)
181
{
182
    target_register_t val;
183
    int offset = reg_offset(reg);
184
 
185
    if (REGSIZE(reg) > sizeof(target_register_t) || offset == -1)
186
        return -1;
187
 
188
    val = _registers[offset/sizeof(target_register_t)];
189
 
190
    return val;
191
}
192
 
193
// Store VALUE in the register corresponding to WHICH in the exception
194
// context.
195
void
196
put_register (regnames_t which, target_register_t value)
197
{
198
    int offset = reg_offset(which);
199
 
200
    if (REGSIZE(which) > sizeof(target_register_t) || offset == -1)
201
        return;
202
 
203
    _registers[offset/sizeof(target_register_t)] = value;
204
}
205
 
206
// Write the contents of register WHICH into VALUE as raw bytes. This
207
// is only used for registers larger than sizeof(target_register_t).
208
// Return non-zero if it is a valid register.
209
int
210
get_register_as_bytes (regnames_t which, char *value)
211
{
212
    int offset = reg_offset(which);
213
 
214
    if (offset != -1) {
215
        memcpy (value, (char *)_registers + offset, REGSIZE(which));
216
        return 1;
217
    }
218
    return 0;
219
}
220
 
221
// Alter the contents of saved register WHICH to contain VALUE. This
222
// is only used for registers larger than sizeof(target_register_t).
223
// Return non-zero if it is a valid register.
224
int
225
put_register_as_bytes (regnames_t which, char *value)
226
{
227
    int offset = reg_offset(which);
228
 
229
    if (offset != -1) {
230
        memcpy ((char *)_registers + offset, value, REGSIZE(which));
231
        return 1;
232
    }
233
    return 0;
234
}
235
 
236
/*----------------------------------------------------------------------
237
 * Single-step support
238
 */
239
 
240
/* Set things up so that the next user resume will execute one instruction.
241
   This may be done by setting breakpoints or setting a single step flag
242
   in the saved user registers, for example. */
243
 
244
static unsigned long  ss_saved_pc = 0;
245
static unsigned long  ss_saved_instr;
246
static unsigned short ss_saved_thumb_instr;
247
 
248
#define FIXME() {diag_printf("FIXME - %s\n", __FUNCTION__); }
249
 
250
// return non-zero for v5 and later
251
static int
252
v5T_semantics(void)
253
{
254
    unsigned id;
255
 
256
    asm volatile ("mrc  p15,0,%0,c0,c0,0\n"
257
                  : "=r" (id) : /* no inputs */);
258
 
259
    return ((id >> 16) & 0xff) >= 5;
260
}
261
 
262
static int
263
ins_will_execute(unsigned long ins)
264
{
265
    unsigned long psr = get_register(PS);  // condition codes
266
    int res = 0;
267
    switch ((ins & 0xF0000000) >> 28) {
268
    case 0x0: // EQ
269
        res = (psr & PS_Z) != 0;
270
        break;
271
    case 0x1: // NE
272
        res = (psr & PS_Z) == 0;
273
        break;
274
    case 0x2: // CS
275
        res = (psr & PS_C) != 0;
276
        break;
277
    case 0x3: // CC
278
        res = (psr & PS_C) == 0;
279
        break;
280
    case 0x4: // MI
281
        res = (psr & PS_N) != 0;
282
        break;
283
    case 0x5: // PL
284
        res = (psr & PS_N) == 0;
285
        break;
286
    case 0x6: // VS
287
        res = (psr & PS_V) != 0;
288
        break;
289
    case 0x7: // VC
290
        res = (psr & PS_V) == 0;
291
        break;
292
    case 0x8: // HI
293
        res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0);
294
        break;
295
    case 0x9: // LS
296
        res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0);
297
        break;
298
    case 0xA: // GE
299
        res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
300
            ((psr & (PS_N|PS_V)) == 0);
301
        break;
302
    case 0xB: // LT
303
        res = ((psr & (PS_N|PS_V)) == PS_N) ||
304
            ((psr & (PS_N|PS_V)) == PS_V);
305
        break;
306
    case 0xC: // GT
307
        res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
308
            ((psr & (PS_N|PS_V)) == 0);
309
        res = ((psr & PS_Z) == 0) && res;
310
        break;
311
    case 0xD: // LE
312
        res = ((psr & (PS_N|PS_V)) == PS_N) ||
313
            ((psr & (PS_N|PS_V)) == PS_V);
314
        res = ((psr & PS_Z) == PS_Z) || res;
315
        break;
316
    case 0xE: // AL
317
        res = TRUE;
318
        break;
319
    case 0xF: // NV
320
        if (((ins & 0x0E000000) >> 24) == 0xA)
321
            res = TRUE;
322
        else
323
            res = FALSE;
324
        break;
325
    }
326
    return res;
327
}
328
 
329
static unsigned long
330
RmShifted(int shift)
331
{
332
    unsigned long Rm = get_register(shift & 0x00F);
333
    int shift_count;
334
    if ((shift & 0x010) == 0) {
335
        shift_count = (shift & 0xF80) >> 7;
336
    } else {
337
        shift_count = get_register((shift & 0xF00) >> 8);
338
    }
339
    switch ((shift & 0x060) >> 5) {
340
    case 0x0: // Logical left
341
        Rm <<= shift_count;
342
        break;
343
    case 0x1: // Logical right
344
        Rm >>= shift_count;
345
        break;
346
    case 0x2: // Arithmetic right
347
        Rm = (unsigned long)((long)Rm >> shift_count);
348
        break;
349
    case 0x3: // Rotate right
350
        if (shift_count == 0) {
351
            // Special case, RORx
352
            Rm >>= 1;
353
            if (get_register(PS) & PS_C) Rm |= 0x80000000;
354
        } else {
355
            Rm = (Rm >> shift_count) | (Rm << (32-shift_count));
356
        }
357
        break;
358
    }
359
    return Rm;
360
}
361
 
362
// Decide the next instruction to be executed for a given instruction
363
static unsigned long *
364
target_ins(unsigned long *pc, unsigned long ins)
365
{
366
    unsigned long new_pc, offset, op2;
367
    unsigned long Rn;
368
    int i, reg_count, c;
369
 
370
    switch ((ins & 0x0C000000) >> 26) {
371
    case 0x0:
372
        // BX or BLX
373
        if ((ins & 0x0FFFFFD0) == 0x012FFF10) {
374
            new_pc = (unsigned long)get_register(ins & 0x0000000F);
375
            return ((unsigned long *)new_pc);
376
        }
377
        // Data processing
378
        new_pc = (unsigned long)(pc+1);
379
        if ((ins & 0x0000F000) == 0x0000F000) {
380
            // Destination register is PC
381
            if ((ins & 0x0FBF0000) != 0x010F0000) {
382
                Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
383
                if ((ins & 0x000F0000) == 0x000F0000) Rn += 8;  // PC prefetch!
384
                if ((ins & 0x02000000) == 0) {
385
                    op2 = RmShifted(ins & 0x00000FFF);
386
                } else {
387
                    op2 = ins & 0x000000FF;
388
                    i = (ins & 0x00000F00) >> 8;  // Rotate count                
389
                    op2 = (op2 >> (i*2)) | (op2 << (32-(i*2)));
390
                }
391
                switch ((ins & 0x01E00000) >> 21) {
392
                case 0x0: // AND
393
                    new_pc = Rn & op2;
394
                    break;
395
                case 0x1: // EOR
396
                    new_pc = Rn ^ op2;
397
                    break;
398
                case 0x2: // SUB
399
                    new_pc = Rn - op2;
400
                    break;
401
                case 0x3: // RSB
402
                    new_pc = op2 - Rn;
403
                    break;
404
                case 0x4: // ADD
405
                    new_pc = Rn + op2;
406
                    break;
407
                case 0x5: // ADC
408
                    c = (get_register(PS) & PS_C) != 0;
409
                    new_pc = Rn + op2 + c;
410
                    break;
411
                case 0x6: // SBC
412
                    c = (get_register(PS) & PS_C) != 0;
413
                    new_pc = Rn - op2 + c - 1;
414
                    break;
415
                case 0x7: // RSC
416
                    c = (get_register(PS) & PS_C) != 0;
417
                    new_pc = op2 - Rn +c - 1;
418
                    break;
419
                case 0x8: // TST
420
                case 0x9: // TEQ
421
                case 0xA: // CMP
422
                case 0xB: // CMN
423
                    break; // PC doesn't change
424
                case 0xC: // ORR
425
                    new_pc = Rn | op2;
426
                    break;
427
                case 0xD: // MOV
428
                    new_pc = op2;
429
                    break;
430
                case 0xE: // BIC
431
                    new_pc = Rn & ~op2;
432
                    break;
433
                case 0xF: // MVN
434
                    new_pc = ~op2;
435
                    break;
436
                }
437
            }
438
        }
439
        return ((unsigned long *)new_pc);
440
    case 0x1:
441
        if ((ins & 0x02000010) == 0x02000010) {
442
            // Undefined!
443
            return (pc+1);
444
        } else {
445
            if ((ins & 0x00100000) == 0) {
446
                // STR
447
                return (pc+1);
448
            } else {
449
                // LDR
450
                if ((ins & 0x0000F000) != 0x0000F000) {
451
                    // Rd not PC
452
                    return (pc+1);
453
                } else {
454
                    Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
455
                    if ((ins & 0x000F0000) == 0x000F0000) Rn += 8;  // PC prefetch!
456
                    if (ins & 0x01000000) {
457
                        // Add/subtract offset before
458
                        if ((ins & 0x02000000) == 0) {
459
                            // Immediate offset
460
                            if (ins & 0x00800000) {
461
                                // Add offset
462
                                Rn += (ins & 0x00000FFF);
463
                            } else {
464
                                // Subtract offset
465
                                Rn -= (ins & 0x00000FFF);
466
                            }
467
                        } else {
468
                            // Offset is in a register
469
                            if (ins & 0x00800000) {
470
                                // Add offset
471
                                Rn += RmShifted(ins & 0x00000FFF);
472
                            } else {
473
                                // Subtract offset
474
                                Rn -= RmShifted(ins & 0x00000FFF);
475
                            }
476
                        }
477
                    }
478
                    return ((unsigned long *)*(unsigned long *)Rn);
479
                }
480
            }
481
        }
482
        return (pc+1);
483
    case 0x2:  // Branch, LDM/STM
484
        if ((ins & 0x02000000) == 0) {
485
            // LDM/STM
486
            if ((ins & 0x00100000) == 0) {
487
                // STM
488
                return (pc+1);
489
            } else {
490
                // LDM
491
                if ((ins & 0x00008000) == 0) {
492
                    // PC not in list
493
                    return (pc+1);
494
                } else {
495
                    Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
496
                    if ((ins & 0x000F0000) == 0x000F0000) Rn += 8;  // PC prefetch!
497
                    offset = ins & 0x0000FFFF;
498
                    reg_count = 0;
499
                    for (i = 0;  i < 15;  i++) {
500
                        if (offset & (1<<i)) reg_count++;
501
                    }
502
                    if (ins & 0x00800000) {
503
                        // Add offset
504
                        Rn += reg_count*4;
505
                    } else {
506
                        // Subtract offset
507
                        Rn -= 4;
508
                    }
509
                    return ((unsigned long *)*(unsigned long *)Rn);
510
                }
511
            }
512
        } else {
513
            // Branch
514
            if (ins_will_execute(ins)) {
515
                offset = (ins & 0x00FFFFFF) << 2;
516
                if (ins & 0x00800000) offset |= 0xFC000000;  // sign extend
517
                new_pc = (unsigned long)(pc+2) + offset;
518
                // If its BLX, make new_pc a thumb address.
519
                if ((ins & 0xFE000000) == 0xFA000000) {
520
                    if ((ins & 0x01000000) == 0x01000000)
521
                        new_pc |= 2;
522
                    new_pc = MAKE_THUMB_ADDR(new_pc);
523
                }
524
                return ((unsigned long *)new_pc);
525
            } else {
526
                // Falls through
527
                return (pc+1);
528
            }
529
        }
530
    case 0x3:  // Coprocessor & SWI
531
        if (((ins & 0x03000000) == 0x03000000) && ins_will_execute(ins)) {
532
           // SWI
533
           return (unsigned long *)(CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4);
534
        } else {
535
           return (pc+1);
536
        }
537
    default:
538
        // Never reached - but fixes compiler warning.
539
        return 0;
540
    }
541
}
542
 
543
// FIXME: target_ins also needs to check for CPSR/THUMB being set and
544
//        set the thumb bit accordingly.
545
 
546
static unsigned long
547
target_thumb_ins(unsigned long pc, unsigned short ins)
548
{
549
    unsigned long new_pc = MAKE_THUMB_ADDR(pc+2); // default is fall-through 
550
                                        // to next thumb instruction
551
    unsigned long offset, arm_ins, sp;
552
    int i;
553
 
554
    switch ((ins & 0xf000) >> 12) {
555
    case 0x4:
556
        // Check for BX or BLX
557
        if ((ins & 0xff07) == 0x4700)
558
            new_pc = (unsigned long)get_register((ins & 0x00078) >> 3);
559
        break;
560
    case 0xb:
561
        // push/pop
562
        // Look for "pop {...,pc}"
563
        if ((ins & 0xf00) == 0xd00) {
564
            // find PC
565
            sp = (unsigned long)get_register(SP);
566
 
567
            for (offset = i = 0; i < 8; i++)
568
              if (ins & (1 << i))
569
                  offset += 4;
570
 
571
            new_pc = *(cyg_uint32 *)(sp + offset);
572
 
573
            if (!v5T_semantics())
574
                new_pc = MAKE_THUMB_ADDR(new_pc);
575
        }
576
        break;
577
    case 0xd:
578
        // Bcc | SWI
579
        // Use ARM function to check condition
580
        arm_ins = ((unsigned long)(ins & 0x0f00)) << 20;
581
        if ((arm_ins & 0xF0000000) == 0xF0000000) {
582
            // SWI
583
            new_pc = CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4;
584
        } else if (ins_will_execute(arm_ins)) {
585
            offset = (ins & 0x00FF) << 1;
586
            if (ins & 0x0080) offset |= 0xFFFFFE00;  // sign extend
587
            new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset);
588
        }
589
        break;
590
    case 0xe:
591
        // check for B
592
        if ((ins & 0x0800) == 0) {
593
            offset = (ins & 0x07FF) << 1;
594
            if (ins & 0x0400) offset |= 0xFFFFF800;  // sign extend
595
            new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset);
596
        }
597
        break;
598
    case 0xf:
599
        // BL/BLX (4byte instruction!)
600
        // First instruction (bit 11 == 0) holds top-part of offset
601
        if ((ins & 0x0800) == 0) {
602
            offset = (ins & 0x07FF) << 12;
603
            if (ins & 0x0400) offset |= 0xFF800000;  // sign extend
604
            // Get second instruction
605
            // Second instruction (bit 11 == 1) holds bottom-part of offset
606
            ins = *(unsigned short*)(pc+2);
607
            // Check for BL/BLX
608
            if ((ins & 0xE800) == 0xE800) {
609
                offset |= (ins & 0x07ff) << 1;
610
                new_pc = (unsigned long)(pc+4) + offset;
611
                // If its BLX, force a full word alignment
612
                // Otherwise, its a thumb address.
613
                if (!(ins & 0x1000))
614
                    new_pc &= ~3;
615
                else
616
                    new_pc = MAKE_THUMB_ADDR(new_pc);
617
            }
618
        }
619
        break;
620
    }
621
 
622
    return new_pc;
623
}
624
 
625
void __single_step (void)
626
{
627
    unsigned long pc = get_register(PC);
628
    unsigned long cpsr = get_register(PS);
629
 
630
    // Calculate address of next instruction to be executed
631
    if (cpsr & CPSR_THUMB_ENABLE) {
632
        // thumb
633
        ss_saved_pc = target_thumb_ins(pc, *(unsigned short*)pc);
634
    } else {
635
        // ARM
636
        unsigned long curins = *(unsigned long*)pc;
637
        if (ins_will_execute(curins)) {
638
            // Decode instruction to decide what the next PC will be
639
            ss_saved_pc = (unsigned long) target_ins((unsigned long*)pc,
640
                                                     curins);
641
        } else {
642
            // The current instruction will not execute (the conditions 
643
            // don't hold)
644
            ss_saved_pc = pc+4;
645
        }
646
    }
647
 
648
    // Set breakpoint according to type
649
    if (IS_THUMB_ADDR(ss_saved_pc)) {
650
        // Thumb instruction
651
        unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc);
652
        ss_saved_thumb_instr = *(unsigned short*)t_pc;
653
        *(unsigned short*)t_pc = HAL_BREAKINST_THUMB;
654
    } else {
655
        // ARM instruction
656
        ss_saved_instr = *(unsigned long*)ss_saved_pc;
657
        *(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM;
658
    }
659
}
660
 
661
/* Clear the single-step state. */
662
 
663
void __clear_single_step (void)
664
{
665
    if (ss_saved_pc != 0) {
666
        // Restore instruction according to type
667
        if (IS_THUMB_ADDR(ss_saved_pc)) {
668
            // Thumb instruction
669
            unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc);
670
            *(unsigned short*)t_pc = ss_saved_thumb_instr;
671
        } else {
672
            // ARM instruction
673
            *(unsigned long*)ss_saved_pc = ss_saved_instr;
674
        }
675
        ss_saved_pc = 0;
676
    }
677
}
678
 
679
void __install_breakpoints (void)
680
{
681
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
682
    /* Install the breakpoints in the breakpoint list */
683
    __install_breakpoint_list();
684
#endif
685
}
686
 
687
void __clear_breakpoints (void)
688
{
689
#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)
690
    __clear_breakpoint_list();
691
#endif
692
}
693
 
694
/* If the breakpoint we hit is in the breakpoint() instruction, return a
695
   non-zero value. */
696
 
697
int
698
__is_breakpoint_function ()
699
{
700
    return get_register (PC) == (target_register_t)&_breakinst;
701
}
702
 
703
 
704
/* Skip the current instruction.  Since this is only called by the
705
   stub when the PC points to a breakpoint or trap instruction,
706
   we can safely just skip 4. */
707
 
708
void __skipinst (void)
709
{
710
    unsigned long pc = get_register(PC);
711
    unsigned long cpsr = get_register(PS);
712
 
713
    if (cpsr & CPSR_THUMB_ENABLE)
714
        pc += 2;
715
    else
716
        pc += 4;
717
 
718
    put_register(PC, pc);
719
}
720
 
721
//-----------------------------------------------------------------------
722
// Thumb-aware GDB interrupt handler.
723
// This is a brute-force replacement of the ones in hal_stub.c. Need to
724
// find a better way of handling it... Maybe... Probably only ARM/thumb
725
// that is this weird.
726
 
727
typedef struct
728
{
729
    cyg_uint32 targetAddr;
730
    union {
731
        cyg_uint32 arm_instr;
732
        cyg_uint16 thumb_instr;
733
    } savedInstr;
734
} instrBuffer;
735
 
736
static instrBuffer break_buffer;
737
 
738
volatile int cyg_hal_gdb_running_step = 0;
739
 
740
// This function is passed thumb/arm information about the PC address
741
// in bit 0. This information is passed on to the break_buffer.
742
void
743
cyg_hal_gdb_place_break (target_register_t pc)
744
{
745
    // Clear flag that we Continued instead of Stepping
746
    cyg_hal_gdb_running_step = 0;
747
 
748
    if (0 == break_buffer.targetAddr) {
749
        // Setting a breakpoint in Thumb or ARM code?
750
       if (IS_THUMB_ADDR(pc)) {
751
            break_buffer.targetAddr = (cyg_uint32)pc;
752
            pc = UNMAKE_THUMB_ADDR(pc);
753
            break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc;
754
            *(cyg_uint16*)pc = HAL_BREAKINST_THUMB;
755
        } else {
756
            break_buffer.targetAddr = (cyg_uint32)pc;
757
            break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc;
758
            *(cyg_uint32*)pc = HAL_BREAKINST_ARM;
759
        }
760
 
761
        __data_cache(CACHE_FLUSH);
762
        __instruction_cache(CACHE_FLUSH);
763
    }
764
}
765
 
766
int
767
cyg_hal_gdb_remove_break (target_register_t pc)
768
{
769
    if ( cyg_hal_gdb_running_step )
770
        return 0; // Do not remove the break: we must hit it!
771
 
772
    if (pc == UNMAKE_THUMB_ADDR(break_buffer.targetAddr)) {
773
        if (IS_THUMB_ADDR(break_buffer.targetAddr)) {
774
            *(cyg_uint16*)pc = break_buffer.savedInstr.thumb_instr;
775
        } else {
776
            *(cyg_uint32*)pc = break_buffer.savedInstr.arm_instr;
777
        }
778
        break_buffer.targetAddr = 0;
779
 
780
        __data_cache(CACHE_FLUSH);
781
        __instruction_cache(CACHE_FLUSH);
782
        return 1;
783
    }
784
    return 0;
785
}
786
 
787
void
788
cyg_hal_gdb_interrupt (target_register_t pc)
789
{
790
    // Clear flag that we Continued instead of Stepping
791
    cyg_hal_gdb_running_step = 0;
792
    // and override existing break? So that a ^C takes effect...
793
    if (0 != break_buffer.targetAddr)
794
        cyg_hal_gdb_remove_break( break_buffer.targetAddr );
795
 
796
    if (0 == break_buffer.targetAddr) {
797
        cyg_uint32 cpsr = get_register(PS);
798
 
799
        if (cpsr & CPSR_THUMB_ENABLE) {
800
            break_buffer.targetAddr = MAKE_THUMB_ADDR((cyg_uint32)pc);
801
            break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc;
802
            *(cyg_uint16*)pc = HAL_BREAKINST_THUMB;
803
        } else {
804
            break_buffer.targetAddr = (cyg_uint32)pc;
805
            break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc;
806
            *(cyg_uint32*)pc = HAL_BREAKINST_ARM;
807
        }
808
 
809
        __data_cache(CACHE_FLUSH);
810
        __instruction_cache(CACHE_FLUSH);
811
    }
812
}
813
 
814
int
815
cyg_hal_gdb_break_is_set (void)
816
{
817
    if (0 != break_buffer.targetAddr) {
818
        return 1;
819
    }
820
    return 0;
821
}
822
 
823
#ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
824
#define ICE_THREAD_KEY0 0xDEAD0001
825
#define ICE_THREAD_KEY1 0xDEAD0002
826
 
827
#define ICE_THREAD_INBUFSIZ  2048
828
#define ICE_THREAD_OUTBUFSIZ 2048
829
#define ICE_THREAD_STACKSIZE 4096
830
 
831
static cyg_uint8 ice_thread_inbuf[ICE_THREAD_INBUFSIZ];
832
static cyg_uint8 ice_thread_outbuf[ICE_THREAD_OUTBUFSIZ];
833
static cyg_uint8 ice_thread_stack[ICE_THREAD_STACKSIZE];
834
 
835
static void ice_thread_proc(void);
836
 
837
struct {
838
    cyg_uint32 _key0;  // Must be ICE_KEY0
839
    cyg_uint8  *in_buffer;
840
    cyg_int32  in_buffer_size;
841
    cyg_uint8  *out_buffer;
842
    cyg_int32  out_buffer_size;
843
    cyg_uint8  *stack;
844
    cyg_int32  stack_size;
845
    void       (*fun)(void);
846
    cyg_uint32 _key1;  // Must be ICE_KEY1
847
} hal_arm_ice_thread_handler = {
848
    ICE_THREAD_KEY0,
849
    ice_thread_inbuf,
850
    ICE_THREAD_INBUFSIZ,
851
    ice_thread_outbuf,
852
    ICE_THREAD_OUTBUFSIZ,
853
    ice_thread_stack,
854
    ICE_THREAD_STACKSIZE,
855
    ice_thread_proc,
856
    ICE_THREAD_KEY1,
857
};
858
 
859
static int
860
ice_thread_query(void)
861
{
862
    switch (ice_thread_inbuf[1]) {
863
    case 'L': // get thread list
864
        stub_pkt_getthreadlist(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));
865
        break;
866
    case 'P': // thread or process information
867
        stub_pkt_getthreadinfo(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));
868
        break;
869
    case 'C': // current thread
870
        stub_pkt_currthread(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));
871
        break;
872
    default:
873
        return 0;
874
    }
875
    return 1;
876
}
877
 
878
static int
879
ice_thread_set(void)
880
{
881
    return 0;
882
}
883
 
884
static void
885
ice_thread_proc(void)
886
{
887
    switch (ice_thread_inbuf[0]) {
888
    case 'g': // Fetch thread registers
889
        stub_format_registers(ice_thread_outbuf);
890
        return;
891
    case 'P': // Update a single register
892
    case 'G': // Update all registers
893
        stub_update_registers(ice_thread_inbuf, ice_thread_outbuf);
894
        return;
895
    case 'H': // Thread set/query
896
        stub_pkt_changethread(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf));
897
        return;
898
    case 'q': // Thread queries
899
        if (ice_thread_query()) return;
900
        break;
901
    case 'Q': // Thread set operations
902
        if (ice_thread_set()) return;
903
        break;
904
    case 'T': // Thread alive?
905
        stub_pkt_thread_alive(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf));
906
        return;
907
    default:
908
    }
909
    strcpy(ice_thread_outbuf, "ENN");  // Dunno
910
}
911
 
912
#endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
913
 
914
#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.