target: e2k: add basic fpu instructions

This commit is contained in:
Alibek Omarov 2020-12-09 22:12:43 +03:00
parent c78d3d7521
commit afce8392d8
7 changed files with 307 additions and 3 deletions

View File

@ -53,6 +53,7 @@ static void e2k_cpu_reset(DeviceState *dev)
env->bn.size = 8;
env->bn.cur = 0;
env->aau.incrs[0] = 1; /* always one */
env->fpcr._one = 1;
// FIXME: testing
env->idr = 0x3a207; // mimic 8c

View File

@ -4,6 +4,7 @@
#include "qemu/bswap.h"
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "fpu/softfloat.h"
void e2k_tcg_initialize(void);
@ -447,6 +448,54 @@ typedef union {
uint64_t raw;
} E2KCtpr;
/* E2K FPU regs are compatible with x87 regs */
#define FPSR_IE (1U << 0) /* invalid operation */
#define FPSR_DE (1U << 1) /* denormalized operand */
#define FPSR_ZE (1U << 2) /* zero divide */
#define FPSR_OE (1U << 3) /* overflow */
#define FPSR_UE (1U << 4) /* underflow */
#define FPSR_PE (1U << 5) /* precision */
typedef union {
struct {
uint32_t ef : 6; /* exception flags */
uint32_t sf : 1; /* stack fault, unused */
uint32_t es : 1; /* error summary status */
uint32_t _c0 : 1; /* condition code 0, unused */
uint32_t c1 : 1; /* condition code 1 */
uint32_t _c2 : 1; /* condition code 2, unused */
uint32_t top: 3; /* stack top, unused */
uint32_t _c3 : 1; /* condition code 3, unused */
uint32_t b : 1; /* fpu busy */
};
uint32_t raw;
} E2KFpsrState;
#define FPCR_EM (FPSR_IE|FPSR_DE|FPSR_ZE|FPSR_OE|FPSR_UE|FPSR_PE)
#define FPCR_PC_SP 0 /* single precision (32 bits) */
#define FPCR_PC_RESERVED 1 /* reserved */
#define FPCR_PC_DP 2 /* double precision (64 bits) */
#define FPCR_PC_XP 3 /* extended precision (80 bits) */
#define FPCR_RC_NEAR 0 /* round to nearest */
#define FPCR_RC_DOWN 1 /* round down */
#define FPCR_RC_UP 2 /* round up */
#define FPCR_RC_CHOP 3 /* round toward zero (truncate) */
typedef union {
struct {
uint32_t em : 6; /* masks flags */
uint32_t _one : 1; /* reserved, always 1 (?) */
uint32_t _zero0 : 1; /* reserved, always 0 */
uint32_t pc : 2; /* precision control */
uint32_t rc : 2; /* rounding control */
uint32_t ic : 1; /* infinity control */
uint32_t _zero1 : 3; /* reserved */
};
uint32_t raw;
} E2KFpcrState;
typedef struct {
union {
uint64_t lo;
@ -510,9 +559,11 @@ typedef struct {
uint64_t idr;
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
uint32_t fpcr; // Floating point control register (FPCR)
uint32_t fpsr; // Floating point state register (FPSR)
E2KFpsrState fpsr; // Floating point state register (FPSR)
E2KFpcrState fpcr; // Floating point control register (FPCR)
float_status fp_status;
E2KAauState aau;
int interrupt_index;
@ -563,6 +614,7 @@ void e2k_break_save_state(CPUE2KState *env);
bool e2k_cpu_tlb_fill(CPUState *cpu, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
void e2k_update_fp_status(CPUE2KState *env);
#define cpu_signal_handler e2k_cpu_signal_handler
#define cpu_list e2k_cpu_list

View File

@ -27,3 +27,22 @@ DEF_HELPER_2(pmovmskb, i64, i64, i64)
DEF_HELPER_1(aau_load_program, void, env)
DEF_HELPER_3(mova_ptr, tl, env, int, int)
DEF_HELPER_3(aau_am, void, env, int, int)
#define DEF_HELPER_3_32_64(name) \
DEF_HELPER_3(name##s, i32, env, i32, i32) \
DEF_HELPER_3(name##d, i64, env, i64, i64)
DEF_HELPER_3_32_64(fadd)
DEF_HELPER_3_32_64(fsub)
DEF_HELPER_3_32_64(fmin)
DEF_HELPER_3_32_64(fmax)
DEF_HELPER_3_32_64(fmul)
DEF_HELPER_3_32_64(fdiv)
DEF_HELPER_3_32_64(fcmpeq)
DEF_HELPER_3_32_64(fcmpneq)
DEF_HELPER_3_32_64(fcmple)
DEF_HELPER_3_32_64(fcmpnle)
DEF_HELPER_3_32_64(fcmplt)
DEF_HELPER_3_32_64(fcmpnlt)
DEF_HELPER_3_32_64(fcmpuod)
DEF_HELPER_3_32_64(fcmpod)

115
target/e2k/helper_fpu.c Normal file
View File

@ -0,0 +1,115 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
static inline void fpu_set_exception(CPUE2KState *env, int mask)
{
env->fpsr.ef |= mask;
if (env->fpsr.ef & (~env->fpcr.em & FPCR_EM)) {
env->fpsr.es = 1;
env->fpsr.b = 1;
}
}
static inline uint8_t save_exception_flags(CPUE2KState *env)
{
uint8_t old_flags = get_float_exception_flags(&env->fp_status);
set_float_exception_flags(0, &env->fp_status);
return old_flags;
}
static inline void merge_exception_flags(CPUE2KState *env, uint8_t old_flags)
{
uint8_t new_flags = get_float_exception_flags(&env->fp_status);
float_raise(old_flags, &env->fp_status);
fpu_set_exception(env,
((new_flags & float_flag_invalid ? FPSR_IE : 0) |
(new_flags & float_flag_divbyzero ? FPSR_ZE : 0) |
(new_flags & float_flag_overflow ? FPSR_OE : 0) |
(new_flags & float_flag_underflow ? FPSR_UE : 0) |
(new_flags & float_flag_inexact ? FPSR_PE : 0) |
(new_flags & float_flag_input_denormal ? FPSR_DE : 0)));
}
void e2k_update_fp_status(CPUE2KState *env)
{
int x;
switch(env->fpcr.rc) {
case FPCR_RC_UP:
x = float_round_up;
break;
case FPCR_RC_DOWN:
x = float_round_down;
break;
case FPCR_RC_CHOP:
x = float_round_to_zero;
break;
case FPCR_RC_NEAR:
x = float_round_nearest_even;
break;
default:
abort();
break;
}
set_float_rounding_mode(x, &env->fp_status);
switch(env->fpcr.pc) {
case FPCR_PC_XP: x = 80; break;
case FPCR_PC_DP: x = 64; break;
case FPCR_PC_SP: x = 32; break;
case FPCR_PC_RESERVED:
default:
abort();
break;
}
set_floatx80_rounding_precision(x, &env->fp_status);
}
#define GENERATE_SIMPLE_FLOAT2_OP(name, function, size) \
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
{ \
uint8_t old_flags = save_exception_flags(env); \
float##size z = float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
merge_exception_flags(env, old_flags); \
return float##size##_val(z); \
}
#define GENERATE_CMP_FLOAT2_OP(name, function, expr, size) \
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
{ \
uint8_t old_flags = save_exception_flags(env); \
uint##size##_t z = expr float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
merge_exception_flags(env, old_flags); \
return z; \
}
#define GENERATE_SIMPLE_FLOAT2_OPS_32_64(name, function) \
GENERATE_SIMPLE_FLOAT2_OP(name##s, function, 32) \
GENERATE_SIMPLE_FLOAT2_OP(name##d, function, 64)
#define GENERATE_CMP_FLOAT2_OPS_32_64(name, function, expr) \
GENERATE_CMP_FLOAT2_OP(name##s, function, 32) \
GENERATE_CMP_FLOAT2_OP(name##d, function, 64)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fadd, add)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fsub, sub)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmin, min)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmax, max)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmul, mul)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fdiv, div)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpeq, eq, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpneq, eq, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmple, le, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnle, le, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmplt, lt, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnlt, lt, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpuod, unordered, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpod, unordered, !)

View File

@ -40,6 +40,8 @@ static uint64_t* state_reg_ptr(CPUE2KState *env, int idx)
case 0x53: return &env->pregs; /* %cr1.lo */
case 0x80: return &env->upsr; /* %upsr */
case 0x83: return &env->lsr; /* %lsr */
case 0x85: return &env->fpcr.raw; /* %fpcr */
case 0x86: return &env->fpsr.raw; /* %fpsr */
default: return NULL;
}
}
@ -86,7 +88,7 @@ uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx)
void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
{
uint64_t *p = state_reg_ptr(env, idx);
if (p != NULL) {
*p = val;
} else {
@ -101,6 +103,10 @@ void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val)
if (p != NULL) {
*p = val;
if (idx == 0x85) { /* %fpcr */
e2k_update_fp_status(env);
}
} else {
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
abort();

View File

@ -4,6 +4,7 @@ e2k_ss.add(files(
'gdbstub.c',
'helper.c',
'helper_aau.c',
'helper_fpu.c',
'helper_int.c',
'helper_sm.c',
'helper_vec.c',

View File

@ -1741,6 +1741,19 @@ static void gen_alopf1_i64(DisasContext *ctx, int chan,
gen_al_result_i64(ctx, chan, dst, tag);
}
static void gen_alopf1_i64_env(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
{
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
gen_tag2_i64(tag, s1.tag, s2.tag);
(*op)(dst, cpu_env, s1.value, s2.value);
gen_al_result_i64(ctx, chan, dst, tag);
}
static void gen_alopf1_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_i32, TCGv_i32))
{
@ -1754,6 +1767,19 @@ static void gen_alopf1_i32(DisasContext *ctx, int chan,
gen_al_result_i32(ctx, chan, dst, tag);
}
static void gen_alopf1_i32_env(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
{
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 tag = e2k_get_temp_i32(ctx);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
gen_tag2_i32(tag, s1.tag, s2.tag);
(*op)(dst, cpu_env, s1.value, s2.value);
gen_al_result_i32(ctx, chan, dst, tag);
}
static void gen_alopf1_i32_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_i32, TCGv_i32))
{
@ -2034,6 +2060,76 @@ static void execute_ext_00(DisasContext *ctx, Instr *instr)
}
break;
}
case 0x30:
if (ctx->version >= 4 || is_chan_0134(chan)) {
/* faddd */
gen_alopf1_i32_env(ctx, chan, gen_helper_fadds);
return;
}
break;
case 0x31:
if (ctx->version >= 4 || is_chan_0134(chan)) {
/* faddd */
gen_alopf1_i64_env(ctx, chan, gen_helper_faddd);
return;
}
break;
case 0x32:
if (ctx->version >= 4 || is_chan_0134(chan)) {
/* fsubs */
gen_alopf1_i32_env(ctx, chan, gen_helper_fsubs);
return;
}
break;
case 0x33:
if (ctx->version >= 4 || is_chan_0134(chan)) {
/* fsubd */
gen_alopf1_i64_env(ctx, chan, gen_helper_fsubd);
return;
}
break;
case 0x34:
if (is_chan_0134(chan)) {
/* fmins */
gen_alopf1_i32_env(ctx, chan, gen_helper_fmins);
return;
}
break;
case 0x35:
if (is_chan_0134(chan)) {
/* fmind */
gen_alopf1_i64_env(ctx, chan, gen_helper_fmind);
return;
}
break;
case 0x36:
if (is_chan_0134(chan)) {
/* fmaxs */
gen_alopf1_i32_env(ctx, chan, gen_helper_fmaxs);
return;
}
break;
case 0x37:
if (is_chan_0134(chan)) {
/* fmaxd */
gen_alopf1_i64_env(ctx, chan, gen_helper_fmaxd);
return;
}
break;
case 0x38:
if (ctx->version >= 4 || is_chan_0134(chan)) {
/* fmuls */
gen_alopf1_i32_env(ctx, chan, gen_helper_fmuls);
return;
}
break;
case 0x39:
if (is_chan_0134(chan)) {
/* fmuld */
gen_alopf1_i64_env(ctx, chan, gen_helper_fmuld);
return;
}
break;
case 0x40:
if (chan == 5) {
// FIXME: temp hack
@ -2068,6 +2164,20 @@ static void execute_ext_00(DisasContext *ctx, Instr *instr)
return;
}
break;
case 0x48:
if (chan == 5) {
/* fdivs */
gen_alopf1_i32_env(ctx, chan, gen_helper_fdivs);
return;
}
break;
case 0x49:
if (chan == 5) {
/* fdivd */
gen_alopf1_i64_env(ctx, chan, gen_helper_fdivd);
return;
}
break;
case 0x61:
if (is_chan_0134(chan)) {
gen_movtd(ctx, chan);