📄 alt_exception_muldiv.s
字号:
/******************************************************************************
* *
* License Agreement *
* *
* Copyright (c) 2003-2005 Altera Corporation, San Jose, California, USA. *
* All rights reserved. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* *
* This agreement shall be governed in all respects by the laws of the State *
* of California and by the laws of the United States of America. *
* *
******************************************************************************/
/*
* This is the software multiply/divide handler for Nios2.
*/
/*
* Provide a label which can be used to pull this file in.
*/
.section .exceptions.start
.globl alt_exception_muldiv
alt_exception_muldiv:
/*
* Pull in the entry/exit code.
*/
.globl alt_exception
.section .exceptions.soft, "xa"
/* INSTRUCTION EMULATION
* ---------------------
*
* Nios II processors generate exceptions for unimplemented instructions.
* The routines below emulate these instructions. Depending on the
* processor core, the only instructions that might need to be emulated
* are div, divu, mul, muli, mulxss, mulxsu, and mulxuu.
*
* The emulations match the instructions, except for the following
* limitations:
*
* 1) The emulation routines do not emulate the use of the exception
* temporary register (et) as a source operand because the exception
* handler already has modified it.
*
* 2) The routines do not emulate the use of the stack pointer (sp) or the
* exception return address register (ea) as a destination because
* modifying these registers crashes the exception handler or the
* interrupted routine.
*
* 3) To save code size, the routines do not emulate the use of the
* breakpoint registers (ba and bt) as operands.
*
* Detailed Design
* ---------------
*
* The emulation routines expect the contents of integer registers r0-r31
* to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp). The
* routines retrieve source operands from the stack and modify the
* destination register's value on the stack prior to the end of the
* exception handler. Then all registers except the destination register
* are restored to their previous values.
*
* The instruction that causes the exception is found at address -4(ea).
* The instruction's OP and OPX fields identify the operation to be
* performed.
*
* One instruction, muli, is an I-type instruction that is identified by
* an OP field of 0x24.
*
* muli AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24-
* 27 22 6 0 <-- LSB of field
*
* The remaining emulated instructions are R-type and have an OP field
* of 0x3a. Their OPX fields identify them.
*
* R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a-
* 27 22 17 11 6 0 <-- LSB of field
*
*
*/
/*
* Split the instruction into its fields. We need 4*A, 4*B, and 4*C as
* offsets to the stack pointer for access to the stored register values.
*/
/* r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP */
roli r3, r2, 7 /* r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB */
roli r4, r3, 3 /* r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB */
roli r6, r4, 2 /* r6 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II */
srai r4, r4, 16 /* r4 = (sign-extended) IMM16 */
xori r6, r6, 0x42 /* r6 = CCC,XXXXXX,NNNNN,PPPPPP,AAAAA,bBBBB,cC */
roli r7, r6, 5 /* r7 = XXXX,NNNNN,PPPPPP,AAAAA,bBBBB,cCCCC,XX */
andi r5, r2, 0x3f /* r5 = 00000000000000000000000000,PPPPPP */
xori r3, r3, 0x40
andi r3, r3, 0x7c /* r3 = 0000000000000000000000000,aAAAA,00 */
andi r6, r6, 0x7c /* r6 = 0000000000000000000000000,bBBBB,00 */
andi r7, r7, 0x7c /* r7 = 0000000000000000000000000,cCCCC,00 */
/* Now either
* r5 = OP
* r3 = 4*(A^16)
* r4 = IMM16 (sign extended)
* r6 = 4*(B^16)
* r7 = 4*(C^16)
* or
* r5 = OP
*/
/*
* Save everything on the stack to make it easy for the emulation routines
* to retrieve the source register operands. The exception entry code has
* already saved some of this so we don't need to do it all again.
*/
addi sp, sp, -60
stw zero, 64(sp) /* Save zero on stack to avoid special case for r0. */
/* Register at and r2-r15 have already been saved. */
stw r16, 0(sp)
stw r17, 4(sp)
stw r18, 8(sp)
stw r19, 12(sp)
stw r20, 16(sp)
stw r21, 20(sp)
stw r22, 24(sp)
stw r23, 28(sp)
/* et @ 32 - Has already been changed.*/
/* bt @ 36 - Usually isn't an operand. */
stw gp, 40(sp)
stw sp, 44(sp)
stw fp, 48(sp)
/* ea @ 52 - Don't bother to save - it's already been changed */
/* ba @ 56 - Breakpoint register usually isn't an operand */
/* ra @ 60 - Has already been saved */
/*
* Prepare for either multiplication or division loop.
* They both loop 32 times.
*/
movi r14, 32
/*
* Get the operands.
*
* It is necessary to check for muli because it uses an I-type instruction
* format, while the other instructions are have an R-type format.
*/
add r3, r3, sp /* r3 = address of A-operand. */
ldw r3, 0(r3) /* r3 = A-operand. */
movi r15, 0x24 /* muli opcode (I-type instruction format) */
beq r5, r15, .Lmul_immed /* muli doesn't use the B register as a source */
add r6, r6, sp /* r6 = address of B-operand. */
ldw r6, 0(r6) /* r6 = B-operand. */
/* r4 = SSSSSSSSSSSSSSSS,-----IMM16------ */
/* IMM16 not needed, align OPX portion */
/* r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000 */
srli r4, r4, 5 /* r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX-- */
andi r4, r4, 0x3f /* r4 = 00000000000000000000000000,-OPX-- */
/* Now
* r5 = OP
* r3 = src1
* r6 = src2
* r4 = OPX (no longer can be muli)
* r7 = 4*(C^16)
* r14 = loop counter
*/
/* ILLEGAL-INSTRUCTION EXCEPTION
* -----------------------------
*
* This code is for Nios II cores that generate exceptions when attempting
* to execute illegal instructions. Nios II cores that support an
* illegal-instruction exception are identified by the presence of the
* macro definition NIOS2_HAS_ILLEGAL_INSTRUCTION_EXCEPTION in system.h .
*
* Remember that illegal instructions are different than unimplemented
* instructions. Illegal instructions are instruction encodings that
* have not been defined by the Nios II ISA. Unimplemented instructions
* are legal instructions that must be emulated by some Nios II cores.
*
* If we get here, all instructions except multiplies and divides
* are illegal.
*
* This code assumes that OP is not muli (because muli was tested above).
* All other multiplies and divides are legal. Anything else is illegal.
*/
movi r8, 0x3a /* OP for R-type mul* and div* */
bne r5, r8, .Lnot_muldiv
/* r15 already is 0x24 */ /* OPX of divu */
beq r4, r15, .Ldivide
movi r15,0x27 /* OPX of mul */
beq r4, r15, .Lmultiply
movi r15,0x07 /* OPX of mulxuu */
beq r4, r15, .Lmultiply
movi r15,0x17 /* OPX of mulxsu */
beq r4, r15, .Lmultiply
movi r15,0x1f /* OPX of mulxss */
beq r4, r15, .Lmultiply
movi r15,0x25 /* OPX of div */
bne r4, r15, .Lnot_muldiv
/* DIVISION
*
* Divide an unsigned dividend by an unsigned divisor using
* a shift-and-subtract algorithm. The example below shows
* 43 div 7 = 6 for 8-bit integers. This classic algorithm uses a
* single register to store both the dividend and the quotient,
* allowing both values to be shifted with a single instruction.
*
* remainder dividend:quotient
* --------- -----------------
* initialize 00000000 00101011:
* shift 00000000 0101011:_
* remainder >= divisor? no 00000000 0101011:0
* shift 00000000 101011:0_
* remainder >= divisor? no 00000000 101011:00
* shift 00000001 01011:00_
* remainder >= divisor? no 00000001 01011:000
* shift 00000010 1011:000_
* remainder >= divisor? no 00000010 1011:0000
* shift 00000101 011:0000_
* remainder >= divisor? no 00000101 011:00000
* shift 00001010 11:00000_
* remainder >= divisor? yes 00001010 11:000001
* remainder -= divisor - 00000111
* ----------
* 00000011 11:000001
* shift 00000111 1:000001_
* remainder >= divisor? yes 00000111 1:0000011
* remainder -= divisor - 00000111
* ----------
* 00000000 1:0000011
* shift 00000001 :0000011_
* remainder >= divisor? no 00000001 :00000110
*
* The quotient is 00000110.
*/
.Ldivide:
/*
* Prepare for division by assuming the result
* is unsigned, and storing its "sign" as 0.
*/
movi r17, 0
/* Which division opcode? */
xori r15, r4, 0x25 /* OPX of div */
bne r15, zero, .Lunsigned_division
/*
* OPX is div. Determine and store the sign of the quotient.
* Then take the absolute value of both operands.
*/
xor r17, r3, r6 /* MSB contains sign of quotient */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -