521 changes: 521 additions & 0 deletions target/riscv/insn_trans/trans_rvzfa.c.inc

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions target/riscv/insn_trans/trans_rvzfh.c.inc
Expand Up @@ -28,8 +28,8 @@
} \
} while (0)

#define REQUIRE_ZFHMIN(ctx) do { \
if (!ctx->cfg_ptr->ext_zfhmin) { \
#define REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx) do { \
if (!ctx->cfg_ptr->ext_zfhmin && !ctx->cfg_ptr->ext_zfbfmin) { \
return false; \
} \
} while (0)
Expand All @@ -46,7 +46,7 @@ static bool trans_flh(DisasContext *ctx, arg_flh *a)
TCGv t0;

REQUIRE_FPU;
REQUIRE_ZFHMIN(ctx);
REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);

decode_save_opc(ctx);
t0 = get_gpr(ctx, a->rs1, EXT_NONE);
Expand All @@ -69,7 +69,7 @@ static bool trans_fsh(DisasContext *ctx, arg_fsh *a)
TCGv t0;

REQUIRE_FPU;
REQUIRE_ZFHMIN(ctx);
REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);

decode_save_opc(ctx);
t0 = get_gpr(ctx, a->rs1, EXT_NONE);
Expand Down Expand Up @@ -574,7 +574,7 @@ static bool trans_fcvt_h_wu(DisasContext *ctx, arg_fcvt_h_wu *a)
static bool trans_fmv_x_h(DisasContext *ctx, arg_fmv_x_h *a)
{
REQUIRE_FPU;
REQUIRE_ZFHMIN(ctx);
REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);

TCGv dest = dest_gpr(ctx, a->rd);

Expand All @@ -594,7 +594,7 @@ static bool trans_fmv_x_h(DisasContext *ctx, arg_fmv_x_h *a)
static bool trans_fmv_h_x(DisasContext *ctx, arg_fmv_h_x *a)
{
REQUIRE_FPU;
REQUIRE_ZFHMIN(ctx);
REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);

TCGv t0 = get_gpr(ctx, a->rs1, EXT_ZERO);

Expand Down
501 changes: 491 additions & 10 deletions target/riscv/kvm.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions target/riscv/kvm_riscv.h
Expand Up @@ -19,6 +19,7 @@
#ifndef QEMU_KVM_RISCV_H
#define QEMU_KVM_RISCV_H

void kvm_riscv_init_user_properties(Object *cpu_obj);
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);

Expand Down
3 changes: 2 additions & 1 deletion target/riscv/op_helper.c
Expand Up @@ -335,7 +335,8 @@ target_ulong helper_mret(CPURISCVState *env)
riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
}

target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV) &&
(prev_priv != PRV_M);
mstatus = set_field(mstatus, MSTATUS_MIE,
get_field(mstatus, MSTATUS_MPIE));
mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
Expand Down
42 changes: 16 additions & 26 deletions target/riscv/translate.c
Expand Up @@ -64,6 +64,7 @@ typedef struct DisasContext {
target_ulong priv_ver;
RISCVMXL misa_mxl_max;
RISCVMXL xl;
RISCVMXL address_xl;
uint32_t misa_ext;
uint32_t opcode;
RISCVExtStatus mstatus_fs;
Expand Down Expand Up @@ -121,29 +122,6 @@ static inline bool has_ext(DisasContext *ctx, uint32_t ext)
return ctx->misa_ext & ext;
}

static bool always_true_p(DisasContext *ctx __attribute__((__unused__)))
{
return true;
}

static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__)))
{
return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb ||
ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo ||
ctx->cfg_ptr->ext_xtheadcondmov ||
ctx->cfg_ptr->ext_xtheadfmemidx || ctx->cfg_ptr->ext_xtheadfmv ||
ctx->cfg_ptr->ext_xtheadmac || ctx->cfg_ptr->ext_xtheadmemidx ||
ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync;
}

#define MATERIALISE_EXT_PREDICATE(ext) \
static bool has_ ## ext ## _p(DisasContext *ctx) \
{ \
return ctx->cfg_ptr->ext_ ## ext ; \
}

MATERIALISE_EXT_PREDICATE(XVentanaCondOps);

#ifdef TARGET_RISCV32
#define get_xl(ctx) MXL_RV32
#elif defined(CONFIG_USER_ONLY)
Expand All @@ -152,6 +130,14 @@ MATERIALISE_EXT_PREDICATE(XVentanaCondOps);
#define get_xl(ctx) ((ctx)->xl)
#endif

#ifdef TARGET_RISCV32
#define get_address_xl(ctx) MXL_RV32
#elif defined(CONFIG_USER_ONLY)
#define get_address_xl(ctx) MXL_RV64
#else
#define get_address_xl(ctx) ((ctx)->address_xl)
#endif

/* The word size for this machine mode. */
static inline int __attribute__((unused)) get_xlen(DisasContext *ctx)
{
Expand Down Expand Up @@ -598,12 +584,13 @@ static TCGv get_address(DisasContext *ctx, int rs1, int imm)
tcg_gen_addi_tl(addr, src1, imm);
if (ctx->pm_mask_enabled) {
tcg_gen_andc_tl(addr, addr, pm_mask);
} else if (get_xl(ctx) == MXL_RV32) {
} else if (get_address_xl(ctx) == MXL_RV32) {
tcg_gen_ext32u_tl(addr, addr);
}
if (ctx->pm_base_enabled) {
tcg_gen_or_tl(addr, addr, pm_base);
}

return addr;
}

Expand Down Expand Up @@ -1104,10 +1091,12 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzawrs.c.inc"
#include "insn_trans/trans_rvzicbo.c.inc"
#include "insn_trans/trans_rvzfa.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
#include "insn_trans/trans_rvk.c.inc"
#include "insn_trans/trans_privileged.c.inc"
#include "insn_trans/trans_svinval.c.inc"
#include "insn_trans/trans_rvbf16.c.inc"
#include "decode-xthead.c.inc"
#include "insn_trans/trans_xthead.c.inc"
#include "insn_trans/trans_xventanacondops.c.inc"
Expand All @@ -1134,7 +1123,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
* that are tested in-order until a decoder matches onto the opcode.
*/
static const struct {
bool (*guard_func)(DisasContext *);
bool (*guard_func)(const RISCVCPUConfig *);
bool (*decode_func)(DisasContext *, uint32_t);
} decoders[] = {
{ always_true_p, decode_insn32 },
Expand Down Expand Up @@ -1163,7 +1152,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
ctx->opcode = opcode32;

for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i) {
if (decoders[i].guard_func(ctx) &&
if (decoders[i].guard_func(ctx->cfg_ptr) &&
decoders[i].decode_func(ctx, opcode32)) {
return;
}
Expand Down Expand Up @@ -1200,6 +1189,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
ctx->misa_mxl_max = env->misa_mxl_max;
ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
ctx->cs = cs;
ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED);
ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
Expand Down
17 changes: 17 additions & 0 deletions target/riscv/vector_helper.c
Expand Up @@ -3554,6 +3554,17 @@ RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32)
GEN_VEXT_VF(vfwmacc_vf_h, 4)
GEN_VEXT_VF(vfwmacc_vf_w, 8)

static uint32_t fwmaccbf16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
{
return float32_muladd(bfloat16_to_float32(a, s),
bfloat16_to_float32(b, s), d, 0, s);
}

RVVCALL(OPFVV3, vfwmaccbf16_vv, WOP_UUU_H, H4, H2, H2, fwmaccbf16)
GEN_VEXT_VV_ENV(vfwmaccbf16_vv, 4)
RVVCALL(OPFVF3, vfwmaccbf16_vf, WOP_UUU_H, H4, H2, fwmacc16)
GEN_VEXT_VF(vfwmaccbf16_vf, 4)

static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
{
return float32_muladd(float16_to_float32(a, true, s),
Expand Down Expand Up @@ -4535,6 +4546,9 @@ RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64)
GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 4)
GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 8)

RVVCALL(OPFVV1, vfwcvtbf16_f_f_v, WOP_UU_H, H4, H2, bfloat16_to_float32)
GEN_VEXT_V_ENV(vfwcvtbf16_f_f_v, 4)

/* Narrowing Floating-Point/Integer Type-Convert Instructions */
/* (TD, T2, TX2) */
#define NOP_UU_B uint8_t, uint16_t, uint32_t
Expand Down Expand Up @@ -4581,6 +4595,9 @@ RVVCALL(OPFVV1, vfncvt_f_f_w_w, NOP_UU_W, H4, H8, float64_to_float32)
GEN_VEXT_V_ENV(vfncvt_f_f_w_h, 2)
GEN_VEXT_V_ENV(vfncvt_f_f_w_w, 4)

RVVCALL(OPFVV1, vfncvtbf16_f_f_w, NOP_UU_H, H2, H4, float32_to_bfloat16)
GEN_VEXT_V_ENV(vfncvtbf16_f_f_w, 2)

/*
* Vector Reduction Operations
*/
Expand Down
2 changes: 0 additions & 2 deletions tests/avocado/riscv_opensbi.py
Expand Up @@ -6,7 +6,6 @@
# later. See the COPYING file in the top-level directory.

from avocado_qemu import QemuSystemTest
from avocado import skip
from avocado_qemu import wait_for_console_pattern

class RiscvOpenSBI(QemuSystemTest):
Expand All @@ -21,7 +20,6 @@ def boot_opensbi(self):
wait_for_console_pattern(self, 'Platform Name')
wait_for_console_pattern(self, 'Boot HART MEDELEG')

@skip("requires OpenSBI fix to work")
def test_riscv32_spike(self):
"""
:avocado: tags=arch:riscv32
Expand Down
3 changes: 3 additions & 0 deletions tests/qtest/meson.build
Expand Up @@ -234,6 +234,9 @@ qtests_s390x = \
'cpu-plug-test',
'migration-test']

qtests_riscv32 = \
(config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])

qos_test_ss = ss.source_set()
qos_test_ss.add(
'ac97-test.c',
Expand Down
450 changes: 450 additions & 0 deletions tests/qtest/sifive-e-aon-watchdog-test.c

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions tests/tcg/riscv64/Makefile.target
Expand Up @@ -12,3 +12,9 @@ run-test-noc: QEMU_OPTS += -cpu rv64,c=false

TESTS += test-aes
run-test-aes: QEMU_OPTS += -cpu rv64,zk=on

# Test for fcvtmod
TESTS += test-fcvtmod
test-fcvtmod: CFLAGS += -march=rv64imafdc
test-fcvtmod: LDFLAGS += -static
run-test-fcvtmod: QEMU_OPTS += -cpu rv64,d=true,Zfa=true
345 changes: 345 additions & 0 deletions tests/tcg/riscv64/test-fcvtmod.c
@@ -0,0 +1,345 @@
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

#define FFLAG_NX_SHIFT 0 /* inexact */
#define FFLAG_UF_SHIFT 1 /* underflow */
#define FFLAG_OF_SHIFT 2 /* overflow */
#define FFLAG_DZ_SHIFT 3 /* divide by zero */
#define FFLAG_NV_SHIFT 4 /* invalid operation */

#define FFLAG_NV (1UL << FFLAG_NV_SHIFT)
#define FFLAG_DZ (1UL << FFLAG_DZ_SHIFT)
#define FFLAG_OF (1UL << FFLAG_OF_SHIFT)
#define FFLAG_UF (1UL << FFLAG_UF_SHIFT)
#define FFLAG_NX (1UL << FFLAG_NX_SHIFT)

typedef struct fp64_fcvt_fcvtmod_testcase {
const char* name;
union {
uint64_t inp_lu;
double inp_lf;
};
uint64_t exp_fcvt;
uint8_t exp_fcvt_fflags;
uint64_t exp_fcvtmod;
uint8_t exp_fcvtmod_fflags;
} fp64_fcvt_fcvtmod_testcase_t;

void print_fflags(uint8_t fflags)
{
int set = 0;

if (fflags == 0) {
printf("-");
return;
}

if (fflags & FFLAG_NV) {
printf("%sFFLAG_NV", set ? " | " : "");
set = 1;
}
if (fflags & FFLAG_DZ) {
printf("%sFFLAG_DZ", set ? " | " : "");
set = 1;
}
if (fflags & FFLAG_OF) {
printf("%sFFLAG_OF", set ? " | " : "");
set = 1;
}
if (fflags & FFLAG_UF) {
printf("%sFFLAG_UF", set ? " | " : "");
set = 1;
}
if (fflags & FFLAG_NX) {
printf("%sFFLAG_NX", set ? " | " : "");
set = 1;
}
}

/* Clear all FP flags. */
static inline void clear_fflags()
{
__asm__ __volatile__("fsflags zero");
}

/* Read all FP flags. */
static inline uint8_t get_fflags()
{
uint64_t v;
__asm__ __volatile__("frflags %0" : "=r"(v));
return (uint8_t)v;
}

/* Move input value (without conversations) into an FP register. */
static inline double do_fmv_d_x(uint64_t inp)
{
double fpr;
__asm__ __volatile__("fmv.d.x %0, %1" : "=f"(fpr) : "r"(inp));
return fpr;
}

static inline uint64_t do_fcvt_w_d(uint64_t inp, uint8_t *fflags)
{
uint64_t ret;
double fpr = do_fmv_d_x(inp);

clear_fflags();

__asm__ __volatile__("fcvt.w.d %0, %1, rtz" : "=r"(ret) : "f"(fpr));

*fflags = get_fflags();

return ret;
}

static inline uint64_t do_fcvtmod_w_d(uint64_t inp, uint8_t *fflags)
{
uint64_t ret;
double fpr = do_fmv_d_x(inp);

clear_fflags();

/* fcvtmod.w.d rd, rs1, rtz = 1100001 01000 rs1 001 rd 1010011 */
asm(".insn r 0x53, 0x1, 0x61, %0, %1, f8" : "=r"(ret) : "f"(fpr));

*fflags = get_fflags();

return ret;
}

static const fp64_fcvt_fcvtmod_testcase_t tests[] = {
/* Zero (exp=0, frac=0) */
{ .name = "+0.0",
.inp_lf = 0x0p0,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0x0000000000000000,
.exp_fcvtmod_fflags = 0 },
{ .name = "-0.0",
.inp_lf = -0x0p0,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0x0000000000000000,
.exp_fcvtmod_fflags = 0 },

/* Subnormal: exp=0 frac!=0 */
{ .name = "Subnormal frac=1",
.inp_lu = 0x0000000000000001,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "Subnormal frac=0xf..f",
.inp_lu = 0x0000ffffffffffff,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "Neg subnormal frac=1",
.inp_lu = 0x0000000000000001,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "Neg subnormal frac=0xf..f",
.inp_lu = 0x8000ffffffffffff,
.exp_fcvt = 0x0000000000000000,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },

/* Infinity: exp=0x7ff, frac=0 */
{ .name = "+INF",
.inp_lu = 0x7ff0000000000000,
.exp_fcvt = 0x000000007fffffff, /* int32 max */
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NV },
{ .name = "-INF",
.inp_lu = 0xfff0000000000000,
.exp_fcvt = 0xffffffff80000000, /* int32 min */
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NV },

/* NaN: exp=7ff, frac!=0 */
{ .name = "canonical NaN",
.inp_lu = 0x7ff8000000000000,
.exp_fcvt = 0x000000007fffffff, /* int32 max */
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NV },
{ .name = "non-canonical NaN",
.inp_lu = 0x7ff8000000100000,
.exp_fcvt = 0x000000007fffffff, /* int32 min */
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NV },

/* Normal numbers: exp!=0, exp!=7ff */
{ .name = "+smallest normal value",
.inp_lu = 0x0010000000000000,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "-smallest normal value",
.inp_lu = 0x8010000000000000,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },

{ .name = "+0.5",
.inp_lf = 0x1p-1,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "-0.5",
.inp_lf = -0x1p-1,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },

{ .name = "+value just below 1.0",
.inp_lu = 0x3fefffffffffffff,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "-value just above -1.0",
.inp_lu = 0xbfefffffffffffff,
.exp_fcvt = 0,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0,
.exp_fcvtmod_fflags = FFLAG_NX },

{ .name = "+1.0",
.inp_lf = 0x1p0,
.exp_fcvt = 0x0000000000000001,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0x0000000000000001,
.exp_fcvtmod_fflags = 0 },
{ .name = "-1.0",
.inp_lf = -0x1p0,
.exp_fcvt = 0xffffffffffffffff,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0xffffffffffffffff,
.exp_fcvtmod_fflags = 0 },

{ .name = "+1.5",
.inp_lu = 0x3ff8000000000000,
.exp_fcvt = 1,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 1,
.exp_fcvtmod_fflags = FFLAG_NX },
{ .name = "-1.5",
.inp_lu = 0xbff8000000000000,
.exp_fcvt = 0xffffffffffffffff,
.exp_fcvt_fflags = FFLAG_NX,
.exp_fcvtmod = 0xffffffffffffffff,
.exp_fcvtmod_fflags = FFLAG_NX },

{ .name = "+max int32 (2147483647)",
.inp_lu = 0x41dfffffffc00000,
.exp_fcvt = 0x000000007fffffff,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0x000000007fffffff,
.exp_fcvtmod_fflags = 0 },
{ .name = "+max int32 +1 (2147483648)",
.inp_lf = 0x1p31,
.exp_fcvt = 0x000000007fffffff,
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = (uint64_t)-2147483648l, /* int32 min */
.exp_fcvtmod_fflags = FFLAG_NV },
{ .name = "+max int32 +2 (2147483649)",
.inp_lu = 0x41e0000000200000,
.exp_fcvt = 0x000000007fffffff,
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = (uint64_t)-2147483647l, /* int32 min +1 */
.exp_fcvtmod_fflags = FFLAG_NV },

{ .name = "-max int32 (-2147483648)",
.inp_lf = -0x1p31,
.exp_fcvt = 0xffffffff80000000,
.exp_fcvt_fflags = 0,
.exp_fcvtmod = 0xffffffff80000000,
.exp_fcvtmod_fflags = 0 },
{ .name = "-max int32 -1 (-2147483649)",
.inp_lf = -0x1.00000002p+31,
.exp_fcvt = 0xffffffff80000000,
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 2147483647, /* int32 max */
.exp_fcvtmod_fflags = FFLAG_NV },
{ .name = "-max int32 -2 (-2147483650)",
.inp_lf = -0x1.00000004p+31,
.exp_fcvt = 0xffffffff80000000,
.exp_fcvt_fflags = FFLAG_NV,
.exp_fcvtmod = 2147483646, /* int32 max -1 */
.exp_fcvtmod_fflags = FFLAG_NV },
};

int run_fcvtmod_tests()
{
uint64_t act_fcvt;
uint8_t act_fcvt_fflags;
uint64_t act_fcvtmod;
uint8_t act_fcvtmod_fflags;

for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
const fp64_fcvt_fcvtmod_testcase_t *t = &tests[i];

act_fcvt = do_fcvt_w_d(t->inp_lu, &act_fcvt_fflags);
int fcvt_correct = act_fcvt == t->exp_fcvt &&
act_fcvt_fflags == t->exp_fcvt_fflags;
act_fcvtmod = do_fcvtmod_w_d(t->inp_lu, &act_fcvtmod_fflags);
int fcvtmod_correct = act_fcvtmod == t->exp_fcvtmod &&
act_fcvtmod_fflags == t->exp_fcvtmod_fflags;

if (fcvt_correct && fcvtmod_correct) {
continue;
}

printf("Test %zu (%s) failed!\n", i, t->name);

double fpr = do_fmv_d_x(t->inp_lu);
printf("inp_lu: 0x%016lx == %lf\n", t->inp_lu, fpr);
printf("inp_lf: %lf\n", t->inp_lf);

uint32_t sign = (t->inp_lu >> 63);
uint32_t exp = (uint32_t)(t->inp_lu >> 52) & 0x7ff;
uint64_t frac = t->inp_lu & 0xfffffffffffffull; /* significand */
int true_exp = exp - 1023;
int shift = true_exp - 52;
uint64_t true_frac = frac | 1ull << 52;

printf("sign=%d, exp=0x%03x, frac=0x%012lx\n", sign, exp, frac);
printf("true_exp=%d, shift=%d, true_frac=0x%016lx\n", true_exp, shift, true_frac);

if (!fcvt_correct) {
printf("act_fcvt: 0x%016lx == %li\n", act_fcvt, act_fcvt);
printf("exp_fcvt: 0x%016lx == %li\n", t->exp_fcvt, t->exp_fcvt);
printf("act_fcvt_fflags: "); print_fflags(act_fcvt_fflags); printf("\n");
printf("exp_fcvt_fflags: "); print_fflags(t->exp_fcvt_fflags); printf("\n");
}

if (!fcvtmod_correct) {
printf("act_fcvtmod: 0x%016lx == %li\n", act_fcvtmod, act_fcvtmod);
printf("exp_fcvtmod: 0x%016lx == %li\n", t->exp_fcvtmod, t->exp_fcvtmod);
printf("act_fcvtmod_fflags: "); print_fflags(act_fcvtmod_fflags); printf("\n");
printf("exp_fcvtmod_fflags: "); print_fflags(t->exp_fcvtmod_fflags); printf("\n");
}

return 1;
}

return 0;
}

int main()
{
return run_fcvtmod_tests();
}
31 changes: 31 additions & 0 deletions tests/unit/test-qga.c
Expand Up @@ -665,6 +665,36 @@ static void test_qga_blockedrpcs(gconstpointer data)
fixture_tear_down(&fix, NULL);
}

static void test_qga_allowedrpcs(gconstpointer data)
{
TestFixture fix;
QDict *ret, *error;
const gchar *class, *desc;

fixture_setup(&fix, "-a guest-ping,guest-get-time", NULL);

/* check allowed RPCs */
ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
qmp_assert_no_error(ret);
qobject_unref(ret);

ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
qmp_assert_no_error(ret);
qobject_unref(ret);

/* check something else */
ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
g_assert_nonnull(ret);
error = qdict_get_qdict(ret, "error");
class = qdict_get_try_str(error, "class");
desc = qdict_get_try_str(error, "desc");
g_assert_cmpstr(class, ==, "CommandNotFound");
g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
qobject_unref(ret);

fixture_tear_down(&fix, NULL);
}

static void test_qga_config(gconstpointer data)
{
GError *error = NULL;
Expand Down Expand Up @@ -1090,6 +1120,7 @@ int main(int argc, char **argv)
test_qga_fsfreeze_status);

g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs);
g_test_add_data_func("/qga/allowedrpcs", NULL, test_qga_allowedrpcs);
g_test_add_data_func("/qga/config", NULL, test_qga_config);
g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
g_test_add_data_func("/qga/guest-exec-separated", &fix,
Expand Down