1 /******************************************************************************
3 * Copyright (C) 2004 - 2014 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
33 * Microblaze HW Exception Handler
34 * - Non self-modifying exception handler for the following exception conditions
36 * - Instruction bus error
38 * - Illegal instruction opcode
40 * - Stack protection violation
43 #include "microblaze_exceptions_g.h"
44 #include "xparameters.h"
47 #define EX_HANDLER_STACK_SIZ (4*21)
48 #define RMSR_OFFSET (20 * 4)
49 #define R17_OFFSET (0)
50 #define REG_OFFSET(regnum) (4 * (regnum + 1))
51 #define NUM_TO_REG(num) r ## num
53 #define R3_TO_STACK(regnum) swi r3, r1, REG_OFFSET(regnum)
54 #define R3_FROM_STACK(regnum) lwi r3, r1, REG_OFFSET(regnum)
56 #define PUSH_REG(regnum) swi NUM_TO_REG(regnum), r1, REG_OFFSET(regnum)
57 #define POP_REG(regnum) lwi NUM_TO_REG(regnum), r1, REG_OFFSET(regnum)
62 swi r5, r1, RMSR_OFFSET;
64 #define PUSH_MSR_AND_ENABLE_EXC \
66 swi r5, r1, RMSR_OFFSET; \
67 ori r5, r5, 0x100; /* Turn ON the EE bit*/ \
72 lwi r5, r1, RMSR_OFFSET; \
76 #define PUSH_R17 swi r17, r1, R17_OFFSET
78 #define POP_R17 lwi r17, r1, R17_OFFSET
81 bri ex_handler_unhandled; \
85 bri ex_handler_unhandled; \
88 /* r3 is the source */
89 #define R3_TO_LWREG_V(regnum) \
90 R3_TO_STACK (regnum); \
93 /* r3 is the source */
94 #define R3_TO_LWREG(regnum) \
95 or NUM_TO_REG (regnum), r0, r3; \
98 /* r3 is the target */
99 #define SWREG_TO_R3_V(regnum) \
100 R3_FROM_STACK (regnum); \
103 /* r3 is the target */
104 #define SWREG_TO_R3(regnum) \
105 or r3, r0, NUM_TO_REG (regnum); \
108 /* regnum is the source */
109 #define FP_EX_OPB_SAVE(regnum) \
110 swi NUM_TO_REG (regnum), r0, mb_fpex_op_b; \
112 bri handle_fp_ex_opa;
114 /* regnum is the source */
115 #define FP_EX_OPB_SAVE_V(regnum) \
116 R3_FROM_STACK (regnum); \
117 swi r3, r0, mb_fpex_op_b; \
118 bri handle_fp_ex_opa;
120 /* regnum is the source */
121 #define FP_EX_OPA_SAVE(regnum) \
122 swi NUM_TO_REG (regnum), r0, mb_fpex_op_a; \
124 bri handle_fp_ex_done;
126 /* regnum is the source */
127 #define FP_EX_OPA_SAVE_V(regnum) \
128 R3_FROM_STACK (regnum); \
129 swi r3, r0, mb_fpex_op_a; \
130 bri handle_fp_ex_done;
132 #define FP_EX_UNHANDLED \
133 bri fp_ex_unhandled; \
138 #define ESR_EXC_MASK 0x0000001F
139 #define ESR_REG_MASK 0x000003E0
140 #define ESR_LW_SW_MASK 0x00000400
141 #define ESR_WORD_MASK 0x00000800
142 #define ESR_DS_MASK 0x00001000
144 /* Extern declarations */
148 #ifdef MICROBLAZE_EXCEPTIONS_ENABLED /* If exceptions are enabled in the processor */
151 * hw_exception_handler - Handler for unaligned exceptions
152 * Exception handler notes:
153 * - Does not handle exceptions other than unaligned exceptions
154 * - Does not handle exceptions during load into r17, r1, r0.
155 * - Does not handle exceptions during store from r17 (cannot be done) and r1 (slows down common case)
157 * Relevant register structures
159 * EAR - |----|----|----|----|----|----|----|----|
160 * - < ## 32 bit faulting address ## >
162 * ESR - |----|----|----|----|----| - | - |-----|-----|
166 * STACK FRAME STRUCTURE
167 * ---------------------
169 * +-------------+ + 0
171 * +-------------+ + 4
174 * +-------------+ + 8
181 * +-------------+ + 80
183 * +-------------+ + 84
189 .global _hw_exception_handler
192 .ent _hw_exception_handler
193 .type _hw_exception_handler, @function
194 _hw_exception_handler:
196 #if defined(XPAR_MICROBLAZE_USE_STACK_PROTECTION) && (XPAR_MICROBLAZE_USE_STACK_PROTECTION == 1)
197 /* Immediately halt for stack protection violation exception without using any stack */
198 swi r3, r0, mb_sp_save_r3; /* Save temporary register */
199 mfs r3, resr; /* Extract ESR[DS] */
200 andi r3, r3, ESR_EXC_MASK;
201 xori r3, r3, 0x7; /* Check for stack protection violation */
202 bnei r3, ex_handler_not_sp_violation;
203 ex_handler_sp_violation:
204 bri 0; /* Halt here if stack protection violation */
205 ex_handler_not_sp_violation:
206 lwi r3, r0, mb_sp_save_r3; /* Restore temporary register */
207 #endif /* defined(XPAR_MICROBLAZE_USE_STACK_PROTECTION) && (XPAR_MICROBLAZE_USE_STACK_PROTECTION == 1) */
209 addik r1, r1, -(EX_HANDLER_STACK_SIZ); /* Create stack frame */
214 #ifdef MICROBLAZE_CAN_HANDLE_EXCEPTIONS_IN_DELAY_SLOTS
216 andi r6, r6, ESR_DS_MASK;
217 beqi r6, ex_handler_no_ds;
222 PUSH_MSR_AND_ENABLE_EXC; /* Exceptions enabled here. This will allow nested exceptions */
225 andi r5, r3, ESR_EXC_MASK; /* Extract ESR[EXC] */
226 #ifndef NO_UNALIGNED_EXCEPTIONS
227 xori r6, r5, 1; /* 00001 = Unaligned Exception */
228 bnei r6, handle_ex_regular;
230 la r4, r0, MB_ExceptionVectorTable; /* Check if user has registered an unaligned exception handler */
232 la r6, r0, XNullHandler; /* If exceptionvectortable entry is still XNullHandler, use */
233 xor r6, r4, r6; /* the default exception handler */
234 beqi r6, handle_unaligned_ex ;
237 #endif /* ! NO_UNALIGNED_EXCEPTIONS */
239 #if defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE)
240 xori r6, r5, 6; /* 00110 = FPU exception */
241 beqi r6, handle_fp_ex; /* Go and decode the FP exception */
242 #endif /* defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE) */
244 handle_other_ex: /* Handle Other exceptions here */
246 cmp r6, r5, r6; /* >= 20 are exceptions we do not handle. */
247 blei r6, ex_handler_unhandled;
250 cmp r6, r5, r6; /* Convert MMU exception indices into an ordinal of 7 */
251 bgti r6, handle_other_ex_tail;
254 handle_other_ex_tail:
255 PUSH_REG(7); /* Save other volatiles before we make procedure calls below */
264 la r4, r0, MB_ExceptionVectorTable; /* Load the Exception vector table base address */
265 addk r7, r5, r5; /* Calculate exception vector offset = r5 * 8 */
268 addk r7, r7, r4; /* Get pointer to exception vector */
269 lwi r5, r7, 4; /* Load argument to exception handler from table */
270 lw r7, r7, r0; /* Load vector itself here */
272 brald r15, r7; /* Branch to handler */
275 POP_REG(7); /* Restore other volatiles */
284 bri ex_handler_done; /* Complete exception handling */
286 #ifndef NO_UNALIGNED_EXCEPTIONS
288 andi r6, r3, ESR_REG_MASK; /* Mask and extract the register operand */
289 srl r6, r6; /* r6 >> 5 */
294 sbi r6, r0, ex_reg_op; /* Store the register operand in a temporary location */
296 andi r6, r3, ESR_LW_SW_MASK; /* Extract ESR[S] */
299 andi r6, r3, ESR_WORD_MASK; /* Extract ESR[W] */
301 lbui r5, r4, 0; /* Exception address in r4 */
302 sbi r5, r0, ex_tmp_data_loc_0; /* Load a word, byte-by-byte from destination address and save it in tmp space */
304 sbi r5, r0, ex_tmp_data_loc_1;
306 sbi r5, r0, ex_tmp_data_loc_2;
308 sbi r5, r0, ex_tmp_data_loc_3;
309 lwi r3, r0, ex_tmp_data_loc_0; /* Get the destination register value into r3 */
312 lbui r5, r4, 0; /* Exception address in r4 */
313 sbi r5, r0, ex_tmp_data_loc_0; /* Load a half-word, byte-by-byte from destination address and save it in tmp space */
315 sbi r5, r0, ex_tmp_data_loc_1;
316 lhui r3, r0, ex_tmp_data_loc_0; /* Get the destination register value into r3 */
318 lbui r5, r0, ex_reg_op; /* Get the destination register number into r5 */
319 la r6, r0, lw_table; /* Form load_word jump table offset (lw_table + (8 * regnum)) */
325 ex_lw_end: /* Exception handling of load word, ends */
327 lbui r5, r0, ex_reg_op; /* Get the destination register number into r5 */
328 la r6, r0, sw_table; /* Form store_word jump table offset (sw_table + (8 * regnum)) */
336 andi r6, r6, ESR_WORD_MASK; /* Extract ESR[W] */
338 swi r3, r0, ex_tmp_data_loc_0;
339 lbui r3, r0, ex_tmp_data_loc_0; /* Store the word, byte-by-byte into destination address */
341 lbui r3, r0, ex_tmp_data_loc_1;
343 lbui r3, r0, ex_tmp_data_loc_2;
345 lbui r3, r0, ex_tmp_data_loc_3;
349 swi r3, r0, ex_tmp_data_loc_0; /* Store the lower half-word, byte-by-byte into destination address */
351 #ifdef __LITTLE_ENDIAN__
352 lbui r3, r0, ex_tmp_data_loc_0;
354 lbui r3, r0, ex_tmp_data_loc_2;
357 #ifdef __LITTLE_ENDIAN__
358 lbui r3, r0, ex_tmp_data_loc_1;
360 lbui r3, r0, ex_tmp_data_loc_3;
363 ex_sw_end: /* Exception handling of store word, ends. */
365 #endif /* !NO_UNALIGNED_EXCEPTIONS */
367 #if defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE)
369 addik r3, r17, -4; /* r17 contains (addr of exception causing FP instruction + 4) */
370 lw r4, r0, r3; /* We might find ourselves in a spot here. Unguaranteed load */
373 la r6, r0, fp_table_opb; /* Decode opB and store its value in mb_fpex_op_b */
386 add r3, r3, r3; /* Calculate (fp_table_opb + (regno * 12)) in r5 */
394 la r6, r0, fp_table_opa; /* Decode opA and store its value in mb_fpex_op_a */
401 add r3, r3, r3; /* Calculate (fp_table_opb + (regno * 12)) in r5 */
409 ori r5, r0, 6; /* Set exception number back to 6 */
410 bri handle_other_ex_tail;
414 #endif /* defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE) */
425 addik r1, r1, (EX_HANDLER_STACK_SIZ); /* Restore stack frame */
426 ex_handler_unhandled:
427 bri 0 /* UNHANDLED. TRAP HERE */
428 .end _hw_exception_handler
430 #ifndef NO_UNALIGNED_EXCEPTIONS
433 * hw_exception_handler Jump Table
434 * - Contains code snippets for each register that caused the unaligned exception.
435 * - Hence exception handler is NOT self-modifying
436 * - Separate table for load exceptions and store exceptions.
437 * - Each table is of size: (8 * 32) = 256 bytes
443 lw_r0: R3_TO_LWREG (0);
445 lw_r2: R3_TO_LWREG (2);
446 lw_r3: R3_TO_LWREG_V (3);
447 lw_r4: R3_TO_LWREG_V (4);
448 lw_r5: R3_TO_LWREG_V (5);
449 lw_r6: R3_TO_LWREG_V (6);
450 lw_r7: R3_TO_LWREG (7);
451 lw_r8: R3_TO_LWREG (8);
452 lw_r9: R3_TO_LWREG (9);
453 lw_r10: R3_TO_LWREG (10);
454 lw_r11: R3_TO_LWREG (11);
455 lw_r12: R3_TO_LWREG (12);
456 lw_r13: R3_TO_LWREG (13);
457 lw_r14: R3_TO_LWREG (14);
458 lw_r15: R3_TO_LWREG (15);
459 lw_r16: R3_TO_LWREG (16);
461 lw_r18: R3_TO_LWREG (18);
462 lw_r19: R3_TO_LWREG (19);
463 lw_r20: R3_TO_LWREG (20);
464 lw_r21: R3_TO_LWREG (21);
465 lw_r22: R3_TO_LWREG (22);
466 lw_r23: R3_TO_LWREG (23);
467 lw_r24: R3_TO_LWREG (24);
468 lw_r25: R3_TO_LWREG (25);
469 lw_r26: R3_TO_LWREG (26);
470 lw_r27: R3_TO_LWREG (27);
471 lw_r28: R3_TO_LWREG (28);
472 lw_r29: R3_TO_LWREG (29);
473 lw_r30: R3_TO_LWREG (30);
474 lw_r31: R3_TO_LWREG (31);
477 sw_r0: SWREG_TO_R3 (0);
479 sw_r2: SWREG_TO_R3 (2);
480 sw_r3: SWREG_TO_R3_V (3);
481 sw_r4: SWREG_TO_R3_V (4);
482 sw_r5: SWREG_TO_R3_V (5);
483 sw_r6: SWREG_TO_R3_V (6);
484 sw_r7: SWREG_TO_R3 (7);
485 sw_r8: SWREG_TO_R3 (8);
486 sw_r9: SWREG_TO_R3 (9);
487 sw_r10: SWREG_TO_R3 (10);
488 sw_r11: SWREG_TO_R3 (11);
489 sw_r12: SWREG_TO_R3 (12);
490 sw_r13: SWREG_TO_R3 (13);
491 sw_r14: SWREG_TO_R3 (14);
492 sw_r15: SWREG_TO_R3 (15);
493 sw_r16: SWREG_TO_R3 (16);
495 sw_r18: SWREG_TO_R3 (18);
496 sw_r19: SWREG_TO_R3 (19);
497 sw_r20: SWREG_TO_R3 (20);
498 sw_r21: SWREG_TO_R3 (21);
499 sw_r22: SWREG_TO_R3 (22);
500 sw_r23: SWREG_TO_R3 (23);
501 sw_r24: SWREG_TO_R3 (24);
502 sw_r25: SWREG_TO_R3 (25);
503 sw_r26: SWREG_TO_R3 (26);
504 sw_r27: SWREG_TO_R3 (27);
505 sw_r28: SWREG_TO_R3 (28);
506 sw_r29: SWREG_TO_R3 (29);
507 sw_r30: SWREG_TO_R3 (30);
508 sw_r31: SWREG_TO_R3 (31);
510 /* Temporary data structures used in the handler */
524 #endif /* ! NO_UNALIGNED_EXCEPTIONS */
526 #if defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE)
528 * FP exception decode jump table.
529 * - Contains code snippets for each register that could have been a source operand for an excepting FP instruction
530 * - Hence exception handler is NOT self-modifying
531 * - Separate table for opA and opB
532 * - Each table is of size: (12 * 32) = 384 bytes
538 opa_r0: FP_EX_OPA_SAVE (0);
539 opa_r1: FP_EX_UNHANDLED;
540 opa_r2: FP_EX_OPA_SAVE (2);
541 opa_r3: FP_EX_OPA_SAVE_V (3);
542 opa_r4: FP_EX_OPA_SAVE_V (4);
543 opa_r5: FP_EX_OPA_SAVE_V (5);
544 opa_r6: FP_EX_OPA_SAVE_V (6);
545 opa_r7: FP_EX_OPA_SAVE (7);
546 opa_r8: FP_EX_OPA_SAVE (8);
547 opa_r9: FP_EX_OPA_SAVE (9);
548 opa_r10: FP_EX_OPA_SAVE (10);
549 opa_r11: FP_EX_OPA_SAVE (11);
550 opa_r12: FP_EX_OPA_SAVE (12);
551 opa_r13: FP_EX_OPA_SAVE (13);
552 opa_r14: FP_EX_UNHANDLED;
553 opa_r15: FP_EX_UNHANDLED;
554 opa_r16: FP_EX_UNHANDLED;
555 opa_r17: FP_EX_UNHANDLED;
556 opa_r18: FP_EX_OPA_SAVE (18);
557 opa_r19: FP_EX_OPA_SAVE (19);
558 opa_r20: FP_EX_OPA_SAVE (20);
559 opa_r21: FP_EX_OPA_SAVE (21);
560 opa_r22: FP_EX_OPA_SAVE (22);
561 opa_r23: FP_EX_OPA_SAVE (23);
562 opa_r24: FP_EX_OPA_SAVE (24);
563 opa_r25: FP_EX_OPA_SAVE (25);
564 opa_r26: FP_EX_OPA_SAVE (26);
565 opa_r27: FP_EX_OPA_SAVE (27);
566 opa_r28: FP_EX_OPA_SAVE (28);
567 opa_r29: FP_EX_OPA_SAVE (29);
568 opa_r30: FP_EX_OPA_SAVE (30);
569 opa_r31: FP_EX_OPA_SAVE (31);
572 opb_r0: FP_EX_OPB_SAVE (0);
573 opb_r1: FP_EX_UNHANDLED;
574 opb_r2: FP_EX_OPB_SAVE (2);
575 opb_r3: FP_EX_OPB_SAVE_V (3);
576 opb_r4: FP_EX_OPB_SAVE_V (4);
577 opb_r5: FP_EX_OPB_SAVE_V (5);
578 opb_r6: FP_EX_OPB_SAVE_V (6);
579 opb_r7: FP_EX_OPB_SAVE (7);
580 opb_r8: FP_EX_OPB_SAVE (8);
581 opb_r9: FP_EX_OPB_SAVE (9);
582 opb_r10: FP_EX_OPB_SAVE (10);
583 opb_r11: FP_EX_OPB_SAVE (11);
584 opb_r12: FP_EX_OPB_SAVE (12);
585 opb_r13: FP_EX_OPB_SAVE (13);
586 opb_r14: FP_EX_UNHANDLED;
587 opb_r15: FP_EX_UNHANDLED;
588 opb_r16: FP_EX_UNHANDLED;
589 opb_r17: FP_EX_UNHANDLED;
590 opb_r18: FP_EX_OPB_SAVE (18);
591 opb_r19: FP_EX_OPB_SAVE (19);
592 opb_r20: FP_EX_OPB_SAVE (20);
593 opb_r21: FP_EX_OPB_SAVE (21);
594 opb_r22: FP_EX_OPB_SAVE (22);
595 opb_r23: FP_EX_OPB_SAVE (23);
596 opb_r24: FP_EX_OPB_SAVE (24);
597 opb_r25: FP_EX_OPB_SAVE (25);
598 opb_r26: FP_EX_OPB_SAVE (26);
599 opb_r27: FP_EX_OPB_SAVE (27);
600 opb_r28: FP_EX_OPB_SAVE (28);
601 opb_r29: FP_EX_OPB_SAVE (29);
602 opb_r30: FP_EX_OPB_SAVE (30);
603 opb_r31: FP_EX_OPB_SAVE (31);
605 #endif /* defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE) */
607 #if defined(MICROBLAZE_FP_EXCEPTION_ENABLED) && defined(MICROBLAZE_FP_EXCEPTION_DECODE)
608 /* This is where we store the opA and opB of the last excepting FP instruction */
617 #endif /* defined (MICROBLAZE_FP_EXCEPTION_ENABLED) && defined (MICROBLAZE_FP_EXCEPTION_DECODE) */
619 #if defined(XPAR_MICROBLAZE_USE_STACK_PROTECTION) && (XPAR_MICROBLAZE_USE_STACK_PROTECTION == 1)
620 /* This is where we store the register used to check which exception occurred */
625 #endif /* defined(XPAR_MICROBLAZE_USE_STACK_PROTECTION) && (XPAR_MICROBLAZE_USE_STACK_PROTECTION == 1) */
627 /* The exception vector table */
630 .global MB_ExceptionVectorTable
631 MB_ExceptionVectorTable:
633 .long 0 /* -- FSL Exception -- */
635 .long 1 /* -- Unaligned Access Exception -- */
637 .long 2 /* -- Illegal Opcode Exception -- */
639 .long 3 /* -- Instruction Bus Exception -- */
641 .long 4 /* -- Data Bus Exception -- */
643 .long 5 /* -- Div-by-0 Exception -- */
645 .long 6 /* -- FPU Exception -- */
647 .long 7 /* -- MMU Exceptions -- */
649 #else /* Dummy exception handler, in case exceptions are not present in the processor */
651 .global _hw_exception_handler
654 .ent _hw_exception_handler
655 _hw_exception_handler:
657 .end _hw_exception_handler
659 #endif /* MICROBLAZE_EXCEPTIONS_ENABLED */