Skip to content

Commit 4b56568

Browse files
Takashi YOSHIIpmundt
authored andcommitted
sh: math-emu support
This implements initial math-emu support, aimed primarily at SH-3. Signed-off-by: Takashi YOSHII <[email protected]> Signed-off-by: Paul Mundt <[email protected]>
1 parent 317a610 commit 4b56568

File tree

7 files changed

+918
-39
lines changed

7 files changed

+918
-39
lines changed

arch/sh/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ config SH_FPU
339339

340340
This option must be set in order to enable the FPU.
341341

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+
342351
config SH_DSP
343352
bool "DSP support"
344353
depends on !CPU_SH4

arch/sh/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
7979
LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
8080

8181
core-y += arch/sh/kernel/ arch/sh/mm/
82+
core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
8283

8384
# Boards
8485
machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x

arch/sh/kernel/traps.c

Lines changed: 125 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,40 +36,15 @@
3636

3737
#ifdef CONFIG_SH_KGDB
3838
#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); \
4543
}
4644
#else
4745
#define CHK_REMOTE_DEBUG(regs)
4846
#endif
4947

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-
7348
#ifdef CONFIG_CPU_SH2
7449
#define TRAP_RESERVED_INST 4
7550
#define TRAP_ILLEGAL_SLOT_INST 6
@@ -575,8 +550,117 @@ int is_dsp_inst(struct pt_regs *regs)
575550
#define is_dsp_inst(regs) (0)
576551
#endif /* CONFIG_SH_DSP */
577552

578-
DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current)
579-
DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
553+
extern int do_fpu_inst(unsigned short, struct pt_regs*);
554+
555+
asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
556+
unsigned long r6, unsigned long r7,
557+
struct pt_regs regs)
558+
{
559+
unsigned long error_code;
560+
struct task_struct *tsk = current;
561+
562+
#ifdef CONFIG_SH_FPU_EMU
563+
unsigned short inst;
564+
int err;
565+
566+
get_user(inst, (unsigned short*)regs.pc);
567+
568+
err = do_fpu_inst(inst, &regs);
569+
if (!err) {
570+
regs.pc += 2;
571+
return;
572+
}
573+
/* not a FPU inst. */
574+
#endif
575+
576+
#ifdef CONFIG_SH_DSP
577+
/* Check if it's a DSP instruction */
578+
if (is_dsp_inst(&regs)) {
579+
/* Enable DSP mode, and restart instruction. */
580+
regs.sr |= SR_DSP;
581+
return;
582+
}
583+
#endif
584+
585+
asm volatile("stc r2_bank, %0": "=r" (error_code));
586+
local_irq_enable();
587+
tsk->thread.error_code = error_code;
588+
tsk->thread.trap_no = TRAP_RESERVED_INST;
589+
CHK_REMOTE_DEBUG(&regs);
590+
force_sig(SIGILL, tsk);
591+
die_if_no_fixup("reserved instruction", &regs, error_code);
592+
}
593+
594+
#ifdef CONFIG_SH_FPU_EMU
595+
static int emulate_branch(unsigned short inst, struct pt_regs* regs)
596+
{
597+
/*
598+
* bfs: 8fxx: PC+=d*2+4;
599+
* bts: 8dxx: PC+=d*2+4;
600+
* bra: axxx: PC+=D*2+4;
601+
* bsr: bxxx: PC+=D*2+4 after PR=PC+4;
602+
* braf:0x23: PC+=Rn*2+4;
603+
* bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
604+
* jmp: 4x2b: PC=Rn;
605+
* jsr: 4x0b: PC=Rn after PR=PC+4;
606+
* rts: 000b: PC=PR;
607+
*/
608+
if ((inst & 0xfd00) == 0x8d00) {
609+
regs->pc += SH_PC_8BIT_OFFSET(inst);
610+
return 0;
611+
}
612+
613+
if ((inst & 0xe000) == 0xa000) {
614+
regs->pc += SH_PC_12BIT_OFFSET(inst);
615+
return 0;
616+
}
617+
618+
if ((inst & 0xf0df) == 0x0003) {
619+
regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
620+
return 0;
621+
}
622+
623+
if ((inst & 0xf0df) == 0x400b) {
624+
regs->pc = regs->regs[(inst & 0x0f00) >> 8];
625+
return 0;
626+
}
627+
628+
if ((inst & 0xffff) == 0x000b) {
629+
regs->pc = regs->pr;
630+
return 0;
631+
}
632+
633+
return 1;
634+
}
635+
#endif
636+
637+
asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
638+
unsigned long r6, unsigned long r7,
639+
struct pt_regs regs)
640+
{
641+
unsigned long error_code;
642+
struct task_struct *tsk = current;
643+
#ifdef CONFIG_SH_FPU_EMU
644+
unsigned short inst;
645+
646+
get_user(inst, (unsigned short *)regs.pc + 1);
647+
if (!do_fpu_inst(inst, &regs)) {
648+
get_user(inst, (unsigned short *)regs.pc);
649+
if (!emulate_branch(inst, &regs))
650+
return;
651+
/* fault in branch.*/
652+
}
653+
/* not a FPU inst. */
654+
#endif
655+
656+
asm volatile("stc r2_bank, %0": "=r" (error_code));
657+
local_irq_enable();
658+
tsk->thread.error_code = error_code;
659+
tsk->thread.trap_no = TRAP_RESERVED_INST;
660+
CHK_REMOTE_DEBUG(&regs);
661+
force_sig(SIGILL, tsk);
662+
die_if_no_fixup("illegal slot instruction", &regs, error_code);
663+
}
580664

581665
asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
582666
unsigned long r6, unsigned long r7,
@@ -634,14 +718,16 @@ void __init trap_init(void)
634718
exception_handling_table[TRAP_ILLEGAL_SLOT_INST]
635719
= (void *)do_illegal_slot_inst;
636720

637-
#ifdef CONFIG_CPU_SH4
638-
if (!(cpu_data->flags & CPU_HAS_FPU)) {
639-
/* For SH-4 lacking an FPU, treat floating point instructions
640-
as reserved. */
641-
/* entry 64 corresponds to EXPEVT=0x800 */
642-
exception_handling_table[64] = (void *)do_reserved_inst;
643-
exception_handling_table[65] = (void *)do_illegal_slot_inst;
644-
}
721+
#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
722+
defined(CONFIG_SH_FPU_EMU)
723+
/*
724+
* For SH-4 lacking an FPU, treat floating point instructions as
725+
* reserved. They'll be handled in the math-emu case, or faulted on
726+
* otherwise.
727+
*/
728+
/* entry 64 corresponds to EXPEVT=0x800 */
729+
exception_handling_table[64] = (void *)do_reserved_inst;
730+
exception_handling_table[65] = (void *)do_illegal_slot_inst;
645731
#endif
646732

647733
/* Setup VBR for boot cpu */

arch/sh/math-emu/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-y := math.o

0 commit comments

Comments
 (0)