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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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