source: sources/examples/soclib_date04/timer4_gmn_handmade/soft/exception.s @ 6

Last change on this file since 6 was 1, checked in by buchmann, 17 years ago

Initial import from CVS repository

File size: 12.9 KB
Line 
1/* 
2 * Authors: Frédéric Pétrot and Denis Hommais
3 * $Log: exception.s,v $
4 * Revision 1.1  2005/03/02 12:37:22  buchmann
5 * Add "soft" directory.
6 * It allows to generate MIPS binary using cross compiler.
7 *
8 * Revision 1.2  2003/07/18 16:21:30  fred
9 * Now interprets the instruction that causes a DBE in order to print the
10 * address responsible for the failure.
11 * Cleaned up the code a little (mainly comments :)
12 *
13 * Revision 1.1  2003/03/10 13:39:07  fred
14 * Adding the hardware dependent stuff to smoothly handle multi
15 * architecture compilation of this kernel
16 * 
17 * Revision 1.1.1.1  2002/02/28 12:58:55  disydent
18 * Creation of Disydent CVS Tree
19 * 
20 * Revision 1.1.1.1  2001/11/19 16:55:37  pwet
21 * Changing the CVS tree structure of disydent
22 * 
23 * Revision 1.3  2001/11/14 12:08:45  fred
24 * Making the ldscript being generated for correct path accesses
25 * Removing the syscall entry of the exception handler for now
26 * 
27 * Revision 1.2  2001/11/09 14:51:03  fred
28 * Remove the reset executable and make the assembler be piped through
29 * cpp.
30 * The ldscript is not usable. I have to think before going on
31 * 
32 * $Id: exception.S,v 1.1 2003/03/10 13:39:07 fred Exp
33 *  Note   : we do not check BD at any time yet! Beware, ...
34 *  Rev 0  : minimal handler to support syscall for system calls
35 *           implementation
36 *  Rev 1  : added correct exception/interruption detection and messages
37 *  Rev 2  : added mult and div interpretation in illegal instruction
38 *  Rev 3  : Makes it compliant with multi-thread/multi-processor
39 *           Stack is thread stack now (it must at least for preemptive
40 *           scheduling stuffs
41 */
42        .rdata
43        .align 2
44msg  :  .ascii "An exception occurred with the following cause :\n\000"
45
46jmptable:
47        .word Int
48        .word Uimp
49        .word Uimp
50        .word Uimp
51        .word AdEL
52        .word AdES
53        .word IBE
54        .word DBE
55        .word Sys
56        .word Bp
57        .word RI
58        .word CpU
59        .word Ovf
60        .word Ukn
61        .word Ukn
62
63        .text
64        .align 2
65        .ent     excep
66excep:
67        /*
68         * Here I save the whole C compatible register context, which is a
69         * waste of time if only assembly functions are to be used
70         * A more optimized way to do things would be to check for critical
71         * events (typically external interrupts) and do the saving only
72         * when an other events took place
73         * Note that this implies to check which registers to save according
74         * to the interrupt handling routines, that are usually user defined!
75         *
76         * Reminder: $26 and $27 are kernel registers that need not be saved
77         * This shall be executed in critical section since the stack pointer
78         * is not properly set until the subu!
79         */
80        .set noreorder
81        /* Shall not touch $1 until it is saved */
82        .set noat
83         
84         subu   $29, $29, 26*4  /* Load kernel stack addr + stack update */
85         sw     $1,   1*4($29)  /*  save all temporaries*/
86        .set at
87         sw     $2,   2*4($29)  /*  others are saved when calling procedures*/
88         sw     $3,   3*4($29)
89         sw     $4,   4*4($29)
90         sw     $5,   5*4($29)
91         sw     $6,   6*4($29)
92         sw     $7,   7*4($29)
93         sw     $8,   8*4($29)
94         sw     $9,   9*4($29)
95         sw    $10,  10*4($29)
96         sw    $11,  11*4($29)
97         sw    $12,  12*4($29)
98         sw    $13,  13*4($29)
99         sw    $14,  14*4($29)
100         sw    $15,  15*4($29)
101         sw    $24,  16*4($29)
102         sw    $25,  17*4($29)
103         mfc0  $26,      $14     /* load EPC into k0 (two cycles befor use)*/
104         sw    $29,  18*4($29)
105         sw    $30,  19*4($29)
106         sw    $31,  20*4($29)
107         sw    $26,  21*4($29)   /* and store it to be recallable*/
108         mfhi  $26
109         sw    $26,  22*4($29)
110         mflo  $26
111         sw    $26,  23*4($29)
112
113         /* Check the cause of the arrival in this code */
114
115         mfc0  $27, $13           /*  load CAUSE into $27*/
116         nop
117         andi  $27, $27,  0x3c    /*  get the exception code (ExcCode)*/
118         beqz  $27, Int           /*  Test if it is an interrupt. If so*/
119         sw     $0,  24*4($29)    /* return address is epc + 0 */
120                                  /* it's faster.*/
121         la    $26,      jmptable /*  load the base of the jump table*/
122                                  /* get the exception code (ExcCode)*/
123         addu  $26, $26, $27      /*  load the offset in the table*/
124         lw    $27,      ($26)    /*  load the pointed value*/
125         li    $26,           4
126         j     $27                /*  and jump there*/
127         sw    $26,  24*4($29)    /* faulty insn is at epc - 4 */
128         nop                      /*  delayed slot too*/
129
130 /*
131  * External interupts:
132  * The meaning of these interupts is for sure system dependent, so
133  * this routine must be adapted to each system particularities
134  *
135  * Right now we just find out what interrupt lead us here, and print
136  * a small message about it.
137  */
138        .rdata
139        .align 2
140        .text
141Int :   
142        .set noat
143         mfc0  $4, $13           /*  load CAUSE into $27*/
144         mfc0  $26, $12           /*  load STATUS into $26*/
145         andi  $4, $4,   0xFF00 /*  mask CAUSE to get the ITs only*/
146         and   $4, $4,   $26    /*  keep only the enabled ITs*/
147         srl   $4, $4,   8      /*  and put them in the LSBees*/
148         beqz  $4,        _endit  /* If none, then what are we doing here? */
149         nop
150
151         .extern  SwitchOnIt
152
153         la     $26, SwitchOnIt
154         jal    $26
155         nop
156
157_endit:
158         j                 _return  /*  go back to user*/
159         nop
160        .set at
161
162 /*
163  * Clearly fatal exceptions as far as we're concerned, ...
164  */
165        .rdata
166        .align 2
167m2  :   .ascii "Unimplemented TLB Exception!\n\000"
168m2k :   .ascii "Reserved Exception!\n\000"
169m2o :   .ascii "Integer Arithmetic Overflow!\n\000"
170
171        .text
172        .align 2
173        .set reorder
174Uimp :   la     $4, m2            /*  load the appropriate message,...*/
175         j      U                 /* */
176Ukn  :   la     $4, m2k           /* */
177         j      U                 /* */
178Ovf  :   la     $4, m2o           /* */
179U    :   la     $2, uputs
180         jal    $2                /*  and print it!*/
181         j      _exit             /* */
182        .set noreorder
183
184 /*
185  * Illegal instructions:
186  * we interpret mult/div and lwl/lwr here, and exit on an other code
187  * Before modifing this code think that NO REGISTER CONTENT should
188  * be touched before the end of the register loading routine
189  * This explains why some code seems duplicated (several mfc0)
190  */
191        .rdata
192m2i  :  .ascii "Illegal or Reserved Instruction!\n\000"
193        .text
194        .set noat
195RI   :   mfc0  $26,      $14      /*  load EPC into $26*/
196         nop                      /* */
197         nop                      /* */
198         lw    $26,      ($26)    /*  $26 contains the faulty ins*/
199         lui   $27,      0xFC00    /*  mask for special*/
200         and   $27, $26, $27        /* */
201         bne   $27,  $0, Ilg         /*  this is not a special trap*/
202
203/*
204 * I do not handle the mult/div trap, as we have added the
205 * instructions in our R3000 model
206 */
207         nop
208
209Ilg:     la     $4, m2i
210         la     $2, uputs
211         jal    $2                /*  we got an illegal ins, so we quit*/
212         nop
213         j      _exit             /* */
214         nop
215
216 /*
217  * Unaligned access:
218  * Quite fatal, I'm afraid
219  */
220        .rdata
221        .align 2
222m3   :  .ascii "Unaligned/unallowed Access while %s address 0x%x at pc 0x%x!\n\000"
223m3l  :  .ascii "reading\000"
224m3e  :  .ascii "writing\000"
225
226        .text
227        .align 2
228        .set reorder
229AdEL :   la     $5,   m3l
230         j      AdE 
231AdES :   la     $5,   m3e
232AdE  :   la     $4,   m3
233        .set noreorder
234         mfc0   $6,   $8          /*  load BAR into thrid arg ($6)*/
235         mfc0   $7,  $14          /*  load EPC into fourth arg ($7)*/
236         la     $2,  uputs
237         jal    $2                /*  print all that stuff*/
238         nop
239         j               _exit
240         nop
241
242 /*
243  * Synchronous bus error
244  */
245        .rdata
246        .align 2
247m4i:    .ascii "Bus error while loading the instrunction at pc 0x%x!\n\000"
248m4d:    .ascii "Bus error while loading the datum at pc 0x%x for addr 0x%x!\n\000"
249        .data
250        .text
251
252        .align 2
253        .set reorder
254IBE :    mfc0   $5,   $14         /*  load EPC */
255         la     $4,   m4i
256         j      BE
257        .set noreorder
258DBE :    la     $4,   m4d
259         /*
260          * The instruction at EPC must be interpreted to get the
261          * address that caused the fault.
262          * The register value must be reloaded from the stack, and
263          * since the storage of the registers is quite exotic right
264          * now, this will work only for registers 1 to 15!
265          */
266         mfc0   $5,   $14         /* load EPC */
267         lw     $6, 0($5)         /* load faulty insn */
268         andi   $8,  $6, 0xFFFF   /* get the imm field of it */
269         srl    $9,  $6, 19
270         andi   $9,  $9, 0x7c     /* get the rs register index times 4 */
271         add    $9, $29, $9       /* compute the stack index of this register */
272         lw     $9, 0($9)
273         addu   $6, $9, $8        /* get the address as computed */
274
275BE :     la     $2,   uputs
276         jal    $2                /*  print all that stuff*/
277         nop
278         j               _exit
279         nop
280
281 /*
282  * Syscall: simple and straightforward.
283  * Even elegant : nothing's done at all anymore
284  */
285        .rdata
286        .align 2
287m5 :    .ascii "Syscall : no actions performed anymore\000"
288        .text
289        .align 2
290Sys : 
291         la     $4, m5
292         la     $2, uputs
293         jalr   $2
294         nop
295         j       _ret_sys         /* get back to caller */
296         nop
297#endif
298
299 /*
300  *
301  * We just indicate we got a breakpoint
302  * This shall be filled on a system per system basis
303  *
304  */
305        .rdata
306        .align 2
307m6 :    .ascii "Breakpoint of code %d!\n\000"
308
309        .text
310        .align 2
311Bp :     la     $4,   m6
312         mfc0   $3, $14           /*  load EPC*/
313         nop
314         nop
315         lw     $5, ($3)          /*  load the 'break' instruction*/
316         li     $3,      0xF      /*  filled delayed slot (load a mask)*/
317         srl    $5,  $5, 16       /*  shift it*/
318         and    $5,  $5, $3       /*  and get the code from the insn*/
319         la     $2,  uputs
320         jal    $2                /*  print the string*/
321         nop
322         j               _return
323         nop
324
325 /*
326  *
327  * Kernel/user violation, or coprocessor unusable.
328  * that's pretty fatal, ain't it ?
329  *
330  */
331        .rdata
332        .align 2
333m7 :    .ascii "Unusable Coprocessor %d!\n\000"
334m70:    .ascii "Trying to use a kernel instruction in user mode!\n\000"
335
336        .text
337        .align 2
338CpU :    mfc0   $3, $13           /*  load CAUSE*/
339         nop
340         li     $2,     0x30000000/* */
341         and    $2, $2, $3        /*  mask to get the CE bits */
342         bnez   $2,     cun       /*  not zero, so it is a CUN*/
343         nop                      /*  cannot put a 'la' here,...*/
344        .set reorder
345         la     $4,     m70       /*  here, it is a kernel violation*/
346         j      C
347        .set noreorder
348cun:     la     $4,   m7
349         srl    $5,   $2,  28     /*  LSByte contains now the copro number*/
350C:       la     $2,   uputs
351         jal    $2
352         nop
353         j               _exit
354         nop
355
356_exit:   li     $2, 100000
357_exit_l: bne    $2, $0,  _exit_l
358         addiu  $2, $2, -1
359         c0     00
360         nop
361
362_return :
363         lw     $2,    2*4($29)
364         j      tmp
365         nop
366_ret_sys: /* Special case for syscall : $2 is not restored */
367tmp:    .set noat     
368         lw     $1,    1*4($29)
369        .set at       
370         lw     $3,    3*4($29)
371         lw     $4,    4*4($29)
372         lw     $5,    5*4($29)
373         lw     $6,    6*4($29)
374         lw     $7,    7*4($29)
375         lw     $8,    8*4($29)
376         lw     $9,    9*4($29)
377         lw    $10,   10*4($29)
378         lw    $11,   11*4($29)
379         lw    $12,   12*4($29)
380         lw    $13,   13*4($29)
381         lw    $14,   14*4($29)
382         lw    $15,   15*4($29)
383         lw    $24,   16*4($29)
384         lw    $25,   17*4($29)
385         lw    $29,   18*4($29)
386         lw    $30,   19*4($29)
387         lw    $31,   20*4($29)
388
389         /* Take care of hi and lo also */
390         lw    $26,   22*4($29)
391         mthi  $26
392         lw    $26,   23*4($29)
393         mtlo  $26
394
395         lw    $26,   21*4($29)   /* This is the epc of this context */
396         lw    $27,   24*4($29)   /* This is the offset: 4 excep, 0 int */
397         addu  $29,   $29, 26*4   /* Stack update : fill lw stall */
398         addu  $26,   $26, $27    /* Addr for return from excep */
399         j     $26                /* Jump back where the exception occured*/
400         rfe                      /* And restore the original mode*/
401        .set     reorder
402        .end  excep
Note: See TracBrowser for help on using the repository browser.