linux/arch/m68k/include/asm/math-emu.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_M68K_SETUP_H
   3#define _ASM_M68K_SETUP_H
   4
   5#include <asm/setup.h>
   6#include <linux/linkage.h>
   7
   8/* Status Register bits */
   9
  10/* accrued exception bits */
  11#define FPSR_AEXC_INEX  3
  12#define FPSR_AEXC_DZ    4
  13#define FPSR_AEXC_UNFL  5
  14#define FPSR_AEXC_OVFL  6
  15#define FPSR_AEXC_IOP   7
  16
  17/* exception status bits */
  18#define FPSR_EXC_INEX1  8
  19#define FPSR_EXC_INEX2  9
  20#define FPSR_EXC_DZ     10
  21#define FPSR_EXC_UNFL   11
  22#define FPSR_EXC_OVFL   12
  23#define FPSR_EXC_OPERR  13
  24#define FPSR_EXC_SNAN   14
  25#define FPSR_EXC_BSUN   15
  26
  27/* quotient byte, assumes big-endian, of course */
  28#define FPSR_QUOTIENT(fpsr) (*((signed char *) &(fpsr) + 1))
  29
  30/* condition code bits */
  31#define FPSR_CC_NAN     24
  32#define FPSR_CC_INF     25
  33#define FPSR_CC_Z       26
  34#define FPSR_CC_NEG     27
  35
  36
  37/* Control register bits */
  38
  39/* rounding mode */
  40#define FPCR_ROUND_RN   0               /* round to nearest/even */
  41#define FPCR_ROUND_RZ   1               /* round to zero */
  42#define FPCR_ROUND_RM   2               /* minus infinity */
  43#define FPCR_ROUND_RP   3               /* plus infinity */
  44
  45/* rounding precision */
  46#define FPCR_PRECISION_X        0       /* long double */
  47#define FPCR_PRECISION_S        1       /* double */
  48#define FPCR_PRECISION_D        2       /* float */
  49
  50
  51/* Flags to select the debugging output */
  52#define PDECODE         0
  53#define PEXECUTE        1
  54#define PCONV           2
  55#define PNORM           3
  56#define PREGISTER       4
  57#define PINSTR          5
  58#define PUNIMPL         6
  59#define PMOVEM          7
  60
  61#define PMDECODE        (1<<PDECODE)
  62#define PMEXECUTE       (1<<PEXECUTE)
  63#define PMCONV          (1<<PCONV)
  64#define PMNORM          (1<<PNORM)
  65#define PMREGISTER      (1<<PREGISTER)
  66#define PMINSTR         (1<<PINSTR)
  67#define PMUNIMPL        (1<<PUNIMPL)
  68#define PMMOVEM         (1<<PMOVEM)
  69
  70#ifndef __ASSEMBLY__
  71
  72#include <linux/kernel.h>
  73#include <linux/sched.h>
  74
  75union fp_mant64 {
  76        unsigned long long m64;
  77        unsigned long m32[2];
  78};
  79
  80union fp_mant128 {
  81        unsigned long long m64[2];
  82        unsigned long m32[4];
  83};
  84
  85/* internal representation of extended fp numbers */
  86struct fp_ext {
  87        unsigned char lowmant;
  88        unsigned char sign;
  89        unsigned short exp;
  90        union fp_mant64 mant;
  91};
  92
  93/* C representation of FPU registers */
  94/* NOTE: if you change this, you have to change the assembler offsets
  95   below and the size in <asm/fpu.h>, too */
  96struct fp_data {
  97        struct fp_ext fpreg[8];
  98        unsigned int fpcr;
  99        unsigned int fpsr;
 100        unsigned int fpiar;
 101        unsigned short prec;
 102        unsigned short rnd;
 103        struct fp_ext temp[2];
 104};
 105
 106#ifdef FPU_EMU_DEBUG
 107extern unsigned int fp_debugprint;
 108
 109#define dprint(bit, fmt, ...) ({                        \
 110        if (fp_debugprint & (1 << (bit)))               \
 111                pr_info(fmt, ##__VA_ARGS__);            \
 112})
 113#else
 114#define dprint(bit, fmt, ...)   no_printk(fmt, ##__VA_ARGS__)
 115#endif
 116
 117#define uprint(str) ({                                  \
 118        static int __count = 3;                         \
 119                                                        \
 120        if (__count > 0) {                              \
 121                pr_err("You just hit an unimplemented " \
 122                       "fpu instruction (%s)\n", str);  \
 123                pr_err("Please report this to ....\n"); \
 124                __count--;                              \
 125        }                                               \
 126})
 127
 128#define FPDATA          ((struct fp_data *)current->thread.fp)
 129
 130#else   /* __ASSEMBLY__ */
 131
 132#define FPDATA          %a2
 133
 134/* offsets from the base register to the floating point data in the task struct */
 135#define FPD_FPREG       (TASK_THREAD+THREAD_FPREG+0)
 136#define FPD_FPCR        (TASK_THREAD+THREAD_FPREG+96)
 137#define FPD_FPSR        (TASK_THREAD+THREAD_FPREG+100)
 138#define FPD_FPIAR       (TASK_THREAD+THREAD_FPREG+104)
 139#define FPD_PREC        (TASK_THREAD+THREAD_FPREG+108)
 140#define FPD_RND         (TASK_THREAD+THREAD_FPREG+110)
 141#define FPD_TEMPFP1     (TASK_THREAD+THREAD_FPREG+112)
 142#define FPD_TEMPFP2     (TASK_THREAD+THREAD_FPREG+124)
 143#define FPD_SIZEOF      (TASK_THREAD+THREAD_FPREG+136)
 144
 145/* offsets on the stack to access saved registers,
 146 * these are only used during instruction decoding
 147 * where we always know how deep we're on the stack.
 148 */
 149#define FPS_DO          (PT_OFF_D0)
 150#define FPS_D1          (PT_OFF_D1)
 151#define FPS_D2          (PT_OFF_D2)
 152#define FPS_A0          (PT_OFF_A0)
 153#define FPS_A1          (PT_OFF_A1)
 154#define FPS_A2          (PT_OFF_A2)
 155#define FPS_SR          (PT_OFF_SR)
 156#define FPS_PC          (PT_OFF_PC)
 157#define FPS_EA          (PT_OFF_PC+6)
 158#define FPS_PC2         (PT_OFF_PC+10)
 159
 160.macro  fp_get_fp_reg
 161        lea     (FPD_FPREG,FPDATA,%d0.w*4),%a0
 162        lea     (%a0,%d0.w*8),%a0
 163.endm
 164
 165/* Macros used to get/put the current program counter.
 166 * 020/030 use a different stack frame then 040/060, for the
 167 * 040/060 the return pc points already to the next location,
 168 * so this only needs to be modified for jump instructions.
 169 */
 170.macro  fp_get_pc dest
 171        move.l  (FPS_PC+4,%sp),\dest
 172.endm
 173
 174.macro  fp_put_pc src,jump=0
 175        move.l  \src,(FPS_PC+4,%sp)
 176.endm
 177
 178.macro  fp_get_instr_data       f,s,dest,label
 179        getuser \f,%sp@(FPS_PC+4)@(0),\dest,\label,%sp@(FPS_PC+4)
 180        addq.l  #\s,%sp@(FPS_PC+4)
 181.endm
 182
 183.macro  fp_get_instr_word       dest,label,addr
 184        fp_get_instr_data       w,2,\dest,\label,\addr
 185.endm
 186
 187.macro  fp_get_instr_long       dest,label,addr
 188        fp_get_instr_data       l,4,\dest,\label,\addr
 189.endm
 190
 191/* These macros are used to read from/write to user space
 192 * on error we jump to the fixup section, load the fault
 193 * address into %a0 and jump to the exit.
 194 * (derived from <asm/uaccess.h>)
 195 */
 196.macro  getuser size,src,dest,label,addr
 197|       printf  ,"[\size<%08x]",1,\addr
 198.Lu1\@: moves\size      \src,\dest
 199
 200        .section .fixup,"ax"
 201        .even
 202.Lu2\@: move.l  \addr,%a0
 203        jra     \label
 204        .previous
 205
 206        .section __ex_table,"a"
 207        .align  4
 208        .long   .Lu1\@,.Lu2\@
 209        .previous
 210.endm
 211
 212.macro  putuser size,src,dest,label,addr
 213|       printf  ,"[\size>%08x]",1,\addr
 214.Lu1\@: moves\size      \src,\dest
 215.Lu2\@:
 216
 217        .section .fixup,"ax"
 218        .even
 219.Lu3\@: move.l  \addr,%a0
 220        jra     \label
 221        .previous
 222
 223        .section __ex_table,"a"
 224        .align  4
 225        .long   .Lu1\@,.Lu3\@
 226        .long   .Lu2\@,.Lu3\@
 227        .previous
 228.endm
 229
 230/* work around binutils idiocy */
 231old_gas=-1
 232.irp    gas_ident.x .x
 233old_gas=old_gas+1
 234.endr
 235.if !old_gas
 236.irp    m b,w,l
 237.macro  getuser.\m src,dest,label,addr
 238        getuser .\m,\src,\dest,\label,\addr
 239.endm
 240.macro  putuser.\m src,dest,label,addr
 241        putuser .\m,\src,\dest,\label,\addr
 242.endm
 243.endr
 244.endif
 245
 246.macro  movestack       nr,arg1,arg2,arg3,arg4,arg5
 247        .if     \nr
 248        movestack       (\nr-1),\arg2,\arg3,\arg4,\arg5
 249        move.l  \arg1,-(%sp)
 250        .endif
 251.endm
 252
 253.macro  printf  bit=-1,string,nr=0,arg1,arg2,arg3,arg4,arg5
 254#ifdef FPU_EMU_DEBUG
 255        .data
 256.Lpdata\@:
 257        .string "\string"
 258        .previous
 259
 260        movem.l %d0/%d1/%a0/%a1,-(%sp)
 261        .if     \bit+1
 262#if 0
 263        moveq   #\bit,%d0
 264        andw    #7,%d0
 265        btst    %d0,fp_debugprint+((31-\bit)/8)
 266#else
 267        btst    #\bit,fp_debugprint+((31-\bit)/8)
 268#endif
 269        jeq     .Lpskip\@
 270        .endif
 271        movestack       \nr,\arg1,\arg2,\arg3,\arg4,\arg5
 272        pea     .Lpdata\@
 273        jsr     printk
 274        lea     ((\nr+1)*4,%sp),%sp
 275.Lpskip\@:
 276        movem.l (%sp)+,%d0/%d1/%a0/%a1
 277#endif
 278.endm
 279
 280.macro  printx  bit,fp
 281#ifdef FPU_EMU_DEBUG
 282        movem.l %d0/%a0,-(%sp)
 283        lea     \fp,%a0
 284#if 0
 285        moveq   #'+',%d0
 286        tst.w   (%a0)
 287        jeq     .Lx1\@
 288        moveq   #'-',%d0
 289.Lx1\@: printf  \bit," %c",1,%d0
 290        move.l  (4,%a0),%d0
 291        bclr    #31,%d0
 292        jne     .Lx2\@
 293        printf  \bit,"0."
 294        jra     .Lx3\@
 295.Lx2\@: printf  \bit,"1."
 296.Lx3\@: printf  \bit,"%08x%08x",2,%d0,%a0@(8)
 297        move.w  (2,%a0),%d0
 298        ext.l   %d0
 299        printf  \bit,"E%04x",1,%d0
 300#else
 301        printf  \bit," %08x%08x%08x",3,%a0@,%a0@(4),%a0@(8)
 302#endif
 303        movem.l (%sp)+,%d0/%a0
 304#endif
 305.endm
 306
 307.macro  debug   instr,args
 308#ifdef FPU_EMU_DEBUG
 309        \instr  \args
 310#endif
 311.endm
 312
 313
 314#endif  /* __ASSEMBLY__ */
 315
 316#endif  /* _ASM_M68K_SETUP_H */
 317