MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / nios2nommu / kernel / entry.S
blob7f71a017d9b754dc20cd0bb19c3d9dc04f11e9c1
1 /*
2  *  linux/arch/nios2nommu/kernel/entry.S
3  *
4  *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
5  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
6  *                      Kenneth Albanowski <kjahds@kjahds.com>,
7  *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
8  *  Copyright (C) 2004  Microtronix Datacom Ltd.
9  *
10  * Based on:
11  *
12  *  linux/arch/m68knommu/kernel/entry.S
13  *
14  *  Copyright (C) 1991, 1992  Linus Torvalds
15  *
16  * This file is subject to the terms and conditions of the GNU General Public
17  * License.  See the file README.legal in the main directory of this archive
18  * for more details.
19  *
20  * Linux/m68k support by Hamish Macdonald
21  *
22  * 68060 fixes by Jesper Skov
23  * ColdFire support by Greg Ungerer (gerg@snapgear.com)
24  * 5307 fixes by David W. Miller
25  * linux 2.4 support David McCullough <davidm@snapgear.com>
26  */
28 #include <linux/sys.h>
29 #include <linux/linkage.h>
30 #include <asm/asm-offsets.h>
31 #include <asm/asm-macros.h>
32 #include <asm/thread_info.h>
33 #include <asm/errno.h>
34 #include <asm/setup.h>
35 #include <asm/segment.h>
36 #include <asm/entry.h>
37 #include <asm/unistd.h>
38 #include <asm/traps.h>
39 #include <asm/processor.h>
41 .text
42 .set noat
43 .set nobreak
45 ENTRY(system_call)
46 /*      SAVE_ALL */
47         rdctl   r10,status              /* enable intrs again */
48         ori     r10,r10,0x0001
49         wrctl   status,r10
51         movi    r2,-LENOSYS
52         stw     r2,PT_R2(sp)            /* default return value in r2 */
53                                         /* original r2 is in orig_r2 */
55         movui   r1,NR_syscalls
56         bgtu    r3,r1,ret_from_exception
57         slli    r1,r3,2
58         movhi   r11,%hiadj(sys_call_table)
59         add     r1,r1,r11
60         ldw     r1,%lo(sys_call_table)(r1)
61         beq     r1,r0,ret_from_exception
63         movi    r11,%lo(0xffffe000)     /* Get thread info pointer */
64         and     r11,sp,r11
65         ldw     r11,TI_FLAGS(r11)
66         BTBNZ   r11,r11,TIF_SYSCALL_TRACE_ASM,1f
68         callr   r1
69         stw     r2,PT_R2(sp)            /* save the return value */
70         br      ret_from_exception
72         SAVE_SWITCH_STACK
73         call    syscall_trace
74         RESTORE_SWITCH_STACK
75         /* wentao: restore r4-9, since they are trashed by syscall_trace */
76         ldw     r4,PT_R4(sp)
77         ldw     r5,PT_R5(sp)
78         ldw     r6,PT_R6(sp)
79         ldw     r7,PT_R7(sp)
80         ldw     r8,PT_R8(sp)
81         ldw     r9,PT_R9(sp)
82         callr   r1
83         stw     r2,PT_R2(sp)            /* save the return value */
84         SAVE_SWITCH_STACK
85         call    syscall_trace
86         RESTORE_SWITCH_STACK
88 ret_from_exception:
89         ldw     r1,PT_STATUS_EXTENSION(sp)      /* check if returning to kernel */
90         TSTBZ   r1,r1,PS_S_ASM,Luser_return     /* if so, skip resched, signals */
92 restore_all:
93         rdctl   r10,status                      /* disable intrs */
94         andi    r10,r10,0xfffe
95         wrctl   status, r10
96         RESTORE_ALL
97         eret
99 Luser_return:
100         GET_THREAD_INFO r24                     /* get thread_info pointer */
101         ldw     r10,TI_FLAGS(r24)               /* get thread_info->flags */
102         ANDI32  r11,r10,_TIF_WORK_MASK_ASM
103         beq     r11,r0,restore_all              /* Nothing to do */
104         BTBZ    r1,r10,TIF_NEED_RESCHED_ASM,Lsignal_return
106 Lwork_resched:
107         call    schedule
108         br      ret_from_exception
110 Lsignal_return:
111         BTBZ    r1,r10,TIF_SIGPENDING_ASM,restore_all
112         mov     r5,sp                   /* pt_regs */
113         SAVE_SWITCH_STACK
114         CLR     r4                      /* oldset = 0 */
115         call    do_signal
116         RESTORE_SWITCH_STACK
117         br      restore_all
120  * Handle software exceptions. Put here so external interrupts
121  * can fall throught to ret_from_interrupt.
122  */
124 software_exception:
125         ldw     r24,-4(ea)              // instruction that caused the exception
126         xorhi   r24,r24,0x003b          // upper half of trap opcode
127         xori    r24,r24,0x683a          // lower half of trap opcode
128         bne     r24,r0,instruction_trap /* N - check for instruction trap */
129         cmpeqi  r11,r2,TRAP_ID_SYSCALL  /* ? Is this a syscall */
130         bne     r11,r0,system_call      /* Y - handle syscall */
131         cmpeqi  r11,r2,TRAP_ID_APPDEBUG /* ? Is this an application debug */
132         bne     r11,r0,app_debug        /* Y - handle app_debug */
133         cmpeqi  r11,r2,63               /* ? Is this the old syscall number */
134         bne     r11,r0,system_call      /* Y - handle syscall to catch older apps*/
135         br      restore_all             /* N - everything else is ignored for now */
137 app_debug:
138         GET_THREAD_INFO r24                     /* get thread_info */
139         ldw     r1,TI_TASK(r24)         /* get thread_info->task */
140         ldw r24,(TASK_THREAD + THREAD_FLAGS)(r1)        /* get thread_info->task->thread.flags */
141         ORI32 r24, r24, NIOS2_FLAG_DEBUG  /* set the debug flag */
142         stw     r24,(TASK_THREAD + THREAD_FLAGS)(r1)    /* save thread_info->task->thread.flags */
143         br      restore_all
146  * This is the generic interrupt handler (for all hardware interrupt
147  * sources). It figures out the vector number and calls the appropriate
148  * interrupt service routine directly.
149  */
150 ENTRY(inthandler)
151         SAVE_ALL
152         /*
153          * Test to see if the exception was a software exception or caused by an
154          * external interrupt, and vector accordingly.
155          */
157         rdctl   r24,estatus
158         andi    r24,r24,1
159         beq     r24,r0,software_exception
160         rdctl   r12,ipending
161         beq     r12,r0,software_exception
163         movi    r24,-1
164         stw     r24,PT_ORIG_R2(sp)
165         
166         /* 
167          * Process an external hardware interrupt. 
168          */
170         addi    ea,ea,-4                /* re-issue the interrupted instruction */
171         stw     ea,PT_EA(sp)
172         rdctl   r9,ienable              /* Isolate possible interrupts */
173         and     r12,r12,r9
174         beq     r12,r0,ret_from_interrupt /* No one to service done */
175         movi    r4,%lo(-1)              /* Start from bit position 0, highest priority */
176                                         /* This is the IRQ # for handler call */
177 1:      addi    r4,r4,1
178         srl     r10,r12,r4
179         andi    r10,r10,1               /* Isolate bit we are interested in */
180         cmpeqi  r11,r4,32                 /* ? End of the register */
181         bne     r11,r0,ret_from_interrupt /* Y - out of here */
182         beq     r10,r0,1b
183         mov     r5,sp                   /* Setup pt_regs pointer for handler call */
184         PUSH    r4                      /* Save state for return */
185         PUSH    r12
186         call    process_int
187         POP     r12
188         POP     r4
189         br      1b                      /* Check for other interrupts while here */
191 ENTRY(ret_from_interrupt)
192         ldw     r4,PT_STATUS_EXTENSION(sp)
193         TSTBZ   r4,r4,PS_S_ASM,Luser_return     // Returning to user
195 #ifdef CONFIG_PREEMPT
196         GET_THREAD_INFO r1
197         ldw     r4,TI_PREEMPT_COUNT(r1)
198         bne     r4,r0,restore_all
200 need_resched:
201         ldw     r4,TI_FLAGS(r1)         // ? Need resched set
202         BTBZ    r10,r4,TIF_NEED_RESCHED_ASM,restore_all
203         ldw     r4,PT_ESTATUS(sp)       // ? Interrupts off
204         BTBZ    r10,r4,NIOS2_STATUS_PIE_OFST_ASM,restore_all
205         movia   r4,PREEMPT_ACTIVE_ASM
206         stw     r4,TI_PREEMPT_COUNT(r1)
207         rdctl   r10,status              /* enable intrs again */
208         ori     r10,r10,0x0001
209         wrctl   status,r10
210         PUSH    r1
211         call    schedule
212         POP     r1
213         mov     r4,r0
214         stw     r4,TI_PREEMPT_COUNT(r1)
215         rdctl   r10,status              /* disable intrs */
216         andi    r10,r10,0xfffe
217         wrctl   status, r10
218         br      need_resched
219 #else
220         br      restore_all
221 #endif
225  * Beware - when entering resume, prev (the current task) is
226  * in r4, next (the new task) is in r5, don't change these
227  * registers.
228  */
229 ENTRY(resume)
231         rdctl   r7,status                       /* save thread status reg */
232         stw     r7,TASK_THREAD+THREAD_KPSR(r4)  
234         andi    r7,r7,0x0fffe                   /* disable interrupts */
235         wrctl   status,r7
237         movia   r8,status_extension             /* save status extension */
238         ldw     r7,0(r8)
239         stw     r7,TASK_THREAD+THREAD_KESR(r4)
241         SAVE_SWITCH_STACK
242         stw     sp,TASK_THREAD+THREAD_KSP(r4)   /* save kernel stack pointer */
243         ldw     sp,TASK_THREAD+THREAD_KSP(r5)   /* restore new thread stack */
244         movia   r24,_current_thread             /* save thread */
245         GET_THREAD_INFO r1
246         stw     r1,0(r24)
247         RESTORE_SWITCH_STACK
248         
249         ldw     r7,TASK_THREAD+THREAD_KESR(r5)  /* restore extended status reg */
250         stw     r7,0(r8)
252         ldw     r7,TASK_THREAD+THREAD_KPSR(r5)  /* restore thread status reg */
253         wrctl   status,r7
254         ret
256 ENTRY(ret_from_fork)
257         call    schedule_tail
258         br      ret_from_exception
260 ENTRY(sys_fork)
261         mov     r4,sp
262         SAVE_SWITCH_STACK
263         call    nios2_vfork
264         RESTORE_SWITCH_STACK
265         ret
267 ENTRY(sys_vfork)
268         mov     r4,sp
269         SAVE_SWITCH_STACK
270         call    nios2_vfork
271         RESTORE_SWITCH_STACK
272         ret
274 ENTRY(sys_execve)
275         mov     r4,sp
276         SAVE_SWITCH_STACK
277         call    nios2_execve
278         RESTORE_SWITCH_STACK
279         ret
281 ENTRY(sys_clone)
282         mov     r4,sp
283         SAVE_SWITCH_STACK
284         call    nios2_clone
285         RESTORE_SWITCH_STACK
286         ret
288 ENTRY(sys_sigsuspend)
289         mov     r4,sp
290         SAVE_SWITCH_STACK
291         call    do_sigsuspend
292         RESTORE_SWITCH_STACK
293         ret
295 ENTRY(sys_rt_sigsuspend)
296         mov     r4,sp
297         SAVE_SWITCH_STACK
298         call    do_rt_sigsuspend
299         RESTORE_SWITCH_STACK
300         ret
302 ENTRY(sys_sigreturn)
303         mov     r4,sp
304         SAVE_SWITCH_STACK
305         call    do_sigreturn
306         RESTORE_SWITCH_STACK
307         ret
309 ENTRY(sys_sigaltstack)
310         ldw     r4,PT_R4(sp)
311         ldw     r5,PT_R5(sp)
312         ldw     r6,PT_SP(sp)
313         SAVE_SWITCH_STACK
314         call    do_sigaltstack
315         RESTORE_SWITCH_STACK
316         ret
318 ENTRY(sys_rt_sigreturn)
319         SAVE_SWITCH_STACK
320         call    do_rt_sigreturn
321         RESTORE_SWITCH_STACK
322         ret
324 /******************************************************************************
325 *                                                                             *
326 * License Agreement                                                           *
327 *                                                                             *
328 * Copyright (c) 2003 Altera Corporation, San Jose, California, USA.           *
329 * All rights reserved.                                                        *
330 *                                                                             *
331 * Permission is hereby granted, free of charge, to any person obtaining a     *
332 * copy of this software and associated documentation files (the "Software"),  *
333 * to deal in the Software without restriction, including without limitation   *
334 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
335 * and/or sell copies of the Software, and to permit persons to whom the       *
336 * Software is furnished to do so, subject to the following conditions:        *
337 *                                                                             *
338 * The above copyright notice and this permission notice shall be included in  *
339 * all copies or substantial portions of the Software.                         *
340 *                                                                             *
341 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
342 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
343 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
344 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
345 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
346 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
347 * DEALINGS IN THE SOFTWARE.                                                   *
348 *                                                                             *
349 * This agreement shall be governed in all respects by the laws of the State   *
350 * of California and by the laws of the United States of America.              *
351 *                                                                             *
352 ******************************************************************************/
354     /*
355      * This is the software exception handler for Nios2.
356      */ 
358      /*
359       * Explicitly allow the use of r1 (the assembler temporary register)
360       * within this code. This register is normally reserved for the use of
361       * the compiler.
362       */
364 ENTRY(instruction_trap)
365         RESTORE_ALL     // Clean off our save & setup for emulation
366         
367     /* INSTRUCTION EMULATION
368     *  ---------------------
369     *
370     * Nios II processors generate exceptions for unimplemented instructions.
371     * The routines below emulate these instructions.  Depending on the
372     * processor core, the only instructions that might need to be emulated
373     * are div, divu, mul, muli, mulxss, mulxsu, and mulxuu.
374     *
375     * The emulations match the instructions, except for the following
376     * limitations:
377     *
378     * 1) The emulation routines do not emulate the use of the exception
379     *    temporary register (et) as a source operand because the exception
380     *    handler already has modified it.
381     *
382     * 2) The routines do not emulate the use of the stack pointer (sp) or the
383     *    exception return address register (ea) as a destination because
384     *    modifying these registers crashes the exception handler or the
385     *    interrupted routine.
386     *
387     * Detailed Design
388     * ---------------
389     *
390     * The emulation routines expect the contents of integer registers r0-r31
391     * to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp).  The
392     * routines retrieve source operands from the stack and modify the
393     * destination register's value on the stack prior to the end of the
394     * exception handler.  Then all registers except the destination register
395     * are restored to their previous values.
396     *
397     * The instruction that causes the exception is found at address -4(ea).
398     * The instruction's OP and OPX fields identify the operation to be
399     * performed.
400     *
401     * One instruction, muli, is an I-type instruction that is identified by
402     * an OP field of 0x24.
403     *
404     * muli   AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24-
405     *           27    22                6      0    <-- LSB of field
406     *
407     * The remaining emulated instructions are R-type and have an OP field
408     * of 0x3a.  Their OPX fields identify them.
409     *
410     * R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a-
411     *           27    22    17     11     6      0  <-- LSB of field
412     * 
413     * 
414     * Opcode Encoding.  muli is identified by its OP value.  Then OPX & 0x02
415     * is used to differentiate between the division opcodes and the remaining
416     * multiplication opcodes.
417     *
418     * Instruction   OP      OPX    OPX & 0x02
419     * -----------   ----    ----   ----------
420     * muli          0x24
421     * divu          0x3a    0x24         0
422     * div           0x3a    0x25         0
423     * mul           0x3a    0x27      != 0
424     * mulxuu        0x3a    0x07      != 0
425     * mulxsu        0x3a    0x17      != 0
426     * mulxss        0x3a    0x1f      != 0
427     */
430     /*
431     * Save everything on the stack to make it easy for the emulation routines
432     * to retrieve the source register operands.
433     */
435     addi sp, sp, -128
436     stw zero,  0(sp)    // Save zero on stack to avoid special case for r0.
437     stw r1,    4(sp)
438     stw r2,    8(sp)
439     stw r3,   12(sp)
440     stw r4,   16(sp)
441     stw r5,   20(sp)
442     stw r6,   24(sp)
443     stw r7,   28(sp)
444     stw r8,   32(sp)
445     stw r9,   36(sp)
446     stw r10,  40(sp)
447     stw r11,  44(sp)
448     stw r12,  48(sp)
449     stw r13,  52(sp)
450     stw r14,  56(sp)
451     stw r15,  60(sp)
452     stw r16,  64(sp)
453     stw r17,  68(sp)
454     stw r18,  72(sp)
455     stw r19,  76(sp)
456     stw r20,  80(sp)
457     stw r21,  84(sp)
458     stw r22,  88(sp)
459     stw r23,  92(sp)
460                         // Don't bother to save et.  It's already been changed.
461     stw bt,  100(sp)
462     stw gp,  104(sp)
463     stw sp,  108(sp)
464     stw fp,  112(sp)
465                         // Don't bother to save ea.  It's already been changed.
466     stw ba,  120(sp)
467     stw ra,  124(sp)
470     /*
471     * Split the instruction into its fields.  We need 4*A, 4*B, and 4*C as
472     * offsets to the stack pointer for access to the stored register values.
473     */
474     ldw r2,-4(ea)       // r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP
475     roli r3,r2,7        // r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB
476     roli r4,r3,3        // r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB
477     roli r5,r4,2        // r5 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II
478     srai r4,r4,16       // r4 = (sign-extended) IMM16
479     roli r6,r5,5        // r6 = XXXX,NNNNN,PPPPPP,AAAAA,BBBBB,CCCCC,XX
480     andi r2,r2,0x3f     // r2 = 00000000000000000000000000,PPPPPP
481     andi r3,r3,0x7c     // r3 = 0000000000000000000000000,AAAAA,00
482     andi r5,r5,0x7c     // r5 = 0000000000000000000000000,BBBBB,00
483     andi r6,r6,0x7c     // r6 = 0000000000000000000000000,CCCCC,00
485     /* Now
486     * r2 = OP
487     * r3 = 4*A
488     * r4 = IMM16 (sign extended)
489     * r5 = 4*B
490     * r6 = 4*C
491     */
494     /*
495     * Get the operands.
496     *
497     * It is necessary to check for muli because it uses an I-type instruction
498     * format, while the other instructions are have an R-type format.
499     *
500     *  Prepare for either multiplication or division loop.
501     *  They both loop 32 times.
502     */
503     movi r14,32
505     add  r3,r3,sp       // r3 = address of A-operand.
506     ldw  r3,0(r3)       // r3 = A-operand.
507     movi r7,0x24        // muli opcode (I-type instruction format)
508     beq r2,r7,mul_immed // muli doesn't use the B register as a source
510     add  r5,r5,sp       // r5 = address of B-operand.
511     ldw  r5,0(r5)       // r5 = B-operand.
512                         // r4 = SSSSSSSSSSSSSSSS,-----IMM16------
513                         // IMM16 not needed, align OPX portion
514                         // r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000
515     srli r4,r4,5        // r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX--
516     andi r4,r4,0x3f     // r4 = 00000000000000000000000000,-OPX--
518     /* Now
519     * r2 = OP
520     * r3 = src1
521     * r5 = src2
522     * r4 = OPX (no longer can be muli)
523     * r6 = 4*C
524     */
528     /*
529     *  Multiply or Divide?
530     */
531     andi r7,r4,0x02    // For R-type multiply instructions, OPX & 0x02 != 0
532     bne r7,zero,multiply
535     /* DIVISION
536     *
537     * Divide an unsigned dividend by an unsigned divisor using
538     * a shift-and-subtract algorithm.  The example below shows
539     * 43 div 7 = 6 for 8-bit integers.  This classic algorithm uses a
540     * single register to store both the dividend and the quotient,
541     * allowing both values to be shifted with a single instruction.
542     *
543     *                               remainder dividend:quotient
544     *                               --------- -----------------
545     *   initialize                   00000000     00101011:
546     *   shift                        00000000     0101011:_
547     *   remainder >= divisor? no     00000000     0101011:0
548     *   shift                        00000000     101011:0_
549     *   remainder >= divisor? no     00000000     101011:00
550     *   shift                        00000001     01011:00_
551     *   remainder >= divisor? no     00000001     01011:000
552     *   shift                        00000010     1011:000_
553     *   remainder >= divisor? no     00000010     1011:0000
554     *   shift                        00000101     011:0000_
555     *   remainder >= divisor? no     00000101     011:00000
556     *   shift                        00001010     11:00000_
557     *   remainder >= divisor? yes    00001010     11:000001
558     *       remainder -= divisor   - 00000111
559     *                              ----------
560     *                                00000011     11:000001
561     *   shift                        00000111     1:000001_
562     *   remainder >= divisor? yes    00000111     1:0000011
563     *       remainder -= divisor   - 00000111
564     *                              ----------
565     *                                00000000     1:0000011
566     *   shift                        00000001     :0000011_
567     *   remainder >= divisor? no     00000001     :00000110
568     *
569     * The quotient is 00000110.
570     */
572 divide:
573     /*
574     *  Prepare for division by assuming the result
575     *  is unsigned, and storing its "sign" as 0.
576     */
577     movi r17,0
580     // Which division opcode?
581     xori r7,r4,0x25         // OPX of div
582     bne r7,zero,unsigned_division
585     /*
586     *  OPX is div.  Determine and store the sign of the quotient.
587     *  Then take the absolute value of both operands.
588     */
589     xor r17,r3,r5       // MSB contains sign of quotient
590     bge r3,zero,dividend_is_nonnegative
591     sub r3,zero,r3      // -r3
592 dividend_is_nonnegative:
593     bge r5,zero,divisor_is_nonnegative
594     sub r5,zero,r5      // -r5
595 divisor_is_nonnegative:
598 unsigned_division:
599     // Initialize the unsigned-division loop.
600     movi r13,0          // remainder = 0
602     /* Now
603     * r3 = dividend : quotient
604     * r4 = 0x25 for div, 0x24 for divu
605     * r5 = divisor
606     * r13 = remainder
607     * r14 = loop counter (already initialized to 32)
608     * r17 = MSB contains sign of quotient
609     */
612     /*
613     *   for (count = 32; count > 0; --count)
614     *   {
615     */
616 divide_loop:
618     /*
619     *       Division:
620     *
621     *       (remainder:dividend:quotient) <<= 1;
622     */
623     slli r13,r13,1
624     cmplt r7,r3,zero        // r7 = MSB of r3
625     or r13,r13,r7
626     slli r3,r3,1
629     /*
630     *       if (remainder >= divisor)
631     *       {
632     *           set LSB of quotient
633     *           remainder -= divisor;
634     *       }
635     */
636     bltu r13,r5,div_skip
637     ori r3,r3,1
638     sub r13,r13,r5
639 div_skip:
641     /*
642     *   }
643     */
644     subi r14,r14,1
645     bne r14,zero,divide_loop
648     /* Now
649     * r3 = quotient
650     * r4 = 0x25 for div, 0x24 for divu
651     * r6 = 4*C
652     * r17 = MSB contains sign of quotient
653     */
655     
656     /*
657     *  Conditionally negate signed quotient.  If quotient is unsigned,
658     *  the sign already is initialized to 0.
659     */
660     bge r17,zero,quotient_is_nonnegative
661     sub r3,zero,r3      // -r3
662 quotient_is_nonnegative:
665     /*
666     *  Final quotient is in r3.
667     */
668     add r6,r6,sp
669     stw r3,0(r6)           // write quotient to stack
670     br restore_registers
675     /* MULTIPLICATION
676     *
677     * A "product" is the number that one gets by summing a "multiplicand"
678     * several times.  The "multiplier" specifies the number of copies of the
679     * multiplicand that are summed.
680     *
681     * Actual multiplication algorithms don't use repeated addition, however.
682     * Shift-and-add algorithms get the same answer as repeated addition, and
683     * they are faster.  To compute the lower half of a product (pppp below)
684     * one shifts the product left before adding in each of the partial products
685     * (a * mmmm) through (d * mmmm).
686     *
687     * To compute the upper half of a product (PPPP below), one adds in the
688     * partial products (d * mmmm) through (a * mmmm), each time following the
689     * add by a right shift of the product.
690     *
691     *     mmmm
692     *   * abcd
693     *   ------
694     *     ####  = d * mmmm
695     *    ####   = c * mmmm
696     *   ####    = b * mmmm
697     *  ####     = a * mmmm
698     * --------
699     * PPPPpppp
700     *
701     * The example above shows 4 partial products.  Computing actual Nios II
702     * products requires 32 partials.
703     *
704     * It is possible to compute the result of mulxsu from the result of mulxuu
705     * because the only difference between the results of these two opcodes is
706     * the value of the partial product associated with the sign bit of rA.
707     *
708     *   mulxsu = mulxuu - (rA < 0) ? rB : 0;
709     *
710     * It is possible to compute the result of mulxss from the result of mulxsu
711     * because the only difference between the results of these two opcodes is
712     * the value of the partial product associated with the sign bit of rB.
713     *
714     *   mulxss = mulxsu - (rB < 0) ? rA : 0;
715     *
716     */
718 mul_immed:
719     // Opcode is muli.  Change it into mul for remainder of algorithm.
720     mov r6,r5              // Field B is dest register, not field C.
721     mov r5,r4              // Field IMM16 is src2, not field B.
722     movi r4,0x27           // OPX of mul is 0x27
724 multiply:
725     // Initialize the multiplication loop.
726     movi r9,0           // mul_product    = 0
727     movi r10,0          // mulxuu_product = 0
728     mov r11,r5          // save original multiplier for mulxsu and mulxss
729     mov r12,r5          // mulxuu_multiplier (will be shifted)
730     movi r16,1          // used to create "rori B,A,1" from "ror B,A,r16"
732     /* Now
733     * r3 = multiplicand
734     * r5 = mul_multiplier
735     * r6 = 4 * dest_register (used later as offset to sp)
736     * r7 = temp
737     * r9 = mul_product
738     * r10 = mulxuu_product
739     * r11 = original multiplier
740     * r12 = mulxuu_multiplier
741     * r14 = loop counter (already initialized)
742     * r16 = 1
743     */
746     /*
747     *   for (count = 32; count > 0; --count)
748     *   {
749     */
750 multiply_loop:
752     /*
753     *       mul_product <<= 1;
754     *       lsb = multiplier & 1;
755     */
756     slli r9,r9,1
757     andi r7,r12,1
759     /*
760     *       if (lsb == 1)
761     *       {
762     *           mulxuu_product += multiplicand;
763     *       }
764     */
765     beq r7,zero,mulx_skip
766     add r10,r10,r3
767     cmpltu r7,r10,r3    // Save the carry from the MSB of mulxuu_product.
768     ror r7,r7,r16       // r7 = 0x80000000 on carry, or else 0x00000000
769 mulx_skip:
771     /*
772     *       if (MSB of mul_multiplier == 1)
773     *       {
774     *           mul_product += multiplicand;
775     *       }
776     */
777     bge r5,zero,mul_skip
778     add r9,r9,r3
779 mul_skip:
781     /*
782     *       mulxuu_product >>= 1;           logical shift
783     *       mul_multiplier <<= 1;           done with MSB
784     *       mulx_multiplier >>= 1;          done with LSB
785     */
786     srli r10,r10,1
787     or r10,r10,r7           // OR in the saved carry bit.
788     slli r5,r5,1
789     srli r12,r12,1
792     /*
793     *   }
794     */
795     subi r14,r14,1
796     bne r14,zero,multiply_loop
799     /*
800     *  Multiply emulation loop done.
801     */
803     /* Now
804     * r3 = multiplicand
805     * r4 = OPX
806     * r6 = 4 * dest_register (used later as offset to sp)
807     * r7 = temp
808     * r9 = mul_product
809     * r10 = mulxuu_product
810     * r11 = original multiplier
811     */
814     // Calculate address for result from 4 * dest_register
815     add r6,r6,sp
818     /*
819     *  Select/compute the result based on OPX.
820     */
823     // OPX == mul?  Then store.
824     xori r7,r4,0x27
825     beq r7,zero,store_product
827     // It's one of the mulx.. opcodes.  Move over the result.
828     mov r9,r10
830     // OPX == mulxuu?  Then store.
831     xori r7,r4,0x07
832     beq r7,zero,store_product
834     // Compute mulxsu
835     //
836     // mulxsu = mulxuu - (rA < 0) ? rB : 0;
837     //
838     bge r3,zero,mulxsu_skip
839     sub r9,r9,r11
840 mulxsu_skip:
842     // OPX == mulxsu?  Then store.
843     xori r7,r4,0x17
844     beq r7,zero,store_product
846     // Compute mulxss
847     //
848     // mulxss = mulxsu - (rB < 0) ? rA : 0;
849     //
850     bge r11,zero,mulxss_skip
851     sub r9,r9,r3
852 mulxss_skip:
853     // At this point, assume that OPX is mulxss, so store
856 store_product:
857     stw  r9,0(r6)
860 restore_registers:
861                         // No need to restore r0.
862     ldw r1,    4(sp)
863     ldw r2,    8(sp)
864     ldw r3,   12(sp)
865     ldw r4,   16(sp)
866     ldw r5,   20(sp)
867     ldw r6,   24(sp)
868     ldw r7,   28(sp)
869     ldw r8,   32(sp)
870     ldw r9,   36(sp)
871     ldw r10,  40(sp)
872     ldw r11,  44(sp)
873     ldw r12,  48(sp)
874     ldw r13,  52(sp)
875     ldw r14,  56(sp)
876     ldw r15,  60(sp)
877     ldw r16,  64(sp)
878     ldw r17,  68(sp)
879     ldw r18,  72(sp)
880     ldw r19,  76(sp)
881     ldw r20,  80(sp)
882     ldw r21,  84(sp)
883     ldw r22,  88(sp)
884     ldw r23,  92(sp)
885     ldw et,   96(sp)
886     ldw bt,  100(sp)
887     ldw gp,  104(sp)
888                         // Don't corrupt sp.
889     ldw fp,  112(sp)
890                         // Don't corrupt ea.
891     ldw ba,  120(sp)
892     ldw ra,  124(sp)
893     addi sp, sp, 128
894     eret
896 .set at
897 .set break