OSDN Git Service

719ad950e5ee40ca1461cfef359c09d53a4b1779
[trx-305dsp/dsp.git] / trx305 / kernel / config / blackfin / _common_bf548 / chip_dump.c
1 /**
2  * \file postmotem533.c
3  * \brief ADSP-BF533用のポストモーテムダンプルーチン群
4  *
5  * ハードウェアエラー用のハンドラと、例外用のハンドラからなる。いずれも呼び出されるとUARTから
6  * ポストモーテム出力を表示する。
7  */
8 #include "jsp_kernel.h"
9 #include <cdefBF548.h>
10
11 /**
12  * \brief UARTおよび付随するDMAの動作を停止し、すべての割り込みを禁止する。
13  *
14  * 最後にUART_IERをクリアするのは、UART割り込みを禁止すると同時にDMAも禁止するため。
15  * UART DMAは、UARTの割り込み線で駆動されているので、割り込みを禁止すればDMAリクエスト
16  * も停止する。
17  *
18  * UARTの初期化をどうするか悩ましいが、ここではそのまま以前の設定を利用することにする。
19  *
20  * ポストモーテム・ダンプを目的としているので、この状態からの回復は考えない。
21  */
22 static void pm_occupy_uart()
23 {
24         /* すべてのコア割り込みを禁止する */
25     asm( "cli r0;" : : : "R0" );
26
27         /* すべてのシステム割り込みソースを禁止する */
28     *pSIC_IMASK0 = 0;
29     *pSIC_IMASK1 = 0;
30     *pSIC_IMASK2 = 0;
31
32         /* UART_IERをディセーブルにすることで、DMAを殺せる */
33     *pUART0_IER_CLEAR = 0xFFFFU;
34 }
35
36 /**
37  * \brief 一文字出力
38  *
39  * UARTの送信レジスタが空になるのを待って一文字出力する。
40  */
41 static void pm_putc( unsigned char c )
42 {
43
44         /* THRが空になるまで待つ */
45     while ( ! ( *pUART0_LSR & THRE ) )
46         ;
47
48         /*  THRが空になったら1文字送信 */
49     *pUART0_THR = c;
50 }
51
52 /**
53  * \brief コンソール入力監視
54  *
55  * UARTの受信レジスタにデータがあれば、読み込む。データが"!"なら真、
56  * それ以外なら偽を返す。
57  */
58 static BOOL is_ready()
59 {
60         /* 受信データはあるか。 */
61     if ( *pUART0_LSR & DR )
62
63     {
64         char c;
65
66         c= *pUART0_RBR;
67         if ( c == '!' )
68             return TRUE;
69     }
70     return FALSE;
71 }
72
73
74 /**
75  * \brief 文字列出力
76  *
77  * 受け取った文字列をUARTに出力する。
78  */
79 static void pm_putstr( char * s )
80 {
81     int i;
82
83     i=0;
84     while( s[i] )   /* 末端のNULLが現れるまで出力 */
85         pm_putc(s[i++]);
86 }
87
88 /**
89  * \brief 1バイトをヘキサデシマルで出力する。
90  */
91 static void pm_puthex1byte( unsigned int data )
92 {
93     int i;
94     int nibble;
95
96         /* 8bit内のすべてのニブルを処理 */
97     for ( i=0; i<2; i++ )
98     {
99             /* 最上位ニブルを抽出 */
100         nibble = ( data >> 4 ) & 0xF;
101             /* 抽出したニブルを出力 */
102         if ( nibble < 10 )
103             pm_putc( nibble + '0' );
104         else
105             pm_putc( nibble - 10 + 'A' );
106             /* 次のニブル */
107         data <<= 4;
108     }
109 }
110
111 /*
112  * \brief 改行記号を出力する
113  */
114 static void pm_putrtn()
115 {
116     pm_putstr("\r\n");
117 }
118
119 /**
120  * \brief 4バイトをヘキサデシマルで出力する。
121  */
122 static void pm_puthex4byte( unsigned int data )
123 {
124     int i;
125     int nibble;
126
127         /* 32bit内のすべてのニブルを処理 */
128     for ( i=0; i<8; i++ )
129     {
130             /* 最上位ニブルを抽出 */
131         nibble = ( data >> 28 ) & 0xF;
132             /* 抽出したニブルを出力 */
133         if ( nibble < 10 )
134             pm_putc( nibble + '0' );
135         else
136             pm_putc( nibble - 10 + 'A' );
137             /* 次のニブル */
138         data <<= 4;
139     }
140
141 }
142
143 /**
144  * \brief 例外フラグ
145  *
146  * 例外が発生したときには真、そうでなければ偽。hwei_handler()に例外か否かを伝える。
147  *
148  * GCCが張り切ってlink/unlink命令の位置を最適化するため、hwei_hanlder()の
149  * 中で性格にfpを手繰れない。そのため、dummyをアクセスすることでlink/unlinkの位置
150  * 最適化の抑止を図る役目もある。効果があるかどうかは不明。
151  */
152 static volatile int expFlag =0;
153 /**
154  * \brief ハードウェア・エラー・ハンドラ
155  *
156  * ハードウェア・エラー時に呼び出されて、ハードウェア・エラー・割り込みのポストモーテム処理を行う。
157  * 最初にFPを手繰って、割り込みのスタックフレームを探す。次にすべての割り込みを禁止し、
158  * UART0を占有したあと、ポーリングを使ってスタックに保存された各レジスタのダンプを行う。
159  * DEF_INH(INHNO_HW_ERROR, { TA_HLNG, hwei_handler });
160  *
161  */
162 void spurious_int_handler()
163 {
164     unsigned int * fp, *ptr ;   /* フレーム・ポインタを手繰っていくための変数 */
165     unsigned int reg;   /* システムレジスタを受け取るための変数 */
166     unsigned int imask, sic_imask0, sic_imask1, sic_imask2; /*マスク記録レジスタ*/
167
168             /* あとで使う */
169     imask = *pIMASK;
170     sic_imask0 = *pSIC_IMASK0;
171     sic_imask1 = *pSIC_IMASK1;
172     sic_imask2 = *pSIC_IMASK2;
173     /* UART0を初期化し、DMAと割り込みを禁止する */
174     pm_occupy_uart();
175
176     while (1)
177     {
178         int count = 0;
179
180         pm_putstr( "Type '!' to display post mortem dump" ); pm_putrtn();
181
182         while ( ! is_ready() )
183         {
184             int i;
185             for ( i=0; i<100000000; i++)
186                 asm volatile ("nop;");
187             if ( count > 30 )
188             {
189                 pm_putstr( "Type '!' to display post mortem dump" ); pm_putrtn();
190                 count = 0;
191             }
192             else
193                 count ++;
194         }
195         pm_putrtn();
196
197
198         /* 現在の関数のFPを取得する */
199         asm ( "%0=fp;" : "=d"((unsigned int)fp) );
200
201         /*
202          * この関数を呼び出した関数 ( interrupt_dispatcher ) のFPを取得する。
203          * FPは呼び出し関数のFPの格納番地を指していることを利用する
204          */
205         fp = (void *)*fp;
206         /*
207          * interrupt_dispatcher を呼び出した関数のFPを取得する。
208          * その関数は割り込みハンドラの入り口処理部に他ならない。
209          */
210         fp = (void *)*fp;
211
212         /* いまや、FPは割り込み受付時の保存されたレジスタ群を指している */
213
214         /* プッシュされた P0を指す */
215         ptr = fp + 2;
216         /*
217          * 上位
218          *      0   1   2   3   4   5   6   7   8   9
219          * -----------------------------------------------
220          *  00  P0  RTS FP  R0  R1  R2  R3  R4  R5  R6
221          *  10  R7  P1  P2  P3  P4  P5  I3  I2  I1  I0
222          *  20  M3  M2  M1  M0  B3  B2  B1  B0  L3  L2
223          *  30  L1  L0  A0x A0w A1x A1w LC1 LC0 LT1 LT0
224          *  40  LB1 LB0 AST RETI
225          * 下位
226          *
227         */
228         if ( expFlag )
229             pm_putstr( "Spurious Exception  !!" );
230         else
231             pm_putstr( "Spurious Interrupt  !!" );
232         pm_putrtn();
233
234         pm_putstr( "Registers On Stack :" );    pm_putrtn();
235         pm_putstr( "P0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
236         pm_putstr( "RETS " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
237         pm_putstr( "FP   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
238         pm_putstr( "R0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
239         pm_putstr( "R1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
240         pm_putstr( "R2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
241         pm_putstr( "R3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
242         pm_putstr( "R4   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
243         pm_putstr( "R5   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
244         pm_putstr( "R6   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
245         pm_putstr( "R7   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
246         pm_putstr( "P1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
247         pm_putstr( "P2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
248         pm_putstr( "P3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
249         pm_putstr( "P4   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
250         pm_putstr( "P5   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
251         pm_putstr( "I3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
252         pm_putstr( "I2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
253         pm_putstr( "I1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
254         pm_putstr( "I0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
255         pm_putstr( "M3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
256         pm_putstr( "M2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
257         pm_putstr( "M1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
258         pm_putstr( "M0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
259         pm_putstr( "B3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
260         pm_putstr( "B2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
261         pm_putstr( "B1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
262         pm_putstr( "B0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
263         pm_putstr( "L3   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
264         pm_putstr( "L2   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
265         pm_putstr( "L1   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
266         pm_putstr( "L0   " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
267         pm_putstr( "A0   " );   pm_puthex1byte( *(ptr--) ); pm_putstr( ":" );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
268         pm_putstr( "A1   " );   pm_puthex1byte( *(ptr--) ); pm_putstr( ":" );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
269         pm_putstr( "LC1  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
270         pm_putstr( "LC0  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
271         pm_putstr( "LT1  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
272         pm_putstr( "LT0  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
273         pm_putstr( "LB1  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
274         pm_putstr( "LB0  " );   pm_puthex4byte( *(ptr--) ); pm_putrtn();
275         pm_putstr( "ASTAT " );  pm_puthex4byte( *(ptr--) ); pm_putrtn();
276         pm_putstr( "RETI  " );  pm_puthex4byte( *(ptr--) ); pm_putrtn();
277         pm_putrtn();
278         pm_putstr( "System Registers :" );  pm_putrtn();
279         pm_putstr( "SIC_IMASK2:1:0 " ); pm_puthex4byte( sic_imask2 );pm_puthex4byte( sic_imask1 );pm_putstr( " : " );pm_puthex4byte( sic_imask0 ); pm_putrtn();
280         pm_putstr( "SIC_ISR1:0   " );   pm_puthex4byte( *pSIC_ISR1 );pm_putstr( " : " );pm_puthex4byte( *pSIC_ISR0 );  pm_putrtn();
281         pm_putstr( "IMASK        " );   pm_puthex4byte( imask ); pm_putrtn();
282         pm_putstr( "ILAT         " );   pm_puthex4byte( *pILAT ); pm_putrtn();
283         pm_putstr( "IPEND        " );   pm_puthex4byte( *pIPEND ); pm_putrtn();
284         asm( "%0=SEQSTAT;" : "=d"(reg) );
285         pm_putstr( "SEQSTAT      " );   pm_puthex4byte( reg ); pm_putrtn();
286         pm_putstr( "  EXCAUSE    " );   pm_puthex1byte( reg & 0x3F ); pm_putrtn();
287         pm_putstr( "  HWERRCAUSE " );   pm_puthex1byte( (reg>>14)&0x1F ); pm_putrtn();
288         pm_putstr( "DMA0_IRQ_STATUS    " ); pm_puthex4byte( *pDMA0_IRQ_STATUS ); pm_putrtn();
289         pm_putstr( "DMA1_IRQ_STATUS    " ); pm_puthex4byte( *pDMA1_IRQ_STATUS ); pm_putrtn();
290         pm_putstr( "DMA2_IRQ_STATUS    " ); pm_puthex4byte( *pDMA2_IRQ_STATUS ); pm_putrtn();
291         pm_putstr( "DMA3_IRQ_STATUS    " ); pm_puthex4byte( *pDMA3_IRQ_STATUS ); pm_putrtn();
292         pm_putstr( "DMA4_IRQ_STATUS    " ); pm_puthex4byte( *pDMA4_IRQ_STATUS ); pm_putrtn();
293         pm_putstr( "DMA5_IRQ_STATUS    " ); pm_puthex4byte( *pDMA5_IRQ_STATUS ); pm_putrtn();
294         pm_putstr( "DMA6_IRQ_STATUS    " ); pm_puthex4byte( *pDMA6_IRQ_STATUS ); pm_putrtn();
295         pm_putstr( "DMA7_IRQ_STATUS    " ); pm_puthex4byte( *pDMA7_IRQ_STATUS ); pm_putrtn();
296         pm_putstr( "DMA8_IRQ_STATUS    " ); pm_puthex4byte( *pDMA8_IRQ_STATUS ); pm_putrtn();
297         pm_putstr( "DMA9_IRQ_STATUS    " ); pm_puthex4byte( *pDMA9_IRQ_STATUS ); pm_putrtn();
298         pm_putstr( "DMA10_IRQ_STATUS    " );    pm_puthex4byte( *pDMA10_IRQ_STATUS ); pm_putrtn();
299         pm_putstr( "DMA11_IRQ_STATUS    " );    pm_puthex4byte( *pDMA11_IRQ_STATUS ); pm_putrtn();
300         pm_putstr( "MDMA_D0_IRQ_STATUS " ); pm_puthex4byte( *pMDMA_D0_IRQ_STATUS ); pm_putrtn();
301         pm_putstr( "MDMA_S0_IRQ_STATUS " ); pm_puthex4byte( *pMDMA_S0_IRQ_STATUS ); pm_putrtn();
302         pm_putstr( "MDMA_D1_IRQ_STATUS " ); pm_puthex4byte( *pMDMA_D1_IRQ_STATUS ); pm_putrtn();
303         pm_putstr( "MDMA_S1_IRQ_STATUS " ); pm_puthex4byte( *pMDMA_S1_IRQ_STATUS ); pm_putrtn();
304         pm_putstr( "SPI0_STAT          " ); pm_puthex4byte( *pSPI0_STAT ); pm_putrtn();
305         pm_putstr( "SPI1_STAT          " ); pm_puthex4byte( *pSPI1_STAT ); pm_putrtn();
306         pm_putstr( "SPI2_STAT          " ); pm_puthex4byte( *pSPI2_STAT ); pm_putrtn();
307         pm_putstr( "EPPI0_STATUS       " ); pm_puthex4byte( *pEPPI0_STATUS ); pm_putrtn();
308         pm_putstr( "EPPI1_STATUS       " ); pm_puthex4byte( *pEPPI1_STATUS ); pm_putrtn();
309         pm_putstr( "EPPI2_STATUS       " ); pm_puthex4byte( *pEPPI2_STATUS ); pm_putrtn();
310         pm_putstr( "SPORT0_STAT        " ); pm_puthex4byte( *pSPORT0_STAT ); pm_putrtn();
311         pm_putstr( "SPORT1_STAT        " ); pm_puthex4byte( *pSPORT1_STAT ); pm_putrtn();
312         pm_putstr( "SPORT2_STAT        " ); pm_puthex4byte( *pSPORT2_STAT ); pm_putrtn();
313         pm_putstr( "SPORT3_STAT        " ); pm_puthex4byte( *pSPORT3_STAT ); pm_putrtn();
314         pm_putstr( "TIMER_STATUS0      " ); pm_puthex4byte( *pTIMER_STATUS0 ); pm_putrtn();
315         pm_putstr( "TIMER_STATUS1      " ); pm_puthex4byte( *pTIMER_STATUS1 ); pm_putrtn();
316         pm_putrtn();
317         pm_putstr( "Calling Stack :" ); pm_putrtn();
318
319         while( fp )
320         {
321             pm_putstr( "Called from " );    pm_puthex4byte( *(fp+1) ); pm_putrtn();
322             fp = *fp;
323         }
324     }
325 }
326
327 /**
328  * \brief CPU例外ハンドラ
329  *
330  * CPU例外ハンドラとしてcfgファイルに登録する。 hwei_handler()は呼ばれたら戻ってこないが、
331  * そのあとにもexpFlagに値を代入しているのは、最適化によってunlink命令の値がルーチン呼び出しの
332  * 前に移動することを防ぐためである。
333  *
334  * DEF_EXC(CPUEXC1, { TA_HLNG, excp_handler} );
335  *
336  */
337 void spurious_exc_handler(VP p_excinf)
338 {
339     expFlag = TRUE;
340     spurious_int_handler();
341 }
342