mirror of
https://github.com/qemu/qemu.git
synced 2024-11-28 06:13:46 +08:00
m68k/ColdFire system emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2851 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
9daea9067a
commit
0633879f1a
@ -308,7 +308,7 @@ LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), m68k)
|
||||
LIBOBJS+= helper.o
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), alpha)
|
||||
@ -466,6 +466,9 @@ endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), m68k)
|
||||
VL_OBJS+= an5206.o mcf5206.o ptimer.o
|
||||
endif
|
||||
ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
endif
|
||||
|
2
configure
vendored
2
configure
vendored
@ -467,7 +467,7 @@ fi
|
||||
if test -z "$target_list" ; then
|
||||
# these targets are portable
|
||||
if [ "$softmmu" = "yes" ] ; then
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu "
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu"
|
||||
fi
|
||||
# the following are Linux specific
|
||||
if [ "$linux_user" = "yes" ] ; then
|
||||
|
18
cpu-exec.c
18
cpu-exec.c
@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
cs_base = 0;
|
||||
pc = env->PC;
|
||||
#elif defined(TARGET_M68K)
|
||||
flags = env->fpcr & M68K_FPCR_PREC;
|
||||
flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S);
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_SH4)
|
||||
@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1)
|
||||
return EXCP_HALTED;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_ALPHA) || defined(TARGET_M68K)
|
||||
if (env1->halted) {
|
||||
if (env1->interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
env1->halted = 0;
|
||||
@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_ALPHA)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_M68K)
|
||||
do_interrupt(0);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1)
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
do_interrupt(env);
|
||||
}
|
||||
#elif defined(TARGET_M68K)
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||
&& ((env->sr & SR_I) >> SR_I_SHIFT)
|
||||
< env->pending_level) {
|
||||
/* Real hardware gets the interrupt vector via an
|
||||
IACK cycle at this point. Current emulated
|
||||
hardware doesn't rely on this, so we
|
||||
provide/save the vector when the interrupt is
|
||||
first signalled. */
|
||||
env->exception_index = env->pending_vector;
|
||||
do_interrupt(1);
|
||||
}
|
||||
#endif
|
||||
/* Don't use the cached interupt_request value,
|
||||
do_interrupt may have updated the EXITTB flag. */
|
||||
|
@ -584,6 +584,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
is_user = ((env->sr & SR_MD) == 0);
|
||||
#elif defined (TARGET_ALPHA)
|
||||
is_user = ((env->ps >> 3) & 3);
|
||||
#elif defined (TARGET_M68K)
|
||||
is_user = ((env->sr & SR_S) == 0);
|
||||
#else
|
||||
#error unimplemented CPU
|
||||
#endif
|
||||
|
89
hw/an5206.c
Normal file
89
hw/an5206.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Arnewsh 5206 ColdFire system emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This code is licenced under the GPL
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x10000
|
||||
#define AN5206_MBAR_ADDR 0x10000000
|
||||
#define AN5206_RAMBAR_ADDR 0x20000000
|
||||
|
||||
/* Stub functions for hardware that doesn't exist. */
|
||||
void pic_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
void DMA_run (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Board init. */
|
||||
|
||||
static void an5206_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model)
|
||||
{
|
||||
CPUState *env;
|
||||
int kernel_size;
|
||||
uint64_t elf_entry;
|
||||
target_ulong entry;
|
||||
|
||||
env = cpu_init();
|
||||
if (!cpu_model)
|
||||
cpu_model = "m5206";
|
||||
cpu_m68k_set_model(env, cpu_model);
|
||||
|
||||
/* Initialize CPU registers. */
|
||||
env->vbr = 0;
|
||||
/* TODO: allow changing MBAR and RAMBAR. */
|
||||
env->mbar = AN5206_MBAR_ADDR | 1;
|
||||
env->rambar0 = AN5206_RAMBAR_ADDR | 1;
|
||||
|
||||
/* DRAM at address zero */
|
||||
cpu_register_physical_memory(0, ram_size,
|
||||
qemu_ram_alloc(ram_size) | IO_MEM_RAM);
|
||||
|
||||
/* Internal SRAM. */
|
||||
cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
|
||||
qemu_ram_alloc(512) | IO_MEM_RAM);
|
||||
|
||||
mcf5206_init(AN5206_MBAR_ADDR, env);
|
||||
|
||||
/* Load kernel. */
|
||||
if (!kernel_filename) {
|
||||
fprintf(stderr, "Kernel image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uboot(kernel_filename, &entry, NULL);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
entry = KERNEL_LOAD_ADDR;
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
env->pc = entry;
|
||||
}
|
||||
|
||||
QEMUMachine an5206_machine = {
|
||||
"an5206",
|
||||
"Arnewsh 5206",
|
||||
an5206_init,
|
||||
};
|
813
hw/mcf5206.c
Normal file
813
hw/mcf5206.c
Normal file
@ -0,0 +1,813 @@
|
||||
/*
|
||||
* Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This code is licenced under the GPL
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
/* General purpose timer module. */
|
||||
typedef struct {
|
||||
uint16_t tmr;
|
||||
uint16_t trr;
|
||||
uint16_t tcr;
|
||||
uint16_t ter;
|
||||
ptimer_state *timer;
|
||||
qemu_irq irq;
|
||||
int irq_state;
|
||||
} m5206_timer_state;
|
||||
|
||||
#define TMR_RST 0x01
|
||||
#define TMR_CLK 0x06
|
||||
#define TMR_FRR 0x08
|
||||
#define TMR_ORI 0x10
|
||||
#define TMR_OM 0x20
|
||||
#define TMR_CE 0xc0
|
||||
|
||||
#define TER_CAP 0x01
|
||||
#define TER_REF 0x02
|
||||
|
||||
static void m5206_timer_update(m5206_timer_state *s)
|
||||
{
|
||||
if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
|
||||
qemu_irq_raise(s->irq);
|
||||
else
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static void m5206_timer_reset(m5206_timer_state *s)
|
||||
{
|
||||
s->tmr = 0;
|
||||
s->trr = 0;
|
||||
}
|
||||
|
||||
static void m5206_timer_recalibrate(m5206_timer_state *s)
|
||||
{
|
||||
int prescale;
|
||||
int mode;
|
||||
|
||||
ptimer_stop(s->timer);
|
||||
|
||||
if ((s->tmr & TMR_RST) == 0)
|
||||
return;
|
||||
|
||||
prescale = (s->tmr >> 8) + 1;
|
||||
mode = (s->tmr >> 1) & 3;
|
||||
if (mode == 2)
|
||||
prescale *= 16;
|
||||
|
||||
if (mode == 3 || mode == 0)
|
||||
cpu_abort(cpu_single_env,
|
||||
"m5206_timer: mode %d not implemented\n", mode);
|
||||
if ((s->tmr & TMR_FRR) == 0)
|
||||
cpu_abort(cpu_single_env,
|
||||
"m5206_timer: free running mode not implemented\n");
|
||||
|
||||
/* Assume 66MHz system clock. */
|
||||
ptimer_set_freq(s->timer, 66000000 / prescale);
|
||||
|
||||
ptimer_set_limit(s->timer, s->trr, 0);
|
||||
|
||||
ptimer_run(s->timer, 0);
|
||||
}
|
||||
|
||||
static void m5206_timer_trigger(void *opaque)
|
||||
{
|
||||
m5206_timer_state *s = (m5206_timer_state *)opaque;
|
||||
s->ter |= TER_REF;
|
||||
m5206_timer_update(s);
|
||||
}
|
||||
|
||||
static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
|
||||
{
|
||||
switch (addr) {
|
||||
case 0:
|
||||
return s->tmr;
|
||||
case 4:
|
||||
return s->trr;
|
||||
case 8:
|
||||
return s->tcr;
|
||||
case 0xc:
|
||||
return s->trr - ptimer_get_count(s->timer);
|
||||
case 0x11:
|
||||
return s->ter;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
|
||||
{
|
||||
switch (addr) {
|
||||
case 0:
|
||||
if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
|
||||
m5206_timer_reset(s);
|
||||
}
|
||||
s->tmr = val;
|
||||
m5206_timer_recalibrate(s);
|
||||
break;
|
||||
case 4:
|
||||
s->trr = val;
|
||||
m5206_timer_recalibrate(s);
|
||||
break;
|
||||
case 8:
|
||||
s->tcr = val;
|
||||
break;
|
||||
case 0xc:
|
||||
ptimer_set_count(s->timer, val);
|
||||
break;
|
||||
case 0x11:
|
||||
s->ter &= ~val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m5206_timer_update(s);
|
||||
}
|
||||
|
||||
static m5206_timer_state *m5206_timer_init(qemu_irq irq)
|
||||
{
|
||||
m5206_timer_state *s;
|
||||
QEMUBH *bh;
|
||||
|
||||
s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
|
||||
bh = qemu_bh_new(m5206_timer_trigger, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->irq = irq;
|
||||
m5206_timer_reset(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* UART */
|
||||
|
||||
typedef struct {
|
||||
uint8_t mr[2];
|
||||
uint8_t sr;
|
||||
uint8_t isr;
|
||||
uint8_t imr;
|
||||
uint8_t bg1;
|
||||
uint8_t bg2;
|
||||
uint8_t fifo[4];
|
||||
uint8_t tb;
|
||||
int current_mr;
|
||||
int fifo_len;
|
||||
int tx_enabled;
|
||||
int rx_enabled;
|
||||
qemu_irq irq;
|
||||
CharDriverState *chr;
|
||||
} m5206_uart_state;
|
||||
|
||||
/* UART Status Register bits. */
|
||||
#define M5206_UART_RxRDY 0x01
|
||||
#define M5206_UART_FFULL 0x02
|
||||
#define M5206_UART_TxRDY 0x04
|
||||
#define M5206_UART_TxEMP 0x08
|
||||
#define M5206_UART_OE 0x10
|
||||
#define M5206_UART_PE 0x20
|
||||
#define M5206_UART_FE 0x40
|
||||
#define M5206_UART_RB 0x80
|
||||
|
||||
/* Interrupt flags. */
|
||||
#define M5206_UART_TxINT 0x01
|
||||
#define M5206_UART_RxINT 0x02
|
||||
#define M5206_UART_DBINT 0x04
|
||||
#define M5206_UART_COSINT 0x80
|
||||
|
||||
/* UMR1 flags. */
|
||||
#define M5206_UART_BC0 0x01
|
||||
#define M5206_UART_BC1 0x02
|
||||
#define M5206_UART_PT 0x04
|
||||
#define M5206_UART_PM0 0x08
|
||||
#define M5206_UART_PM1 0x10
|
||||
#define M5206_UART_ERR 0x20
|
||||
#define M5206_UART_RxIRQ 0x40
|
||||
#define M5206_UART_RxRTS 0x80
|
||||
|
||||
static void m5206_uart_update(m5206_uart_state *s)
|
||||
{
|
||||
s->isr &= ~(M5206_UART_TxINT | M5206_UART_RxINT);
|
||||
if (s->sr & M5206_UART_TxRDY)
|
||||
s->isr |= M5206_UART_TxINT;
|
||||
if ((s->sr & ((s->mr[0] & M5206_UART_RxIRQ)
|
||||
? M5206_UART_FFULL : M5206_UART_RxRDY)) != 0)
|
||||
s->isr |= M5206_UART_RxINT;
|
||||
|
||||
qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
|
||||
}
|
||||
|
||||
static uint32_t m5206_uart_read(m5206_uart_state *s, uint32_t addr)
|
||||
{
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
return s->mr[s->current_mr];
|
||||
case 0x04:
|
||||
return s->sr;
|
||||
case 0x0c:
|
||||
{
|
||||
uint8_t val;
|
||||
int i;
|
||||
|
||||
if (s->fifo_len == 0)
|
||||
return 0;
|
||||
|
||||
val = s->fifo[0];
|
||||
s->fifo_len--;
|
||||
for (i = 0; i < s->fifo_len; i++)
|
||||
s->fifo[i] = s->fifo[i + 1];
|
||||
s->sr &= ~M5206_UART_FFULL;
|
||||
if (s->fifo_len == 0)
|
||||
s->sr &= ~M5206_UART_RxRDY;
|
||||
m5206_uart_update(s);
|
||||
return val;
|
||||
}
|
||||
case 0x10:
|
||||
/* TODO: Implement IPCR. */
|
||||
return 0;
|
||||
case 0x14:
|
||||
return s->isr;
|
||||
case 0x18:
|
||||
return s->bg1;
|
||||
case 0x1c:
|
||||
return s->bg2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update TxRDY flag and set data if present and enabled. */
|
||||
static void m5206_uart_do_tx(m5206_uart_state *s)
|
||||
{
|
||||
if (s->tx_enabled && (s->sr & M5206_UART_TxEMP) == 0) {
|
||||
if (s->chr)
|
||||
qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
|
||||
s->sr |= M5206_UART_TxEMP;
|
||||
}
|
||||
if (s->tx_enabled) {
|
||||
s->sr |= M5206_UART_TxRDY;
|
||||
} else {
|
||||
s->sr &= ~M5206_UART_TxRDY;
|
||||
}
|
||||
}
|
||||
|
||||
static void m5206_do_command(m5206_uart_state *s, uint8_t cmd)
|
||||
{
|
||||
/* Misc command. */
|
||||
switch ((cmd >> 4) & 3) {
|
||||
case 0: /* No-op. */
|
||||
break;
|
||||
case 1: /* Reset mode register pointer. */
|
||||
s->current_mr = 0;
|
||||
break;
|
||||
case 2: /* Reset receiver. */
|
||||
s->rx_enabled = 0;
|
||||
s->fifo_len = 0;
|
||||
s->sr &= ~(M5206_UART_RxRDY | M5206_UART_FFULL);
|
||||
break;
|
||||
case 3: /* Reset transmitter. */
|
||||
s->tx_enabled = 0;
|
||||
s->sr |= M5206_UART_TxEMP;
|
||||
s->sr &= ~M5206_UART_TxRDY;
|
||||
break;
|
||||
case 4: /* Reset error status. */
|
||||
break;
|
||||
case 5: /* Reset break-change interrupt. */
|
||||
s->isr &= ~M5206_UART_DBINT;
|
||||
break;
|
||||
case 6: /* Start break. */
|
||||
case 7: /* Stop break. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Transmitter command. */
|
||||
switch ((cmd >> 2) & 3) {
|
||||
case 0: /* No-op. */
|
||||
break;
|
||||
case 1: /* Enable. */
|
||||
s->tx_enabled = 1;
|
||||
m5206_uart_do_tx(s);
|
||||
break;
|
||||
case 2: /* Disable. */
|
||||
s->tx_enabled = 0;
|
||||
m5206_uart_do_tx(s);
|
||||
break;
|
||||
case 3: /* Reserved. */
|
||||
fprintf(stderr, "m5206_uart: Bad TX command\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Receiver command. */
|
||||
switch (cmd & 3) {
|
||||
case 0: /* No-op. */
|
||||
break;
|
||||
case 1: /* Enable. */
|
||||
s->rx_enabled = 1;
|
||||
break;
|
||||
case 2:
|
||||
s->rx_enabled = 0;
|
||||
break;
|
||||
case 3: /* Reserved. */
|
||||
fprintf(stderr, "m5206_uart: Bad RX command\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void m5206_uart_write(m5206_uart_state *s, uint32_t addr, uint32_t val)
|
||||
{
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
s->mr[s->current_mr] = val;
|
||||
s->current_mr = 1;
|
||||
break;
|
||||
case 0x04:
|
||||
/* CSR is ignored. */
|
||||
break;
|
||||
case 0x08: /* Command Register. */
|
||||
m5206_do_command(s, val);
|
||||
break;
|
||||
case 0x0c: /* Transmit Buffer. */
|
||||
s->sr &= ~M5206_UART_TxEMP;
|
||||
s->tb = val;
|
||||
m5206_uart_do_tx(s);
|
||||
break;
|
||||
case 0x10:
|
||||
/* ACR is ignored. */
|
||||
break;
|
||||
case 0x14:
|
||||
s->imr = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m5206_uart_update(s);
|
||||
}
|
||||
|
||||
static void m5206_uart_reset(m5206_uart_state *s)
|
||||
{
|
||||
s->fifo_len = 0;
|
||||
s->mr[0] = 0;
|
||||
s->mr[1] = 0;
|
||||
s->sr = M5206_UART_TxEMP;
|
||||
s->tx_enabled = 0;
|
||||
s->rx_enabled = 0;
|
||||
s->isr = 0;
|
||||
s->imr = 0;
|
||||
}
|
||||
|
||||
static void m5206_uart_push_byte(m5206_uart_state *s, uint8_t data)
|
||||
{
|
||||
/* Break events overwrite the last byte if the fifo is full. */
|
||||
if (s->fifo_len == 4)
|
||||
s->fifo_len--;
|
||||
|
||||
s->fifo[s->fifo_len] = data;
|
||||
s->fifo_len++;
|
||||
s->sr |= M5206_UART_RxRDY;
|
||||
if (s->fifo_len == 4)
|
||||
s->sr |= M5206_UART_FFULL;
|
||||
|
||||
m5206_uart_update(s);
|
||||
}
|
||||
|
||||
static void m5206_uart_event(void *opaque, int event)
|
||||
{
|
||||
m5206_uart_state *s = (m5206_uart_state *)opaque;
|
||||
|
||||
switch (event) {
|
||||
case CHR_EVENT_BREAK:
|
||||
s->isr |= M5206_UART_DBINT;
|
||||
m5206_uart_push_byte(s, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int m5206_uart_can_receive(void *opaque)
|
||||
{
|
||||
m5206_uart_state *s = (m5206_uart_state *)opaque;
|
||||
|
||||
return s->rx_enabled && (s->sr & M5206_UART_FFULL) == 0;
|
||||
}
|
||||
|
||||
static void m5206_uart_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
m5206_uart_state *s = (m5206_uart_state *)opaque;
|
||||
|
||||
m5206_uart_push_byte(s, buf[0]);
|
||||
}
|
||||
|
||||
static m5206_uart_state *m5206_uart_init(qemu_irq irq, CharDriverState *chr)
|
||||
{
|
||||
m5206_uart_state *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(m5206_uart_state));
|
||||
s->chr = chr;
|
||||
s->irq = irq;
|
||||
if (chr) {
|
||||
qemu_chr_add_handlers(chr, m5206_uart_can_receive, m5206_uart_receive,
|
||||
m5206_uart_event, s);
|
||||
}
|
||||
m5206_uart_reset(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* System Integration Module. */
|
||||
|
||||
typedef struct {
|
||||
CPUState *env;
|
||||
m5206_timer_state *timer[2];
|
||||
m5206_uart_state *uart[2];
|
||||
uint8_t scr;
|
||||
uint8_t icr[14];
|
||||
uint16_t imr; /* 1 == interrupt is masked. */
|
||||
uint16_t ipr;
|
||||
uint8_t rsr;
|
||||
uint8_t swivr;
|
||||
uint8_t par;
|
||||
/* Include the UART vector registers here. */
|
||||
uint8_t uivr[2];
|
||||
} m5206_mbar_state;
|
||||
|
||||
/* Interrupt controller. */
|
||||
|
||||
static int m5206_find_pending_irq(m5206_mbar_state *s)
|
||||
{
|
||||
int level;
|
||||
int vector;
|
||||
uint16_t active;
|
||||
int i;
|
||||
|
||||
level = 0;
|
||||
vector = 0;
|
||||
active = s->ipr & ~s->imr;
|
||||
if (!active)
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < 14; i++) {
|
||||
if (active & (1 << i)) {
|
||||
if ((s->icr[i] & 0x1f) > level) {
|
||||
level = s->icr[i] & 0x1f;
|
||||
vector = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level < 4)
|
||||
vector = 0;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
static void m5206_mbar_update(m5206_mbar_state *s)
|
||||
{
|
||||
int irq;
|
||||
int vector;
|
||||
int level;
|
||||
|
||||
irq = m5206_find_pending_irq(s);
|
||||
if (irq) {
|
||||
int tmp;
|
||||
tmp = s->icr[irq];
|
||||
level = (tmp >> 2) & 7;
|
||||
if (tmp & 0x80) {
|
||||
/* Autovector. */
|
||||
vector = 24 + level;
|
||||
} else {
|
||||
switch (irq) {
|
||||
case 8: /* SWT */
|
||||
vector = s->swivr;
|
||||
break;
|
||||
case 12: /* UART1 */
|
||||
vector = s->uivr[0];
|
||||
break;
|
||||
case 13: /* UART2 */
|
||||
vector = s->uivr[1];
|
||||
break;
|
||||
default:
|
||||
/* Unknown vector. */
|
||||
fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
|
||||
vector = 0xf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
level = 0;
|
||||
vector = 0;
|
||||
}
|
||||
m68k_set_irq_level(s->env, level, vector);
|
||||
}
|
||||
|
||||
static void m5206_mbar_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
if (level) {
|
||||
s->ipr |= 1 << irq;
|
||||
} else {
|
||||
s->ipr &= ~(1 << irq);
|
||||
}
|
||||
m5206_mbar_update(s);
|
||||
}
|
||||
|
||||
/* System Integration Module. */
|
||||
|
||||
static void m5206_mbar_reset(m5206_mbar_state *s)
|
||||
{
|
||||
s->scr = 0xc0;
|
||||
s->icr[1] = 0x04;
|
||||
s->icr[2] = 0x08;
|
||||
s->icr[3] = 0x0c;
|
||||
s->icr[4] = 0x10;
|
||||
s->icr[5] = 0x14;
|
||||
s->icr[6] = 0x18;
|
||||
s->icr[7] = 0x1c;
|
||||
s->icr[8] = 0x1c;
|
||||
s->icr[9] = 0x80;
|
||||
s->icr[10] = 0x80;
|
||||
s->icr[11] = 0x80;
|
||||
s->icr[12] = 0x00;
|
||||
s->icr[13] = 0x00;
|
||||
s->imr = 0x3ffe;
|
||||
s->rsr = 0x80;
|
||||
s->swivr = 0x0f;
|
||||
s->par = 0;
|
||||
}
|
||||
|
||||
static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
|
||||
{
|
||||
if (offset >= 0x100 && offset < 0x120) {
|
||||
return m5206_timer_read(s->timer[0], offset - 0x100);
|
||||
} else if (offset >= 0x120 && offset < 0x140) {
|
||||
return m5206_timer_read(s->timer[1], offset - 0x120);
|
||||
} else if (offset >= 0x140 && offset < 0x160) {
|
||||
return m5206_uart_read(s->uart[0], offset - 0x140);
|
||||
} else if (offset >= 0x180 && offset < 0x1a0) {
|
||||
return m5206_uart_read(s->uart[1], offset - 0x180);
|
||||
}
|
||||
switch (offset) {
|
||||
case 0x03: return s->scr;
|
||||
case 0x14 ... 0x20: return s->icr[offset - 0x13];
|
||||
case 0x36: return s->imr;
|
||||
case 0x3a: return s->ipr;
|
||||
case 0x40: return s->rsr;
|
||||
case 0x41: return 0;
|
||||
case 0x42: return s->swivr;
|
||||
case 0x50:
|
||||
/* DRAM mask register. */
|
||||
/* FIXME: currently hardcoded to 128Mb. */
|
||||
{
|
||||
uint32_t mask = ~0;
|
||||
while (mask > ram_size)
|
||||
mask >>= 1;
|
||||
return mask & 0x0ffe0000;
|
||||
}
|
||||
case 0x5c: return 1; /* DRAM bank 1 empty. */
|
||||
case 0xcb: return s->par;
|
||||
case 0x170: return s->uivr[0];
|
||||
case 0x1b0: return s->uivr[1];
|
||||
}
|
||||
cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
if (offset >= 0x100 && offset < 0x120) {
|
||||
m5206_timer_write(s->timer[0], offset - 0x100, value);
|
||||
return;
|
||||
} else if (offset >= 0x120 && offset < 0x140) {
|
||||
m5206_timer_write(s->timer[1], offset - 0x120, value);
|
||||
return;
|
||||
} else if (offset >= 0x140 && offset < 0x160) {
|
||||
m5206_uart_write(s->uart[0], offset - 0x140, value);
|
||||
return;
|
||||
} else if (offset >= 0x180 && offset < 0x1a0) {
|
||||
m5206_uart_write(s->uart[1], offset - 0x180, value);
|
||||
return;
|
||||
}
|
||||
switch (offset) {
|
||||
case 0x03:
|
||||
s->scr = value;
|
||||
break;
|
||||
case 0x14 ... 0x20:
|
||||
s->icr[offset - 0x13] = value;
|
||||
m5206_mbar_update(s);
|
||||
break;
|
||||
case 0x36:
|
||||
s->imr = value;
|
||||
m5206_mbar_update(s);
|
||||
break;
|
||||
case 0x40:
|
||||
s->rsr &= ~value;
|
||||
break;
|
||||
case 0x41:
|
||||
/* TODO: implement watchdog. */
|
||||
break;
|
||||
case 0x42:
|
||||
s->swivr = value;
|
||||
break;
|
||||
case 0xcb:
|
||||
s->par = value;
|
||||
break;
|
||||
case 0x170:
|
||||
s->uivr[0] = value;
|
||||
break;
|
||||
case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
|
||||
/* Not implemented: UART Output port bits. */
|
||||
break;
|
||||
case 0x1b0:
|
||||
s->uivr[1] = value;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal peripherals use a variety of register widths.
|
||||
This lookup table allows a single routine to handle all of them. */
|
||||
static const int m5206_mbar_width[] =
|
||||
{
|
||||
/* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
/* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
|
||||
/* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
|
||||
/* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
|
||||
/* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
|
||||
static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
|
||||
|
||||
static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
if (m5206_mbar_width[offset >> 2] > 1) {
|
||||
uint16_t val;
|
||||
val = m5206_mbar_readw(opaque, offset & ~1);
|
||||
if ((offset & 1) == 0) {
|
||||
val >>= 8;
|
||||
}
|
||||
return val & 0xff;
|
||||
}
|
||||
return m5206_mbar_read(s, offset);
|
||||
}
|
||||
|
||||
static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
if (width > 2) {
|
||||
uint32_t val;
|
||||
val = m5206_mbar_readl(opaque, offset & ~3);
|
||||
if ((offset & 3) == 0)
|
||||
val >>= 16;
|
||||
return val & 0xffff;
|
||||
} else if (width < 2) {
|
||||
uint16_t val;
|
||||
val = m5206_mbar_readb(opaque, offset) << 8;
|
||||
val |= m5206_mbar_readb(opaque, offset + 1);
|
||||
return val;
|
||||
}
|
||||
return m5206_mbar_read(s, offset);
|
||||
}
|
||||
|
||||
static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
if (width < 4) {
|
||||
uint32_t val;
|
||||
val = m5206_mbar_readw(opaque, offset) << 16;
|
||||
val |= m5206_mbar_readw(opaque, offset + 2);
|
||||
return val;
|
||||
}
|
||||
return m5206_mbar_read(s, offset);
|
||||
}
|
||||
|
||||
static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value);
|
||||
static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value);
|
||||
|
||||
static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
if (width > 1) {
|
||||
uint32_t tmp;
|
||||
tmp = m5206_mbar_readw(opaque, offset & ~1);
|
||||
if (offset & 1) {
|
||||
tmp = (tmp & 0xff00) | value;
|
||||
} else {
|
||||
tmp = (tmp & 0x00ff) | (value << 8);
|
||||
}
|
||||
m5206_mbar_writew(opaque, offset & ~1, tmp);
|
||||
return;
|
||||
}
|
||||
m5206_mbar_write(s, offset, value);
|
||||
}
|
||||
|
||||
static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
if (width > 2) {
|
||||
uint32_t tmp;
|
||||
tmp = m5206_mbar_readl(opaque, offset & ~3);
|
||||
if (offset & 3) {
|
||||
tmp = (tmp & 0xffff0000) | value;
|
||||
} else {
|
||||
tmp = (tmp & 0x0000ffff) | (value << 16);
|
||||
}
|
||||
m5206_mbar_writel(opaque, offset & ~3, tmp);
|
||||
return;
|
||||
} else if (width < 2) {
|
||||
m5206_mbar_writeb(opaque, offset, value >> 8);
|
||||
m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
|
||||
return;
|
||||
}
|
||||
m5206_mbar_write(s, offset, value);
|
||||
}
|
||||
|
||||
static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
if (width < 4) {
|
||||
m5206_mbar_writew(opaque, offset, value >> 16);
|
||||
m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
|
||||
return;
|
||||
}
|
||||
m5206_mbar_write(s, offset, value);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
|
||||
m5206_mbar_readb,
|
||||
m5206_mbar_readw,
|
||||
m5206_mbar_readl
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
|
||||
m5206_mbar_writeb,
|
||||
m5206_mbar_writew,
|
||||
m5206_mbar_writel
|
||||
};
|
||||
|
||||
qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
|
||||
{
|
||||
m5206_mbar_state *s;
|
||||
qemu_irq *pic;
|
||||
int iomemtype;
|
||||
|
||||
s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
|
||||
iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
|
||||
m5206_mbar_writefn, s);
|
||||
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
|
||||
|
||||
pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
|
||||
s->timer[0] = m5206_timer_init(pic[9]);
|
||||
s->timer[1] = m5206_timer_init(pic[10]);
|
||||
s->uart[0] = m5206_uart_init(pic[12], serial_hds[0]);
|
||||
s->uart[1] = m5206_uart_init(pic[13], serial_hds[1]);
|
||||
s->env = env;
|
||||
|
||||
m5206_mbar_reset(s);
|
||||
return pic;
|
||||
}
|
||||
|
@ -1977,13 +1977,12 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#elif defined(TARGET_M68K)
|
||||
{
|
||||
m68k_def_t *def;
|
||||
def = m68k_find_by_name("cfv4e");
|
||||
if (def == NULL) {
|
||||
if (cpu_model == NULL)
|
||||
cpu_model = "cfv4e";
|
||||
if (cpu_m68k_set_model(env, cpu_model)) {
|
||||
cpu_abort(cpu_single_env,
|
||||
"Unable to find m68k CPU definition\n");
|
||||
}
|
||||
cpu_m68k_register(cpu_single_env, def);
|
||||
env->pc = regs->pc;
|
||||
env->dregs[0] = regs->d0;
|
||||
env->dregs[1] = regs->d1;
|
||||
|
@ -65,6 +65,8 @@
|
||||
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
|
||||
#elif defined (TARGET_ALPHA)
|
||||
#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
|
||||
#elif defined (TARGET_M68K)
|
||||
#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@ -86,6 +88,8 @@
|
||||
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
|
||||
#elif defined (TARGET_ALPHA)
|
||||
#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
|
||||
#elif defined (TARGET_M68K)
|
||||
#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* m68k virtual CPU header
|
||||
*
|
||||
* Copyright (c) 2005-2006 CodeSourcery
|
||||
* Copyright (c) 2005-2007 CodeSourcery
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -50,6 +50,8 @@
|
||||
#define EXCP_UNSUPPORTED 61
|
||||
#define EXCP_ICE 13
|
||||
|
||||
#define EXCP_RTE 0x100
|
||||
|
||||
typedef struct CPUM68KState {
|
||||
uint32_t dregs[8];
|
||||
uint32_t aregs[8];
|
||||
@ -76,6 +78,12 @@ typedef struct CPUM68KState {
|
||||
struct {
|
||||
uint32_t ar;
|
||||
} mmu;
|
||||
|
||||
/* Control registers. */
|
||||
uint32_t vbr;
|
||||
uint32_t mbar;
|
||||
uint32_t rambar0;
|
||||
|
||||
/* ??? remove this. */
|
||||
uint32_t t1;
|
||||
|
||||
@ -84,7 +92,10 @@ typedef struct CPUM68KState {
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
int user_mode_only;
|
||||
uint32_t address;
|
||||
int halted;
|
||||
|
||||
int pending_vector;
|
||||
int pending_level;
|
||||
|
||||
uint32_t qregs[MAX_QREGS];
|
||||
|
||||
@ -94,6 +105,7 @@ typedef struct CPUM68KState {
|
||||
CPUM68KState *cpu_m68k_init(void);
|
||||
int cpu_m68k_exec(CPUM68KState *s);
|
||||
void cpu_m68k_close(CPUM68KState *s);
|
||||
void do_interrupt(int is_hw);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
@ -120,12 +132,19 @@ enum {
|
||||
#define CCF_V 0x02
|
||||
#define CCF_Z 0x04
|
||||
#define CCF_N 0x08
|
||||
#define CCF_X 0x01
|
||||
#define CCF_X 0x10
|
||||
|
||||
#define SR_I_SHIFT 8
|
||||
#define SR_I 0x0700
|
||||
#define SR_M 0x1000
|
||||
#define SR_S 0x2000
|
||||
#define SR_T 0x8000
|
||||
|
||||
typedef struct m68k_def_t m68k_def_t;
|
||||
|
||||
m68k_def_t *m68k_find_by_name(const char *);
|
||||
void cpu_m68k_register(CPUM68KState *, m68k_def_t *);
|
||||
int cpu_m68k_set_model(CPUM68KState *env, const char * name);
|
||||
|
||||
void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
|
||||
|
||||
#define M68K_FPCR_PREC (1 << 6)
|
||||
|
||||
|
@ -40,8 +40,12 @@ static inline void regs_to_env(void)
|
||||
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "softmmu_exec.h"
|
||||
#endif
|
||||
|
||||
void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op);
|
||||
float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1);
|
||||
void helper_movec(CPUM68KState *env, int reg, uint32_t val);
|
||||
|
||||
void cpu_loop_exit(void);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* m68k op helpers
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery
|
||||
* Copyright (c) 2006-2007 CodeSourcery
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -147,3 +147,65 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void helper_movec(CPUM68KState *env, int reg, uint32_t val)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x02: /* CACR */
|
||||
/* Ignored. */
|
||||
break;
|
||||
case 0x801: /* VBR */
|
||||
env->vbr = val;
|
||||
break;
|
||||
/* TODO: Implement control registers. */
|
||||
default:
|
||||
cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
|
||||
reg, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* MMU */
|
||||
|
||||
/* TODO: This will need fixing once the MMU is implemented. */
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
env->exception_index = EXCP_ACCESS;
|
||||
env->mmu.ar = address;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
int prot;
|
||||
|
||||
address &= TARGET_PAGE_MASK;
|
||||
prot = PAGE_READ | PAGE_WRITE;
|
||||
return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
|
||||
}
|
||||
|
||||
/* Notify CPU of a pending interrupt. Prioritization and vectoring should
|
||||
be handled by the interrupt controller. Real hardware only requests
|
||||
the vector when the interrupt is acknowledged by the CPU. For
|
||||
simplicitly we calculate it when the interrupt is signalled. */
|
||||
void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
|
||||
{
|
||||
env->pending_level = level;
|
||||
env->pending_vector = vector;
|
||||
if (level)
|
||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
else
|
||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,16 +27,38 @@ static inline int gen_im32(uint32_t i)
|
||||
return qreg;
|
||||
}
|
||||
|
||||
static inline void gen_op_ldf32(int dest, int addr)
|
||||
static inline void gen_op_ldf32_raw(int dest, int addr)
|
||||
{
|
||||
gen_op_ld32(dest, addr);
|
||||
gen_op_ld32_raw(dest, addr);
|
||||
}
|
||||
|
||||
static inline void gen_op_stf32(int addr, int dest)
|
||||
static inline void gen_op_stf32_raw(int addr, int dest)
|
||||
{
|
||||
gen_op_st32(addr, dest);
|
||||
gen_op_st32_raw(addr, dest);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static inline void gen_op_ldf32_user(int dest, int addr)
|
||||
{
|
||||
gen_op_ld32_user(dest, addr);
|
||||
}
|
||||
|
||||
static inline void gen_op_stf32_user(int addr, int dest)
|
||||
{
|
||||
gen_op_st32_user(addr, dest);
|
||||
}
|
||||
|
||||
static inline void gen_op_ldf32_kernel(int dest, int addr)
|
||||
{
|
||||
gen_op_ld32_kernel(dest, addr);
|
||||
}
|
||||
|
||||
static inline void gen_op_stf32_kernel(int addr, int dest)
|
||||
{
|
||||
gen_op_st32_kernel(addr, dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void gen_op_pack_32_f32(int dest, int src)
|
||||
{
|
||||
gen_op_mov32(dest, src);
|
||||
|
101
target-m68k/op.c
101
target-m68k/op.c
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* m68k micro operations
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery
|
||||
* Copyright (c) 2006-2007 CodeSourcery
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -86,7 +86,7 @@ void set_opf64(int qreg, float64 val)
|
||||
}
|
||||
}
|
||||
|
||||
#define OP(name) void OPPROTO op_##name (void)
|
||||
#define OP(name) void OPPROTO glue(op_,name) (void)
|
||||
|
||||
OP(mov32)
|
||||
{
|
||||
@ -316,77 +316,6 @@ OP(ext16s32)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* Load/store ops. */
|
||||
OP(ld8u32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_op(PARAM1, ldub(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(ld8s32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_op(PARAM1, ldsb(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(ld16u32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_op(PARAM1, lduw(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(ld16s32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_op(PARAM1, ldsw(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(ld32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_op(PARAM1, ldl(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(st8)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM1);
|
||||
stb(addr, get_op(PARAM2));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(st16)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM1);
|
||||
stw(addr, get_op(PARAM2));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(st32)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM1);
|
||||
stl(addr, get_op(PARAM2));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(ldf64)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_opf64(PARAM1, ldfq(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(stf64)
|
||||
{
|
||||
uint32_t addr = get_op(PARAM1);
|
||||
stfq(addr, get_opf64(PARAM2));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(flush_flags)
|
||||
{
|
||||
int cc_op = PARAM1;
|
||||
@ -454,6 +383,13 @@ OP(divs)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(halt)
|
||||
{
|
||||
env->halted = 1;
|
||||
RAISE_EXCEPTION(EXCP_HLT);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(raise_exception)
|
||||
{
|
||||
RAISE_EXCEPTION(PARAM1);
|
||||
@ -679,3 +615,22 @@ OP(compare_quietf64)
|
||||
set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(movec)
|
||||
{
|
||||
int op1 = get_op(PARAM1);
|
||||
uint32_t op2 = get_op(PARAM2);
|
||||
helper_movec(env, op1, op2);
|
||||
}
|
||||
|
||||
/* Memory access. */
|
||||
|
||||
#define MEMSUFFIX _raw
|
||||
#include "op_mem.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "op_mem.h"
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "op_mem.h"
|
||||
#endif
|
||||
|
140
target-m68k/op_helper.c
Normal file
140
target-m68k/op_helper.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* M68K helper routines
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
void do_interrupt(int is_hw)
|
||||
{
|
||||
env->exception_index = -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
/* Try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
target_phys_addr_t pc;
|
||||
int ret;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (__builtin_expect(ret, 0)) {
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (target_phys_addr_t)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
cpu_loop_exit();
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
static void do_rte(void)
|
||||
{
|
||||
uint32_t sp;
|
||||
uint32_t fmt;
|
||||
|
||||
sp = env->aregs[7];
|
||||
fmt = ldl_kernel(sp);
|
||||
env->pc = ldl_kernel(sp + 4);
|
||||
sp |= (fmt >> 28) & 3;
|
||||
env->sr = fmt & 0xffff;
|
||||
env->aregs[7] = sp + 8;
|
||||
}
|
||||
|
||||
void do_interrupt(int is_hw)
|
||||
{
|
||||
uint32_t sp;
|
||||
uint32_t fmt;
|
||||
uint32_t retaddr;
|
||||
uint32_t vector;
|
||||
|
||||
fmt = 0;
|
||||
retaddr = env->pc;
|
||||
|
||||
if (!is_hw) {
|
||||
switch (env->exception_index) {
|
||||
case EXCP_RTE:
|
||||
/* Return from an exception. */
|
||||
do_rte();
|
||||
return;
|
||||
}
|
||||
if (env->exception_index >= EXCP_TRAP0
|
||||
&& env->exception_index <= EXCP_TRAP15) {
|
||||
/* Move the PC after the trap instruction. */
|
||||
retaddr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Implement USP. */
|
||||
sp = env->aregs[7];
|
||||
|
||||
vector = env->exception_index << 2;
|
||||
|
||||
fmt |= 0x40000000;
|
||||
fmt |= (sp & 3) << 28;
|
||||
fmt |= vector << 16;
|
||||
fmt |= env->sr;
|
||||
|
||||
/* ??? This could cause MMU faults. */
|
||||
sp &= ~3;
|
||||
sp -= 4;
|
||||
stl_kernel(sp, retaddr);
|
||||
sp -= 4;
|
||||
stl_kernel(sp, fmt);
|
||||
env->aregs[7] = sp;
|
||||
env->sr |= SR_S;
|
||||
if (is_hw) {
|
||||
env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
|
||||
}
|
||||
/* Jump to vector. */
|
||||
env->pc = ldl_kernel(env->vbr + vector);
|
||||
}
|
||||
|
||||
#endif
|
46
target-m68k/op_mem.h
Normal file
46
target-m68k/op_mem.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Load/store ops. */
|
||||
#define MEM_LD_OP(name,suffix) \
|
||||
OP(glue(glue(ld,name),MEMSUFFIX)) \
|
||||
{ \
|
||||
uint32_t addr = get_op(PARAM2); \
|
||||
set_op(PARAM1, glue(glue(ld,suffix),MEMSUFFIX)(addr)); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
MEM_LD_OP(8u32,ub)
|
||||
MEM_LD_OP(8s32,sb)
|
||||
MEM_LD_OP(16u32,uw)
|
||||
MEM_LD_OP(16s32,sw)
|
||||
MEM_LD_OP(32,l)
|
||||
|
||||
#undef MEM_LD_OP
|
||||
|
||||
#define MEM_ST_OP(name,suffix) \
|
||||
OP(glue(glue(st,name),MEMSUFFIX)) \
|
||||
{ \
|
||||
uint32_t addr = get_op(PARAM1); \
|
||||
glue(glue(st,suffix),MEMSUFFIX)(addr, get_op(PARAM2)); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
MEM_ST_OP(8,b)
|
||||
MEM_ST_OP(16,w)
|
||||
MEM_ST_OP(32,l)
|
||||
|
||||
#undef MEM_ST_OP
|
||||
|
||||
OP(glue(ldf64,MEMSUFFIX))
|
||||
{
|
||||
uint32_t addr = get_op(PARAM2);
|
||||
set_opf64(PARAM1, glue(ldfq,MEMSUFFIX)(addr));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(glue(stf64,MEMSUFFIX))
|
||||
{
|
||||
uint32_t addr = get_op(PARAM1);
|
||||
glue(stfq,MEMSUFFIX)(addr, get_opf64(PARAM2));
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef MEMSUFFIX
|
@ -24,6 +24,7 @@ DEFF64(F6, fregs[6])
|
||||
DEFF64(F7, fregs[7])
|
||||
DEFF64(FP_RESULT, fp_result)
|
||||
DEFO32(PC, pc)
|
||||
DEFO32(SR, sr)
|
||||
DEFO32(CC_OP, cc_op)
|
||||
DEFR(T0, AREG1, QMODE_I32)
|
||||
DEFO32(CC_DEST, cc_dest)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* m68k translation
|
||||
*
|
||||
* Copyright (c) 2005-2006 CodeSourcery
|
||||
* Copyright (c) 2005-2007 CodeSourcery
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -30,6 +30,8 @@
|
||||
#include "disas.h"
|
||||
#include "m68k-qreg.h"
|
||||
|
||||
//#define DEBUG_DISPATCH 1
|
||||
|
||||
static inline void qemu_assert(int cond, const char *msg)
|
||||
{
|
||||
if (!cond) {
|
||||
@ -43,6 +45,7 @@ typedef struct DisasContext {
|
||||
target_ulong pc;
|
||||
int is_jmp;
|
||||
int cc_op;
|
||||
int user;
|
||||
uint32_t fpcr;
|
||||
struct TranslationBlock *tb;
|
||||
int singlestep_enabled;
|
||||
@ -50,6 +53,12 @@ typedef struct DisasContext {
|
||||
|
||||
#define DISAS_JUMP_NEXT 4
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define IS_USER(s) 1
|
||||
#else
|
||||
#define IS_USER(s) s->user
|
||||
#endif
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
/* ??? Fix exceptions. */
|
||||
static void *gen_throws_exception;
|
||||
@ -68,6 +77,25 @@ enum {
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
|
||||
#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
|
||||
#else
|
||||
#define gen_st(s, name, addr, val) do { \
|
||||
if (IS_USER(s)) \
|
||||
gen_op_st##name##_user(addr, val); \
|
||||
else \
|
||||
gen_op_st##name##_kernel(addr, val); \
|
||||
} while (0)
|
||||
#define gen_ld(s, name, val, addr) do { \
|
||||
if (IS_USER(s)) \
|
||||
gen_op_ld##name##_user(val, addr); \
|
||||
else \
|
||||
gen_op_ld##name##_kernel(val, addr); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#include "op-hacks.h"
|
||||
|
||||
#define OS_BYTE 0
|
||||
@ -101,40 +129,49 @@ static m68k_def_t m68k_cpu_defs[] = {
|
||||
|
||||
typedef void (*disas_proc)(DisasContext *, uint16_t);
|
||||
|
||||
#ifdef DEBUG_DISPATCH
|
||||
#define DISAS_INSN(name) \
|
||||
static void real_disas_##name (DisasContext *s, uint16_t insn); \
|
||||
static void disas_##name (DisasContext *s, uint16_t insn) { \
|
||||
if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \
|
||||
real_disas_##name(s, insn); } \
|
||||
static void real_disas_##name (DisasContext *s, uint16_t insn)
|
||||
#else
|
||||
#define DISAS_INSN(name) \
|
||||
static void disas_##name (DisasContext *s, uint16_t insn)
|
||||
#endif
|
||||
|
||||
/* Generate a load from the specified address. Narrow values are
|
||||
sign extended to full register width. */
|
||||
static inline int gen_load(int opsize, int addr, int sign)
|
||||
static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
|
||||
{
|
||||
int tmp;
|
||||
switch(opsize) {
|
||||
case OS_BYTE:
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
if (sign)
|
||||
gen_op_ld8s32(tmp, addr);
|
||||
gen_ld(s, 8s32, tmp, addr);
|
||||
else
|
||||
gen_op_ld8u32(tmp, addr);
|
||||
gen_ld(s, 8u32, tmp, addr);
|
||||
break;
|
||||
case OS_WORD:
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
if (sign)
|
||||
gen_op_ld16s32(tmp, addr);
|
||||
gen_ld(s, 16s32, tmp, addr);
|
||||
else
|
||||
gen_op_ld16u32(tmp, addr);
|
||||
gen_ld(s, 16u32, tmp, addr);
|
||||
break;
|
||||
case OS_LONG:
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
gen_op_ld32(tmp, addr);
|
||||
gen_ld(s, 32, tmp, addr);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
tmp = gen_new_qreg(QMODE_F32);
|
||||
gen_op_ldf32(tmp, addr);
|
||||
gen_ld(s, f32, tmp, addr);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
tmp = gen_new_qreg(QMODE_F64);
|
||||
gen_op_ldf64(tmp, addr);
|
||||
gen_ld(s, f64, tmp, addr);
|
||||
break;
|
||||
default:
|
||||
qemu_assert(0, "bad load size");
|
||||
@ -144,23 +181,23 @@ static inline int gen_load(int opsize, int addr, int sign)
|
||||
}
|
||||
|
||||
/* Generate a store. */
|
||||
static inline void gen_store(int opsize, int addr, int val)
|
||||
static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
|
||||
{
|
||||
switch(opsize) {
|
||||
case OS_BYTE:
|
||||
gen_op_st8(addr, val);
|
||||
gen_st(s, 8, addr, val);
|
||||
break;
|
||||
case OS_WORD:
|
||||
gen_op_st16(addr, val);
|
||||
gen_st(s, 16, addr, val);
|
||||
break;
|
||||
case OS_LONG:
|
||||
gen_op_st32(addr, val);
|
||||
gen_st(s, 32, addr, val);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_op_stf32(addr, val);
|
||||
gen_st(s, f32, addr, val);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
gen_op_stf64(addr, val);
|
||||
gen_st(s, f64, addr, val);
|
||||
break;
|
||||
default:
|
||||
qemu_assert(0, "bad store size");
|
||||
@ -170,13 +207,13 @@ static inline void gen_store(int opsize, int addr, int val)
|
||||
|
||||
/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
|
||||
otherwise generate a store. */
|
||||
static int gen_ldst(int opsize, int addr, int val)
|
||||
static int gen_ldst(DisasContext *s, int opsize, int addr, int val)
|
||||
{
|
||||
if (val > 0) {
|
||||
gen_store(opsize, addr, val);
|
||||
gen_store(s, opsize, addr, val);
|
||||
return 0;
|
||||
} else {
|
||||
return gen_load(opsize, addr, val != 0);
|
||||
return gen_load(s, opsize, addr, val != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +228,7 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base)
|
||||
int tmp;
|
||||
|
||||
offset = s->pc;
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);
|
||||
/* ??? Check W/L bit. */
|
||||
@ -216,9 +253,9 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base)
|
||||
static inline uint32_t read_im32(DisasContext *s)
|
||||
{
|
||||
uint32_t im;
|
||||
im = ((uint32_t)lduw(s->pc)) << 16;
|
||||
im = ((uint32_t)lduw_code(s->pc)) << 16;
|
||||
s->pc += 2;
|
||||
im |= lduw(s->pc);
|
||||
im |= lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
return im;
|
||||
}
|
||||
@ -343,7 +380,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
|
||||
case 5: /* Indirect displacement. */
|
||||
reg += QREG_A0;
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
gen_op_add32(tmp, reg, gen_im32((int16_t)ext));
|
||||
return tmp;
|
||||
@ -353,7 +390,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
|
||||
case 7: /* Other */
|
||||
switch (reg) {
|
||||
case 0: /* Absolute short. */
|
||||
offset = ldsw(s->pc);
|
||||
offset = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
return gen_im32(offset);
|
||||
case 1: /* Absolute long. */
|
||||
@ -362,7 +399,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
|
||||
case 2: /* pc displacement */
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
offset = s->pc;
|
||||
offset += ldsw(s->pc);
|
||||
offset += ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
return gen_im32(offset);
|
||||
case 3: /* pc index+displacement. */
|
||||
@ -391,7 +428,7 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
|
||||
if (addrp)
|
||||
*addrp = tmp;
|
||||
}
|
||||
return gen_ldst(opsize, tmp, val);
|
||||
return gen_ldst(s, opsize, tmp, val);
|
||||
}
|
||||
|
||||
/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is
|
||||
@ -424,10 +461,10 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
|
||||
}
|
||||
case 2: /* Indirect register */
|
||||
reg += QREG_A0;
|
||||
return gen_ldst(opsize, reg, val);
|
||||
return gen_ldst(s, opsize, reg, val);
|
||||
case 3: /* Indirect postincrement. */
|
||||
reg += QREG_A0;
|
||||
result = gen_ldst(opsize, reg, val);
|
||||
result = gen_ldst(s, opsize, reg, val);
|
||||
/* ??? This is not exception safe. The instruction may still
|
||||
fault after this point. */
|
||||
if (val > 0 || !addrp)
|
||||
@ -443,7 +480,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
|
||||
if (addrp)
|
||||
*addrp = tmp;
|
||||
}
|
||||
result = gen_ldst(opsize, tmp, val);
|
||||
result = gen_ldst(s, opsize, tmp, val);
|
||||
/* ??? This is not exception safe. The instruction may still
|
||||
fault after this point. */
|
||||
if (val > 0 || !addrp) {
|
||||
@ -467,16 +504,16 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
if (val)
|
||||
offset = ldsb(s->pc + 1);
|
||||
offset = ldsb_code(s->pc + 1);
|
||||
else
|
||||
offset = ldub(s->pc + 1);
|
||||
offset = ldub_code(s->pc + 1);
|
||||
s->pc += 2;
|
||||
break;
|
||||
case OS_WORD:
|
||||
if (val)
|
||||
offset = ldsw(s->pc);
|
||||
offset = ldsw_code(s->pc);
|
||||
else
|
||||
offset = lduw(s->pc);
|
||||
offset = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
break;
|
||||
case OS_LONG:
|
||||
@ -622,6 +659,14 @@ DISAS_INSN(scc)
|
||||
gen_set_label(l1);
|
||||
}
|
||||
|
||||
/* Force a TB lookup after an instruction that changes the CPU state. */
|
||||
static void gen_lookup_tb(DisasContext *s)
|
||||
{
|
||||
gen_flush_cc_op(s);
|
||||
gen_op_mov32(QREG_PC, gen_im32(s->pc));
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
/* Generate a jump to to the address in qreg DEST. */
|
||||
static void gen_jmp(DisasContext *s, int dest)
|
||||
{
|
||||
@ -735,7 +780,7 @@ DISAS_INSN(divl)
|
||||
int reg;
|
||||
uint16_t ext;
|
||||
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (ext & 0x87f8) {
|
||||
gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
|
||||
@ -903,13 +948,13 @@ DISAS_INSN(sats)
|
||||
gen_logic_cc(s, tmp);
|
||||
}
|
||||
|
||||
static void gen_push(int val)
|
||||
static void gen_push(DisasContext *s, int val)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
gen_op_sub32(tmp, QREG_SP, gen_im32(4));
|
||||
gen_store(OS_LONG, tmp, val);
|
||||
gen_store(s, OS_LONG, tmp, val);
|
||||
gen_op_mov32(QREG_SP, tmp);
|
||||
}
|
||||
|
||||
@ -922,7 +967,7 @@ DISAS_INSN(movem)
|
||||
int tmp;
|
||||
int is_load;
|
||||
|
||||
mask = lduw(s->pc);
|
||||
mask = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
tmp = gen_lea(s, insn, OS_LONG);
|
||||
addr = gen_new_qreg(QMODE_I32);
|
||||
@ -935,10 +980,10 @@ DISAS_INSN(movem)
|
||||
else
|
||||
reg = AREG(i, 0);
|
||||
if (is_load) {
|
||||
tmp = gen_load(OS_LONG, addr, 0);
|
||||
tmp = gen_load(s, OS_LONG, addr, 0);
|
||||
gen_op_mov32(reg, tmp);
|
||||
} else {
|
||||
gen_store(OS_LONG, addr, reg);
|
||||
gen_store(s, OS_LONG, addr, reg);
|
||||
}
|
||||
if (mask != 1)
|
||||
gen_op_add32(addr, addr, gen_im32(4));
|
||||
@ -963,7 +1008,7 @@ DISAS_INSN(bitop_im)
|
||||
opsize = OS_LONG;
|
||||
op = (insn >> 6) & 3;
|
||||
|
||||
bitnum = lduw(s->pc);
|
||||
bitnum = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (bitnum & 0xff00) {
|
||||
disas_undef(s, insn);
|
||||
@ -1155,9 +1200,8 @@ DISAS_INSN(clr)
|
||||
gen_logic_cc(s, gen_im32(0));
|
||||
}
|
||||
|
||||
DISAS_INSN(move_from_ccr)
|
||||
static int gen_get_ccr(DisasContext *s)
|
||||
{
|
||||
int reg;
|
||||
int dest;
|
||||
|
||||
gen_flush_flags(s);
|
||||
@ -1165,8 +1209,17 @@ DISAS_INSN(move_from_ccr)
|
||||
gen_op_get_xflag(dest);
|
||||
gen_op_shl32(dest, dest, gen_im32(4));
|
||||
gen_op_or32(dest, dest, QREG_CC_DEST);
|
||||
return dest;
|
||||
}
|
||||
|
||||
DISAS_INSN(move_from_ccr)
|
||||
{
|
||||
int reg;
|
||||
int ccr;
|
||||
|
||||
ccr = gen_get_ccr(s);
|
||||
reg = DREG(insn, 0);
|
||||
gen_partset_reg(OS_WORD, reg, dest);
|
||||
gen_partset_reg(OS_WORD, reg, ccr);
|
||||
}
|
||||
|
||||
DISAS_INSN(neg)
|
||||
@ -1184,7 +1237,16 @@ DISAS_INSN(neg)
|
||||
s->cc_op = CC_OP_SUB;
|
||||
}
|
||||
|
||||
DISAS_INSN(move_to_ccr)
|
||||
static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
|
||||
{
|
||||
gen_op_logic_cc(gen_im32(val & 0xf));
|
||||
gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
|
||||
if (!ccr_only) {
|
||||
gen_op_mov32(QREG_SR, gen_im32(val & 0xff00));
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
|
||||
{
|
||||
int src1;
|
||||
int reg;
|
||||
@ -1199,19 +1261,26 @@ DISAS_INSN(move_to_ccr)
|
||||
gen_op_shr32(src1, reg, gen_im32(4));
|
||||
gen_op_and32(src1, src1, gen_im32(1));
|
||||
gen_op_update_xflag_tst(src1);
|
||||
if (!ccr_only) {
|
||||
gen_op_and32(QREG_SR, reg, gen_im32(0xff00));
|
||||
}
|
||||
}
|
||||
else if ((insn & 0x3f) != 0x3c)
|
||||
else if ((insn & 0x3f) == 0x3c)
|
||||
{
|
||||
uint8_t val;
|
||||
val = ldsb(s->pc);
|
||||
uint16_t val;
|
||||
val = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
gen_op_logic_cc(gen_im32(val & 0xf));
|
||||
gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
|
||||
gen_set_sr_im(s, val, ccr_only);
|
||||
}
|
||||
else
|
||||
disas_undef(s, insn);
|
||||
}
|
||||
|
||||
DISAS_INSN(move_to_ccr)
|
||||
{
|
||||
gen_set_sr(s, insn, 1);
|
||||
}
|
||||
|
||||
DISAS_INSN(not)
|
||||
{
|
||||
int reg;
|
||||
@ -1244,7 +1313,7 @@ DISAS_INSN(pea)
|
||||
int tmp;
|
||||
|
||||
tmp = gen_lea(s, insn, OS_LONG);
|
||||
gen_push(tmp);
|
||||
gen_push(s, tmp);
|
||||
}
|
||||
|
||||
DISAS_INSN(ext)
|
||||
@ -1322,7 +1391,7 @@ DISAS_INSN(mull)
|
||||
|
||||
/* The upper 32 bits of the product are discarded, so
|
||||
muls.l and mulu.l are functionally equivalent. */
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (ext & 0x87ff) {
|
||||
gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
|
||||
@ -1343,12 +1412,12 @@ DISAS_INSN(link)
|
||||
int reg;
|
||||
int tmp;
|
||||
|
||||
offset = ldsw(s->pc);
|
||||
offset = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
reg = AREG(insn, 0);
|
||||
tmp = gen_new_qreg(QMODE_I32);
|
||||
gen_op_sub32(tmp, QREG_SP, gen_im32(4));
|
||||
gen_store(OS_LONG, tmp, reg);
|
||||
gen_store(s, OS_LONG, tmp, reg);
|
||||
if (reg != QREG_SP)
|
||||
gen_op_mov32(reg, tmp);
|
||||
gen_op_add32(QREG_SP, tmp, gen_im32(offset));
|
||||
@ -1363,7 +1432,7 @@ DISAS_INSN(unlk)
|
||||
src = gen_new_qreg(QMODE_I32);
|
||||
reg = AREG(insn, 0);
|
||||
gen_op_mov32(src, reg);
|
||||
tmp = gen_load(OS_LONG, src, 0);
|
||||
tmp = gen_load(s, OS_LONG, src, 0);
|
||||
gen_op_mov32(reg, tmp);
|
||||
gen_op_add32(QREG_SP, src, gen_im32(4));
|
||||
}
|
||||
@ -1376,7 +1445,7 @@ DISAS_INSN(rts)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = gen_load(OS_LONG, QREG_SP, 0);
|
||||
tmp = gen_load(s, OS_LONG, QREG_SP, 0);
|
||||
gen_op_add32(QREG_SP, QREG_SP, gen_im32(4));
|
||||
gen_jmp(s, tmp);
|
||||
}
|
||||
@ -1390,7 +1459,7 @@ DISAS_INSN(jump)
|
||||
tmp = gen_lea(s, insn, OS_LONG);
|
||||
if ((insn & 0x40) == 0) {
|
||||
/* jsr */
|
||||
gen_push(gen_im32(s->pc));
|
||||
gen_push(s, gen_im32(s->pc));
|
||||
}
|
||||
gen_jmp(s, tmp);
|
||||
}
|
||||
@ -1460,14 +1529,14 @@ DISAS_INSN(branch)
|
||||
op = (insn >> 8) & 0xf;
|
||||
offset = (int8_t)insn;
|
||||
if (offset == 0) {
|
||||
offset = ldsw(s->pc);
|
||||
offset = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
} else if (offset == -1) {
|
||||
offset = read_im32(s);
|
||||
}
|
||||
if (op == 1) {
|
||||
/* bsr */
|
||||
gen_push(gen_im32(s->pc));
|
||||
gen_push(s, gen_im32(s->pc));
|
||||
}
|
||||
gen_flush_cc_op(s);
|
||||
if (op > 1) {
|
||||
@ -1752,68 +1821,154 @@ DISAS_INSN(ff1)
|
||||
cpu_abort(NULL, "Unimplemented insn: ff1");
|
||||
}
|
||||
|
||||
static int gen_get_sr(DisasContext *s)
|
||||
{
|
||||
int ccr;
|
||||
int sr;
|
||||
|
||||
ccr = gen_get_ccr(s);
|
||||
sr = gen_new_qreg(QMODE_I32);
|
||||
gen_op_and32(sr, QREG_SR, gen_im32(0xffe0));
|
||||
gen_op_or32(sr, sr, ccr);
|
||||
return sr;
|
||||
}
|
||||
|
||||
DISAS_INSN(strldsr)
|
||||
{
|
||||
uint16_t ext;
|
||||
uint32_t addr;
|
||||
|
||||
addr = s->pc - 2;
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (ext != 0x46FC)
|
||||
if (ext != 0x46FC) {
|
||||
gen_exception(s, addr, EXCP_UNSUPPORTED);
|
||||
else
|
||||
return;
|
||||
}
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (IS_USER(s) || (ext & SR_S) == 0) {
|
||||
gen_exception(s, addr, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
gen_push(s, gen_get_sr(s));
|
||||
gen_set_sr_im(s, ext, 0);
|
||||
}
|
||||
|
||||
DISAS_INSN(move_from_sr)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
int reg;
|
||||
int sr;
|
||||
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
sr = gen_get_sr(s);
|
||||
reg = DREG(insn, 0);
|
||||
gen_partset_reg(OS_WORD, reg, sr);
|
||||
}
|
||||
|
||||
DISAS_INSN(move_to_sr)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
gen_set_sr(s, insn, 0);
|
||||
gen_lookup_tb(s);
|
||||
}
|
||||
|
||||
DISAS_INSN(move_from_usp)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* TODO: Implement USP. */
|
||||
gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
|
||||
}
|
||||
|
||||
DISAS_INSN(move_to_usp)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* TODO: Implement USP. */
|
||||
gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
|
||||
}
|
||||
|
||||
DISAS_INSN(halt)
|
||||
{
|
||||
gen_exception(s, s->pc, EXCP_HLT);
|
||||
gen_flush_cc_op(s);
|
||||
gen_jmp(s, gen_im32(s->pc));
|
||||
gen_op_halt();
|
||||
}
|
||||
|
||||
DISAS_INSN(stop)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
uint16_t ext;
|
||||
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
|
||||
gen_set_sr_im(s, ext, 0);
|
||||
disas_halt(s, insn);
|
||||
}
|
||||
|
||||
DISAS_INSN(rte)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
gen_exception(s, s->pc - 2, EXCP_RTE);
|
||||
}
|
||||
|
||||
DISAS_INSN(movec)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
uint16_t ext;
|
||||
int reg;
|
||||
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
|
||||
if (ext & 0x8000) {
|
||||
reg = AREG(ext, 12);
|
||||
} else {
|
||||
reg = DREG(ext, 12);
|
||||
}
|
||||
gen_op_movec(gen_im32(ext & 0xfff), reg);
|
||||
gen_lookup_tb(s);
|
||||
}
|
||||
|
||||
DISAS_INSN(intouch)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* ICache fetch. Implement as no-op. */
|
||||
}
|
||||
|
||||
DISAS_INSN(cpushl)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* Cache push/invalidate. Implement as no-op. */
|
||||
}
|
||||
|
||||
DISAS_INSN(wddata)
|
||||
@ -1823,7 +1978,12 @@ DISAS_INSN(wddata)
|
||||
|
||||
DISAS_INSN(wdebug)
|
||||
{
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
if (IS_USER(s)) {
|
||||
gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
|
||||
return;
|
||||
}
|
||||
/* TODO: Implement wdebug. */
|
||||
qemu_assert(0, "WDEBUG not implemented");
|
||||
}
|
||||
|
||||
DISAS_INSN(trap)
|
||||
@ -1843,7 +2003,7 @@ DISAS_INSN(fpu)
|
||||
int round;
|
||||
int opsize;
|
||||
|
||||
ext = lduw(s->pc);
|
||||
ext = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
opmode = ext & 0x7f;
|
||||
switch ((ext >> 13) & 7) {
|
||||
@ -1928,10 +2088,10 @@ DISAS_INSN(fpu)
|
||||
if (ext & mask) {
|
||||
if (ext & (1 << 13)) {
|
||||
/* store */
|
||||
gen_op_stf64(addr, dest);
|
||||
gen_st(s, f64, addr, dest);
|
||||
} else {
|
||||
/* load */
|
||||
gen_op_ldf64(dest, addr);
|
||||
gen_ld(s, f64, dest, addr);
|
||||
}
|
||||
if (ext & (mask - 1))
|
||||
gen_op_add32(addr, addr, gen_im32(8));
|
||||
@ -2060,10 +2220,10 @@ DISAS_INSN(fbcc)
|
||||
int l1;
|
||||
|
||||
addr = s->pc;
|
||||
offset = ldsw(s->pc);
|
||||
offset = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
if (insn & (1 << 6)) {
|
||||
offset = (offset << 16) | lduw(s->pc);
|
||||
offset = (offset << 16) | lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
}
|
||||
|
||||
@ -2143,6 +2303,18 @@ DISAS_INSN(fbcc)
|
||||
gen_jmp_tb(s, 1, addr + offset);
|
||||
}
|
||||
|
||||
DISAS_INSN(frestore)
|
||||
{
|
||||
/* TODO: Implement frestore. */
|
||||
qemu_assert(0, "FRESTORE not implemented");
|
||||
}
|
||||
|
||||
DISAS_INSN(fsave)
|
||||
{
|
||||
/* TODO: Implement fsave. */
|
||||
qemu_assert(0, "FSAVE not implemented");
|
||||
}
|
||||
|
||||
static disas_proc opcode_table[65536];
|
||||
|
||||
static void
|
||||
@ -2168,11 +2340,10 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
|
||||
i <<= 1;
|
||||
from = opcode & ~(i - 1);
|
||||
to = from + i;
|
||||
for (i = from; i < to; i++)
|
||||
{
|
||||
for (i = from; i < to; i++) {
|
||||
if ((i & mask) == opcode)
|
||||
opcode_table[i] = proc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Register m68k opcode handlers. Order is important.
|
||||
@ -2274,6 +2445,8 @@ register_m68k_insns (m68k_def_t *def)
|
||||
INSN(undef_fpu, f000, f000, CF_A);
|
||||
INSN(fpu, f200, ffc0, CF_FPU);
|
||||
INSN(fbcc, f280, ffc0, CF_FPU);
|
||||
INSN(frestore, f340, ffc0, CF_FPU);
|
||||
INSN(fsave, f340, ffc0, CF_FPU);
|
||||
INSN(intouch, f340, ffc0, CF_A);
|
||||
INSN(cpushl, f428, ff38, CF_A);
|
||||
INSN(wddata, fb00, ff00, CF_A);
|
||||
@ -2287,7 +2460,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s)
|
||||
{
|
||||
uint16_t insn;
|
||||
|
||||
insn = lduw(s->pc);
|
||||
insn = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
|
||||
opcode_table[insn](s, insn);
|
||||
@ -2576,6 +2749,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
dc->cc_op = CC_OP_DYNAMIC;
|
||||
dc->singlestep_enabled = env->singlestep_enabled;
|
||||
dc->fpcr = env->fpcr;
|
||||
dc->user = (env->sr & SR_S) == 0;
|
||||
nb_gen_labels = 0;
|
||||
lj = -1;
|
||||
do {
|
||||
@ -2675,6 +2849,19 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
|
||||
return gen_intermediate_code_internal(env, tb, 1);
|
||||
}
|
||||
|
||||
void cpu_reset(CPUM68KState *env)
|
||||
{
|
||||
memset(env, 0, offsetof(CPUM68KState, breakpoints));
|
||||
#if !defined (CONFIG_USER_ONLY)
|
||||
env->sr = 0x2700;
|
||||
#endif
|
||||
/* ??? FP regs should be initialized to NaN. */
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
/* TODO: We should set PC from the interrupt vector. */
|
||||
env->pc = 0;
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
CPUM68KState *cpu_m68k_init(void)
|
||||
{
|
||||
CPUM68KState *env;
|
||||
@ -2684,10 +2871,7 @@ CPUM68KState *cpu_m68k_init(void)
|
||||
return NULL;
|
||||
cpu_exec_init(env);
|
||||
|
||||
memset(env, 0, sizeof(CPUM68KState));
|
||||
/* ??? FP regs should be initialized to NaN. */
|
||||
cpu_single_env = env;
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
cpu_reset(env);
|
||||
return env;
|
||||
}
|
||||
|
||||
@ -2696,23 +2880,20 @@ void cpu_m68k_close(CPUM68KState *env)
|
||||
free(env);
|
||||
}
|
||||
|
||||
m68k_def_t *m68k_find_by_name(const char *name)
|
||||
int cpu_m68k_set_model(CPUM68KState *env, const char * name)
|
||||
{
|
||||
m68k_def_t *def;
|
||||
|
||||
def = m68k_cpu_defs;
|
||||
while (def->name)
|
||||
{
|
||||
for (def = m68k_cpu_defs; def->name; def++) {
|
||||
if (strcmp(def->name, name) == 0)
|
||||
return def;
|
||||
def++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!def->name)
|
||||
return 1;
|
||||
|
||||
void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def)
|
||||
{
|
||||
register_m68k_insns(def);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpu_dump_state(CPUState *env, FILE *f,
|
||||
@ -2737,24 +2918,3 @@ void cpu_dump_state(CPUState *env, FILE *f,
|
||||
cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
|
||||
}
|
||||
|
||||
/* ??? */
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
env->exception_index = EXCP_ACCESS;
|
||||
env->mmu.ar = address;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error not implemented
|
||||
|
||||
#endif
|
||||
|
2
vl.c
2
vl.c
@ -6833,6 +6833,8 @@ void register_machines(void)
|
||||
qemu_register_machine(&shix_machine);
|
||||
#elif defined(TARGET_ALPHA)
|
||||
/* XXX: TODO */
|
||||
#elif defined(TARGET_M68K)
|
||||
qemu_register_machine(&an5206_machine);
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user