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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [hal/] [arm/] [xscale/] [cores/] [v2_0/] [src/] [xscale_stub.c] - Blame information for rev 861

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      xscale_stub.c
4
//
5
//      HAL stub support code for Intel XScale cores.
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):    msalter
44
// Contributors: msalter
45
// Date:         2002-10-18
46
// Purpose:      XScale core stub support
47
// Description:  Implementations of HW debugging support.
48
//
49
//####DESCRIPTIONEND####
50
//
51
//========================================================================*/
52
 
53
#include <pkgconf/hal.h>
54
#include <pkgconf/system.h>
55
#include <cyg/infra/diag.h>
56
#include <cyg/hal/hal_stub.h>           // Stub macros
57
 
58
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
59
/*------------------------------------------------------------------------*/
60
//  HW Debug support
61
 
62
// Define this to support two watchpoints. If not defined, one watchpoint with
63
// a power of two range is supported.
64
#define USE_TWO_WATCHPOINTS 1
65
 
66
static inline void set_ibcr0(unsigned x)
67
{
68
    asm volatile ("mcr p15,0,%0,c14,c8,0" : : "r"(x) );
69
}
70
 
71
static inline unsigned get_ibcr0(void)
72
{
73
    unsigned x;
74
    asm volatile ("mrc p15,0,%0,c14,c8,0" : "=r"(x) : );
75
    return x;
76
}
77
 
78
static inline void set_ibcr1(unsigned x)
79
{
80
    asm volatile ("mcr p15,0,%0,c14,c9,0" : : "r"(x) );
81
}
82
 
83
static inline unsigned get_ibcr1(void)
84
{
85
    unsigned x;
86
    asm volatile ("mrc p15,0,%0,c14,c9,0" : "=r"(x) : );
87
    return x;
88
}
89
 
90
static inline void set_dbr0(unsigned x)
91
{
92
    asm volatile ("mcr p15,0,%0,c14,c0,0" : : "r"(x) );
93
}
94
 
95
static inline unsigned get_dbr0(void)
96
{
97
    unsigned x;
98
    asm volatile ("mrc p15,0,%0,c14,c0,0" : "=r"(x) : );
99
    return x;
100
}
101
 
102
static inline void set_dbr1(unsigned x)
103
{
104
    asm volatile ("mcr p15,0,%0,c14,c3,0" : : "r"(x) );
105
}
106
 
107
static inline unsigned get_dbr1(void)
108
{
109
    unsigned x;
110
    asm volatile ("mrc p15,0,%0,c14,c3,0" : "=r"(x) : );
111
    return x;
112
}
113
 
114
static inline void set_dbcon(unsigned x)
115
{
116
    asm volatile ("mcr p15,0,%0,c14,c4,0" : : "r"(x) );
117
}
118
 
119
static inline unsigned get_dbcon(void)
120
{
121
    unsigned x;
122
    asm volatile ("mrc p15,0,%0,c14,c4,0" : "=r"(x) : );
123
    return x;
124
}
125
 
126
static inline void set_dcsr(unsigned x)
127
{
128
    asm volatile ("mcr p14,0,%0,c10,c0,0" : : "r"(x) );
129
}
130
 
131
static inline unsigned get_dcsr(void)
132
{
133
    unsigned x;
134
    asm volatile ("mrc p14,0,%0,c10,c0,0" : "=r"(x) : );
135
    return x;
136
}
137
 
138
int cyg_hal_plf_hw_breakpoint(int setflag, void *vaddr, int len)
139
{
140
    unsigned int addr = (unsigned)vaddr;
141
 
142
    if (setflag) {
143
        if (!(get_ibcr0() & 1))
144
            set_ibcr0(addr | 1);
145
        else if (!(get_ibcr1() & 1))
146
            set_ibcr1(addr | 1);
147
        else
148
            return -1;
149
    } else {
150
        unsigned x = (addr | 1);
151
        if (get_ibcr0() == x)
152
            set_ibcr0(0);
153
        else if (get_ibcr1() == x)
154
            set_ibcr1(0);
155
        else
156
            return -1;
157
    }
158
 
159
    return 0;
160
}
161
 
162
#define WATCH_MODE_NONE   0
163
#define WATCH_MODE_WRITE  1
164
#define WATCH_MODE_ACCESS 2
165
#define WATCH_MODE_READ   3
166
 
167
#ifndef HAL_STUB_HW_WATCHPOINT_LIST_SIZE
168
#error
169
#endif
170
 
171
int cyg_hal_plf_hw_watchpoint(int setflag, void *vaddr, int len, int type)
172
{
173
    unsigned int mode, addr = (unsigned)vaddr;
174
    unsigned dbcon = get_dbcon();
175
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1
176
    unsigned int mask, bit_nr;
177
 
178
    mask = 0x80000000;
179
    bit_nr = 31;
180
    while (bit_nr) {
181
        if (len & mask)
182
            break;
183
        bit_nr--;
184
        mask >>= 1;
185
    }
186
    mask = ~(0xffffffff << bit_nr);
187
#endif
188
 
189
    if (setflag) {
190
        /* set a watchpoint */
191
        if (type == 2)
192
            mode = WATCH_MODE_WRITE;  // break on write
193
        else if (type == 3)
194
            mode = WATCH_MODE_READ;   // break on read
195
        else if (type == 4)
196
            mode = WATCH_MODE_ACCESS; // break on any access
197
        else
198
            return 1;
199
 
200
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1
201
        mode |= 0x100;
202
#endif
203
 
204
        if (!(dbcon & 3)) {
205
            set_dbr0(addr);
206
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1
207
            set_dbr1(mask);
208
#endif
209
            set_dbcon(dbcon | mode);
210
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2
211
        } else if (!(dbcon & (3 << 2))) {
212
            set_dbr1(addr);
213
            set_dbcon(dbcon | (mode << 2));
214
#endif
215
        } else
216
            return 1;
217
 
218
    } else {
219
        /* clear a watchpoint */
220
        if ((dbcon & 3) && get_dbr0() == addr)
221
            set_dbcon(dbcon & ~3);
222
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2
223
        else if ((dbcon & (3 << 2)) && get_dbr1() == addr)
224
            set_dbcon(dbcon & ~(3 << 2));
225
#endif
226
        else
227
            return 1;
228
    }
229
    return 0;
230
}
231
 
232
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2
233
 
234
// The XScale hardware does not provide a way of positively identinfying
235
// which of the two watchpoints triggered and exception. The following
236
// code makes a best effort at determining this by decoding the opcode
237
// of the instruction which caused the watchpoint trigger. It is *not*
238
// 100% reliable.
239
 
240
// Some bits common to most ld/st instructions.
241
#define I_bit (1 << 25)
242
#define P_bit (1 << 24)
243
#define U_bit (1 << 23)
244
#define B_bit (1 << 22)
245
#define W_bit (1 << 21)
246
#define L_bit (1 << 20)
247
 
248
// Return non-zero if opcode at given PC is a store instruction for
249
// purposes of triggering watchpoints.
250
static int
251
is_store_insn(unsigned pc)
252
{
253
    unsigned opcode = *(unsigned *)pc;
254
 
255
    if ((opcode & 0x0fb00ff0) == 0x01000090) {
256
        // SWP          xxxx 0001 0B00 _Rn_ _Rd_ 0000 1001 _Rm_
257
        return 1;
258
    }
259
 
260
    if ((opcode & 0x0c000000) == 0x04000000) {
261
        // LDR/STR      xxxx 010P UBWL _Rn_ _Rd_ iiii iiii iiii
262
        // LDR/STR      xxxx 011P UBWL _Rn_ _Rd_ ssss sSh0 _Rm_
263
        // Addressing mode 2,  Load/Store word or unsigned byte
264
        return (opcode & L_bit) == 0;
265
    }
266
 
267
    if ((opcode & 0x0e000090) == 0x00000090 &&
268
        (opcode & 0x00000060) &&
269
        ((opcode & (1 << 22)) || (opcode & 0x00000f00) == 0) &&
270
        ((opcode & (P_bit | W_bit)) != W_bit)) {
271
        // LDR/STR    xxxx 000P U1WL _Rn_ _Rd_ iiii 1SH1 iiii
272
        // LDR/STR    xxxx 000P U0WL _Rn_ _Rd_ 0000 1SH1 _Rm_
273
        // Addressing Mode 3, Load/Store halfword, load signed byte
274
        return (opcode & L_bit) == 0;
275
    }
276
 
277
    if ((opcode & 0x0e000000) == 0x08000000) {
278
        // LDM/STM      xxxx 100P USWL _Rn_ rrrr rrrr rrrr rrrr
279
        return (opcode & L_bit) == 0;
280
    }
281
 
282
    if ((opcode & 0x0e000000) == 0x0c000000) {
283
        // LDC/STC      xxxx 110P UNWL _Rn_ CRd_ CP#_ iiii iiii
284
        return (opcode & L_bit) == 0;
285
    }
286
 
287
    return 0;
288
}
289
 
290
static int
291
is_thumb_store_insn(unsigned pc)
292
{
293
    unsigned short opcode = *(unsigned short *)pc;
294
 
295
    opcode &= 0xfe00;
296
 
297
    if (opcode == 0xb400)
298
        return 1;  // PUSH
299
    if (opcode == 0x5000)
300
        return 1;  // STR Rd, [Rn, Rm]
301
    if (opcode == 0x5400)
302
        return 1;  // STRB Rd, [Rn, Rm]
303
    if (opcode == 0x5200)
304
        return 1;  // STRH Rd, [Rn, Rm]
305
 
306
    opcode &= 0xf800;
307
    if (opcode == 0xc000)
308
        return 1;  // STM
309
    if (opcode == 0x6000)
310
        return 1;  // STR Rd, [Rn, #5bit_offset]
311
    if (opcode == 0x9000)
312
        return 1;  // STR Rd, [SP, #8bit_offset]
313
    if (opcode == 0x7000)
314
        return 1;  // STRB Rd, [Rn, #5bit_offset]
315
    if (opcode == 0x8000)
316
        return 1;  // STRH Rd, [Rn, #5bit_offset]
317
 
318
    return 0;
319
}
320
 
321
// Return non-zero if given waddr matches an access at addr.
322
static int
323
waddr_match(unsigned waddr, unsigned addr, int size)
324
{
325
    if (addr <= waddr && waddr < (addr + size))
326
        return 1;
327
    return 0;
328
}
329
 
330
// Return non-zero if given value matches value at watchpoint address.
331
static int
332
wval_match(unsigned waddr, unsigned val, int size)
333
{
334
    unsigned wval = *(unsigned *)(waddr & ~3);
335
    int i;
336
 
337
    if (size == 4)
338
        return (wval == val);
339
    if (size == 2) {
340
        val &= 0xffff;
341
        return ((wval & 0xffff) == val || ((wval >> 16) == val));
342
    }
343
    if (size == 1) {
344
        val &= 0xff;
345
        for (i = 0; i < 4; i++) {
346
            if ((wval & 0xff) == val)
347
                return 1;
348
            wval >>= 8;
349
        }
350
    }
351
    return 0;
352
}
353
 
354
static char _sztab[8] = { 4, 2, 1, 1, 4, 2, 1, 2 };
355
 
356
// Given the watch addresses and watch modes for each of the enabled
357
// watchpoints, figure out which one triggered the current exception.
358
static unsigned
359
find_thumb_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1)
360
{
361
    unsigned pc = get_register(PC) - 4;
362
    unsigned short opcode = *(unsigned short *)pc;
363
    unsigned short opcode_f8, opcode_fe;
364
    unsigned val, wd0, wd1, addr = 0;
365
    int  is_store, use_val, i, offset, size, Rn, Rd, Rm;
366
 
367
    opcode_f8 = opcode & 0xf800;
368
    opcode_fe = opcode & 0xfe00;
369
 
370
    size = 0;
371
    is_store = 0;
372
    val = use_val = 0;
373
 
374
    switch (opcode_f8) {
375
    case 0xc000: // STMIA Rn!, <list>
376
        is_store = 1;
377
    case 0xc800: // LDMIA Rn!, <list>
378
        Rn = (opcode >> 8) & 7;
379
        is_store = (opcode & 0x800) == 0;
380
        for (i = 0; i < 8; i++)
381
            if (opcode & (1 << i))
382
                size += 4;
383
        if (!is_store && (opcode & (1 << Rn))) {
384
            // We can't reconstruct address from opcode because base
385
            // was destroyed. Best we can do is try to match data at
386
            // watchpoint addresses with data in one of the registers.
387
            wd0 = *(unsigned *)(wa0 & ~3);
388
            wd1 = *(unsigned *)(wa1 & ~3);
389
            if (wd0 != wd1) {
390
                for (i = size = 0; i < 8; i++) {
391
                    if (opcode & (1 << i)) {
392
                        val = get_register(i);
393
                        if (val == wd0)
394
                            return wa0;
395
                        else if (val == wd1)
396
                            return wa1;
397
                    }
398
                }
399
            }
400
            return wa0;  // 50% chance of being right
401
        } else
402
            addr = get_register(Rn) - size;
403
        break;
404
    case 0x6000: // STR  Rd, [Rn, #5bit]
405
    case 0x7000: // STRB Rd, [Rn, #5bit]
406
    case 0x8000: // STRH Rd, [Rn, #5bit]
407
        is_store = 1;
408
    case 0x6800: // LDR  Rd, [Rn, #5bit]
409
    case 0x7800: // LDRB Rd, [Rn, #5bit]
410
    case 0x8800: // LDRH Rd, [Rn, #5bit]
411
        Rd = opcode & 7;
412
        Rn = (opcode >> 3) & 7;
413
        if ((opcode & 0xf000) == 0x6000)
414
            size = 4;
415
        else if ((opcode & 0xf000) == 0x8000)
416
            size = 2;
417
        else
418
            size = 1;
419
        if (!is_store && Rd == Rn) {
420
            // We can't reconstruct address from opcode because base
421
            // or offset register was destroyed. Best we can do is try
422
            // to match data at watchpoint addresses with data in Rd.
423
            use_val = 1;
424
            val = get_register(Rd);
425
        } else {
426
            offset = ((opcode >> 6) & 0x1f) * size;
427
            addr = get_register(Rn) + offset;
428
        }
429
        break;
430
    case 0x4800: // LDR Rd, [PC, #8bit]
431
        size = 4;
432
        addr = pc + 4 + ((opcode & 0xff) * 4);
433
        break;
434
    case 0x9000: // STR Rd, [SP, #8bit]
435
        is_store = 1;
436
    case 0x9800: // LDR Rd, [SP, #8bit]
437
        size = 4;
438
        addr = get_register(SP) + ((opcode & 0xff) * 4);
439
        break;
440
    default:
441
        switch (opcode_fe) {
442
        case 0x5000:  // STR   Rd, [Rn, Rm]
443
        case 0x5400:  // STRB  Rd, [Rn, Rm]
444
        case 0x5200:  // STRH  Rd, [Rn, Rm]
445
            is_store = 1;
446
        case 0x5600:  // LDRSB Rd, [Rn, Rm]
447
        case 0x5800:  // LDR   Rd, [Rn, Rm]
448
        case 0x5c00:  // LDRB  Rd, [Rn, Rm]
449
        case 0x5a00:  // LDRH  Rd, [Rn, Rm]
450
        case 0x5e00:  // LDRSH Rd, [Rn, Rm]
451
            Rd = opcode & 7;
452
            Rn = (opcode >> 3) & 7;
453
            Rm = (opcode >> 6) & 7;
454
            size = _sztab[(opcode >> 9) & 7];
455
            if (!is_store && (Rd == Rn || Rd == Rm)) {
456
                // We can't reconstruct address from opcode because base
457
                // or offset register was destroyed. Best we can do is try
458
                // to match data at watchpoint addresses with data in Rd.
459
                use_val = 1;
460
                val = get_register(Rd);
461
            } else
462
                addr = Rn + Rm;
463
            break;
464
        case 0xb400:  // PUSH
465
            is_store = 1;
466
        case 0xbc00:  // POP
467
            for (i = 0; i < 9; i++)
468
                if (opcode & (1 << i))
469
                    size += 4;
470
            addr = get_register(SP);
471
            if (!is_store)
472
                addr -= size;
473
            break;
474
        }
475
        break;
476
    }
477
    if (use_val) {
478
        // We can read from watchpoint addresses and compare against
479
        // whatever is in the Rd from a load. This is not perfect,
480
        // but its the best we can do.
481
        if (wval_match(wa0, val, size))
482
            return wa0;
483
        if (wval_match(wa1, val, size))
484
            return wa1;
485
    } else if (size) {
486
        if (waddr_match(wa0, addr, size))
487
            return wa0;
488
        if (waddr_match(wa1, addr, size))
489
            return wa1;
490
    }
491
    return wa0;  // should never happen, but return valid address
492
}
493
 
494
// Given the watch addresses and watch modes for each of the enabled
495
// watchpoints, figure out which one triggered the current exception.
496
static unsigned
497
find_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1)
498
{
499
    unsigned pc = get_register(PC) - 4;
500
    unsigned cpsr = get_register(PS);
501
    unsigned opcode, Rn, Rd, Rm, base, addr, val = 0, wd0, wd1;
502
    int  is_store, use_val, i, offset, shift, size;
503
 
504
    if (cpsr & CPSR_THUMB_ENABLE)
505
        is_store = is_thumb_store_insn(pc);
506
    else
507
        is_store = is_store_insn(pc);
508
 
509
    // First try the easy cases where all we need to know is whether or
510
    // not the instruction is a load or store.
511
    if ((mode0 == WATCH_MODE_READ && mode1 == WATCH_MODE_WRITE) ||
512
        (mode1 == WATCH_MODE_READ && mode0 == WATCH_MODE_WRITE)) {
513
        if (is_store)
514
            return (mode0 == WATCH_MODE_WRITE) ? wa0 : wa1;
515
        else
516
            return (mode0 == WATCH_MODE_READ) ? wa0 : wa1;
517
    }
518
    if ((mode0 == WATCH_MODE_READ && is_store) ||
519
        (mode0 == WATCH_MODE_WRITE && !is_store))
520
        return wa1;
521
    if ((mode1 == WATCH_MODE_READ && is_store) ||
522
        (mode1 == WATCH_MODE_WRITE && !is_store))
523
        return wa0;
524
 
525
    // Okay. Now try to figure out address by decoding the opcode.
526
 
527
    if (cpsr & CPSR_THUMB_ENABLE)
528
        return find_thumb_watch_address(wa0, mode0, wa1, mode1);
529
 
530
    opcode = *(unsigned *)pc;
531
    Rn = (opcode >> 16) & 15;
532
    Rd = (opcode >> 12) & 15;
533
    Rm = opcode & 15;
534
 
535
    size = use_val = 0;
536
    addr = 0;
537
 
538
    if ((opcode & 0x0fb00ff0) == 0x01000090) {
539
        // SWP          xxxx 0001 0B00 _Rn_ _Rd_ 0000 1001 _Rm_
540
        addr = get_register(Rn);
541
        size = (opcode & B_bit) ? 1 : 4;
542
    } else if ((opcode & 0x0c000000) == 0x04000000) {
543
        // LDR/STR      xxxx 010P UBWL _Rn_ _Rd_ iiii iiii iiii
544
        // LDR/STR      xxxx 011P UBWL _Rn_ _Rd_ ssss sSh0 _Rm_
545
        // Addressing mode 2,  Load/Store word or unsigned byte
546
 
547
        size = (opcode & B_bit) ? 1 : 4;
548
 
549
        if ((opcode & (P_bit | W_bit)) == (P_bit | W_bit)) {
550
            // This is easy because address is written back to Rn
551
            addr = get_register(Rn);
552
        } else if (!is_store &&
553
                   (Rd == Rn || ((opcode & I_bit) && Rd == Rm))) {
554
            // We can't reconstruct address from opcode because base
555
            // or offset register was destroyed. Best we can do is try
556
            // to match data at watchpoint addresses with data in Rd.
557
            use_val = 1;
558
            val = get_register(Rd);
559
        } else {
560
            if (opcode & I_bit) {
561
                shift = (opcode >> 7) & 0x1f;
562
                offset = get_register(Rm);
563
                switch ((opcode >> 5) & 3) {
564
                case 0:
565
                    offset <<= shift;
566
                    break;
567
                case 1:
568
                    offset >>= shift;
569
                    offset &= (0xffffffffU >> shift);
570
                    break;
571
                case 2:
572
                    offset >>= shift;
573
                    break;
574
                case 3:
575
                    if (shift) {
576
                        for (i = 0; i < shift; i++)
577
                            offset = ((offset >> 1) & 0x7fffffff) | ((offset & 1) << 31);
578
                    } else {
579
                        offset >>= 1;
580
                        offset &= 0x80000000;
581
                        offset |= ((cpsr & 0x20000000) << 2);
582
                    }
583
                    break;
584
                }
585
            } else
586
                offset = opcode & 0xfff;
587
 
588
            if ((opcode & U_bit) == 0)
589
                offset = -offset;
590
 
591
            if (Rn == 15)
592
                base = pc + 8;
593
            else
594
                base = get_register(Rn);
595
 
596
            if (opcode & P_bit)
597
                addr = base + offset; // pre-index
598
            else
599
                addr = base - offset; // post-index writeback
600
 
601
            size = (opcode & B_bit) ? 1 : 4;
602
        }
603
    } else if ((opcode & 0x0e000090) == 0x00000090 &&
604
               (opcode & 0x00000060) &&
605
               ((opcode & (1 << 22)) || (opcode & 0x00000f00) == 0) &&
606
               ((opcode & (P_bit | W_bit)) != W_bit)) {
607
        // LDR/STR    xxxx 000P U1WL _Rn_ _Rd_ iiii 1SH1 iiii
608
        // LDR/STR    xxxx 000P U0WL _Rn_ _Rd_ 0000 1SH1 _Rm_
609
        // Addressing Mode 3, Load/Store halfword, load signed byte
610
 
611
        size = (opcode & (1 << 5)) ? 2 : 1;
612
 
613
        if ((opcode & (P_bit | W_bit)) == (P_bit | W_bit)) {
614
            // This is easy because address is written back to Rn
615
            addr = get_register(Rn);
616
        } if (!is_store &&
617
              (Rd == Rn || ((opcode & (1 << 22)) && Rd == Rm))) {
618
            // We can't reconstruct address from opcode because base
619
            // or offset register was destroyed. Best we can do is try
620
            // to match data at watchpoint addresses with data in Rd.
621
            use_val = 1;
622
            val = get_register(Rd);
623
        } else {
624
            if (opcode & (1 << 22))
625
                offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
626
            else
627
                offset = get_register(opcode & 15);
628
 
629
            if ((opcode & U_bit) == 0)
630
                offset = -offset;
631
 
632
            if (Rn == 15)
633
                base = pc + 8;
634
            else
635
                base = get_register(Rn);
636
 
637
            if (opcode & P_bit)
638
                addr = base + offset; // pre-index
639
            else
640
            addr = base - offset; // post-index writeback
641
        }
642
    } else if ((opcode & 0x0e000000) == 0x08000000) {
643
        // LDM/STM      xxxx 100P USWL _Rn_ rrrr rrrr rrrr rrrr
644
        for (i = size = 0; i < 16; i++)
645
            if (opcode & (1 << i))
646
                size += 4;
647
 
648
        base = get_register(Rn);
649
        if (!is_store && (opcode & (1 << Rn))) {
650
            // We can't reconstruct address from opcode because base
651
            // was destroyed. Best we can do is try to match data at
652
            // watchpoint addresses with data in one of the registers.
653
            wd0 = *(unsigned *)(wa0 & ~3);
654
            wd1 = *(unsigned *)(wa1 & ~3);
655
            if (wd0 != wd1) {
656
                for (i = size = 0; i < 16; i++) {
657
                    if (opcode & (1 << i)) {
658
                        val = get_register(i);
659
                        if (val == wd0)
660
                            return wa0;
661
                        else if (val == wd1)
662
                            return wa1;
663
                    }
664
                }
665
            }
666
            return wa0;  // 50% chance of being right
667
        } else {
668
            if (opcode & U_bit){
669
                if (opcode & W_bit)
670
                    addr = base - size;
671
                else
672
                    addr = base;
673
                if (opcode & P_bit)
674
                    addr += 4;
675
            } else {
676
                if (opcode & W_bit)
677
                    addr = base;
678
                else
679
                    addr = base - size;
680
                if ((opcode & P_bit) == 0)
681
                    addr += 4;
682
            }
683
        }
684
    } else if ((opcode & 0x0e000000) == 0x0c000000) {
685
        // LDC/STC      xxxx 110P UNWL _Rn_ CRd_ CP#_ iiii iiii
686
        size = 4;
687
        offset = (opcode & 0xff) * 4;
688
        if ((opcode & U_bit) == 0)
689
            offset = -offset;
690
        if ((opcode & P_bit) && (opcode & W_bit))
691
            addr = get_register(Rn);
692
        else
693
            addr = get_register(Rn) + offset;
694
    }
695
 
696
    if (use_val) {
697
        // We can read from watchpoint addresses and compare against
698
        // whatever is in the Rd from a load. This is not perfect,
699
        // but its the best we can do.
700
        if (wval_match(wa0, val, size))
701
            return wa0;
702
        if (wval_match(wa1, val, size))
703
            return wa1;
704
    } else {
705
        if (waddr_match(wa0, addr, size))
706
            return wa0;
707
        if (waddr_match(wa1, addr, size))
708
            return wa1;
709
    }
710
    return wa0;  // should never happen, but return valid address
711
}
712
#endif
713
 
714
// Return indication of whether or not we stopped because of a
715
// watchpoint or hardware breakpoint. If stopped by a watchpoint,
716
// also set '*data_addr_p' to the data address which triggered the
717
// watchpoint.
718
int cyg_hal_plf_is_stopped_by_hardware(void **data_addr_p)
719
{
720
    unsigned fsr, dcsr, dbcon, kind = 0;
721
 
722
    // Check for debug event
723
    asm volatile ("mrc p15,0,%0,c5,c0,0" : "=r"(fsr) : );
724
    if ((fsr & 0x200) == 0)
725
        return HAL_STUB_HW_STOP_NONE;
726
 
727
    // There was a debug event. Check the MOE for details
728
    dcsr = get_dcsr();
729
    switch ((dcsr >> 2) & 7) {
730
      case 1:  // HW breakpoint
731
      case 3:  // BKPT breakpoint
732
        return HAL_STUB_HW_STOP_BREAK;
733
      case 2:  // Watchpoint
734
        dbcon = get_dbcon();
735
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2
736
        if (dbcon & 0x100) {
737
#endif
738
            if ((kind = (dbcon & 3)) != WATCH_MODE_NONE)
739
                *data_addr_p = (void *)get_dbr0();
740
#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2
741
        } else {
742
            // This can get tricky because the debug unit offers no way to
743
            // tell which watchpoint triggered.
744
            if ((kind = (dbcon & 3)) == WATCH_MODE_NONE) {
745
                if ((kind = ((dbcon >> 2) & 3)) != WATCH_MODE_NONE)
746
                    *data_addr_p = (void *)get_dbr1();
747
            } else if ((kind = ((dbcon >> 2) & 3)) == WATCH_MODE_NONE) {
748
                if ((kind = (dbcon & 3)) != WATCH_MODE_NONE)
749
                    *data_addr_p = (void *)get_dbr0();
750
            } else {
751
                // This is the tricky part. We have to look at the trapping
752
                // opcode (which has already issued) to try to see if we can
753
                // tell which watchpoint triggered. Turn off watchpoints while
754
                // we figure this out.
755
                set_dcsr(dcsr & ~0x80000000);
756
                *data_addr_p = (void *)find_watch_address(get_dbr0(), dbcon & 3,
757
                                                          get_dbr1(), (dbcon >> 2) & 3);
758
                set_dcsr(dcsr);
759
 
760
                if (*data_addr_p == (void *)get_dbr0())
761
                    kind = dbcon & 3;
762
                else if (*data_addr_p == (void *)get_dbr1())
763
                    kind = (dbcon >> 2) & 3;
764
                else
765
                    kind = WATCH_MODE_NONE;
766
            }
767
        }
768
#endif
769
        if (kind == WATCH_MODE_WRITE)
770
            return HAL_STUB_HW_STOP_WATCH;
771
        if (kind == WATCH_MODE_ACCESS)
772
            return HAL_STUB_HW_STOP_AWATCH;
773
        if (kind == WATCH_MODE_READ)
774
            return HAL_STUB_HW_STOP_RWATCH;
775
        // should never get here
776
        break;
777
    }
778
    return HAL_STUB_HW_STOP_NONE;
779
}
780
#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
781
 
782
/*------------------------------------------------------------------------*/
783
// EOF xscale_stub.c
784
 

powered by: WebSVN 2.1.0

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