204 lines
6.0 KiB
C
204 lines
6.0 KiB
C
/***************************************************************************
|
|
* Copyright (C) 01/2008 by Olaf Rempel *
|
|
* razzor@kopf-tisch.de *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; version 2 of the License *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
#include <stdint.h>
|
|
#include "AT91SAM7S256.h"
|
|
#include "board.h"
|
|
|
|
static void dbgu_putchar(char c)
|
|
{
|
|
while (!(*AT91C_DBGU_CSR & AT91C_US_TXEMPTY));
|
|
*AT91C_DBGU_THR = c;
|
|
if (c == '\n') {
|
|
while (!(*AT91C_DBGU_CSR & AT91C_US_TXEMPTY));
|
|
*AT91C_DBGU_THR = '\r';
|
|
}
|
|
}
|
|
|
|
static void dbgu_puts(const char *p)
|
|
{
|
|
while (*p != '\0')
|
|
dbgu_putchar(*p++);
|
|
}
|
|
|
|
static void dbgu_hexvar(const char *name, uint32_t var)
|
|
{
|
|
dbgu_puts(name);
|
|
|
|
char buf[11];
|
|
buf[0] = '0';
|
|
buf[1] = 'x';
|
|
uint32_t i;
|
|
for (i = 9; i > 1; i--) {
|
|
buf[i] = (var & 0x0F);
|
|
buf[i] += (buf[i] < 0xa) ? '0' : ('a' - 0x0a);
|
|
var >>= 4;
|
|
}
|
|
buf[10] = '\0';
|
|
dbgu_puts(buf);
|
|
}
|
|
|
|
/*
|
|
ARM7TDMI 32bit Undefined Address Instruction Fetch Abort
|
|
(ASR:0x02020a01 AASR:0x80000008)
|
|
--- Registerdump (cpsr:0xa0000013 - SVC):
|
|
r0:0x00000002 r1:0x0000000c r2:0x00200038 r3:0x80000000
|
|
r4:0x0020fffc r5:0x00101788 r6:0x00000180 r7:0x41000000
|
|
r8:0x00008400 r9:0x00100004 sl:0x03000294 fp:0x0020fe84
|
|
ip:0x0020fe10 sp:0x0020fe70 lr:0x00102174 pc:0x80000004
|
|
--- Stackdump:
|
|
0x0020fe70: 0x0020fe7c 0x00101648 0x001015a8 0x0020feaf
|
|
0x0020fe80: 0x0020fec0 0x0020fe90 0x00101780 0x00101620
|
|
0x0020fe90: 0x00000002 0x00000000 0x00000030 0x00000000
|
|
0x0020fea0: 0x001029a8 0x307830b0 0x33383730 0x00303337
|
|
*/
|
|
void at91_abt_handler(uint32_t cpsr, uint32_t *registers)
|
|
{
|
|
/* enable Debug Port with 115200 Baud (+0.16%) */
|
|
AT91S_DBGU *dbgu = AT91C_BASE_DBGU;
|
|
dbgu->DBGU_BRGR = BAUD_TO_DIV(115200);
|
|
dbgu->DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
|
|
dbgu->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_RSTSTA;
|
|
|
|
/* switch pins to UART */
|
|
*AT91C_PIOA_PDR = AT91C_PA9_DRXD | AT91C_PA10_DTXD;
|
|
|
|
|
|
AT91_REG asr = *AT91C_MC_ASR;
|
|
if (asr & AT91C_MC_MST0)
|
|
dbgu_puts("PDC ");
|
|
else if (asr & AT91C_MC_MST1)
|
|
dbgu_puts("ARM7TDMI ");
|
|
|
|
switch (asr & AT91C_MC_ABTSZ) {
|
|
case AT91C_MC_ABTSZ_BYTE:
|
|
dbgu_puts("8bit ");
|
|
break;
|
|
case AT91C_MC_ABTSZ_HWORD:
|
|
dbgu_puts("16bit ");
|
|
break;
|
|
case AT91C_MC_ABTSZ_WORD:
|
|
dbgu_puts("32bit ");
|
|
break;
|
|
}
|
|
|
|
if (asr & AT91C_MC_UNDADD)
|
|
dbgu_puts("Undefined Address ");
|
|
else if (asr & AT91C_MC_MISADD)
|
|
dbgu_puts("Misaliged Address ");
|
|
|
|
switch (asr & AT91C_MC_ABTTYP) {
|
|
case AT91C_MC_ABTTYP_DATAR:
|
|
dbgu_puts("Data Read ");
|
|
break;
|
|
|
|
case AT91C_MC_ABTTYP_DATAW:
|
|
dbgu_puts("Data Write ");
|
|
break;
|
|
|
|
case AT91C_MC_ABTTYP_FETCH:
|
|
dbgu_puts("Prefetch ");
|
|
break;
|
|
}
|
|
|
|
dbgu_hexvar("Abort\n(ASR:", asr);
|
|
dbgu_hexvar(" AASR:", *AT91C_MC_AASR);
|
|
dbgu_puts(")\n");
|
|
|
|
dbgu_hexvar("--- Registerdump (cpsr:", cpsr);
|
|
dbgu_puts(" - ");
|
|
switch (cpsr & 0x1F) {
|
|
case 0x10: dbgu_puts("USR"); break;
|
|
case 0x11: dbgu_puts("FIQ"); break;
|
|
case 0x12: dbgu_puts("IRQ"); break;
|
|
case 0x13: dbgu_puts("SVC"); break;
|
|
case 0x17: dbgu_puts("ABT"); break;
|
|
case 0x1B: dbgu_puts("UND"); break;
|
|
case 0x1F: dbgu_puts("SYS"); break;
|
|
}
|
|
|
|
dbgu_hexvar("):\n r0:", registers[3]);
|
|
dbgu_hexvar(" r1:", registers[4]);
|
|
dbgu_hexvar(" r2:", registers[5]);
|
|
dbgu_hexvar(" r3:", registers[6]);
|
|
dbgu_hexvar("\n r4:", registers[7]);
|
|
dbgu_hexvar(" r5:", registers[8]);
|
|
dbgu_hexvar(" r6:", registers[9]);
|
|
dbgu_hexvar(" r7:", registers[10]);
|
|
dbgu_hexvar("\n r8:", registers[11]);
|
|
dbgu_hexvar(" r9:", registers[12]);
|
|
dbgu_hexvar(" sl:", registers[13]);
|
|
dbgu_hexvar(" fp:", registers[14]);
|
|
dbgu_hexvar("\n ip:", registers[15]);
|
|
dbgu_hexvar(" sp:", registers[0]);
|
|
dbgu_hexvar(" lr:", registers[1]);
|
|
dbgu_hexvar(" pc:", registers[2]);
|
|
|
|
dbgu_puts("\n--- Stackdump:");
|
|
uint32_t *val = (uint32_t *)(registers[0] & ~0x0F);
|
|
for ( ; val < (uint32_t *)(registers[0] & ~0x0F) +16; val++) {
|
|
if (!((uint32_t)val & 0x0F)) {
|
|
dbgu_hexvar("\n", (uint32_t)val);
|
|
dbgu_putchar(':');
|
|
}
|
|
dbgu_hexvar(" ", *val);
|
|
}
|
|
dbgu_putchar('\n');
|
|
}
|
|
|
|
__attribute__((naked)) void ABT_Handler(void)
|
|
{
|
|
asm volatile (
|
|
".equ ARM_MODE_ABT, 0x17 \n\t"
|
|
".equ I_BIT, 0x80 \n\t"
|
|
".equ F_BIT, 0x40 \n\t"
|
|
|
|
/* disable interrupts (F_BIT not set on entry) */
|
|
"msr CPSR_c, #ARM_MODE_ABT | I_BIT | F_BIT \n\t"
|
|
|
|
/* store all registers */
|
|
"stmfd sp!, { r0-r12 } \n\t"
|
|
|
|
/* saved cpsr (from aborted mode) */
|
|
"mrs r0, SPSR \n\t"
|
|
|
|
/* address of abort (pc) */
|
|
"mov r3, lr \n\t"
|
|
|
|
/* enter previous mode and get lr(r14), sp(r13) */
|
|
/* TODO: interrupts might be enabled? */
|
|
/* TODO: thumb mode enabled? */
|
|
"msr CPSR_c, r0 \n\t"
|
|
"mov r1, sp \n\t"
|
|
"mov r2, lr \n\t"
|
|
|
|
/* return to abort mode */
|
|
"msr CPSR_c, #ARM_MODE_ABT | I_BIT | F_BIT \n\t"
|
|
|
|
/* store remaining registers (r1-r3 == r13-r15) */
|
|
"stmfd sp!, { r1-r3 } \n\t"
|
|
"mov r1, sp \n\t"
|
|
|
|
/* execute C Handler (cpsr, registers) */
|
|
"ldr r5, =at91_abt_handler \n\t"
|
|
"mov lr, pc \n\t"
|
|
"bx r5 \n\t"
|
|
"b . \n\t"
|
|
);
|
|
}
|