arch/sparc/math-emu/math_64.c

Source file repositories/reference/linux-study-clean/arch/sparc/math-emu/math_64.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/math-emu/math_64.c
Extension
.c
Size
16230 bytes
Lines
526
Domain
Architecture Layer
Bucket
arch/sparc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if((eflag & (eflag - 1)) != 0) {
			if(eflag & FP_EX_INVALID)
				eflag = FP_EX_INVALID;
			else if(eflag & FP_EX_OVERFLOW)
				eflag = FP_EX_OVERFLOW;
			else if(eflag & FP_EX_UNDERFLOW)
				eflag = FP_EX_UNDERFLOW;
			else if(eflag & FP_EX_DIVZERO)
				eflag = FP_EX_DIVZERO;
			else if(eflag & FP_EX_INEXACT)
				eflag = FP_EX_INEXACT;
		}
	}

	/* Set CEXC, here is the rule:
	 *
	 *    In general all FPU ops will set one and only one
	 *    bit in the CEXC field, this is always the case
	 *    when the IEEE exception trap is enabled in TEM.
	 */
	fsr &= ~(FSR_CEXC_MASK);
	fsr |= ((long)eflag << FSR_CEXC_SHIFT);

	/* Set the AEXC field, rule is:
	 *
	 *    If a trap would not be generated, the
	 *    CEXC just generated is OR'd into the
	 *    existing value of AEXC.
	 */
	if(would_trap == 0)
		fsr |= ((long)eflag << FSR_AEXC_SHIFT);

	/* If trapping, indicate fault trap type IEEE. */
	if(would_trap != 0)
		fsr |= (1UL << 14);

	current_thread_info()->xfsr[0] = fsr;

	/* If we will not trap, advance the program counter over
	 * the instruction being handled.
	 */
	if(would_trap == 0) {
		regs->tpc = regs->tnpc;
		regs->tnpc += 4;
	}

	return (would_trap ? 0 : 1);
}

typedef union {
	u32 s;
	u64 d;
	u64 q[2];
} *argp;

int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap)
{
	unsigned long pc = regs->tpc;
	unsigned long tstate = regs->tstate;
	u32 insn = 0;
	int type = 0;
	/* ftt tells which ftt it may happen in, r is rd, b is rs2 and a is rs1. The *u arg tells
	   whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack)
	   non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */
#define TYPE(ftt, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) | (ftt << 9)
	int freg;
	static u64 zero[2] = { 0L, 0L };
	int flags;
	FP_DECL_EX;
	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
	FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
	int IR;
	long XR, xfsr;

	if (tstate & TSTATE_PRIV)
		die_if_kernel("unfinished/unimplemented FPop from kernel", regs);
	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
	if (test_thread_flag(TIF_32BIT))
		pc = (u32)pc;
	if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
		if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
			switch ((insn >> 5) & 0x1ff) {
			/* QUAD - ftt == 3 */
			case FMOVQ:
			case FNEGQ:
			case FABSQ: TYPE(3,3,0,3,0,0,0); break;
			case FSQRTQ: TYPE(3,3,1,3,1,0,0); break;
			case FADDQ:
			case FSUBQ:

Annotation

Implementation Notes