1/*	$NetBSD: bds_emul.S,v 1.5 2011/08/16 06:55:11 matt 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/cpu.h>			/* for MIPS_CURLWP */
41#include <mips/trap.h>			/* for T_RES_INST */
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 _C_LABEL(mips_emul_daddi)	# 030 DADDI (*)
105	PTR_WORD _C_LABEL(mips_emul_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	daddiu	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(ufetch_uint32)
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