Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: math-emu support

This implements initial math-emu support, aimed primarily at SH-3.

Signed-off-by: Takashi YOSHII <takasi-y@ops.dti.ne.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

authored by

Takashi YOSHII and committed by
Paul Mundt
4b565680 317a6104

+918 -39
+9
arch/sh/Kconfig
··· 339 339 340 340 This option must be set in order to enable the FPU. 341 341 342 + config SH_FPU_EMU 343 + bool "FPU emulation support" 344 + depends on !SH_FPU && EXPERIMENTAL 345 + default n 346 + help 347 + Selecting this option will enable support for software FPU emulation. 348 + Most SH-3 users will want to say Y here, whereas most SH-4 users will 349 + want to say N. 350 + 342 351 config SH_DSP 343 352 bool "DSP support" 344 353 depends on !CPU_SH4
+1
arch/sh/Makefile
··· 79 79 LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) 80 80 81 81 core-y += arch/sh/kernel/ arch/sh/mm/ 82 + core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ 82 83 83 84 # Boards 84 85 machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
+125 -39
arch/sh/kernel/traps.c
··· 36 36 37 37 #ifdef CONFIG_SH_KGDB 38 38 #include <asm/kgdb.h> 39 - #define CHK_REMOTE_DEBUG(regs) \ 40 - { \ 41 - if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \ 42 - { \ 43 - (*kgdb_debug_hook)(regs); \ 44 - } \ 39 + #define CHK_REMOTE_DEBUG(regs) \ 40 + { \ 41 + if (kgdb_debug_hook && !user_mode(regs))\ 42 + (*kgdb_debug_hook)(regs); \ 45 43 } 46 44 #else 47 45 #define CHK_REMOTE_DEBUG(regs) 48 46 #endif 49 - 50 - #define DO_ERROR(trapnr, signr, str, name, tsk) \ 51 - asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ 52 - unsigned long r6, unsigned long r7, \ 53 - struct pt_regs regs) \ 54 - { \ 55 - unsigned long error_code; \ 56 - \ 57 - /* Check if it's a DSP instruction */ \ 58 - if (is_dsp_inst(&regs)) { \ 59 - /* Enable DSP mode, and restart instruction. */ \ 60 - regs.sr |= SR_DSP; \ 61 - return; \ 62 - } \ 63 - \ 64 - asm volatile("stc r2_bank, %0": "=r" (error_code)); \ 65 - local_irq_enable(); \ 66 - tsk->thread.error_code = error_code; \ 67 - tsk->thread.trap_no = trapnr; \ 68 - CHK_REMOTE_DEBUG(&regs); \ 69 - force_sig(signr, tsk); \ 70 - die_if_no_fixup(str,&regs,error_code); \ 71 - } 72 47 73 48 #ifdef CONFIG_CPU_SH2 74 49 #define TRAP_RESERVED_INST 4 ··· 550 575 #define is_dsp_inst(regs) (0) 551 576 #endif /* CONFIG_SH_DSP */ 552 577 553 - DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current) 554 - DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current) 578 + extern int do_fpu_inst(unsigned short, struct pt_regs*); 579 + 580 + asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, 581 + unsigned long r6, unsigned long r7, 582 + struct pt_regs regs) 583 + { 584 + unsigned long error_code; 585 + struct task_struct *tsk = current; 586 + 587 + #ifdef CONFIG_SH_FPU_EMU 588 + unsigned short inst; 589 + int err; 590 + 591 + get_user(inst, (unsigned short*)regs.pc); 592 + 593 + err = do_fpu_inst(inst, &regs); 594 + if (!err) { 595 + regs.pc += 2; 596 + return; 597 + } 598 + /* not a FPU inst. */ 599 + #endif 600 + 601 + #ifdef CONFIG_SH_DSP 602 + /* Check if it's a DSP instruction */ 603 + if (is_dsp_inst(&regs)) { 604 + /* Enable DSP mode, and restart instruction. */ 605 + regs.sr |= SR_DSP; 606 + return; 607 + } 608 + #endif 609 + 610 + asm volatile("stc r2_bank, %0": "=r" (error_code)); 611 + local_irq_enable(); 612 + tsk->thread.error_code = error_code; 613 + tsk->thread.trap_no = TRAP_RESERVED_INST; 614 + CHK_REMOTE_DEBUG(&regs); 615 + force_sig(SIGILL, tsk); 616 + die_if_no_fixup("reserved instruction", &regs, error_code); 617 + } 618 + 619 + #ifdef CONFIG_SH_FPU_EMU 620 + static int emulate_branch(unsigned short inst, struct pt_regs* regs) 621 + { 622 + /* 623 + * bfs: 8fxx: PC+=d*2+4; 624 + * bts: 8dxx: PC+=d*2+4; 625 + * bra: axxx: PC+=D*2+4; 626 + * bsr: bxxx: PC+=D*2+4 after PR=PC+4; 627 + * braf:0x23: PC+=Rn*2+4; 628 + * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4; 629 + * jmp: 4x2b: PC=Rn; 630 + * jsr: 4x0b: PC=Rn after PR=PC+4; 631 + * rts: 000b: PC=PR; 632 + */ 633 + if ((inst & 0xfd00) == 0x8d00) { 634 + regs->pc += SH_PC_8BIT_OFFSET(inst); 635 + return 0; 636 + } 637 + 638 + if ((inst & 0xe000) == 0xa000) { 639 + regs->pc += SH_PC_12BIT_OFFSET(inst); 640 + return 0; 641 + } 642 + 643 + if ((inst & 0xf0df) == 0x0003) { 644 + regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4; 645 + return 0; 646 + } 647 + 648 + if ((inst & 0xf0df) == 0x400b) { 649 + regs->pc = regs->regs[(inst & 0x0f00) >> 8]; 650 + return 0; 651 + } 652 + 653 + if ((inst & 0xffff) == 0x000b) { 654 + regs->pc = regs->pr; 655 + return 0; 656 + } 657 + 658 + return 1; 659 + } 660 + #endif 661 + 662 + asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, 663 + unsigned long r6, unsigned long r7, 664 + struct pt_regs regs) 665 + { 666 + unsigned long error_code; 667 + struct task_struct *tsk = current; 668 + #ifdef CONFIG_SH_FPU_EMU 669 + unsigned short inst; 670 + 671 + get_user(inst, (unsigned short *)regs.pc + 1); 672 + if (!do_fpu_inst(inst, &regs)) { 673 + get_user(inst, (unsigned short *)regs.pc); 674 + if (!emulate_branch(inst, &regs)) 675 + return; 676 + /* fault in branch.*/ 677 + } 678 + /* not a FPU inst. */ 679 + #endif 680 + 681 + asm volatile("stc r2_bank, %0": "=r" (error_code)); 682 + local_irq_enable(); 683 + tsk->thread.error_code = error_code; 684 + tsk->thread.trap_no = TRAP_RESERVED_INST; 685 + CHK_REMOTE_DEBUG(&regs); 686 + force_sig(SIGILL, tsk); 687 + die_if_no_fixup("illegal slot instruction", &regs, error_code); 688 + } 555 689 556 690 asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, 557 691 unsigned long r6, unsigned long r7, ··· 718 634 exception_handling_table[TRAP_ILLEGAL_SLOT_INST] 719 635 = (void *)do_illegal_slot_inst; 720 636 721 - #ifdef CONFIG_CPU_SH4 722 - if (!(cpu_data->flags & CPU_HAS_FPU)) { 723 - /* For SH-4 lacking an FPU, treat floating point instructions 724 - as reserved. */ 725 - /* entry 64 corresponds to EXPEVT=0x800 */ 726 - exception_handling_table[64] = (void *)do_reserved_inst; 727 - exception_handling_table[65] = (void *)do_illegal_slot_inst; 728 - } 637 + #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \ 638 + defined(CONFIG_SH_FPU_EMU) 639 + /* 640 + * For SH-4 lacking an FPU, treat floating point instructions as 641 + * reserved. They'll be handled in the math-emu case, or faulted on 642 + * otherwise. 643 + */ 644 + /* entry 64 corresponds to EXPEVT=0x800 */ 645 + exception_handling_table[64] = (void *)do_reserved_inst; 646 + exception_handling_table[65] = (void *)do_illegal_slot_inst; 729 647 #endif 730 648 731 649 /* Setup VBR for boot cpu */
+1
arch/sh/math-emu/Makefile
··· 1 + obj-y := math.o
+624
arch/sh/math-emu/math.c
··· 1 + /* 2 + * arch/sh/math-emu/math.c 3 + * 4 + * Copyright (C) 2006 Takashi YOSHII <takasi-y@ops.dti.ne.jp> 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + */ 10 + #include <linux/config.h> 11 + #include <linux/kernel.h> 12 + #include <linux/errno.h> 13 + #include <linux/types.h> 14 + #include <linux/sched.h> 15 + #include <linux/signal.h> 16 + 17 + #include <asm/system.h> 18 + #include <asm/uaccess.h> 19 + #include <asm/processor.h> 20 + #include <asm/io.h> 21 + 22 + #include "sfp-util.h" 23 + #include <math-emu/soft-fp.h> 24 + #include <math-emu/single.h> 25 + #include <math-emu/double.h> 26 + 27 + #define FPUL (fregs->fpul) 28 + #define FPSCR (fregs->fpscr) 29 + #define FPSCR_RM (FPSCR&3) 30 + #define FPSCR_DN ((FPSCR>>18)&1) 31 + #define FPSCR_PR ((FPSCR>>19)&1) 32 + #define FPSCR_SZ ((FPSCR>>20)&1) 33 + #define FPSCR_FR ((FPSCR>>21)&1) 34 + #define FPSCR_MASK 0x003fffffUL 35 + 36 + #define BANK(n) (n^(FPSCR_FR?16:0)) 37 + #define FR ((unsigned long*)(fregs->fp_regs)) 38 + #define FR0 (FR[BANK(0)]) 39 + #define FRn (FR[BANK(n)]) 40 + #define FRm (FR[BANK(m)]) 41 + #define DR ((unsigned long long*)(fregs->fp_regs)) 42 + #define DRn (DR[BANK(n)/2]) 43 + #define DRm (DR[BANK(m)/2]) 44 + 45 + #define XREG(n) (n^16) 46 + #define XFn (FR[BANK(XREG(n))]) 47 + #define XFm (FR[BANK(XREG(m))]) 48 + #define XDn (DR[BANK(XREG(n))/2]) 49 + #define XDm (DR[BANK(XREG(m))/2]) 50 + 51 + #define R0 (regs->regs[0]) 52 + #define Rn (regs->regs[n]) 53 + #define Rm (regs->regs[m]) 54 + 55 + #define WRITE(d,a) ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;}) 56 + #define READ(d,a) ({if(get_user(d, (typeof (d)*)a)) return -EFAULT;}) 57 + 58 + #define PACK_S(r,f) FP_PACK_SP(&r,f) 59 + #define UNPACK_S(f,r) FP_UNPACK_SP(f,&r) 60 + #define PACK_D(r,f) \ 61 + {u32 t[2]; FP_PACK_DP(t,f); ((u32*)&r)[0]=t[1]; ((u32*)&r)[1]=t[0];} 62 + #define UNPACK_D(f,r) \ 63 + {u32 t[2]; t[0]=((u32*)&r)[1]; t[1]=((u32*)&r)[0]; FP_UNPACK_DP(f,t);} 64 + 65 + // 2 args instructions. 66 + #define BOTH_PRmn(op,x) \ 67 + FP_DECL_EX; if(FPSCR_PR) op(D,x,DRm,DRn); else op(S,x,FRm,FRn); 68 + 69 + #define CMP_X(SZ,R,M,N) do{ \ 70 + FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \ 71 + UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \ 72 + FP_CMP_##SZ(R, Fn, Fm, 2); }while(0) 73 + #define EQ_X(SZ,R,M,N) do{ \ 74 + FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \ 75 + UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \ 76 + FP_CMP_EQ_##SZ(R, Fn, Fm); }while(0) 77 + #define CMP(OP) ({ int r; BOTH_PRmn(OP##_X,r); r; }) 78 + 79 + static int 80 + fcmp_gt(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 81 + { 82 + if (CMP(CMP) > 0) 83 + regs->sr |= 1; 84 + else 85 + regs->sr &= ~1; 86 + 87 + return 0; 88 + } 89 + 90 + static int 91 + fcmp_eq(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 92 + { 93 + if (CMP(CMP /*EQ*/) == 0) 94 + regs->sr |= 1; 95 + else 96 + regs->sr &= ~1; 97 + return 0; 98 + } 99 + 100 + #define ARITH_X(SZ,OP,M,N) do{ \ 101 + FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); FP_DECL_##SZ(Fr); \ 102 + UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \ 103 + FP_##OP##_##SZ(Fr, Fn, Fm); \ 104 + PACK_##SZ(N, Fr); }while(0) 105 + 106 + static int 107 + fadd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 108 + { 109 + BOTH_PRmn(ARITH_X, ADD); 110 + return 0; 111 + } 112 + 113 + static int 114 + fsub(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 115 + { 116 + BOTH_PRmn(ARITH_X, SUB); 117 + return 0; 118 + } 119 + 120 + static int 121 + fmul(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 122 + { 123 + BOTH_PRmn(ARITH_X, MUL); 124 + return 0; 125 + } 126 + 127 + static int 128 + fdiv(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 129 + { 130 + BOTH_PRmn(ARITH_X, DIV); 131 + return 0; 132 + } 133 + 134 + static int 135 + fmac(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 136 + { 137 + FP_DECL_EX; 138 + FP_DECL_S(Fr); 139 + FP_DECL_S(Ft); 140 + FP_DECL_S(F0); 141 + FP_DECL_S(Fm); 142 + FP_DECL_S(Fn); 143 + UNPACK_S(F0, FR0); 144 + UNPACK_S(Fm, FRm); 145 + UNPACK_S(Fn, FRn); 146 + FP_MUL_S(Ft, Fm, F0); 147 + FP_ADD_S(Fr, Fn, Ft); 148 + PACK_S(FRn, Fr); 149 + return 0; 150 + } 151 + 152 + // to process fmov's extention (odd n for DR access XD). 153 + #define FMOV_EXT(x) if(x&1) x+=16-1 154 + 155 + static int 156 + fmov_idx_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 157 + int n) 158 + { 159 + if (FPSCR_SZ) { 160 + FMOV_EXT(n); 161 + READ(FRn, Rm + R0 + 4); 162 + n++; 163 + READ(FRn, Rm + R0); 164 + } else { 165 + READ(FRn, Rm + R0); 166 + } 167 + 168 + return 0; 169 + } 170 + 171 + static int 172 + fmov_mem_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 173 + int n) 174 + { 175 + if (FPSCR_SZ) { 176 + FMOV_EXT(n); 177 + READ(FRn, Rm + 4); 178 + n++; 179 + READ(FRn, Rm); 180 + } else { 181 + READ(FRn, Rm); 182 + } 183 + 184 + return 0; 185 + } 186 + 187 + static int 188 + fmov_inc_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 189 + int n) 190 + { 191 + if (FPSCR_SZ) { 192 + FMOV_EXT(n); 193 + READ(FRn, Rm + 4); 194 + n++; 195 + READ(FRn, Rm); 196 + Rm += 8; 197 + } else { 198 + READ(FRn, Rm); 199 + Rm += 4; 200 + } 201 + 202 + return 0; 203 + } 204 + 205 + static int 206 + fmov_reg_idx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 207 + int n) 208 + { 209 + if (FPSCR_SZ) { 210 + FMOV_EXT(m); 211 + WRITE(FRm, Rn + R0 + 4); 212 + m++; 213 + WRITE(FRm, Rn + R0); 214 + } else { 215 + WRITE(FRm, Rn + R0); 216 + } 217 + 218 + return 0; 219 + } 220 + 221 + static int 222 + fmov_reg_mem(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 223 + int n) 224 + { 225 + if (FPSCR_SZ) { 226 + FMOV_EXT(m); 227 + WRITE(FRm, Rn + 4); 228 + m++; 229 + WRITE(FRm, Rn); 230 + } else { 231 + WRITE(FRm, Rn); 232 + } 233 + 234 + return 0; 235 + } 236 + 237 + static int 238 + fmov_reg_dec(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 239 + int n) 240 + { 241 + if (FPSCR_SZ) { 242 + FMOV_EXT(m); 243 + Rn -= 8; 244 + WRITE(FRm, Rn + 4); 245 + m++; 246 + WRITE(FRm, Rn); 247 + } else { 248 + Rn -= 4; 249 + WRITE(FRm, Rn); 250 + } 251 + 252 + return 0; 253 + } 254 + 255 + static int 256 + fmov_reg_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, 257 + int n) 258 + { 259 + if (FPSCR_SZ) { 260 + FMOV_EXT(m); 261 + FMOV_EXT(n); 262 + DRn = DRm; 263 + } else { 264 + FRn = FRm; 265 + } 266 + 267 + return 0; 268 + } 269 + 270 + static int 271 + fnop_mn(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) 272 + { 273 + return -EINVAL; 274 + } 275 + 276 + // 1 arg instructions. 277 + #define NOTYETn(i) static int i(struct sh_fpu_soft_struct *fregs, int n) \ 278 + { printk( #i " not yet done.\n"); return 0; } 279 + 280 + NOTYETn(ftrv) 281 + NOTYETn(fsqrt) 282 + NOTYETn(fipr) 283 + NOTYETn(fsca) 284 + NOTYETn(fsrra) 285 + 286 + #define EMU_FLOAT_X(SZ,N) do { \ 287 + FP_DECL_##SZ(Fn); \ 288 + FP_FROM_INT_##SZ(Fn, FPUL, 32, int); \ 289 + PACK_##SZ(N, Fn); }while(0) 290 + static int ffloat(struct sh_fpu_soft_struct *fregs, int n) 291 + { 292 + FP_DECL_EX; 293 + 294 + if (FPSCR_PR) 295 + EMU_FLOAT_X(D, DRn); 296 + else 297 + EMU_FLOAT_X(S, FRn); 298 + 299 + return 0; 300 + } 301 + 302 + #define EMU_FTRC_X(SZ,N) do { \ 303 + FP_DECL_##SZ(Fn); \ 304 + UNPACK_##SZ(Fn, N); \ 305 + FP_TO_INT_##SZ(FPUL, Fn, 32, 1); }while(0) 306 + static int ftrc(struct sh_fpu_soft_struct *fregs, int n) 307 + { 308 + FP_DECL_EX; 309 + 310 + if (FPSCR_PR) 311 + EMU_FTRC_X(D, DRn); 312 + else 313 + EMU_FTRC_X(S, FRn); 314 + 315 + return 0; 316 + } 317 + 318 + static int fcnvsd(struct sh_fpu_soft_struct *fregs, int n) 319 + { 320 + FP_DECL_EX; 321 + FP_DECL_S(Fn); 322 + FP_DECL_D(Fr); 323 + UNPACK_S(Fn, FPUL); 324 + FP_CONV(D, S, 2, 1, Fr, Fn); 325 + PACK_D(DRn, Fr); 326 + return 0; 327 + } 328 + 329 + static int fcnvds(struct sh_fpu_soft_struct *fregs, int n) 330 + { 331 + FP_DECL_EX; 332 + FP_DECL_D(Fn); 333 + FP_DECL_S(Fr); 334 + UNPACK_D(Fn, DRn); 335 + FP_CONV(S, D, 1, 2, Fr, Fn); 336 + PACK_S(FPUL, Fr); 337 + return 0; 338 + } 339 + 340 + static int fxchg(struct sh_fpu_soft_struct *fregs, int flag) 341 + { 342 + FPSCR ^= flag; 343 + return 0; 344 + } 345 + 346 + static int fsts(struct sh_fpu_soft_struct *fregs, int n) 347 + { 348 + FRn = FPUL; 349 + return 0; 350 + } 351 + 352 + static int flds(struct sh_fpu_soft_struct *fregs, int n) 353 + { 354 + FPUL = FRn; 355 + return 0; 356 + } 357 + 358 + static int fneg(struct sh_fpu_soft_struct *fregs, int n) 359 + { 360 + FRn ^= (1 << (_FP_W_TYPE_SIZE - 1)); 361 + return 0; 362 + } 363 + 364 + static int fabs(struct sh_fpu_soft_struct *fregs, int n) 365 + { 366 + FRn &= ~(1 << (_FP_W_TYPE_SIZE - 1)); 367 + return 0; 368 + } 369 + 370 + static int fld0(struct sh_fpu_soft_struct *fregs, int n) 371 + { 372 + FRn = 0; 373 + return 0; 374 + } 375 + 376 + static int fld1(struct sh_fpu_soft_struct *fregs, int n) 377 + { 378 + FRn = (_FP_EXPBIAS_S << (_FP_FRACBITS_S - 1)); 379 + return 0; 380 + } 381 + 382 + static int fnop_n(struct sh_fpu_soft_struct *fregs, int n) 383 + { 384 + return -EINVAL; 385 + } 386 + 387 + /// Instruction decoders. 388 + 389 + static int id_fxfd(struct sh_fpu_soft_struct *, int); 390 + static int id_fnxd(struct sh_fpu_soft_struct *, struct pt_regs *, int, int); 391 + 392 + static int (*fnxd[])(struct sh_fpu_soft_struct *, int) = { 393 + fsts, flds, ffloat, ftrc, fneg, fabs, fsqrt, fsrra, 394 + fld0, fld1, fcnvsd, fcnvds, fnop_n, fnop_n, fipr, id_fxfd 395 + }; 396 + 397 + static int (*fnmx[])(struct sh_fpu_soft_struct *, struct pt_regs *, int, int) = { 398 + fadd, fsub, fmul, fdiv, fcmp_eq, fcmp_gt, fmov_idx_reg, fmov_reg_idx, 399 + fmov_mem_reg, fmov_inc_reg, fmov_reg_mem, fmov_reg_dec, 400 + fmov_reg_reg, id_fnxd, fmac, fnop_mn}; 401 + 402 + static int id_fxfd(struct sh_fpu_soft_struct *fregs, int x) 403 + { 404 + const int flag[] = { FPSCR_SZ, FPSCR_PR, FPSCR_FR, 0 }; 405 + switch (x & 3) { 406 + case 3: 407 + fxchg(fregs, flag[x >> 2]); 408 + break; 409 + case 1: 410 + ftrv(fregs, x - 1); 411 + break; 412 + default: 413 + fsca(fregs, x); 414 + } 415 + return 0; 416 + } 417 + 418 + static int 419 + id_fnxd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int x, int n) 420 + { 421 + return (fnxd[x])(fregs, n); 422 + } 423 + 424 + static int 425 + id_fnmx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code) 426 + { 427 + int n = (code >> 8) & 0xf, m = (code >> 4) & 0xf, x = code & 0xf; 428 + return (fnmx[x])(fregs, regs, m, n); 429 + } 430 + 431 + static int 432 + id_sys(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code) 433 + { 434 + int n = ((code >> 8) & 0xf); 435 + unsigned long *reg = (code & 0x0010) ? &FPUL : &FPSCR; 436 + 437 + switch (code & 0xf0ff) { 438 + case 0x005a: 439 + case 0x006a: 440 + Rn = *reg; 441 + break; 442 + case 0x405a: 443 + case 0x406a: 444 + *reg = Rn; 445 + break; 446 + case 0x4052: 447 + case 0x4062: 448 + Rn -= 4; 449 + WRITE(*reg, Rn); 450 + break; 451 + case 0x4056: 452 + case 0x4066: 453 + READ(*reg, Rn); 454 + Rn += 4; 455 + break; 456 + default: 457 + return -EINVAL; 458 + } 459 + 460 + return 0; 461 + } 462 + 463 + static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_regs *regs) 464 + { 465 + if ((code & 0xf000) == 0xf000) 466 + return id_fnmx(fregs, regs, code); 467 + else 468 + return id_sys(fregs, regs, code); 469 + } 470 + 471 + /** 472 + * denormal_to_double - Given denormalized float number, 473 + * store double float 474 + * 475 + * @fpu: Pointer to sh_fpu_hard structure 476 + * @n: Index to FP register 477 + */ 478 + static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n) 479 + { 480 + unsigned long du, dl; 481 + unsigned long x = fpu->fpul; 482 + int exp = 1023 - 126; 483 + 484 + if (x != 0 && (x & 0x7f800000) == 0) { 485 + du = (x & 0x80000000); 486 + while ((x & 0x00800000) == 0) { 487 + x <<= 1; 488 + exp--; 489 + } 490 + x &= 0x007fffff; 491 + du |= (exp << 20) | (x >> 3); 492 + dl = x << 29; 493 + 494 + fpu->fp_regs[n] = du; 495 + fpu->fp_regs[n+1] = dl; 496 + } 497 + } 498 + 499 + /** 500 + * ieee_fpe_handler - Handle denormalized number exception 501 + * 502 + * @regs: Pointer to register structure 503 + * 504 + * Returns 1 when it's handled (should not cause exception). 505 + */ 506 + static int ieee_fpe_handler(struct pt_regs *regs) 507 + { 508 + unsigned short insn = *(unsigned short *)regs->pc; 509 + unsigned short finsn; 510 + unsigned long nextpc; 511 + int nib[4] = { 512 + (insn >> 12) & 0xf, 513 + (insn >> 8) & 0xf, 514 + (insn >> 4) & 0xf, 515 + insn & 0xf}; 516 + 517 + if (nib[0] == 0xb || 518 + (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ 519 + regs->pr = regs->pc + 4; 520 + 521 + if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */ 522 + nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); 523 + finsn = *(unsigned short *) (regs->pc + 2); 524 + } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */ 525 + if (regs->sr & 1) 526 + nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); 527 + else 528 + nextpc = regs->pc + 4; 529 + finsn = *(unsigned short *) (regs->pc + 2); 530 + } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */ 531 + if (regs->sr & 1) 532 + nextpc = regs->pc + 4; 533 + else 534 + nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); 535 + finsn = *(unsigned short *) (regs->pc + 2); 536 + } else if (nib[0] == 0x4 && nib[3] == 0xb && 537 + (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */ 538 + nextpc = regs->regs[nib[1]]; 539 + finsn = *(unsigned short *) (regs->pc + 2); 540 + } else if (nib[0] == 0x0 && nib[3] == 0x3 && 541 + (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */ 542 + nextpc = regs->pc + 4 + regs->regs[nib[1]]; 543 + finsn = *(unsigned short *) (regs->pc + 2); 544 + } else if (insn == 0x000b) { /* rts */ 545 + nextpc = regs->pr; 546 + finsn = *(unsigned short *) (regs->pc + 2); 547 + } else { 548 + nextpc = regs->pc + 2; 549 + finsn = insn; 550 + } 551 + 552 + if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ 553 + struct task_struct *tsk = current; 554 + 555 + if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) { 556 + /* FPU error */ 557 + denormal_to_double (&tsk->thread.fpu.hard, 558 + (finsn >> 8) & 0xf); 559 + tsk->thread.fpu.hard.fpscr &= 560 + ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); 561 + set_tsk_thread_flag(tsk, TIF_USEDFPU); 562 + } else { 563 + tsk->thread.trap_no = 11; 564 + tsk->thread.error_code = 0; 565 + force_sig(SIGFPE, tsk); 566 + } 567 + 568 + regs->pc = nextpc; 569 + return 1; 570 + } 571 + 572 + return 0; 573 + } 574 + 575 + asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5, 576 + unsigned long r6, unsigned long r7, 577 + struct pt_regs regs) 578 + { 579 + struct task_struct *tsk = current; 580 + 581 + if (ieee_fpe_handler (&regs)) 582 + return; 583 + 584 + regs.pc += 2; 585 + tsk->thread.trap_no = 11; 586 + tsk->thread.error_code = 0; 587 + force_sig(SIGFPE, tsk); 588 + } 589 + 590 + /** 591 + * fpu_init - Initialize FPU registers 592 + * @fpu: Pointer to software emulated FPU registers. 593 + */ 594 + static void fpu_init(struct sh_fpu_soft_struct *fpu) 595 + { 596 + int i; 597 + 598 + fpu->fpscr = FPSCR_INIT; 599 + fpu->fpul = 0; 600 + 601 + for (i = 0; i < 16; i++) { 602 + fpu->fp_regs[i] = 0; 603 + fpu->xfp_regs[i]= 0; 604 + } 605 + } 606 + 607 + /** 608 + * do_fpu_inst - Handle reserved instructions for FPU emulation 609 + * @inst: instruction code. 610 + * @regs: registers on stack. 611 + */ 612 + int do_fpu_inst(unsigned short inst, struct pt_regs *regs) 613 + { 614 + struct task_struct *tsk = current; 615 + struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft); 616 + 617 + if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) { 618 + /* initialize once. */ 619 + fpu_init(fpu); 620 + set_tsk_thread_flag(tsk, TIF_USEDFPU); 621 + } 622 + 623 + return fpu_emulate(inst, fpu, regs); 624 + }
+72
arch/sh/math-emu/sfp-util.h
··· 1 + /* 2 + * These are copied from glibc/stdlib/longlong.h 3 + */ 4 + 5 + #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ 6 + do { \ 7 + UWtype __x; \ 8 + __x = (al) + (bl); \ 9 + (sh) = (ah) + (bh) + (__x < (al)); \ 10 + (sl) = __x; \ 11 + } while (0) 12 + 13 + #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ 14 + do { \ 15 + UWtype __x; \ 16 + __x = (al) - (bl); \ 17 + (sh) = (ah) - (bh) - (__x > (al)); \ 18 + (sl) = __x; \ 19 + } while (0) 20 + 21 + #define umul_ppmm(w1, w0, u, v) \ 22 + __asm__ ("dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \ 23 + : "=r" ((u32)(w1)), "=r" ((u32)(w0)) \ 24 + : "r" ((u32)(u)), "r" ((u32)(v)) \ 25 + : "macl", "mach") 26 + 27 + #define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) 28 + #define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) 29 + #define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) 30 + 31 + #define udiv_qrnnd(q, r, n1, n0, d) \ 32 + do { \ 33 + UWtype __d1, __d0, __q1, __q0; \ 34 + UWtype __r1, __r0, __m; \ 35 + __d1 = __ll_highpart (d); \ 36 + __d0 = __ll_lowpart (d); \ 37 + \ 38 + __r1 = (n1) % __d1; \ 39 + __q1 = (n1) / __d1; \ 40 + __m = (UWtype) __q1 * __d0; \ 41 + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ 42 + if (__r1 < __m) \ 43 + { \ 44 + __q1--, __r1 += (d); \ 45 + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ 46 + if (__r1 < __m) \ 47 + __q1--, __r1 += (d); \ 48 + } \ 49 + __r1 -= __m; \ 50 + \ 51 + __r0 = __r1 % __d1; \ 52 + __q0 = __r1 / __d1; \ 53 + __m = (UWtype) __q0 * __d0; \ 54 + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ 55 + if (__r0 < __m) \ 56 + { \ 57 + __q0--, __r0 += (d); \ 58 + if (__r0 >= (d)) \ 59 + if (__r0 < __m) \ 60 + __q0--, __r0 += (d); \ 61 + } \ 62 + __r0 -= __m; \ 63 + \ 64 + (q) = (UWtype) __q1 * __ll_B | __q0; \ 65 + (r) = __r0; \ 66 + } while (0) 67 + 68 + #define abort() return 0 69 + 70 + #define __BYTE_ORDER __LITTLE_ENDIAN 71 + 72 +
+86
include/asm-sh/sfp-machine.h
··· 1 + /* Machine-dependent software floating-point definitions. 2 + SuperH kernel version. 3 + Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. 4 + This file is part of the GNU C Library. 5 + Contributed by Richard Henderson (rth@cygnus.com), 6 + Jakub Jelinek (jj@ultra.linux.cz), 7 + David S. Miller (davem@redhat.com) and 8 + Peter Maydell (pmaydell@chiark.greenend.org.uk). 9 + 10 + The GNU C Library is free software; you can redistribute it and/or 11 + modify it under the terms of the GNU Library General Public License as 12 + published by the Free Software Foundation; either version 2 of the 13 + License, or (at your option) any later version. 14 + 15 + The GNU C Library is distributed in the hope that it will be useful, 16 + but WITHOUT ANY WARRANTY; without even the implied warranty of 17 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 + Library General Public License for more details. 19 + 20 + You should have received a copy of the GNU Library General Public 21 + License along with the GNU C Library; see the file COPYING.LIB. If 22 + not, write to the Free Software Foundation, Inc., 23 + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 24 + 25 + #ifndef _SFP_MACHINE_H 26 + #define _SFP_MACHINE_H 27 + 28 + #include <linux/config.h> 29 + 30 + #define _FP_W_TYPE_SIZE 32 31 + #define _FP_W_TYPE unsigned long 32 + #define _FP_WS_TYPE signed long 33 + #define _FP_I_TYPE long 34 + 35 + #define _FP_MUL_MEAT_S(R,X,Y) \ 36 + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) 37 + #define _FP_MUL_MEAT_D(R,X,Y) \ 38 + _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) 39 + #define _FP_MUL_MEAT_Q(R,X,Y) \ 40 + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) 41 + 42 + #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) 43 + #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) 44 + #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) 45 + 46 + #define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) 47 + #define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 48 + #define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 49 + #define _FP_NANSIGN_S 0 50 + #define _FP_NANSIGN_D 0 51 + #define _FP_NANSIGN_Q 0 52 + 53 + #define _FP_KEEPNANFRACP 1 54 + 55 + /* 56 + * If one NaN is signaling and the other is not, 57 + * we choose that one, otherwise we choose X. 58 + */ 59 + #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ 60 + do { \ 61 + if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ 62 + && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \ 63 + { \ 64 + R##_s = Y##_s; \ 65 + _FP_FRAC_COPY_##wc(R,Y); \ 66 + } \ 67 + else \ 68 + { \ 69 + R##_s = X##_s; \ 70 + _FP_FRAC_COPY_##wc(R,X); \ 71 + } \ 72 + R##_c = FP_CLS_NAN; \ 73 + } while (0) 74 + 75 + //#define FP_ROUNDMODE FPSCR_RM 76 + #define FP_DENORM_ZERO 1/*FPSCR_DN*/ 77 + 78 + /* Exception flags. */ 79 + #define FP_EX_INVALID (1<<4) 80 + #define FP_EX_DIVZERO (1<<3) 81 + #define FP_EX_OVERFLOW (1<<2) 82 + #define FP_EX_UNDERFLOW (1<<1) 83 + #define FP_EX_INEXACT (1<<0) 84 + 85 + #endif 86 +