QEMU main repository: Please see https://www.qemu.org/docs/master/devel/submitting-a-patch.html for how to submit changes to QEMU. Pull Requests are ignored. Please only use release tarballs from the QEMU website. http://www.qemu.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
7.4 KiB

/*
* QEMU RX CPU
*
* Copyright (c) 2019 Yoshinori Sato
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/qemu-print.h"
#include "qapi/error.h"
#include "cpu.h"
#include "migration/vmstate.h"
#include "exec/cputlb.h"
#include "exec/page-protection.h"
#include "exec/translation-block.h"
#include "hw/loader.h"
#include "fpu/softfloat.h"
#include "tcg/debug-assert.h"
static void rx_cpu_set_pc(CPUState *cs, vaddr value)
{
RXCPU *cpu = RX_CPU(cs);
cpu->env.pc = value;
}
hw/core: Add CPUClass.get_pc Populate this new method for all targets. Always match the result that would be given by cpu_get_tb_cpu_state, as we will want these values to correspond in the logs. Reviewed-by: Taylor Simpson <tsimpson@quicinc.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> (target/sparc) Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- Cc: Eduardo Habkost <eduardo@habkost.net> (supporter:Machine core) Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> (supporter:Machine core) Cc: "Philippe Mathieu-Daudé" <f4bug@amsat.org> (reviewer:Machine core) Cc: Yanan Wang <wangyanan55@huawei.com> (reviewer:Machine core) Cc: Michael Rolnik <mrolnik@gmail.com> (maintainer:AVR TCG CPUs) Cc: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> (maintainer:CRIS TCG CPUs) Cc: Taylor Simpson <tsimpson@quicinc.com> (supporter:Hexagon TCG CPUs) Cc: Song Gao <gaosong@loongson.cn> (maintainer:LoongArch TCG CPUs) Cc: Xiaojuan Yang <yangxiaojuan@loongson.cn> (maintainer:LoongArch TCG CPUs) Cc: Laurent Vivier <laurent@vivier.eu> (maintainer:M68K TCG CPUs) Cc: Jiaxun Yang <jiaxun.yang@flygoat.com> (reviewer:MIPS TCG CPUs) Cc: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> (reviewer:MIPS TCG CPUs) Cc: Chris Wulff <crwulff@gmail.com> (maintainer:NiosII TCG CPUs) Cc: Marek Vasut <marex@denx.de> (maintainer:NiosII TCG CPUs) Cc: Stafford Horne <shorne@gmail.com> (odd fixer:OpenRISC TCG CPUs) Cc: Yoshinori Sato <ysato@users.sourceforge.jp> (reviewer:RENESAS RX CPUs) Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> (maintainer:SPARC TCG CPUs) Cc: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> (maintainer:TriCore TCG CPUs) Cc: Max Filippov <jcmvbkbc@gmail.com> (maintainer:Xtensa TCG CPUs) Cc: qemu-arm@nongnu.org (open list:ARM TCG CPUs) Cc: qemu-ppc@nongnu.org (open list:PowerPC TCG CPUs) Cc: qemu-riscv@nongnu.org (open list:RISC-V TCG CPUs) Cc: qemu-s390x@nongnu.org (open list:S390 TCG CPUs)
4 years ago
static vaddr rx_cpu_get_pc(CPUState *cs)
{
RXCPU *cpu = RX_CPU(cs);
return cpu->env.pc;
}
static void rx_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
RXCPU *cpu = RX_CPU(cs);
tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
cpu->env.pc = tb->pc;
}
static void rx_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
const uint64_t *data)
{
RXCPU *cpu = RX_CPU(cs);
cpu->env.pc = data[0];
}
static bool rx_cpu_has_work(CPUState *cs)
{
return cs->interrupt_request &
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR);
}
static int riscv_cpu_mmu_index(CPUState *cs, bool ifunc)
{
return 0;
}
static void rx_cpu_reset_hold(Object *obj, ResetType type)
{
CPUState *cs = CPU(obj);
RXCPUClass *rcc = RX_CPU_GET_CLASS(obj);
CPURXState *env = cpu_env(cs);
uint32_t *resetvec;
if (rcc->parent_phases.hold) {
rcc->parent_phases.hold(obj, type);
}
memset(env, 0, offsetof(CPURXState, end_reset_fields));
resetvec = rom_ptr(0xfffffffc, 4);
if (resetvec) {
/* In the case of kernel, it is ignored because it is not set. */
env->pc = ldl_p(resetvec);
}
rx_cpu_unpack_psw(env, 0, 1);
env->regs[0] = env->isp = env->usp = 0;
env->fpsw = 0;
set_flush_to_zero(1, &env->fp_status);
set_flush_inputs_to_zero(1, &env->fp_status);
/*
* TODO: this is not the correct NaN propagation rule for this
* architecture. The "RX Family User's Manual: Software" table 1.6
* defines the propagation rules as "prefer SNaN over QNaN;
* then prefer dest over source", which is float_2nan_prop_s_ab.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
/* Default NaN value: sign bit clear, set frac msb */
set_float_default_nan_pattern(0b01000000, &env->fp_status);
fpu: allow flushing of output denormals to be after rounding Currently we handle flushing of output denormals in uncanon_normal always before we deal with rounding. This works for architectures that detect tininess before rounding, but is usually not the right place when the architecture detects tininess after rounding. For example, for x86 the SDM states that the MXCSR FTZ control bit causes outputs to be flushed to zero "when it detects a floating-point underflow condition". This means that we mustn't flush to zero if the input is such that after rounding it is no longer tiny. At least one of our guest architectures does underflow detection after rounding but flushing of denormals before rounding (MIPS MSA); this means we need to have a config knob for this that is separate from our existing tininess_before_rounding setting. Add an ftz_detection flag. For consistency with tininess_before_rounding, we make it default to "detect ftz after rounding"; this means that we need to explicitly set the flag to "detect ftz before rounding" on every existing architecture that sets flush_to_zero, so that this commit has no behaviour change. (This means more code change here but for the long term a less confusing API.) For several architectures the current behaviour is either definitely or possibly wrong; annotate those with TODO comments. These architectures are definitely wrong (and should detect ftz after rounding): * x86 * Alpha For these architectures the spec is unclear: * MIPS (for non-MSA) * RX * SH4 PA-RISC makes ftz detection IMPDEF, but we aren't setting the "tininess before rounding" setting that we ought to. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
2 years ago
/*
* TODO: "RX Family RXv1 Instruction Set Architecture" is not 100% clear
* on whether flush-to-zero should happen before or after rounding, but
* section 1.3.2 says that it happens when underflow is detected, and
* implies that underflow is detected after rounding. So this may not
* be the correct setting.
*/
set_float_ftz_detection(float_ftz_before_rounding, &env->fp_status);
}
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
char *typename;
oc = object_class_by_name(cpu_model);
if (oc != NULL && object_class_dynamic_cast(oc, TYPE_RX_CPU) != NULL) {
return oc;
}
typename = g_strdup_printf(RX_CPU_TYPE_NAME("%s"), cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
return oc;
}
static void rx_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
RXCPUClass *rcc = RX_CPU_GET_CLASS(dev);
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
qemu_init_vcpu(cs);
cpu_reset(cs);
rcc->parent_realize(dev, errp);
}
static void rx_cpu_set_irq(void *opaque, int no, int request)
{
RXCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
int irq = request & 0xff;
static const int mask[] = {
[RX_CPU_IRQ] = CPU_INTERRUPT_HARD,
[RX_CPU_FIR] = CPU_INTERRUPT_FIR,
};
if (irq) {
cpu->env.req_irq = irq;
cpu->env.req_ipl = (request >> 8) & 0x0f;
cpu_interrupt(cs, mask[no]);
} else {
cpu_reset_interrupt(cs, mask[no]);
}
}
static void rx_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
{
info->endian = BFD_ENDIAN_LITTLE;
info->mach = bfd_mach_rx;
info->print_insn = print_insn_rx;
}
static bool rx_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
uint32_t address, physical, prot;
/* Linear mapping */
address = physical = addr & TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
return true;
}
static void rx_cpu_init(Object *obj)
{
RXCPU *cpu = RX_CPU(obj);
qdev_init_gpio_in(DEVICE(cpu), rx_cpu_set_irq, 2);
}
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps rx_sysemu_ops = {
.has_work = rx_cpu_has_work,
.get_phys_page_debug = rx_cpu_get_phys_page_debug,
};
#include "accel/tcg/cpu-ops.h"
static const TCGCPUOps rx_tcg_ops = {
.initialize = rx_translate_init,
.translate_code = rx_translate_code,
.synchronize_from_tb = rx_cpu_synchronize_from_tb,
.restore_state_to_opc = rx_restore_state_to_opc,
.tlb_fill = rx_cpu_tlb_fill,
.cpu_exec_interrupt = rx_cpu_exec_interrupt,
.cpu_exec_halt = rx_cpu_has_work,
.do_interrupt = rx_cpu_do_interrupt,
};
static void rx_cpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CPUClass *cc = CPU_CLASS(klass);
RXCPUClass *rcc = RX_CPU_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
device_class_set_parent_realize(dc, rx_cpu_realize,
&rcc->parent_realize);
resettable_class_set_parent_phases(rc, NULL, rx_cpu_reset_hold, NULL,
&rcc->parent_phases);
cc->class_by_name = rx_cpu_class_by_name;
cc->mmu_index = riscv_cpu_mmu_index;
cc->dump_state = rx_cpu_dump_state;
cc->set_pc = rx_cpu_set_pc;
hw/core: Add CPUClass.get_pc Populate this new method for all targets. Always match the result that would be given by cpu_get_tb_cpu_state, as we will want these values to correspond in the logs. Reviewed-by: Taylor Simpson <tsimpson@quicinc.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> (target/sparc) Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- Cc: Eduardo Habkost <eduardo@habkost.net> (supporter:Machine core) Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> (supporter:Machine core) Cc: "Philippe Mathieu-Daudé" <f4bug@amsat.org> (reviewer:Machine core) Cc: Yanan Wang <wangyanan55@huawei.com> (reviewer:Machine core) Cc: Michael Rolnik <mrolnik@gmail.com> (maintainer:AVR TCG CPUs) Cc: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> (maintainer:CRIS TCG CPUs) Cc: Taylor Simpson <tsimpson@quicinc.com> (supporter:Hexagon TCG CPUs) Cc: Song Gao <gaosong@loongson.cn> (maintainer:LoongArch TCG CPUs) Cc: Xiaojuan Yang <yangxiaojuan@loongson.cn> (maintainer:LoongArch TCG CPUs) Cc: Laurent Vivier <laurent@vivier.eu> (maintainer:M68K TCG CPUs) Cc: Jiaxun Yang <jiaxun.yang@flygoat.com> (reviewer:MIPS TCG CPUs) Cc: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> (reviewer:MIPS TCG CPUs) Cc: Chris Wulff <crwulff@gmail.com> (maintainer:NiosII TCG CPUs) Cc: Marek Vasut <marex@denx.de> (maintainer:NiosII TCG CPUs) Cc: Stafford Horne <shorne@gmail.com> (odd fixer:OpenRISC TCG CPUs) Cc: Yoshinori Sato <ysato@users.sourceforge.jp> (reviewer:RENESAS RX CPUs) Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> (maintainer:SPARC TCG CPUs) Cc: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> (maintainer:TriCore TCG CPUs) Cc: Max Filippov <jcmvbkbc@gmail.com> (maintainer:Xtensa TCG CPUs) Cc: qemu-arm@nongnu.org (open list:ARM TCG CPUs) Cc: qemu-ppc@nongnu.org (open list:PowerPC TCG CPUs) Cc: qemu-riscv@nongnu.org (open list:RISC-V TCG CPUs) Cc: qemu-s390x@nongnu.org (open list:S390 TCG CPUs)
4 years ago
cc->get_pc = rx_cpu_get_pc;
cc->sysemu_ops = &rx_sysemu_ops;
cc->gdb_read_register = rx_cpu_gdb_read_register;
cc->gdb_write_register = rx_cpu_gdb_write_register;
cc->disas_set_info = rx_cpu_disas_set_info;
cc->gdb_core_xml_file = "rx-core.xml";
cc->tcg_ops = &rx_tcg_ops;
}
static const TypeInfo rx_cpu_info = {
.name = TYPE_RX_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(RXCPU),
.instance_align = __alignof(RXCPU),
.instance_init = rx_cpu_init,
.abstract = true,
.class_size = sizeof(RXCPUClass),
.class_init = rx_cpu_class_init,
};
static const TypeInfo rx62n_rx_cpu_info = {
.name = TYPE_RX62N_CPU,
.parent = TYPE_RX_CPU,
};
static void rx_cpu_register_types(void)
{
type_register_static(&rx_cpu_info);
type_register_static(&rx62n_rx_cpu_info);
}
type_init(rx_cpu_register_types)