From 03261851a10dd2d6900a0a00a7515a0a46fb5d76 Mon Sep 17 00:00:00 2001 From: Ranjith Kumaran Date: Fri, 17 Mar 2000 22:48:54 +0000 Subject: 20000317 sourceware import --- libgloss/mips/entry.S | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 libgloss/mips/entry.S (limited to 'libgloss/mips/entry.S') diff --git a/libgloss/mips/entry.S b/libgloss/mips/entry.S new file mode 100644 index 000000000..3630c552f --- /dev/null +++ b/libgloss/mips/entry.S @@ -0,0 +1,281 @@ +/* entry.S - exception handler for emulating MIPS16 'entry' and 'exit' + pseudo-instructions. These instructions are generated by the compiler + when the -mentry switch is used. The instructions are not implemented + in the MIPS16 CPU; hence the exception handler that emulates them. + + This module contains the following public functions: + + * void __install_entry_handler(void); + + This function installs the entry/exit exception handler. It should + be called before executing any MIPS16 functions that were compiled with + -mentry, typically before main() is called. + + * void __remove_entry_handler(void); + + This function removes the entry/exit exception handler. It should + be called when the program is exiting, or when it is known that no + more MIPS16 functions compiled with -mentry will be called. +*/ + +#ifdef __mips16 +/* This file contains 32 bit assembly code. */ + .set nomips16 +#endif + +#include "regs.S" + +#define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */ +#define EXC_RI 0x28 /* 101000 == 10 << 2 */ + +/* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */ + +#define DEBUG 0 + +#if DEBUG + + .sdata +int_count: + .space 4 /* interrupt count modulo 16 */ +int_cause: + .space 4*16 /* last 16 interrupt causes */ +#endif + + .text + + .set noreorder /* Do NOT reorder instructions */ + + +/* __entry_exit_handler - the reserved instruction exception handler + that emulates the entry and exit instruction. */ + +__entry_exit_handler: + .set noat /* Do NOT use at register */ +#if DEBUG +/* Must avoid using 'la' pseudo-op because it uses gp register, which + may not have a good value in an exception handler. */ + +# la k0, int_count /* intcount = (intcount + 1) & 0xf */ + lui k0 ,%hi(int_count) + addiu k0, k0 ,%lo(int_count) + lw k1, (k0) + addiu k1, k1, 1 + andi k1, k1, 0x0f + sw k1, (k0) +# la k0, int_cause /* k1 = &int_cause[intcount] */ + lui k0, %hi(int_cause) + addiu k0, k0, %lo(int_cause) + sll k1, k1, 2 + add k1, k1, k0 +#endif + mfc0 k0, C0_CAUSE /* Fetch cause */ +#if DEBUG + sw k0, -4(k1) /* Save exception cause in buffer */ +#endif + mfc0 k1, C0_EPC /* Check for Reserved Inst. without */ + and k0, CAUSE_EXCMASK /* destroying any register */ + subu k0, EXC_RI + bne k0, zero, check_others /* Sorry, go do something else */ + + and k0, k1, 1 /* Check for TR mode (pc.0 = 1) */ + beq k0, zero, ri_in_32 /* Sorry, RI in 32-bit mode */ + xor k1, 1 + +/* Since we now are going to emulate or die, we can use all the T-registers */ +/* that MIPS16 does not use (at, t0-t8), and we don't have to save them. */ + + .set at /* Now it's ok to use at again */ + +#if 0 + j leave + rfe +#endif + + lhu t0, 0(k1) /* Fetch the offending instruction */ + xor t8, k1, 1 /* Prepare t8 for exit */ + and t1, t0, 0xf81f /* Check for entry/exit opcode */ + bne t1, 0xe809, other_ri + +deareg: and t1, t0, 0x0700 /* Isolate the three a-bits */ + srl t1, 6 /* Adjust them so x4 is applied */ + slt t2, t1, 17 /* See if this is the exit instruction */ + beqz t2, doexit + la t2, savea + subu t2, t1 + jr t2 /* Jump into the instruction table */ + rfe /* We run the rest in user-mode */ + + /* This is the entry instruction! */ + sw a3, 12(sp) /* 4: a0-a3 saved */ + sw a2, 8(sp) /* 3: a0-a2 saved */ + sw a1, 4(sp) /* 2: a0-a1 saved */ + sw a0, 0(sp) /* 1: a0 saved */ +savea: /* 0: No arg regs saved */ + +dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */ + move t7, sp /* Temporary SP */ + beq t1, zero, desreg + subu sp, 32 /* Default SP adjustment */ + sw ra, -4(t7) + subu t7, 4 + +desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */ + beq t1, zero, leave + subu t1, 0x0040 + beq t1, zero, leave /* Only one to save... */ + sw s0, -4(t7) /* Do the first one */ + sw s1, -8(t7) /* Do the last one */ + +leave: jr t8 /* Exit to unmodified EPC */ + nop /* Urgh - the only nop!! */ + +doexf0: mtc1 v0,$f0 /* Copy float value */ + b doex2 + +doexf1: mtc1 v1,$f0 /* Copy double value */ + mtc1 v0,$f1 + b doex2 + +doexit: slt t2, t1, 21 + beq t2, zero, doexf0 + slt t2, t1, 25 + beq t2, zero, doexf1 + +doex2: and t1, t0, 0x0020 /* Isolate ra bit */ + beq t1, zero, dxsreg /* t1 holds ra-bit */ + addu t7, sp, 32 /* Temporary SP */ + lw ra, -4(t7) + subu t7, 4 + +dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */ + beq t1, zero, leavex + subu t1, 0x0040 + beq t1, zero, leavex /* Only one to save... */ + lw s0, -4(t7) /* Do the first one */ + lw s1, -8(t7) /* Do the last one */ + +leavex: jr ra /* Exit to ra */ + addu sp, 32 /* Clean up stack pointer */ + +/* Come here for exceptions we can't handle. */ + +ri_in_32: +other_ri: +check_others: /* call the previous handler */ + la k0,__previous + jr k0 + nop + +__exception_code: + .set noreorder + la k0, __entry_exit_handler +# lui k0, %hi(exception) +# addiu k0, k0, %lo(exception) + jr k0 + nop + .set reorder +__exception_code_end: + + .data +__previous: + .space (__exception_code_end - __exception_code) + .text + + +/* void __install_entry_handler(void) + + Install our entry/exit reserved instruction exception handler. +*/ + .ent __install_entry_handler + .globl __install_entry_handler +__install_entry_handler: + .set noreorder + mfc0 a0,C0_SR + nop + li a1,SR_BEV + and a1,a1,a0 + beq a1,$0,baseaddr + lui a0,0x8000 /* delay slot */ + lui a0,0xbfc0 + addiu a0,a0,0x0100 +baseaddr: + addiu a0,a0,0x080 /* a0 = base vector table address */ + li a1,(__exception_code_end - __exception_code) + la a2,__exception_code + la a3,__previous +/* there must be a better way of doing this???? */ +copyloop: + lw v0,0(a0) + sw v0,0(a3) + lw v0,0(a2) + sw v0,0(a0) + addiu a0,a0,4 + addiu a2,a2,4 + addiu a3,a3,4 + subu a1,a1,4 + bne a1,$0,copyloop + nop + j ra + nop + .set reorder + .end __install_entry_handler + + +/* void __remove_entry_handler(void); + + Remove our entry/exit reserved instruction exception handler. +*/ + + .ent __remove_entry_handler + .globl __remove_entry_handler +__remove_entry_handler: + .set noreorder + + mfc0 a0,C0_SR + nop + li a1,SR_BEV + and a1,a1,a0 + beq a1,$0,res_baseaddr + lui a0,0x8000 /* delay slot */ + lui a0,0xbfc0 + addiu a0,a0,0x0200 +res_baseaddr: + addiu a0,a0,0x0180 /* a0 = base vector table address */ + li a1,(__exception_code_end - __exception_code) + la a3,__previous + +/* there must be a better way of doing this???? */ +res_copyloop: + lw v0,0(a3) + sw v0,0(a0) + addiu a0,a0,4 + addiu a3,a3,4 + subu a1,a1,4 + bne a1,$0,res_copyloop + nop + j ra + nop + .set reorder + .end __remove_entry_handler + + +/* software_init_hook - install entry/exit handler and arrange to have it + removed at exit. This function is called by crt0.S. */ + + .text + .globl software_init_hook + .ent software_init_hook +software_init_hook: + .set noreorder + subu sp, sp, 8 /* allocate stack space */ + sw ra, 4(sp) /* save return address */ + jal __install_entry_handler /* install entry/exit handler */ + nop + lui a0, %hi(__remove_entry_handler) /* arrange for exit to */ + jal atexit /* de-install handler */ + addiu a0, a0, %lo(__remove_entry_handler) /* delay slot */ + lw ra, 4(sp) /* get return address */ + j ra /* return */ + addu sp, sp, 8 /* deallocate stack */ + .set reorder + .end software_init_hook -- cgit v1.2.3