aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/m68k/Kconfig1
-rw-r--r--hw/m68k/q800.c92
-rw-r--r--target/m68k/cpu.c193
-rw-r--r--target/m68k/cpu.h5
-rw-r--r--target/m68k/fpu_helper.c10
-rw-r--r--target/m68k/translate.c16
6 files changed, 286 insertions, 31 deletions
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
index c757e7dfa4..60d7bcfb8f 100644
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -22,3 +22,4 @@ config Q800
select ESCC
select ESP
select DP8393X
+ select OR_IRQ
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 4db2b9bbc7..2af0e2532e 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -29,6 +29,7 @@
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/irq.h"
+#include "hw/or-irq.h"
#include "elf.h"
#include "hw/loader.h"
#include "ui/console.h"
@@ -47,6 +48,7 @@
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
+#include "migration/vmstate.h"
#define MACROM_ADDR 0x40800000
#define MACROM_SIZE 0x00100000
@@ -94,10 +96,14 @@
* CPU.
*/
-typedef struct {
+#define TYPE_GLUE "q800-glue"
+OBJECT_DECLARE_SIMPLE_TYPE(GLUEState, GLUE)
+
+struct GLUEState {
+ SysBusDevice parent_obj;
M68kCPU *cpu;
uint8_t ipr;
-} GLUEState;
+};
static void GLUE_set_irq(void *opaque, int irq, int level)
{
@@ -119,6 +125,58 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
m68k_set_irq_level(s->cpu, 0, 0);
}
+static void glue_reset(DeviceState *dev)
+{
+ GLUEState *s = GLUE(dev);
+
+ s->ipr = 0;
+}
+
+static const VMStateDescription vmstate_glue = {
+ .name = "q800-glue",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(ipr, GLUEState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+/*
+ * If the m68k CPU implemented its inbound irq lines as GPIO lines
+ * rather than via the m68k_set_irq_level() function we would not need
+ * this cpu link property and could instead provide outbound IRQ lines
+ * that the board could wire up to the CPU.
+ */
+static Property glue_properties[] = {
+ DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void glue_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+
+ qdev_init_gpio_in(dev, GLUE_set_irq, 8);
+}
+
+static void glue_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_glue;
+ dc->reset = glue_reset;
+ device_class_set_props(dc, glue_properties);
+}
+
+static const TypeInfo glue_info = {
+ .name = TYPE_GLUE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GLUEState),
+ .instance_init = glue_init,
+ .class_init = glue_class_init,
+};
+
static void main_cpu_reset(void *opaque)
{
M68kCPU *cpu = opaque;
@@ -173,13 +231,13 @@ static void q800_init(MachineState *machine)
CPUState *cs;
DeviceState *dev;
DeviceState *via_dev;
+ DeviceState *escc_orgate;
SysBusESPState *sysbus_esp;
ESPState *esp;
SysBusDevice *sysbus;
BusState *adb_bus;
NubusBus *nubus;
- GLUEState *irq;
- qemu_irq *pic;
+ DeviceState *glue;
DriveInfo *dinfo;
linux_boot = (kernel_filename != NULL);
@@ -213,10 +271,9 @@ static void q800_init(MachineState *machine)
}
/* IRQ Glue */
-
- irq = g_new0(GLUEState, 1);
- irq->cpu = cpu;
- pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
+ glue = qdev_new(TYPE_GLUE);
+ object_property_set_link(OBJECT(glue), "cpu", OBJECT(cpu), &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(glue), &error_fatal);
/* VIA */
@@ -228,8 +285,10 @@ static void q800_init(MachineState *machine)
sysbus = SYS_BUS_DEVICE(via_dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, VIA_BASE);
- qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]);
- qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, pic[1]);
+ qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0,
+ qdev_get_gpio_in(glue, 0));
+ qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1,
+ qdev_get_gpio_in(glue, 1));
adb_bus = qdev_get_child_bus(via_dev, "adb.0");
@@ -270,7 +329,7 @@ static void q800_init(MachineState *machine)
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, SONIC_BASE);
sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE);
- sysbus_connect_irq(sysbus, 0, pic[2]);
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 2));
/* SCC */
@@ -285,8 +344,14 @@ static void q800_init(MachineState *machine)
qdev_prop_set_uint32(dev, "chnAtype", 0);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
- sysbus_connect_irq(sysbus, 0, pic[3]);
- sysbus_connect_irq(sysbus, 1, pic[3]);
+
+ /* Logically OR both its IRQs together */
+ escc_orgate = DEVICE(object_new(TYPE_OR_IRQ));
+ object_property_set_int(OBJECT(escc_orgate), "num-lines", 2, &error_fatal);
+ qdev_realize_and_unref(escc_orgate, NULL, &error_fatal);
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0));
+ sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1));
+ qdev_connect_gpio_out(DEVICE(escc_orgate), 0, qdev_get_gpio_in(glue, 3));
sysbus_mmio_map(sysbus, 0, SCC_BASE);
/* SCSI */
@@ -448,6 +513,7 @@ static const TypeInfo q800_machine_typeinfo = {
static void q800_machine_register_types(void)
{
type_register_static(&q800_machine_typeinfo);
+ type_register_static(&glue_info);
}
type_init(q800_machine_register_types)
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 72c545149e..b811a0bdde 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -260,10 +260,198 @@ static void m68k_cpu_initfn(Object *obj)
cpu_set_cpustate_pointers(cpu);
}
+#if defined(CONFIG_SOFTMMU)
+static bool fpu_needed(void *opaque)
+{
+ M68kCPU *s = opaque;
+
+ return m68k_feature(&s->env, M68K_FEATURE_CF_FPU) ||
+ m68k_feature(&s->env, M68K_FEATURE_FPU);
+}
+
+typedef struct m68k_FPReg_tmp {
+ FPReg *parent;
+ uint64_t tmp_mant;
+ uint16_t tmp_exp;
+} m68k_FPReg_tmp;
+
+static void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
+{
+ CPU_LDoubleU temp;
+
+ temp.d = f;
+ *pmant = temp.l.lower;
+ *pexp = temp.l.upper;
+}
+
+static floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
+{
+ CPU_LDoubleU temp;
+
+ temp.l.upper = upper;
+ temp.l.lower = mant;
+ return temp.d;
+}
+
+static int freg_pre_save(void *opaque)
+{
+ m68k_FPReg_tmp *tmp = opaque;
+
+ cpu_get_fp80(&tmp->tmp_mant, &tmp->tmp_exp, tmp->parent->d);
+
+ return 0;
+}
+
+static int freg_post_load(void *opaque, int version)
+{
+ m68k_FPReg_tmp *tmp = opaque;
+
+ tmp->parent->d = cpu_set_fp80(tmp->tmp_mant, tmp->tmp_exp);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_freg_tmp = {
+ .name = "freg_tmp",
+ .post_load = freg_post_load,
+ .pre_save = freg_pre_save,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(tmp_mant, m68k_FPReg_tmp),
+ VMSTATE_UINT16(tmp_exp, m68k_FPReg_tmp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_freg = {
+ .name = "freg",
+ .fields = (VMStateField[]) {
+ VMSTATE_WITH_TMP(FPReg, m68k_FPReg_tmp, vmstate_freg_tmp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int fpu_post_load(void *opaque, int version)
+{
+ M68kCPU *s = opaque;
+
+ cpu_m68k_restore_fp_status(&s->env);
+
+ return 0;
+}
+
+const VMStateDescription vmmstate_fpu = {
+ .name = "cpu/fpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = fpu_needed,
+ .post_load = fpu_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(env.fpcr, M68kCPU),
+ VMSTATE_UINT32(env.fpsr, M68kCPU),
+ VMSTATE_STRUCT_ARRAY(env.fregs, M68kCPU, 8, 0, vmstate_freg, FPReg),
+ VMSTATE_STRUCT(env.fp_result, M68kCPU, 0, vmstate_freg, FPReg),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool cf_spregs_needed(void *opaque)
+{
+ M68kCPU *s = opaque;
+
+ return m68k_feature(&s->env, M68K_FEATURE_CF_ISA_A);
+}
+
+const VMStateDescription vmstate_cf_spregs = {
+ .name = "cpu/cf_spregs",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cf_spregs_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64_ARRAY(env.macc, M68kCPU, 4),
+ VMSTATE_UINT32(env.macsr, M68kCPU),
+ VMSTATE_UINT32(env.mac_mask, M68kCPU),
+ VMSTATE_UINT32(env.rambar0, M68kCPU),
+ VMSTATE_UINT32(env.mbar, M68kCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool cpu_68040_mmu_needed(void *opaque)
+{
+ M68kCPU *s = opaque;
+
+ return m68k_feature(&s->env, M68K_FEATURE_M68040);
+}
+
+const VMStateDescription vmstate_68040_mmu = {
+ .name = "cpu/68040_mmu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_68040_mmu_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(env.mmu.ar, M68kCPU),
+ VMSTATE_UINT32(env.mmu.ssw, M68kCPU),
+ VMSTATE_UINT16(env.mmu.tcr, M68kCPU),
+ VMSTATE_UINT32(env.mmu.urp, M68kCPU),
+ VMSTATE_UINT32(env.mmu.srp, M68kCPU),
+ VMSTATE_BOOL(env.mmu.fault, M68kCPU),
+ VMSTATE_UINT32_ARRAY(env.mmu.ttr, M68kCPU, 4),
+ VMSTATE_UINT32(env.mmu.mmusr, M68kCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool cpu_68040_spregs_needed(void *opaque)
+{
+ M68kCPU *s = opaque;
+
+ return m68k_feature(&s->env, M68K_FEATURE_M68040);
+}
+
+const VMStateDescription vmstate_68040_spregs = {
+ .name = "cpu/68040_spregs",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_68040_spregs_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(env.vbr, M68kCPU),
+ VMSTATE_UINT32(env.cacr, M68kCPU),
+ VMSTATE_UINT32(env.sfc, M68kCPU),
+ VMSTATE_UINT32(env.dfc, M68kCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_m68k_cpu = {
.name = "cpu",
- .unmigratable = 1,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(env.dregs, M68kCPU, 8),
+ VMSTATE_UINT32_ARRAY(env.aregs, M68kCPU, 8),
+ VMSTATE_UINT32(env.pc, M68kCPU),
+ VMSTATE_UINT32(env.sr, M68kCPU),
+ VMSTATE_INT32(env.current_sp, M68kCPU),
+ VMSTATE_UINT32_ARRAY(env.sp, M68kCPU, 3),
+ VMSTATE_UINT32(env.cc_op, M68kCPU),
+ VMSTATE_UINT32(env.cc_x, M68kCPU),
+ VMSTATE_UINT32(env.cc_n, M68kCPU),
+ VMSTATE_UINT32(env.cc_v, M68kCPU),
+ VMSTATE_UINT32(env.cc_c, M68kCPU),
+ VMSTATE_UINT32(env.cc_z, M68kCPU),
+ VMSTATE_INT32(env.pending_vector, M68kCPU),
+ VMSTATE_INT32(env.pending_level, M68kCPU),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmmstate_fpu,
+ &vmstate_cf_spregs,
+ &vmstate_68040_mmu,
+ &vmstate_68040_spregs,
+ NULL
+ },
};
+#endif
static void m68k_cpu_class_init(ObjectClass *c, void *data)
{
@@ -287,13 +475,12 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
#if defined(CONFIG_SOFTMMU)
cc->do_transaction_failed = m68k_cpu_transaction_failed;
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
+ dc->vmsd = &vmstate_m68k_cpu;
#endif
cc->disas_set_info = m68k_cpu_disas_set_info;
cc->tcg_initialize = m68k_tcg_init;
cc->gdb_num_core_regs = 18;
-
- dc->vmsd = &vmstate_m68k_cpu;
}
static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data)
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 521ac67cdd..de5b9875fe 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -33,8 +33,6 @@
#define OS_PACKED 6
#define OS_UNSIZED 7
-#define MAX_QREGS 32
-
#define EXCP_ACCESS 2 /* Access (MMU) error. */
#define EXCP_ADDRESS 3 /* Address error. */
#define EXCP_ILLEGAL 4 /* Illegal instruction. */
@@ -139,8 +137,6 @@ typedef struct CPUM68KState {
int pending_vector;
int pending_level;
- uint32_t qregs[MAX_QREGS];
-
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@@ -183,6 +179,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
+void cpu_m68k_restore_fp_status(CPUM68KState *env);
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 9acf60dfd4..797000e748 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -135,10 +135,8 @@ static void restore_rounding_mode(CPUM68KState *env)
}
}
-void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val)
+void cpu_m68k_restore_fp_status(CPUM68KState *env)
{
- env->fpcr = val & 0xffff;
-
if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
cf_restore_precision_mode(env);
} else {
@@ -147,6 +145,12 @@ void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val)
restore_rounding_mode(env);
}
+void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val)
+{
+ env->fpcr = val & 0xffff;
+ cpu_m68k_restore_fp_status(env);
+}
+
void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val)
{
FloatRoundMode rounding_mode = get_float_rounding_mode(&env->fp_status);
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 3fc67aa452..133a404919 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -438,7 +438,7 @@ static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
}
/*
- * Handle a base + index + displacement effective addresss.
+ * Handle a base + index + displacement effective address.
* A NULL_QREG base means pc-relative.
*/
static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
@@ -1696,7 +1696,7 @@ static void bcd_add(TCGv dest, TCGv src)
/*
* t1 = (src + 0x066) + dest + X
- * = result with some possible exceding 0x6
+ * = result with some possible exceeding 0x6
*/
t0 = tcg_const_i32(0x066);
@@ -1706,7 +1706,7 @@ static void bcd_add(TCGv dest, TCGv src)
tcg_gen_add_i32(t1, t0, dest);
tcg_gen_add_i32(t1, t1, QREG_CC_X);
- /* we will remove exceding 0x6 where there is no carry */
+ /* we will remove exceeding 0x6 where there is no carry */
/*
* t0 = (src + 0x0066) ^ dest
@@ -1736,7 +1736,7 @@ static void bcd_add(TCGv dest, TCGv src)
tcg_temp_free(t0);
/*
- * remove the exceding 0x6
+ * remove the exceeding 0x6
* for digits that have not generated a carry
*/
@@ -2638,7 +2638,7 @@ DISAS_INSN(negx)
gen_flush_flags(s); /* compute old Z */
/*
- * Perform substract with borrow.
+ * Perform subtract with borrow.
* (X, N) = -(src + X);
*/
@@ -2653,7 +2653,7 @@ DISAS_INSN(negx)
/*
* Compute signed-overflow for negation. The normal formula for
* subtraction is (res ^ src) & (src ^ dest), but with dest==0
- * this simplies to res & src.
+ * this simplifies to res & src.
*/
tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
@@ -3159,7 +3159,7 @@ static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
gen_flush_flags(s); /* compute old Z */
/*
- * Perform substract with borrow.
+ * Perform subtract with borrow.
* (X, N) = dest - (src + X);
*/
@@ -3169,7 +3169,7 @@ static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
- /* Compute signed-overflow for substract. */
+ /* Compute signed-overflow for subtract. */
tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
tcg_gen_xor_i32(tmp, dest, src);