xref: /netbsd/sys/arch/mips/mips/mips_emul.c (revision c4a72b64)
1 /*	$NetBSD: mips_emul.c,v 1.2 2002/07/21 05:47:51 gmcgarry Exp $ */
2 
3 /*
4  * Copyright (c) 1999 Shuichiro URATA.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/user.h>
33 
34 #include <mips/locore.h>
35 #include <mips/mips_opcode.h>
36 
37 #include <machine/cpu.h>
38 #include <mips/reg.h>
39 #include <mips/regnum.h>			/* symbolic register indices */
40 #include <mips/vmparam.h>			/* for VM_MAX_ADDRESS */
41 #include <mips/trap.h>
42 
43 extern	void MachEmulateFP(u_int32_t, struct frame *, u_int32_t);
44 
45 static __inline void	send_sigsegv(u_int32_t, u_int32_t, struct frame *,
46 			    u_int32_t);
47 static __inline void	update_pc(struct frame *, u_int32_t);
48 
49 vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
50 void	MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *);
51 
52 void	MachEmulateLWC0(u_int32_t inst, struct frame *, u_int32_t);
53 void	MachEmulateSWC0(u_int32_t inst, struct frame *, u_int32_t);
54 void	MachEmulateSpecial(u_int32_t inst, struct frame *, u_int32_t);
55 void	MachEmulateLWC1(u_int32_t inst, struct frame *, u_int32_t);
56 void	MachEmulateLDC1(u_int32_t inst, struct frame *, u_int32_t);
57 void	MachEmulateSWC1(u_int32_t inst, struct frame *, u_int32_t);
58 void	MachEmulateSDC1(u_int32_t inst, struct frame *, u_int32_t);
59 
60 void	bcemul_lb(u_int32_t inst, struct frame *, u_int32_t);
61 void	bcemul_lbu(u_int32_t inst, struct frame *, u_int32_t);
62 void	bcemul_lh(u_int32_t inst, struct frame *, u_int32_t);
63 void	bcemul_lhu(u_int32_t inst, struct frame *, u_int32_t);
64 void	bcemul_lw(u_int32_t inst, struct frame *, u_int32_t);
65 void	bcemul_lwl(u_int32_t inst, struct frame *, u_int32_t);
66 void	bcemul_lwr(u_int32_t inst, struct frame *, u_int32_t);
67 void	bcemul_sb(u_int32_t inst, struct frame *, u_int32_t);
68 void	bcemul_sh(u_int32_t inst, struct frame *, u_int32_t);
69 void	bcemul_sw(u_int32_t inst, struct frame *, u_int32_t);
70 void	bcemul_swl(u_int32_t inst, struct frame *, u_int32_t);
71 void	bcemul_swr(u_int32_t inst, struct frame *f, u_int32_t);
72 
73 /*
74  * MIPS2 LL instruction emulation state
75  */
76 struct {
77 	struct proc *proc;
78 	vaddr_t addr;
79 	u_int32_t value;
80 } llstate;
81 
82 /*
83  * Analyse 'next' PC address taking account of branch/jump instructions
84  */
85 vaddr_t
86 MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch)
87 	struct frame *f;
88 	vaddr_t instpc;
89 	unsigned fpuCSR;
90 	int allowNonBranch;
91 {
92 #define	BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2))
93 	InstFmt inst;
94 	vaddr_t nextpc;
95 
96 	if (instpc < MIPS_KSEG0_START)
97 		inst.word = fuiword((void *)instpc);
98 	else
99 		inst.word = *(unsigned *)instpc;
100 
101 	switch ((int)inst.JType.op) {
102 	case OP_SPECIAL:
103 		if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR)
104 			nextpc = f->f_regs[inst.RType.rs];
105 		else if (allowNonBranch)
106 			nextpc = instpc + 4;
107 		else
108 			panic("MachEmulateBranch: Non-branch");
109 		break;
110 
111 	case OP_BCOND:
112 		switch ((int)inst.IType.rt) {
113 		case OP_BLTZ:
114 		case OP_BLTZAL:
115 		case OP_BLTZL:		/* squashed */
116 		case OP_BLTZALL:	/* squashed */
117 			if ((int)(f->f_regs[inst.RType.rs]) < 0)
118 				nextpc = BRANCHTARGET(instpc);
119 			else
120 				nextpc = instpc + 8;
121 			break;
122 
123 		case OP_BGEZ:
124 		case OP_BGEZAL:
125 		case OP_BGEZL:		/* squashed */
126 		case OP_BGEZALL:	/* squashed */
127 			if ((int)(f->f_regs[inst.RType.rs]) >= 0)
128 				nextpc = BRANCHTARGET(instpc);
129 			else
130 				nextpc = instpc + 8;
131 			break;
132 
133 		default:
134 			panic("MachEmulateBranch: Bad branch cond");
135 		}
136 		break;
137 
138 	case OP_J:
139 	case OP_JAL:
140 		nextpc = (inst.JType.target << 2) |
141 			((unsigned)instpc & 0xF0000000);
142 		break;
143 
144 	case OP_BEQ:
145 	case OP_BEQL:	/* squashed */
146 		if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt])
147 			nextpc = BRANCHTARGET(instpc);
148 		else
149 			nextpc = instpc + 8;
150 		break;
151 
152 	case OP_BNE:
153 	case OP_BNEL:	/* squashed */
154 		if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt])
155 			nextpc = BRANCHTARGET(instpc);
156 		else
157 			nextpc = instpc + 8;
158 		break;
159 
160 	case OP_BLEZ:
161 	case OP_BLEZL:	/* squashed */
162 		if ((int)(f->f_regs[inst.RType.rs]) <= 0)
163 			nextpc = BRANCHTARGET(instpc);
164 		else
165 			nextpc = instpc + 8;
166 		break;
167 
168 	case OP_BGTZ:
169 	case OP_BGTZL:	/* squashed */
170 		if ((int)(f->f_regs[inst.RType.rs]) > 0)
171 			nextpc = BRANCHTARGET(instpc);
172 		else
173 			nextpc = instpc + 8;
174 		break;
175 
176 	case OP_COP1:
177 		if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) {
178 			int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0;
179 			if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE)
180 				condition = !condition;
181 			if (condition)
182 				nextpc = BRANCHTARGET(instpc);
183 			else
184 				nextpc = instpc + 8;
185 		}
186 		else if (allowNonBranch)
187 			nextpc = instpc + 4;
188 		else
189 			panic("MachEmulateBranch: Bad COP1 branch instruction");
190 		break;
191 
192 	default:
193 		if (!allowNonBranch)
194 			panic("MachEmulateBranch: Non-branch instruction");
195 		nextpc = instpc + 4;
196 	}
197 	return nextpc;
198 #undef	BRANCHTARGET
199 }
200 
201 /*
202  * Emulate instructions (including floating-point instructions)
203  */
204 void
205 MachEmulateInst(status, cause, opc, frame)
206 	u_int32_t status;
207 	u_int32_t cause;
208 	u_int32_t opc;
209 	struct frame *frame;
210 {
211 	u_int32_t inst;
212 
213 	/*
214 	 *  Fetch the instruction.
215 	 */
216 	if (cause & MIPS_CR_BR_DELAY)
217 		inst = fuword((u_int32_t *)opc+1);
218 	else
219 		inst = fuword((u_int32_t *)opc);
220 
221 	switch (((InstFmt)inst).FRType.op) {
222 	case OP_LWC0:
223 		MachEmulateLWC0(inst, frame, cause);
224 		break;
225 	case OP_SWC0:
226 		MachEmulateSWC0(inst, frame, cause);
227 		break;
228 	case OP_SPECIAL:
229 		MachEmulateSpecial(inst, frame, cause);
230 		break;
231 	case OP_COP1:
232 		MachEmulateFP(inst, frame, cause);
233 		break;
234 #if defined(SOFTFLOAT)
235 	case OP_LWC1:
236 		MachEmulateLWC1(inst, frame, cause);
237 		break;
238 	case OP_LDC1:
239 		MachEmulateLDC1(inst, frame, cause);
240 		break;
241 	case OP_SWC1:
242 		MachEmulateSWC1(inst, frame, cause);
243 		break;
244 	case OP_SDC1:
245 		MachEmulateSDC1(inst, frame, cause);
246 		break;
247 #endif
248 	default:
249 		frame->f_regs[CAUSE] = cause;
250 		frame->f_regs[BADVADDR] = opc;
251 		trapsignal(curproc, SIGSEGV, opc);
252 	}
253 }
254 
255 static __inline void
256 send_sigsegv(u_int32_t vaddr, u_int32_t exccode, struct frame *frame,
257     u_int32_t cause)
258 {
259 
260 	cause = (cause & 0xFFFFFF00) | (exccode << MIPS_CR_EXC_CODE_SHIFT);
261 
262 	frame->f_regs[CAUSE] = cause;
263 	frame->f_regs[BADVADDR] = vaddr;
264 	trapsignal(curproc, SIGSEGV, vaddr);
265 }
266 
267 static __inline void
268 update_pc(struct frame *frame, u_int32_t cause)
269 {
270 
271 	if (cause & MIPS_CR_BR_DELAY)
272 		frame->f_regs[PC] = MachEmulateBranch(frame, frame->f_regs[PC],
273 		    PCB_FSR(curpcb), 0);
274 	else
275 		frame->f_regs[PC] += 4;
276 }
277 
278 /*
279  * MIPS2 LL instruction
280  */
281 void
282 MachEmulateLWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
283 {
284 	u_int32_t	vaddr;
285 	int16_t		offset;
286 	void		*t;
287 
288 	offset = inst & 0xFFFF;
289 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
290 
291 	/* segment and alignment check */
292 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
293 		frame->f_regs[CAUSE] = cause;
294 		frame->f_regs[BADVADDR] = vaddr;
295 		trapsignal(curproc, SIGBUS, vaddr);
296 		return;
297 	}
298 
299 	t = &(frame->f_regs[(inst>>16)&0x1F]);
300 
301 	if (copyin((void *)vaddr, t, 4) != 0) {
302 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
303 		return;
304 	}
305 
306 	llstate.proc = curproc;
307 	llstate.addr = vaddr;
308 	llstate.value = *((u_int32_t *)t);
309 
310 	update_pc(frame, cause);
311 }
312 
313 /*
314  * MIPS2 SC instruction
315  */
316 void
317 MachEmulateSWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
318 {
319 	u_int32_t	vaddr, value;
320 	int16_t		offset;
321 	mips_reg_t	*t;
322 
323 	offset = inst & 0xFFFF;
324 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
325 
326 	/* segment and alignment check */
327 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
328 		frame->f_regs[CAUSE] = cause;
329 		frame->f_regs[BADVADDR] = vaddr;
330 		trapsignal(curproc, SIGBUS, vaddr);
331 		return;
332 	}
333 
334 	t = (mips_reg_t *)&(frame->f_regs[(inst>>16)&0x1F]);
335 
336 	/*
337 	 * Check that the process and address match the last
338 	 * LL instruction.
339 	 */
340 	if (curproc == llstate.proc && vaddr == llstate.addr) {
341 		llstate.proc = NULL;
342 		/*
343 		 * Check that the data at the address hasn't changed
344 		 * since the LL instruction.
345 		 */
346 		if (copyin((void *)vaddr, &value, 4) != 0) {
347 			send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
348 			return;
349 		}
350 		if (value == llstate.value) {
351 			/* SC successful */
352 			if (copyout(t, (void *)vaddr, 4) != 0) {
353 				send_sigsegv(vaddr, T_TLB_ST_MISS,
354 				    frame, cause);
355 				return;
356 			}
357 			*t = 1;
358 			update_pc(frame, cause);
359 			return;
360 		}
361 	}
362 
363 	/* SC failed */
364 	*t = 0;
365 	update_pc(frame, cause);
366 }
367 
368 void
369 MachEmulateSpecial(u_int32_t inst, struct frame *frame, u_int32_t cause)
370 {
371 	switch (((InstFmt)inst).RType.func) {
372 	case OP_SYNC:
373 		/* nothing */
374 		break;
375 	default:
376 		frame->f_regs[CAUSE] = cause;
377 		frame->f_regs[BADVADDR] = frame->f_regs[PC];
378 		trapsignal(curproc, SIGSEGV, frame->f_regs[PC]);
379 	}
380 
381 	update_pc(frame, cause);
382 }
383 
384 #if defined(SOFTFLOAT)
385 
386 #define LWSWC1_MAXLOOP	12
387 
388 void
389 MachEmulateLWC1(u_int32_t inst, struct frame *frame, u_int32_t cause)
390 {
391 	u_int32_t	vaddr;
392 	int16_t		offset;
393 	void		*t;
394 	mips_reg_t	pc;
395 	int		i;
396 
397 	offset = inst & 0xFFFF;
398 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
399 
400 	/* segment and alignment check */
401 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
402 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
403 		return;
404 	}
405 
406 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
407 
408 	if (copyin((void *)vaddr, t, 4) != 0) {
409 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
410 		return;
411 	}
412 
413 	pc = frame->f_regs[PC];
414 	update_pc(frame, cause);
415 
416 	if (cause & MIPS_CR_BR_DELAY)
417 		return;
418 
419 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
420 		if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
421 			return;
422 
423 		vaddr = frame->f_regs[PC];	/* XXX truncates to 32 bits */
424 		inst = fuiword((u_int32_t *)vaddr);
425 		if (((InstFmt)inst).FRType.op != OP_LWC1)
426 			return;
427 
428 		offset = inst & 0xFFFF;
429 		vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
430 
431 		/* segment and alignment check */
432 		if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
433 			send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
434 			return;
435 		}
436 
437 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
438 
439 		if (copyin((void *)vaddr, t, 4) != 0) {
440 			send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
441 			return;
442 		}
443 
444 		pc = frame->f_regs[PC];
445 		update_pc(frame, cause);
446 	}
447 }
448 
449 void
450 MachEmulateLDC1(u_int32_t inst, struct frame *frame, u_int32_t cause)
451 {
452 	u_int32_t	vaddr;
453 	int16_t		offset;
454 	void		*t;
455 
456 	offset = inst & 0xFFFF;
457 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
458 
459 	/* segment and alignment check */
460 	if (vaddr & 0x80000007) {
461 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
462 		return;
463 	}
464 
465 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
466 
467 	if (copyin((void *)vaddr, t, 8) != 0) {
468 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
469 		return;
470 	}
471 
472 	update_pc(frame, cause);
473 }
474 
475 void
476 MachEmulateSWC1(u_int32_t inst, struct frame *frame, u_int32_t cause)
477 {
478 	u_int32_t	vaddr;
479 	int16_t		offset;
480 	void		*t;
481 	mips_reg_t	pc;
482 	int		i;
483 
484 	offset = inst & 0xFFFF;
485 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
486 
487 	/* segment and alignment check */
488 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
489 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
490 		return;
491 	}
492 
493 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
494 
495 	if (copyout(t, (void *)vaddr, 4) != 0) {
496 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
497 		return;
498 	}
499 
500 	pc = frame->f_regs[PC];
501 	update_pc(frame, cause);
502 
503 	if (cause & MIPS_CR_BR_DELAY)
504 		return;
505 
506 	for (i = 1; i < LWSWC1_MAXLOOP; i++) {
507 		if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
508 			return;
509 
510 		vaddr = frame->f_regs[PC];	/* XXX truncates to 32 bits */
511 		inst = fuiword((u_int32_t *)vaddr);
512 		if (((InstFmt)inst).FRType.op != OP_SWC1)
513 			return;
514 
515 		offset = inst & 0xFFFF;
516 		vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
517 
518 		/* segment and alignment check */
519 		if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
520 			send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
521 			return;
522 		}
523 
524 		t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]);
525 
526 		if (copyout(t, (void *)vaddr, 4) != 0) {
527 			send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
528 			return;
529 		}
530 
531 		pc = frame->f_regs[PC];
532 		update_pc(frame, cause);
533 	}
534 }
535 
536 void
537 MachEmulateSDC1(u_int32_t inst, struct frame *frame, u_int32_t cause)
538 {
539 	u_int32_t	vaddr;
540 	int16_t		offset;
541 	void		*t;
542 
543 	offset = inst & 0xFFFF;
544 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
545 
546 	/* segment and alignment check */
547 	if (vaddr & 0x80000007) {
548 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
549 		return;
550 	}
551 
552 	t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]);
553 
554 	if (copyout(t, (void *)vaddr, 8) != 0) {
555 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
556 		return;
557 	}
558 
559 	update_pc(frame, cause);
560 }
561 
562 void
563 bcemul_lb(u_int32_t inst, struct frame *frame, u_int32_t cause)
564 {
565 	u_int32_t	vaddr;
566 	int16_t		offset;
567 	int8_t		x;
568 
569 	offset = inst & 0xFFFF;
570 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
571 
572 	/* segment check */
573 	if (vaddr & 0x80000000) {
574 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
575 		return;
576 	}
577 
578 	if (copyin((void *)vaddr, &x, 1) != 0) {
579 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
580 		return;
581 	}
582 
583 	frame->f_regs[(inst>>16)&0x1F] = (int32_t)x;
584 
585 	update_pc(frame, cause);
586 }
587 
588 void
589 bcemul_lbu(u_int32_t inst, struct frame *frame, u_int32_t cause)
590 {
591 	u_int32_t	vaddr;
592 	int16_t		offset;
593 	u_int8_t	x;
594 
595 	offset = inst & 0xFFFF;
596 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
597 
598 	/* segment check */
599 	if (vaddr & 0x80000000) {
600 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
601 		return;
602 	}
603 
604 	if (copyin((void *)vaddr, &x, 1) != 0) {
605 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
606 		return;
607 	}
608 
609 	frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x;
610 
611 	update_pc(frame, cause);
612 }
613 
614 void
615 bcemul_lh(u_int32_t inst, struct frame *frame, u_int32_t cause)
616 {
617 	u_int32_t	vaddr;
618 	int16_t		offset;
619 	int16_t		x;
620 
621 	offset = inst & 0xFFFF;
622 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
623 
624 	/* segment and alignment check */
625 	if (vaddr & 0x80000001) {
626 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
627 		return;
628 	}
629 
630 	if (copyin((void *)vaddr, &x, 2) != 0) {
631 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
632 		return;
633 	}
634 
635 	frame->f_regs[(inst>>16)&0x1F] = (int32_t)x;
636 
637 	update_pc(frame, cause);
638 }
639 
640 void
641 bcemul_lhu(u_int32_t inst, struct frame *frame, u_int32_t cause)
642 {
643 	u_int32_t	vaddr;
644 	int16_t		offset;
645 	u_int16_t	x;
646 
647 	offset = inst & 0xFFFF;
648 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
649 
650 	/* segment and alignment check */
651 	if (vaddr & 0x80000001) {
652 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
653 		return;
654 	}
655 
656 	if (copyin((void *)vaddr, &x, 2) != 0) {
657 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
658 		return;
659 	}
660 
661 	frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x;
662 
663 	update_pc(frame, cause);
664 }
665 
666 void
667 bcemul_lw(u_int32_t inst, struct frame *frame, u_int32_t cause)
668 {
669 	u_int32_t	vaddr;
670 	int16_t		offset;
671 
672 	offset = inst & 0xFFFF;
673 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
674 
675 	/* segment and alignment check */
676 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
677 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
678 		return;
679 	}
680 
681 	if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 4) != 0) {
682 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
683 		return;
684 	}
685 
686 	update_pc(frame, cause);
687 }
688 
689 void
690 bcemul_lwl(u_int32_t inst, struct frame *frame, u_int32_t cause)
691 {
692 	u_int32_t	vaddr, a, x, shift;
693 	int16_t		offset;
694 
695 	offset = inst & 0xFFFF;
696 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
697 
698 	/* segment check */
699 	if (vaddr & 0x80000000) {
700 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
701 		return;
702 	}
703 
704 	if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) {
705 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
706 		return;
707 	}
708 
709 	x = frame->f_regs[(inst>>16)&0x1F];
710 
711 	shift = (3 - (vaddr & 0x00000003)) * 8;
712 	a <<= shift;
713 	x &= ~(0xFFFFFFFFUL << shift);
714 	x |= a;
715 
716 	frame->f_regs[(inst>>16)&0x1F] = x;
717 
718 	update_pc(frame, cause);
719 }
720 
721 void
722 bcemul_lwr(u_int32_t inst, struct frame *frame, u_int32_t cause)
723 {
724 	u_int32_t	vaddr, a, x, shift;
725 	int16_t		offset;
726 
727 	offset = inst & 0xFFFF;
728 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
729 
730 	/* segment check */
731 	if (vaddr & 0x80000000) {
732 		send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
733 		return;
734 	}
735 
736 	if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) {
737 		send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
738 		return;
739 	}
740 
741 	x = frame->f_regs[(inst>>16)&0x1F];
742 
743 	shift = (vaddr & 0x00000003) * 8;
744 	a >>= shift;
745 	x &= ~(0xFFFFFFFFUL >> shift);
746 	x |= a;
747 
748 	frame->f_regs[(inst>>16)&0x1F] = x;
749 
750 	update_pc(frame, cause);
751 }
752 
753 void
754 bcemul_sb(u_int32_t inst, struct frame *frame, u_int32_t cause)
755 {
756 	u_int32_t	vaddr;
757 	int16_t		offset;
758 
759 	offset = inst & 0xFFFF;
760 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
761 
762 	/* segment check */
763 	if (vaddr & 0x80000000) {
764 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
765 		return;
766 	}
767 
768 	if (subyte((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
769 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
770 		return;
771 	}
772 
773 	update_pc(frame, cause);
774 }
775 
776 void
777 bcemul_sh(u_int32_t inst, struct frame *frame, u_int32_t cause)
778 {
779 	u_int32_t	vaddr;
780 	int16_t		offset;
781 
782 	offset = inst & 0xFFFF;
783 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
784 
785 	/* segment and alignment check */
786 	if (vaddr & 0x80000001) {
787 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
788 		return;
789 	}
790 
791 	if (susword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
792 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
793 		return;
794 	}
795 
796 	update_pc(frame, cause);
797 }
798 
799 void
800 bcemul_sw(u_int32_t inst, struct frame *frame, u_int32_t cause)
801 {
802 	u_int32_t	vaddr;
803 	int16_t		offset;
804 
805 	offset = inst & 0xFFFF;
806 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
807 
808 	/* segment and alignment check */
809 	if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
810 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
811 		return;
812 	}
813 
814 	if (suword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) {
815 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
816 		return;
817 	}
818 
819 	update_pc(frame, cause);
820 }
821 
822 void
823 bcemul_swl(u_int32_t inst, struct frame *frame, u_int32_t cause)
824 {
825 	u_int32_t	vaddr, a, x, shift;
826 	int16_t		offset;
827 
828 	offset = inst & 0xFFFF;
829 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
830 
831 	/* segment check */
832 	if (vaddr & 0x80000000) {
833 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
834 		return;
835 	}
836 
837 	if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) {
838 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
839 		return;
840 	}
841 
842 	x = frame->f_regs[(inst>>16)&0x1F];
843 
844 	shift = (3 - (vaddr & 0x00000003)) * 8;
845 	x >>= shift;
846 	a &= ~(0xFFFFFFFFUL >> shift);
847 	a |= x;
848 
849 	if (suword((void *)vaddr, a) < 0) {
850 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
851 		return;
852 	}
853 
854 	update_pc(frame, cause);
855 }
856 
857 void
858 bcemul_swr(u_int32_t inst, struct frame *frame, u_int32_t cause)
859 {
860 	u_int32_t	vaddr, a, x, shift;
861 	int16_t		offset;
862 
863 	offset = inst & 0xFFFF;
864 	vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
865 
866 	/* segment check */
867 	if (vaddr & 0x80000000) {
868 		send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
869 		return;
870 	}
871 
872 	if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) {
873 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
874 		return;
875 	}
876 
877 	x = frame->f_regs[(inst>>16)&0x1F];
878 
879 	shift = (vaddr & 0x00000003) * 8;
880 	x <<= shift;
881 	a &= ~(0xFFFFFFFFUL << shift);
882 	a |= x;
883 
884 	if (suword((void *)vaddr, a) < 0) {
885 		send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
886 		return;
887 	}
888 
889 	update_pc(frame, cause);
890 }
891 #endif /* defined(SOFTFLOAT) */
892