1// See LICENSE for license details. 2 3#ifndef _RISCV_FP_EMULATION_H 4#define _RISCV_FP_EMULATION_H 5 6#include "emulation.h" 7 8#define GET_PRECISION(insn) (((insn) >> 25) & 3) 9#define GET_RM(insn) (((insn) >> 12) & 7) 10#define PRECISION_S 0 11#define PRECISION_D 1 12 13#ifdef __riscv_flen 14# define GET_F32_REG(insn, pos, regs) ({ \ 15 register int32_t value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ 16 uintptr_t tmp; \ 17 asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ 18 value; }) 19# define SET_F32_REG(insn, pos, regs, val) ({ \ 20 register uint32_t value asm("a0") = (val); \ 21 uintptr_t offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ 22 uintptr_t tmp; \ 23 asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) 24# define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0) 25# define GET_F64_REG(insn, pos, regs) ({ \ 26 register uintptr_t value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ 27 uintptr_t tmp; \ 28 asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ 29 sizeof(uintptr_t) == 4 ? *(int64_t*)value : (int64_t)value; }) 30# define SET_F64_REG(insn, pos, regs, val) ({ \ 31 uint64_t __val = (val); \ 32 register uintptr_t value asm("a0") = sizeof(uintptr_t) == 4 ? (uintptr_t)&__val : (uintptr_t)__val; \ 33 uintptr_t offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ 34 uintptr_t tmp; \ 35 asm volatile ("1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) 36# define GET_FCSR() read_csr(fcsr) 37# define SET_FCSR(value) write_csr(fcsr, (value)) 38# define GET_FRM() read_csr(frm) 39# define SET_FRM(value) write_csr(frm, (value)) 40# define GET_FFLAGS() read_csr(fflags) 41# define SET_FFLAGS(value) write_csr(fflags, (value)) 42 43# define SETUP_STATIC_ROUNDING(insn) ({ \ 44 register long tp asm("tp") = read_csr(frm); \ 45 if (likely(((insn) & MASK_FUNCT3) == MASK_FUNCT3)) ; \ 46 else if (GET_RM(insn) > 4) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); \ 47 else tp = GET_RM(insn); \ 48 asm volatile ("":"+r"(tp)); }) 49# define softfloat_raiseFlags(which) set_csr(fflags, which) 50# define softfloat_roundingMode ({ register int tp asm("tp"); tp; }) 51# define SET_FS_DIRTY() ((void) 0) 52#else 53# define GET_F64_REG(insn, pos, regs) (*(int64_t*)((void*)((regs) + 32) + (SHIFT_RIGHT(insn, (pos)-3) & 0xf8))) 54# define SET_F64_REG(insn, pos, regs, val) (GET_F64_REG(insn, pos, regs) = (val)) 55# define GET_F32_REG(insn, pos, regs) (*(int32_t*)&GET_F64_REG(insn, pos, regs)) 56# define SET_F32_REG(insn, pos, regs, val) (GET_F32_REG(insn, pos, regs) = (val)) 57# define GET_FCSR() ({ register int tp asm("tp"); tp & 0xFF; }) 58# define SET_FCSR(value) ({ asm volatile("add tp, x0, %0" :: "rI"((value) & 0xFF)); SET_FS_DIRTY(); }) 59# define GET_FRM() (GET_FCSR() >> 5) 60# define SET_FRM(value) SET_FCSR(GET_FFLAGS() | ((value) << 5)) 61# define GET_FFLAGS() (GET_FCSR() & 0x1F) 62# define SET_FFLAGS(value) SET_FCSR((GET_FRM() << 5) | ((value) & 0x1F)) 63 64# define SETUP_STATIC_ROUNDING(insn) ({ \ 65 register int tp asm("tp"); tp &= 0xFF; \ 66 if (likely(((insn) & MASK_FUNCT3) == MASK_FUNCT3)) tp |= tp << 8; \ 67 else if (GET_RM(insn) > 4) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); \ 68 else tp |= GET_RM(insn) << 13; \ 69 asm volatile ("":"+r"(tp)); }) 70# define softfloat_raiseFlags(which) ({ asm volatile ("or tp, tp, %0" :: "rI"(which)); }) 71# define softfloat_roundingMode ({ register int tp asm("tp"); tp >> 13; }) 72# define SET_FS_DIRTY() set_csr(mstatus, MSTATUS_FS) 73#endif 74 75#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs)) 76#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs)) 77#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs)) 78#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs)) 79#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs)) 80#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs)) 81#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY()) 82#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY()) 83 84#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs)) 85#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs)) 86#define GET_F64_RS2C(insn, regs) (GET_F64_REG(insn, 2, regs)) 87#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs)) 88 89#endif 90