1/*        $NetBSD: bds_emul.S,v 1.10 2019/04/06 03:06:26 thorpej Exp $          */
2
3/*
4 * Copyright (c) 1992, 1993
5 *        The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *        @(#)fp.s  8.1 (Berkeley) 6/10/93
35 */
36
37#include <sys/cdefs.h>
38
39#include <mips/asm.h>
40#include <mips/trap.h>                            /* for T_RES_INST */
41#include <mips/cpuregs.h>
42
43#include "assym.h"
44
45/* insns are reordered in the way as MIPS architecture imposes */
46          .set      reorder
47
48#define   REG_REGMASK         (0x1f << REG_SCALESHIFT)
49
50/*
51 * Emulate CPU instruction in branch delay slot.
52 * These instructions are not implemented and causes SIGILL.
53 *  jump/branch
54 *  COP0
55 *  trap/syscall/break
56 *
57 * Args are same as mips_emul_fp, eg.
58 * void mips_emul_delayslot(uint32_t insn, struct trapframe *tf, uint32_t cause);
59 * It should be used to emulate an instruction in a branch delay slot.
60 */
61LEAF(mips_emul_branchdelayslot)
62          REG_PROLOGUE
63          REG_S     zero, TF_REG_ZERO(a1)                   # ensure zero has value 0
64          REG_EPILOGUE
65          move      t3, ra                                  # need to save this locally
66
67          srl       t0, a0, 26-PTR_SCALESHIFT
68          andi      t0, 0x3F << PTR_SCALESHIFT
69          PTR_L     t9, bcemul_optbl(t0)
70          jr        t9
71
72          .rdata
73bcemul_optbl:
74          PTR_WORD bcemul_special                           # 000 SPECIAL
75          PTR_WORD bcemul_sigill                            # 001 REGIMM
76          PTR_WORD bcemul_sigill                            # 002 J
77          PTR_WORD bcemul_sigill                            # 003 JAL
78          PTR_WORD bcemul_sigill                            # 004 BEQ
79          PTR_WORD bcemul_sigill                            # 005 BNE
80          PTR_WORD bcemul_sigill                            # 006 BLEZ
81          PTR_WORD bcemul_sigill                            # 007 BGTZ
82          PTR_WORD bcemul_addi                              # 010 ADDI
83          PTR_WORD bcemul_addiu                             # 011 ADDIU
84          PTR_WORD bcemul_slti                              # 012 SLTI
85          PTR_WORD bcemul_sltiu                             # 013 SLTIU
86          PTR_WORD bcemul_andi                              # 014 ANDI
87          PTR_WORD bcemul_ori                     # 015 ORI
88          PTR_WORD bcemul_xori                              # 016 XORI
89          PTR_WORD bcemul_lui                     # 017 LUI
90          PTR_WORD bcemul_sigill                            # 020 COP0
91          PTR_WORD _C_LABEL(mips_emul_fp)                   # 021 COP1
92          PTR_WORD bcemul_sigill                            # 022 COP2
93          PTR_WORD bcemul_sigill                            # 023 COP1X
94          PTR_WORD bcemul_sigill                            # 024 BEQL
95          PTR_WORD bcemul_sigill                            # 025 BNEL
96          PTR_WORD bcemul_sigill                            # 026 BNEZL
97          PTR_WORD bcemul_sigill                            # 027 BGTZL
98#ifdef __mips_o32
99          PTR_WORD bcemul_sigill                            # 030 DADDI (*)
100          PTR_WORD bcemul_sigill                            # 031 DADDIU (*)
101          PTR_WORD bcemul_sigill                            # 030 LDL (*)
102          PTR_WORD bcemul_sigill                            # 031 LDR (*)
103#else
104          PTR_WORD bcemul_daddi                             # 030 DADDI (*)
105          PTR_WORD bcemul_daddiu                            # 031 DADDIU (*)
106          PTR_WORD _C_LABEL(mips_emul_ldl)        # 032 LDL (*)
107          PTR_WORD _C_LABEL(mips_emul_ldr)        # 033 LDR (*)
108#endif
109          PTR_WORD bcemul_sigill                            # 034 SPECIAL2
110          PTR_WORD bcemul_sigill                            # 035 JALX
111          PTR_WORD bcemul_sigill                            # 036 MDMX
112          PTR_WORD bcemul_sigill                            # 037 SPECIAL3
113          PTR_WORD _C_LABEL(mips_emul_lb)                   # 040 LB
114          PTR_WORD _C_LABEL(mips_emul_lh)                   # 041 LH
115          PTR_WORD _C_LABEL(mips_emul_lwl)        # 042 LWL
116          PTR_WORD _C_LABEL(mips_emul_lw)                   # 043 LW
117          PTR_WORD _C_LABEL(mips_emul_lbu)        # 044 LBU
118          PTR_WORD _C_LABEL(mips_emul_lhu)        # 045 LHU
119          PTR_WORD _C_LABEL(mips_emul_lwr)        # 046 LWR
120#ifdef __mips_o32
121          PTR_WORD bcemul_sigill                            # 047 LWU (*)
122#else
123          PTR_WORD _C_LABEL(mips_emul_lwu)        # 047 LWU (*)
124#endif
125          PTR_WORD _C_LABEL(mips_emul_sb)                   # 050 SB
126          PTR_WORD _C_LABEL(mips_emul_sh)                   # 051 SH
127          PTR_WORD _C_LABEL(mips_emul_swl)        # 052 SWL
128          PTR_WORD _C_LABEL(mips_emul_sw)                   # 053 SW
129#ifdef __mips_o32
130          PTR_WORD bcemul_sigill                            # 054 SDL (*)
131          PTR_WORD bcemul_sigill                            # 055 SDR (*)
132#else
133          PTR_WORD _C_LABEL(mips_emul_sdl)        # 054 SDL (*)
134          PTR_WORD _C_LABEL(mips_emul_sdr)        # 055 SDR (*)
135#endif
136          PTR_WORD _C_LABEL(mips_emul_swr)        # 056 SWR
137          PTR_WORD bcemul_sigill                            # 057 CACHE
138          PTR_WORD bcemul_sigill                            # 060 LL
139          PTR_WORD _C_LABEL(mips_emul_lwc1)       # 061 LWC1
140          PTR_WORD bcemul_sigill                            # 062 LWC2
141          PTR_WORD bcemul_sigill                            # 063 PREF
142          PTR_WORD bcemul_sigill                            # 064 LLD (*)
143          PTR_WORD _C_LABEL(mips_emul_ldc1)       # 065 LDC
144          PTR_WORD bcemul_sigill                            # 066 LDC2
145#ifdef __mips_o32
146          PTR_WORD bcemul_sigill                            # 067 LD (*)
147#else
148          PTR_WORD _C_LABEL(mips_emul_ld)                   # 067 LD (*)
149#endif
150          PTR_WORD bcemul_sigill                            # 070 SC
151          PTR_WORD _C_LABEL(mips_emul_swc1)       # 071 SWC1
152          PTR_WORD bcemul_sigill                            # 072 SWC2
153          PTR_WORD bcemul_sigill                            # 073
154          PTR_WORD bcemul_sigill                            # 074 SCD (*)
155          PTR_WORD _C_LABEL(mips_emul_sdc1)       # 075 SDC1
156          PTR_WORD bcemul_sigill                            # 076 SDC2
157#ifdef __mips_o32
158          PTR_WORD bcemul_sigill                            # 077 SD (*)
159#else
160          PTR_WORD _C_LABEL(mips_emul_sd)                   # 077 SD (*)
161#endif
162
163          .text
164bcemul_immed_prologue:
165          srl       t1, a0, 21-REG_SCALESHIFT     # rs (source)
166          srl       t2, a0, 16-REG_SCALESHIFT     # rt (dest)
167          andi      t1, REG_REGMASK
168          andi      t2, REG_REGMASK
169          PTR_ADDU t1, a1
170          PTR_ADDU t2, a1
171          sll       v1, a0, 16
172          sra       v1, v1, 16                              # signed immed
173          REG_PROLOGUE
174          REG_L     v0, TF_REG_ZERO(t1)           # load source
175          REG_EPILOGUE
176          jr        ra                                      # execute the instruction
177
178bcemul_uimmed_prologue:
179          srl       t1, a0, 21-REG_SCALESHIFT     # rs (source)
180          srl       t2, a0, 16-REG_SCALESHIFT     # rt (dest)
181          andi      t1, REG_REGMASK
182          andi      t2, REG_REGMASK
183          PTR_ADDU t1, a1
184          PTR_ADDU t2, a1
185          andi      v1, a0, 0xffff                          # unsigned immed
186          REG_PROLOGUE
187          REG_L     v0, TF_REG_ZERO(t1)           # load source
188          REG_EPILOGUE
189          jr        ra
190
191#ifndef __mips_o32
192bcemul_daddi:
193          bal       bcemul_immed_prologue
194          dadd      t0, v0, v1
195          b         bcemul_check_add_overflow
196#endif
197
198bcemul_addi:
199          bal       bcemul_immed_prologue
200          addu      t0, v0, v1
201
202bcemul_check_add_overflow:
203          move      ta0, t0             # result
204          move      ta1, v0             # addend 1
205          move      ta2, v1             # addend 2
206
207bcemul_check_overflow:
208          /* Overflow check */
209          xor       ta2, ta1  /* negative + positive can't overflow */
210          bltz      ta2, bcemul_store_and_done
211
212          /* must have added two positive or two negative numbers */
213          xor       ta1, ta0  /* result have same signedness as source? */
214          bgez      ta1, bcemul_store_and_done /* yes, then we didn't overflow */
215
216          b         bcemul_sigill
217
218bcemul_addiu:
219          bal       bcemul_immed_prologue
220          addu      t0, v0, v1
221          b         bcemul_store_and_done
222
223#ifndef __mips_o32
224bcemul_daddiu:
225          bal       bcemul_immed_prologue
226          daddu     t0, v0, v1
227          b         bcemul_store_and_done
228#endif
229
230bcemul_slti:
231          bal       bcemul_immed_prologue
232          slt       t0, v0, v1
233          b         bcemul_store_and_done
234
235bcemul_sltiu:
236          bal       bcemul_immed_prologue
237          sltu      t0, v0, v1
238          b         bcemul_store_and_done
239
240bcemul_andi:
241          bal       bcemul_uimmed_prologue
242          and       t0, v0, v1
243          b         bcemul_store_and_done
244
245bcemul_ori:
246          bal       bcemul_uimmed_prologue
247          or        t0, v0, v1
248          b         bcemul_store_and_done
249
250bcemul_xori:
251          bal       bcemul_uimmed_prologue
252          xor       t0, v0, v1
253          b         bcemul_store_and_done
254
255bcemul_lui:
256          srl       t2, a0, 16-REG_SCALESHIFT     # rt
257          andi      t2, REG_REGMASK
258          PTR_ADDU t2, a1
259          sll       t0, a0, 16
260          b         bcemul_store_and_done
261
262          .rdata
263bcemul_specialtbl:
264          PTR_WORD bcemul_special_genshift        # 000 SLL
265          PTR_WORD bcemul_sigill                            # 001 MOVC1
266          PTR_WORD bcemul_special_genshift        # 002 SRL
267          PTR_WORD bcemul_special_genshift        # 003 SRA
268          PTR_WORD bcemul_special_genshiftv       # 004 SLLV
269          PTR_WORD bcemul_sigill                            # 005
270          PTR_WORD bcemul_special_genshiftv       # 006 SRLV
271          PTR_WORD bcemul_special_genshiftv       # 007 SRAV
272          PTR_WORD bcemul_sigill                            # 010 JR
273          PTR_WORD bcemul_sigill                            # 011 JALR
274          PTR_WORD bcemul_sigill                            # 012 MOVZ
275          PTR_WORD bcemul_sigill                            # 013 MOVN
276          PTR_WORD bcemul_sigill                            # 014 SYSCALL
277          PTR_WORD bcemul_sigill                            # 015 BREAK
278          PTR_WORD bcemul_sigill                            # 016
279          PTR_WORD bcemul_special_sync            # 017 SYNC
280          PTR_WORD bcemul_special_mfhilo                    # 020 MFHI
281          PTR_WORD bcemul_special_mthilo                    # 021 MTHI
282          PTR_WORD bcemul_special_mfhilo                    # 022 MFLO
283          PTR_WORD bcemul_special_mthilo                    # 023 MTLO
284#ifdef __mips_o32
285          PTR_WORD bcemul_sigill                            # 024 DSLLV (*)
286          PTR_WORD bcemul_sigill                            # 025
287          PTR_WORD bcemul_sigill                            # 026 DSRLV (*)
288          PTR_WORD bcemul_sigill                            # 027 DSRAV (*)
289#else
290          PTR_WORD bcemul_special_genshiftv       # 024 DSLLV (*)
291          PTR_WORD bcemul_sigill                            # 025
292          PTR_WORD bcemul_special_genshiftv       # 026 DSRLV (*)
293          PTR_WORD bcemul_special_genshiftv       # 027 DSRAV (*)
294#endif
295          PTR_WORD bcemul_special_genmultdiv      # 030 MULT
296          PTR_WORD bcemul_special_genmultdiv      # 031 MULTU
297          PTR_WORD bcemul_special_genmultdiv      # 032 DIV
298          PTR_WORD bcemul_special_genmultdiv      # 033 DIVU
299#ifdef __mips_o32
300          PTR_WORD bcemul_sigill                            # 034 DMULT (*)
301          PTR_WORD bcemul_sigill                            # 035 DMULTU (*)
302          PTR_WORD bcemul_sigill                            # 036 DDIV (*)
303          PTR_WORD bcemul_sigill                            # 037 DDIVU (*)
304#else
305          PTR_WORD bcemul_special_genmultdiv      # 034 DMULT (*)
306          PTR_WORD bcemul_special_genmultdiv      # 035 DMULTU (*)
307          PTR_WORD bcemul_special_genmultdiv      # 036 DDIV (*)
308          PTR_WORD bcemul_special_genmultdiv      # 037 DDIVU (*)
309#endif
310          PTR_WORD bcemul_special_genadd                    # 040 ADD
311          PTR_WORD bcemul_special_gen3op                    # 041 ADDU
312          PTR_WORD bcemul_special_gensub                    # 042 SUB
313          PTR_WORD bcemul_special_gen3op                    # 043 SUBU
314          PTR_WORD bcemul_special_gen3op                    # 044 AND
315          PTR_WORD bcemul_special_gen3op                    # 045 OR
316          PTR_WORD bcemul_special_gen3op                    # 046 XOR
317          PTR_WORD bcemul_special_gen3op                    # 047 NOR
318          PTR_WORD bcemul_sigill                            # 050
319          PTR_WORD bcemul_sigill                            # 051
320          PTR_WORD bcemul_special_gen3op                    # 052 SLT
321          PTR_WORD bcemul_special_gen3op                    # 053 SLTU
322#ifdef __mips_o32
323          PTR_WORD bcemul_sigill                            # 054 DADD (*)
324          PTR_WORD bcemul_sigill                            # 055 DADDU (*)
325          PTR_WORD bcemul_sigill                            # 056 DSUB (*)
326          PTR_WORD bcemul_sigill                            # 057 DSUBU (*)
327#else
328          PTR_WORD bcemul_special_genadd                    # 054 DADD (*)
329          PTR_WORD bcemul_special_gen3op                    # 055 DADDU (*)
330          PTR_WORD bcemul_special_gensub                    # 056 DSUB (*)
331          PTR_WORD bcemul_special_gen3op                    # 057 DSUBU (*)
332#endif
333          PTR_WORD bcemul_sigill                            # 060 TGE
334          PTR_WORD bcemul_sigill                            # 061 TGEU
335          PTR_WORD bcemul_sigill                            # 062 TLT
336          PTR_WORD bcemul_sigill                            # 063 TLTU
337          PTR_WORD bcemul_sigill                            # 064 TEQ
338          PTR_WORD bcemul_sigill                            # 065
339          PTR_WORD bcemul_sigill                            # 066 TNE
340          PTR_WORD bcemul_sigill                            # 067
341#ifdef __mips_o32
342          PTR_WORD bcemul_sigill                            # 070 DSLL (*)
343          PTR_WORD bcemul_sigill                            # 071
344          PTR_WORD bcemul_sigill                            # 072 DSRL (*)
345          PTR_WORD bcemul_sigill                            # 073 DSRA (*)
346          PTR_WORD bcemul_sigill                            # 074 DSLL32 (*)
347          PTR_WORD bcemul_sigill                            # 075
348          PTR_WORD bcemul_sigill                            # 076 DSRL32 (*)
349          PTR_WORD bcemul_sigill                            # 077 DSRA32 (*)
350#else
351          PTR_WORD bcemul_special_genshift        # 070 DSLL (*)
352          PTR_WORD bcemul_sigill                            # 071
353          PTR_WORD bcemul_special_genshift        # 072 DSRL (*)
354          PTR_WORD bcemul_special_genshift        # 073 DSRA (*)
355          PTR_WORD bcemul_special_genshift        # 074 DSLL32 (*)
356          PTR_WORD bcemul_sigill                            # 075
357          PTR_WORD bcemul_special_genshift        # 076 DSRL32 (*)
358          PTR_WORD bcemul_special_genshift        # 077 DSRA32 (*)
359#endif
360
361          .text
362          .set push
363          .set noreorder
364          .set nomacro
365          .set mips64
366bcemul_special_op:
367          jr        ra;       sllv      t0, v0, v1          # 000 SLL
368          jr        ra;       nop                           # 001 MOVC1
369          jr        ra;       srlv      t0, v0, v1          # 002 SRL
370          jr        ra;       srav      t0, v0, v1          # 003 SRA
371          jr        ra;       sllv      t0, v0, v1          # 004 SLLV
372          jr        ra;       nop                           # 005 *
373          jr        ra;       srlv      t0, v0, v1          # 006 SRLV
374          jr        ra;       srav      t0, v0, v1          # 007 SRAV
375
376          jr        ra;       nop                           # 010 JR
377          jr        ra;       nop                           # 011 JALR
378          jr        ra;       movz      t0, v0, v1          # 012 MOVZ
379          jr        ra;       movn      t0, v0, v1          # 013 MOVN
380          jr        ra;       nop                           # 014 SYSCALL
381          jr        ra;       nop                           # 015 BREAK
382          jr        ra;       nop                           # 016 *
383          jr        ra;       nop                           # 017 SYNC
384
385          jr        ra;       mfhi      t0                  # 020 MFHI
386          jr        ra;       mthi      v0                  # 021 MTHI
387          jr        ra;       mflo      t0                  # 022 MFLO
388          jr        ra;       mtlo      v0                  # 023 MTLO
389          jr        ra;       dsllv     t0, v0, v1          # 024 DSLLV
390          jr        ra;       nop                           # 025 *
391          jr        ra;       dsrlv     t0, v0, v1          # 026 DSRLV
392          jr        ra;       dsrav     t0, v0, v1          # 027 DSRAV
393
394          jr        ra;       mult      v0, v1              # 030 MULT
395          jr        ra;       multu     v0, v1              # 031 MULTU
396          jr        ra;       div       $0, v0, v1          # 032 DIV
397          jr        ra;       divu      $0, v0, v1          # 033 DIVU
398          jr        ra;       dmult     v0, v1              # 034 DMULT
399          jr        ra;       dmultu    v0, v1              # 035 DMULTU
400          jr        ra;       ddiv      $0, v0, v1          # 036 DDIV
401          jr        ra;       ddivu     $0, v0, v1          # 037 DDIVU
402
403          jr        ra;       add       t0, v0, v1          # 040 ADD
404          jr        ra;       addu      t0, v0, v1          # 041 ADDU
405          jr        ra;       sub       t0, v0, v1          # 042 SUB
406          jr        ra;       subu      t0, v0, v1          # 043 SUBU
407          jr        ra;       and       t0, v0, v1          # 044 AND
408          jr        ra;       or        t0, v0, v1          # 045 OR
409          jr        ra;       xor       t0, v0, v1          # 046 XOR
410          jr        ra;       nor       t0, v0, v1          # 047 NOR
411
412          jr        ra;       nop                           # 050 *
413          jr        ra;       nop                           # 051 *
414          jr        ra;       slt       t0, v0, v1          # 052 SLT
415          jr        ra;       sltu      t0, v0, v1          # 053 SLTU
416          jr        ra;       dadd      t0, v0, v1          # 054 DADD
417          jr        ra;       daddu     t0, v0, v1          # 055 DADDU
418          jr        ra;       dsub      t0, v0, v1          # 056 DSUB
419          jr        ra;       dsubu     t0, v0, v1          # 057 DSUBU
420
421          jr        ra;       tge       v0, v1              # 060 TGE
422          jr        ra;       tgeu      v0, v1              # 061 TGEU
423          jr        ra;       tlt       v0, v1              # 062 TLT
424          jr        ra;       tltu      v0, v1              # 063 TLTU
425          jr        ra;       teq       v0, v1              # 064 TEQ
426          jr        ra;       nop                           # 065 *
427          jr        ra;       tne       v0, v1              # 066 TNE
428          jr        ra;       nop                           # 067 *
429
430          jr        ra;       dsllv     t0, v0, v1          # 070 DSLL
431          jr        ra;       nop                           # 071 *
432          jr        ra;       dsrlv     t0, v0, v1          # 072 DSRL
433          jr        ra;       dsrav     t0, v0, v1          # 073 DSRA
434          jr        ra;       dsllv     t0, v0, v1          # 074 DSLL32
435          jr        ra;       nop                           # 075 *
436          jr        ra;       dsrlv     t0, v0, v1          # 076 DSRL32
437          jr        ra;       dsrav     t0, v0, v1          # 077 DSRA32
438          .set pop
439
440bcemul_special:
441          andi      t0, a0, 0x3f                            # get special code
442          sll       t1, t0, 3                     # calculate index in specialop
443          sll       t0, PTR_SCALESHIFT
444          PTR_L     t9, bcemul_specialtbl(t0)
445          PTR_LA    t0, bcemul_special_op(t1)
446          jr        t9
447
448bcemul_special_3op_prologue:
449          move      t9, t0
450          srl       t0, a0, 21-REG_SCALESHIFT     # rs (source1)
451          srl       t1, a0, 16-REG_SCALESHIFT     # rt (source2)
452          srl       t2, a0, 11-REG_SCALESHIFT     # rd (dest)
453          andi      t0, REG_REGMASK
454          andi      t1, REG_REGMASK
455          andi      t2, REG_REGMASK
456          PTR_ADDU t0, a1
457          PTR_ADDU t1, a1
458          PTR_ADDU t2, a1
459          REG_PROLOGUE
460          REG_L     v0, TF_REG_ZERO(t0)           # load source1
461          REG_L     v1, TF_REG_ZERO(t1)           # load source2
462          REG_EPILOGUE
463          jr        t9
464
465bcemul_special_2src_prologue:
466          move      t9, t0
467          srl       t0, a0, 21-REG_SCALESHIFT     # rs (source1)
468          srl       t1, a0, 16-REG_SCALESHIFT     # rt (source2)
469          andi      t0, REG_REGMASK
470          andi      t1, REG_REGMASK
471          PTR_ADDU t0, a1
472          PTR_ADDU t1, a1
473          REG_PROLOGUE
474          REG_L     v0, TF_REG_ZERO(t0)           # load source1
475          REG_L     v1, TF_REG_ZERO(t1)           # load source2
476          REG_EPILOGUE
477          jr        t9
478
479bcemul_special_genshift:
480          move      t9, t0
481          srl       t1, a0, 16-REG_SCALESHIFT     # rt (source)
482          srl       t2, a0, 11-REG_SCALESHIFT     # rd (dest)
483          srl       v1, a0, 6                     # sa
484          andi      t1, REG_REGMASK
485          andi      t2, REG_REGMASK
486          beqz      t2, bcemul_done                         # fast escape for nop variants
487          andi      v1, 0x001F
488#ifndef __mips_o32
489          /*
490           * Deal with DSLL32, DSRA32, DSRL32 who need 32 added to their
491           * shift count.
492           */
493          andi      v0, a0, 077                             # focus on special op
494          sltiu     v0, v0, 074                             # less than DSLL32?
495          xori      v0, 1                                   # invert result
496          sll       v0, 5                                   # shift by 5 (now 0 or 32)
497          addu      v1, v0                                  # add to shift count
498#endif
499          PTR_ADDU t1, a1
500          PTR_ADDU t2, a1
501          REG_PROLOGUE
502          REG_L     v0, TF_REG_ZERO(t1)           # load source
503          REG_EPILOGUE
504          jal       t9
505          j         bcemul_store_and_done
506
507bcemul_special_sync:
508          b         bcemul_done
509
510bcemul_special_mfhilo:
511          srl       t2, a0, 11-REG_SCALESHIFT     # rd (dest)
512          andi      t2, REG_REGMASK
513          PTR_ADDU t1, a1, TF_REG_MULHI
514          PTR_ADDU t2, a1
515          and       v0, a0, 2                     # bit 1: 0=HI 1=LO
516          sll       v0, REG_SCALESHIFT - 1
517#if TF_REG_MULLO < TF_REG_MULHI
518          PTR_SUBU t1, v0
519#else
520          PTR_ADDU t1, v0
521#endif
522          REG_PROLOGUE
523          REG_L     t0, TF_REG_ZERO(t1)           # load source (mullo or mulhi)
524          REG_EPILOGUE
525          b         bcemul_store_and_done
526
527bcemul_special_mthilo:
528          srl       t1, a0, 21-REG_SCALESHIFT     # rs (source)
529          andi      t1, REG_REGMASK
530          PTR_ADDU t1, a1
531          PTR_ADDU t2, a1, TF_REG_MULHI
532          and       v0, a0, 2                     # bit 1: 0=HI l=LO
533          sll       v0, REG_SCALESHIFT - 1
534#if TF_REG_MULLO < TF_REG_MULHI
535          PTR_SUBU t2, v0
536#else
537          PTR_ADDU t2, v0
538#endif
539          REG_PROLOGUE
540          REG_L     t0, TF_REG_ZERO(t1)
541          REG_EPILOGUE
542          b         bcemul_store_and_done
543
544bcemul_special_genmultdiv:
545          bal       bcemul_special_2src_prologue  # grab operands and do it.
546          mflo      v0
547          mfhi      v1
548          REG_PROLOGUE
549          REG_S     v0, TF_REG_MULLO(a1)
550          REG_S     v1, TF_REG_MULHI(a1)
551          REG_EPILOGUE
552          b         bcemul_done
553
554bcemul_special_genadd:
555          bal       bcemul_special_3op_prologue
556          b         bcemul_check_add_overflow
557
558bcemul_special_gensub:
559          bal       bcemul_special_3op_prologue
560
561          /*
562           * t0 = v0 - v1 which means v0 = t0 + v1
563           * Now we can the same logic for overflow from addition.
564           */
565          move      ta0, v0
566          move      ta1, t0
567          move      ta2, v1
568
569          b         bcemul_check_overflow
570
571bcemul_special_genshiftv:
572bcemul_special_gen3op:
573          bal       bcemul_special_3op_prologue
574          #b        bcemul_store_and_done         # fallthrough to bcemul_store_and_done
575
576bcemul_store_and_done:
577          beq       a1, t2, bcemul_done # don't store to zero
578          REG_PROLOGUE
579          REG_S     t0, TF_REG_ZERO(t2)
580          REG_EPILOGUE
581          #b        bcemul_done                   # fallthrough to bcemul_done
582
583bcemul_done:
584/*
585 * Succeeded to emulate instruction with no error
586 * so compute the next PC.
587 */
588          PTR_SUBU sp, CALLFRAME_SIZ
589          REG_S     t3, CALLFRAME_RA(sp)
590          REG_S     s0, CALLFRAME_S0(sp)
591          move      s0, a1                        # save trapfame
592
593          /* Fetch previous branch instruction */
594          REG_PROLOGUE
595          REG_L     a0, TF_REG_EPC(s0)
596          REG_EPILOGUE
597          jal       _C_LABEL(mips_ufetch32)
598
599          /* Calculate branch destination */
600          sll       t0, v0, 16
601          sra       t0, t0, 16-2
602          REG_PROLOGUE
603          REG_L     t1, TF_REG_EPC(s0)
604          PTR_ADDU t0, 4
605          PTR_ADDU t1, t0
606          REG_S     t1, TF_REG_EPC(s0)
607          REG_EPILOGUE
608
609          REG_L     ra, CALLFRAME_RA(sp)
610          REG_L     s0, CALLFRAME_S0(sp)
611          PTR_ADDU sp, CALLFRAME_SIZ
612          jr        ra
613
614/*
615 * Send SIGILL, SIGFPE.
616 * Args are same as mips_emul_fp.
617 */
618bcemul_sigill:
619          li        t0, 0xFFFFFF00
620          and       a2, a2, t0
621          ori       a2, a2, T_RES_INST << MIPS_CR_EXC_CODE_SHIFT
622          REG_PROLOGUE
623          REG_S     a2, TF_REG_CAUSE(a1)
624          REG_EPILOGUE
625
626          move      ra, t3                                  # restore ra
627          move      a1, a0                                  # code = instruction
628          move      a0, MIPS_CURLWP                         # get current process
629          j         _C_LABEL(mips_fpuillinst)
630
631END(mips_emul_branchdelayslot)
632