⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emulate_instr.s

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 S
字号:
/*	@(#)emulate_instr.s	4.2      (ULTRIX)        8/13/90	*//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | *//* | Reserved.  This software contains proprietary and confidential | *//* | information of MIPS and its suppliers.  Use, disclosure or     | *//* | reproduction is prohibited without the prior express written   | *//* | consent of MIPS.                                               | *//* ------------------------------------------------------------------ *//************************************************************************ * *	Modification History: locore.s * *   5-Dec-89 -- jmartin *	Fix flush_ea to flush the entire EMULATE_AREA icache. * *   4-Dec-89 -- jmartin *	Fix function flush_ea to use new PTE format. * *//* * emulate_instr.s -- general instruction emulation/execution */#include "../machine/param.h"#include "../machine/cpu.h"#include "../machine/reg.h"#include "../machine/regdef.h"#include "../machine/asm.h"#include "../machine/softfp.h"#include "../machine/vmparam.h"#include "../machine/pte.h"#include "../h/signal.h"#include "../../machine/common/cpuconf.h"#include "assym.h"	u	=	UADDRIMPORT(exception_exit,0)IMPORT(cpu,4)IMPORT(kn5800_wbflush_addr,4)/* * The emulate_instr() is a routune with a locore.s interface which emulates * or executes an instruction and changes the state of the user's registers * where they reside at the locore.s interface level. * * This routine is called via jal emulate_instr and eventually gets back to * the return address in ra. * * input parameters: *	a0 -- the current exception frame *	a1 -- the instruction to emulate *	a2 -- the epc for the instruction to emulate (also in the pcb) *	ra -- the return address * input parameters in the process's pcb (valid on return) *	PCB_BD_EPC -- the epc for the instruction to emulate *	PCB_BD_CAUSE -- the cause register with the branch delay bit set *			correctly with respect to the epc above * return state: *	a3 -- the resulting program counter after the emulated instruction *	a0 -- the new or existing exception frame *      user's register values as modified by emulated instruction in either *	the register or in the exception frame (as per the locore.s interface) * * In the cases that this instruction is going to be executed on the user's * stack the return address (from the place in the kernel emulate_instr() was * called) is saved in the pcb at PCB_BD_RA.  The value on PCB_BD_RA is zero * when not doing this emulation so that spurious reserved break instructions  * used for this emulation can be detected (in VEC_breakpoint).  PCB_BD_RA is * normally used on the return path from the executed instruction via the break * instruction that will get executed after it.  If the instruction causes an * error the trap() routine looks for a non-zero value of PCB_BD_RA so it * will know the real values for the epc and cause register for this error are * in PCB_BD_EPC and PCB_BD_CAUSE. */LEAF(emulate_instr)	bne	a1,zero,1f	# is this a nop?	addu	a3,a2,4		# the next pc is just the next instr (epc)+4	j	ra		# return	1:	# Check for instructions which unconditionally transfer control to	# a program counter to other than just the next instruction.	srl	s0,a1,IMMED_SHIFT	# is this an unconditional branch instr?	bne	s0,OPCODE_BEQ<<(OPCODE_SHIFT-16),2f	sll	a1,IMMED_SHIFT		# sign extend the immediate offset	sra	a1,IMMED_SHIFT-2	addu	a3,a2,a1		# add the epc (a2) to the offset (a1)	addu	a3,4	j	ra			# return2:	# Note that s0 is assumed to hold the opcode until it is determined	# how the instruction is to be executed or emulated.	srl	s0,a1,OPCODE_SHIFT	bne	s0,OPCODE_J,2f		# is this a jump instruction?	and	a3,a2,PC_JMP_MASK	# get the high bits from the epc (a2)	and	a1,TARGET_MASK		# get the target from the instr (a1)	sll	a1,2			# shift the target left two bits	or	a3,a1			# combine the target and epc bits	j	ra			# return2:	bne	s0,OPCODE_JAL,3f	# is this a jump and link instr?	addu	s0,a2,8			# epc (a2) + 8 value of the link reg	sw	s0,EF_RA*4(a0)		# store value of the link in user's RA	and	a3,a2,PC_JMP_MASK	# get the high bits from the epc (a2)	and	a1,TARGET_MASK		# get the target from the instr (a1)	sll	a1,2			# shift the target left two bits	or	a3,a1			# combine the target and epc bits	j	ra			# return3:	# Check for jump register and jump and link register instructions	bne	s0,OPCODE_SPECIAL,5f	# check for SPECIAL opcode	and	a3,a1,FUNC_MASK	beq	a3,FUNC_JR,4f		# is this a jump reg instr?	bne	a3,FUNC_JALR,5f		# is this a jump and link reg instr?	addu	a2,8			# epc (a2) + 8 value of the link reg	sw	a2,EF_RA*4(a0)		# store value of the link in user's RA4:	# get the register for the target address of the jump instruction	# then just return	srl	a1,BASE_SHIFT-2	and	a1,BASE_MASK<<2	lw	a1,jreg_tbl(a1)	j	a1jreg_tbl:	.word	jreg_zero:1, jreg_AT:1, jreg_v0:1, jreg_v1:1, jreg_a0:1	.word	jreg_a1:1, jreg_a2:1, jreg_a3:1, jreg_t0:1, jreg_t1:1	.word	jreg_t2:1, jreg_t3:1, jreg_t4:1, jreg_t5:1, jreg_t6:1	.word	jreg_t7:1, jreg_s0:1, jreg_s1:1, jreg_s2:1, jreg_s3:1	.word	jreg_s4:1, jreg_s5:1, jreg_s6:1, jreg_s7:1, jreg_t8:1	.word	jreg_t9:1, jreg_k0:1, jreg_k1:1, jreg_gp:1, jreg_sp:1	.word	jreg_s8:1, jreg_ra:1jreg_zero:	move	a3,zero;	j	rajreg_AT:	lw	a3,EF_AT*4(a0);	j	rajreg_v0:	move	a3,v0;		j	rajreg_v1:	move	a3,v1;		j	rajreg_a0:	lw	a3,EF_A0*4(a0);	j	rajreg_a1:	lw	a3,EF_A1*4(a0);	j	rajreg_a2:	lw	a3,EF_A2*4(a0);	j	rajreg_a3:	lw	a3,EF_A3*4(a0);	j	rajreg_t0:	move	a3,t0;		j	rajreg_t1:	move	a3,t1;		j	rajreg_t2:	move	a3,t2;		j	rajreg_t3:	move	a3,t3;		j	rajreg_t4:	move	a3,t4;		j	rajreg_t5:	move	a3,t5;		j	rajreg_t6:	move	a3,t6;		j	rajreg_t7:	move	a3,t7;		j	rajreg_s0:	lw	a3,EF_S0*4(a0);	j	rajreg_s1:	move	a3,s1;		j	rajreg_s2:	move	a3,s2;		j	rajreg_s3:	move	a3,s3;		j	rajreg_s4:	move	a3,s4;		j	rajreg_s5:	move	a3,s5;		j	rajreg_s6:	move	a3,s6;		j	rajreg_s7:	move	a3,s7;		j	rajreg_t8:	move	a3,t8;		j	rajreg_t9:	move	a3,t9;		j	rajreg_k0:	move	a3,k0;		j	rajreg_k1:	lw	a3,EF_K1*4(a0);	j	rajreg_gp:	lw	a3,EF_GP*4(a0);	j	rajreg_sp:	lw	a3,EF_SP*4(a0);	j	rajreg_s8:	move	a3,s8;		j	rajreg_ra:	lw	a3,EF_RA*4(a0);	j	ra5:/* * At this point all the simple instructions have been emulated so * the instruction will be copied into the user area and executed * there.  Branch instructions are handled differently from the * rest of the instructions.  For branch instructions the branch * with a modified offset is executed.  The offset is modified to * branch over the first break instruction to the second break * instruction. * *	branch (offset)--- *	nop              | *	break A          | *	break B  <-------- * * For all other instructions (non-branch) the instruction is just * executed followed by a break. * *	instr *	break A */	beq	s0,OPCODE_BCOND,1f	# is this a BCOND branch?	and	a3,s0,BRANCH_MASK	# is this a general branch?	beq	a3,OPCODE_BRANCHES,1f	and	a3,s0,COPN_MASK		# is this a coprocessor op?	bne	a3,OPCODE_COPN,2f	srl	a3,a1,COPN_BCSHIFT	# is this a coprocessor branch?	and	a3,COPN_BCMASK	bne	a3,COPN_BC,2f1:/* * The instruction is now known to be a branch so save the instruction * for the return trip (to determine the target) and build a branch with * a modified offset.  Then write out the instruction, a nop, a break A * and a break B.  Clean-up the caches and return from the exception to * the modified branch. */	sw	ra,u+PCB_BD_RA		# save emulate_instr caller's ra	li	a2,EMULATE_AREA		# load address to use for emulation area	sw	a2,EF_EPC*4(a0)		# use it for the user's return pc	sw	a1,u+PCB_BD_INSTR	# save the branch instruction	srl	a1,IMMED_SHIFT		# remove the offset from the branch	sll	a1,IMMED_SHIFT	or	a1,8>>2			# set the modified offset	sw	a1,0(a2)		# store the modified branch instruction	sw	zero,4(a2)		# store the nop instruction	lw	a3,break_A		# get a break A instruction	sw	a3,8(a2)		# store the break A instruction	lw	a3,break_B		# get a break B instruction	sw	a3,12(a2)		# store the break B instruction	j	flush_ea		# flush emulate area from i cache2:	sw	ra,u+PCB_BD_RA		# save emulate_instr caller's ra	li	a2,EMULATE_AREA		# load address to use for emulation area	sw	a2,EF_EPC*4(a0)		# use it for the user's return pc	sw	a1,0(a2)		# store the instruction	lw	a3,break_A		# get a break A instruction	sw	a3,4(a2)		# store the break A instruction	j	flush_ea		# flush emulate area from i cachebreak_A:	break	BRK_BD_NOTTAKENbreak_B:	break	BRK_BD_TAKEN	END(emulate_instr)/* * flush i-cache for emulate area */LEAF(flush_ea)	lw	a3,u+U_PROCP		# current procp	lw	a1,P_STAKBR(a3)		# base of stack pte's	lhu	a2,P_STAKPT(a3)		# pages of stack pte's	subu	a1,(HIGHPAGES+1)*4	# LDSLOT backup to last pte of stack	mul	a2,NPTEPG*4		# offset past last stack pte	addu	a1,a2	lw	a1,0(a1)		# get pte for top of user stack	and	a1,PG_PFNUM	sll	a1,8			# abstract format to R2000/R3000	and	a1,(MAXCACHE-1)		# where the page starts in cache	or	a1,K0BASE		# alias for cache page	addu	a1,NBPG-EA_SIZE		# offset to emulate area	.set noreorder	nop	mtc0	zero,C0_SR		# interrupts off	nop	.set reorder	/*	 * DECsystem 58xx systems need to make sure that the write buffer	 * is empty to avoid an R3000 chip bug. So we use a2 which is no	 * longer needed to accomplish this.	 */	lw	a2, cpu			# Get cpu (really system) type	bne	a2, DS_5800, 1f		# If not DECsystem 5800 skip the flush	lw	a2, kn5800_wbflush_addr	# Get address to read to cause a wbflush	lw	a2, (a2)		# do the write buffer flush1:	la	a3,1f	or	a3,K1BASE	addu	a2,a1,EA_SIZE		# upper limit for the flush below	j	a3			# run uncached	.set	noreorder1:	nop	nop	nop	li	a3,SR_ISC|SR_SWC	mtc0	a3,C0_SR		# isolate and swap	nop	nop2:	addu	a1,8			# flush emulate area	sb	zero,-8(a1)	bltu	a1,a2,2b	sb	zero,-4(a1)		# BDSLOT	nop	nop	mtc0	zero,C0_SR		# unisolate and unswap	nop	nop	.set	reorder	lw	s0,EF_SR*4(a0)		# load a0 with the SR at the time of 	.set 	noreorder	nop					#  the exception.	mtc0	s0,C0_SR		# replace the SR to disable interrupts	nop	.set  	reorder	j	exception_exit		# branch to exit the exception code	END(flush_ea)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -