Commit 0633879f1ac38b18d84c46dda506300cc8329723
1 parent
9daea906
m68k/ColdFire system emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2851 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
19 changed files
with
1548 additions
and
207 deletions
Makefile.target
| @@ -308,7 +308,7 @@ LIBOBJS+= op_helper.o helper.o | @@ -308,7 +308,7 @@ LIBOBJS+= op_helper.o helper.o | ||
| 308 | endif | 308 | endif |
| 309 | 309 | ||
| 310 | ifeq ($(TARGET_BASE_ARCH), m68k) | 310 | ifeq ($(TARGET_BASE_ARCH), m68k) |
| 311 | -LIBOBJS+= helper.o | 311 | +LIBOBJS+= op_helper.o helper.o |
| 312 | endif | 312 | endif |
| 313 | 313 | ||
| 314 | ifeq ($(TARGET_BASE_ARCH), alpha) | 314 | ifeq ($(TARGET_BASE_ARCH), alpha) |
| @@ -466,6 +466,9 @@ endif | @@ -466,6 +466,9 @@ endif | ||
| 466 | ifeq ($(TARGET_BASE_ARCH), sh4) | 466 | ifeq ($(TARGET_BASE_ARCH), sh4) |
| 467 | VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o | 467 | VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o |
| 468 | endif | 468 | endif |
| 469 | +ifeq ($(TARGET_BASE_ARCH), m68k) | ||
| 470 | +VL_OBJS+= an5206.o mcf5206.o ptimer.o | ||
| 471 | +endif | ||
| 469 | ifdef CONFIG_GDBSTUB | 472 | ifdef CONFIG_GDBSTUB |
| 470 | VL_OBJS+=gdbstub.o | 473 | VL_OBJS+=gdbstub.o |
| 471 | endif | 474 | endif |
configure
| @@ -467,7 +467,7 @@ fi | @@ -467,7 +467,7 @@ fi | ||
| 467 | if test -z "$target_list" ; then | 467 | if test -z "$target_list" ; then |
| 468 | # these targets are portable | 468 | # these targets are portable |
| 469 | if [ "$softmmu" = "yes" ] ; then | 469 | if [ "$softmmu" = "yes" ] ; then |
| 470 | - 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 " | 470 | + 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" |
| 471 | fi | 471 | fi |
| 472 | # the following are Linux specific | 472 | # the following are Linux specific |
| 473 | if [ "$linux_user" = "yes" ] ; then | 473 | if [ "$linux_user" = "yes" ] ; then |
cpu-exec.c
| @@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void) | @@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void) | ||
| 196 | cs_base = 0; | 196 | cs_base = 0; |
| 197 | pc = env->PC; | 197 | pc = env->PC; |
| 198 | #elif defined(TARGET_M68K) | 198 | #elif defined(TARGET_M68K) |
| 199 | - flags = env->fpcr & M68K_FPCR_PREC; | 199 | + flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S); |
| 200 | cs_base = 0; | 200 | cs_base = 0; |
| 201 | pc = env->pc; | 201 | pc = env->pc; |
| 202 | #elif defined(TARGET_SH4) | 202 | #elif defined(TARGET_SH4) |
| @@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1) | @@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1) | ||
| 297 | return EXCP_HALTED; | 297 | return EXCP_HALTED; |
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | -#elif defined(TARGET_ALPHA) | 300 | +#elif defined(TARGET_ALPHA) || defined(TARGET_M68K) |
| 301 | if (env1->halted) { | 301 | if (env1->halted) { |
| 302 | if (env1->interrupt_request & CPU_INTERRUPT_HARD) { | 302 | if (env1->interrupt_request & CPU_INTERRUPT_HARD) { |
| 303 | env1->halted = 0; | 303 | env1->halted = 0; |
| @@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1) | @@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1) | ||
| 390 | do_interrupt(env); | 390 | do_interrupt(env); |
| 391 | #elif defined(TARGET_ALPHA) | 391 | #elif defined(TARGET_ALPHA) |
| 392 | do_interrupt(env); | 392 | do_interrupt(env); |
| 393 | +#elif defined(TARGET_M68K) | ||
| 394 | + do_interrupt(0); | ||
| 393 | #endif | 395 | #endif |
| 394 | } | 396 | } |
| 395 | env->exception_index = -1; | 397 | env->exception_index = -1; |
| @@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1) | @@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1) | ||
| 542 | if (interrupt_request & CPU_INTERRUPT_HARD) { | 544 | if (interrupt_request & CPU_INTERRUPT_HARD) { |
| 543 | do_interrupt(env); | 545 | do_interrupt(env); |
| 544 | } | 546 | } |
| 547 | +#elif defined(TARGET_M68K) | ||
| 548 | + if (interrupt_request & CPU_INTERRUPT_HARD | ||
| 549 | + && ((env->sr & SR_I) >> SR_I_SHIFT) | ||
| 550 | + < env->pending_level) { | ||
| 551 | + /* Real hardware gets the interrupt vector via an | ||
| 552 | + IACK cycle at this point. Current emulated | ||
| 553 | + hardware doesn't rely on this, so we | ||
| 554 | + provide/save the vector when the interrupt is | ||
| 555 | + first signalled. */ | ||
| 556 | + env->exception_index = env->pending_vector; | ||
| 557 | + do_interrupt(1); | ||
| 558 | + } | ||
| 545 | #endif | 559 | #endif |
| 546 | /* Don't use the cached interupt_request value, | 560 | /* Don't use the cached interupt_request value, |
| 547 | do_interrupt may have updated the EXITTB flag. */ | 561 | do_interrupt may have updated the EXITTB flag. */ |
exec-all.h
| @@ -584,6 +584,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | @@ -584,6 +584,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | ||
| 584 | is_user = ((env->sr & SR_MD) == 0); | 584 | is_user = ((env->sr & SR_MD) == 0); |
| 585 | #elif defined (TARGET_ALPHA) | 585 | #elif defined (TARGET_ALPHA) |
| 586 | is_user = ((env->ps >> 3) & 3); | 586 | is_user = ((env->ps >> 3) & 3); |
| 587 | +#elif defined (TARGET_M68K) | ||
| 588 | + is_user = ((env->sr & SR_S) == 0); | ||
| 587 | #else | 589 | #else |
| 588 | #error unimplemented CPU | 590 | #error unimplemented CPU |
| 589 | #endif | 591 | #endif |
hw/an5206.c
0 โ 100644
| 1 | +/* | ||
| 2 | + * Arnewsh 5206 ColdFire system emulation. | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2007 CodeSourcery. | ||
| 5 | + * | ||
| 6 | + * This code is licenced under the GPL | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +#include "vl.h" | ||
| 10 | + | ||
| 11 | +#define KERNEL_LOAD_ADDR 0x10000 | ||
| 12 | +#define AN5206_MBAR_ADDR 0x10000000 | ||
| 13 | +#define AN5206_RAMBAR_ADDR 0x20000000 | ||
| 14 | + | ||
| 15 | +/* Stub functions for hardware that doesn't exist. */ | ||
| 16 | +void pic_info(void) | ||
| 17 | +{ | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +void irq_info(void) | ||
| 21 | +{ | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +void DMA_run (void) | ||
| 25 | +{ | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +/* Board init. */ | ||
| 29 | + | ||
| 30 | +static void an5206_init(int ram_size, int vga_ram_size, int boot_device, | ||
| 31 | + DisplayState *ds, const char **fd_filename, int snapshot, | ||
| 32 | + const char *kernel_filename, const char *kernel_cmdline, | ||
| 33 | + const char *initrd_filename, const char *cpu_model) | ||
| 34 | +{ | ||
| 35 | + CPUState *env; | ||
| 36 | + int kernel_size; | ||
| 37 | + uint64_t elf_entry; | ||
| 38 | + target_ulong entry; | ||
| 39 | + | ||
| 40 | + env = cpu_init(); | ||
| 41 | + if (!cpu_model) | ||
| 42 | + cpu_model = "m5206"; | ||
| 43 | + cpu_m68k_set_model(env, cpu_model); | ||
| 44 | + | ||
| 45 | + /* Initialize CPU registers. */ | ||
| 46 | + env->vbr = 0; | ||
| 47 | + /* TODO: allow changing MBAR and RAMBAR. */ | ||
| 48 | + env->mbar = AN5206_MBAR_ADDR | 1; | ||
| 49 | + env->rambar0 = AN5206_RAMBAR_ADDR | 1; | ||
| 50 | + | ||
| 51 | + /* DRAM at address zero */ | ||
| 52 | + cpu_register_physical_memory(0, ram_size, | ||
| 53 | + qemu_ram_alloc(ram_size) | IO_MEM_RAM); | ||
| 54 | + | ||
| 55 | + /* Internal SRAM. */ | ||
| 56 | + cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512, | ||
| 57 | + qemu_ram_alloc(512) | IO_MEM_RAM); | ||
| 58 | + | ||
| 59 | + mcf5206_init(AN5206_MBAR_ADDR, env); | ||
| 60 | + | ||
| 61 | + /* Load kernel. */ | ||
| 62 | + if (!kernel_filename) { | ||
| 63 | + fprintf(stderr, "Kernel image must be specified\n"); | ||
| 64 | + exit(1); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); | ||
| 68 | + entry = elf_entry; | ||
| 69 | + if (kernel_size < 0) { | ||
| 70 | + kernel_size = load_uboot(kernel_filename, &entry, NULL); | ||
| 71 | + } | ||
| 72 | + if (kernel_size < 0) { | ||
| 73 | + kernel_size = load_image(kernel_filename, | ||
| 74 | + phys_ram_base + KERNEL_LOAD_ADDR); | ||
| 75 | + entry = KERNEL_LOAD_ADDR; | ||
| 76 | + } | ||
| 77 | + if (kernel_size < 0) { | ||
| 78 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); | ||
| 79 | + exit(1); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + env->pc = entry; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +QEMUMachine an5206_machine = { | ||
| 86 | + "an5206", | ||
| 87 | + "Arnewsh 5206", | ||
| 88 | + an5206_init, | ||
| 89 | +}; |
hw/mcf5206.c
0 โ 100644
| 1 | +/* | ||
| 2 | + * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2007 CodeSourcery. | ||
| 5 | + * | ||
| 6 | + * This code is licenced under the GPL | ||
| 7 | + */ | ||
| 8 | +#include "vl.h" | ||
| 9 | + | ||
| 10 | +/* General purpose timer module. */ | ||
| 11 | +typedef struct { | ||
| 12 | + uint16_t tmr; | ||
| 13 | + uint16_t trr; | ||
| 14 | + uint16_t tcr; | ||
| 15 | + uint16_t ter; | ||
| 16 | + ptimer_state *timer; | ||
| 17 | + qemu_irq irq; | ||
| 18 | + int irq_state; | ||
| 19 | +} m5206_timer_state; | ||
| 20 | + | ||
| 21 | +#define TMR_RST 0x01 | ||
| 22 | +#define TMR_CLK 0x06 | ||
| 23 | +#define TMR_FRR 0x08 | ||
| 24 | +#define TMR_ORI 0x10 | ||
| 25 | +#define TMR_OM 0x20 | ||
| 26 | +#define TMR_CE 0xc0 | ||
| 27 | + | ||
| 28 | +#define TER_CAP 0x01 | ||
| 29 | +#define TER_REF 0x02 | ||
| 30 | + | ||
| 31 | +static void m5206_timer_update(m5206_timer_state *s) | ||
| 32 | +{ | ||
| 33 | + if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) | ||
| 34 | + qemu_irq_raise(s->irq); | ||
| 35 | + else | ||
| 36 | + qemu_irq_lower(s->irq); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +static void m5206_timer_reset(m5206_timer_state *s) | ||
| 40 | +{ | ||
| 41 | + s->tmr = 0; | ||
| 42 | + s->trr = 0; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +static void m5206_timer_recalibrate(m5206_timer_state *s) | ||
| 46 | +{ | ||
| 47 | + int prescale; | ||
| 48 | + int mode; | ||
| 49 | + | ||
| 50 | + ptimer_stop(s->timer); | ||
| 51 | + | ||
| 52 | + if ((s->tmr & TMR_RST) == 0) | ||
| 53 | + return; | ||
| 54 | + | ||
| 55 | + prescale = (s->tmr >> 8) + 1; | ||
| 56 | + mode = (s->tmr >> 1) & 3; | ||
| 57 | + if (mode == 2) | ||
| 58 | + prescale *= 16; | ||
| 59 | + | ||
| 60 | + if (mode == 3 || mode == 0) | ||
| 61 | + cpu_abort(cpu_single_env, | ||
| 62 | + "m5206_timer: mode %d not implemented\n", mode); | ||
| 63 | + if ((s->tmr & TMR_FRR) == 0) | ||
| 64 | + cpu_abort(cpu_single_env, | ||
| 65 | + "m5206_timer: free running mode not implemented\n"); | ||
| 66 | + | ||
| 67 | + /* Assume 66MHz system clock. */ | ||
| 68 | + ptimer_set_freq(s->timer, 66000000 / prescale); | ||
| 69 | + | ||
| 70 | + ptimer_set_limit(s->timer, s->trr, 0); | ||
| 71 | + | ||
| 72 | + ptimer_run(s->timer, 0); | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +static void m5206_timer_trigger(void *opaque) | ||
| 76 | +{ | ||
| 77 | + m5206_timer_state *s = (m5206_timer_state *)opaque; | ||
| 78 | + s->ter |= TER_REF; | ||
| 79 | + m5206_timer_update(s); | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) | ||
| 83 | +{ | ||
| 84 | + switch (addr) { | ||
| 85 | + case 0: | ||
| 86 | + return s->tmr; | ||
| 87 | + case 4: | ||
| 88 | + return s->trr; | ||
| 89 | + case 8: | ||
| 90 | + return s->tcr; | ||
| 91 | + case 0xc: | ||
| 92 | + return s->trr - ptimer_get_count(s->timer); | ||
| 93 | + case 0x11: | ||
| 94 | + return s->ter; | ||
| 95 | + default: | ||
| 96 | + return 0; | ||
| 97 | + } | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) | ||
| 101 | +{ | ||
| 102 | + switch (addr) { | ||
| 103 | + case 0: | ||
| 104 | + if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { | ||
| 105 | + m5206_timer_reset(s); | ||
| 106 | + } | ||
| 107 | + s->tmr = val; | ||
| 108 | + m5206_timer_recalibrate(s); | ||
| 109 | + break; | ||
| 110 | + case 4: | ||
| 111 | + s->trr = val; | ||
| 112 | + m5206_timer_recalibrate(s); | ||
| 113 | + break; | ||
| 114 | + case 8: | ||
| 115 | + s->tcr = val; | ||
| 116 | + break; | ||
| 117 | + case 0xc: | ||
| 118 | + ptimer_set_count(s->timer, val); | ||
| 119 | + break; | ||
| 120 | + case 0x11: | ||
| 121 | + s->ter &= ~val; | ||
| 122 | + break; | ||
| 123 | + default: | ||
| 124 | + break; | ||
| 125 | + } | ||
| 126 | + m5206_timer_update(s); | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +static m5206_timer_state *m5206_timer_init(qemu_irq irq) | ||
| 130 | +{ | ||
| 131 | + m5206_timer_state *s; | ||
| 132 | + QEMUBH *bh; | ||
| 133 | + | ||
| 134 | + s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state)); | ||
| 135 | + bh = qemu_bh_new(m5206_timer_trigger, s); | ||
| 136 | + s->timer = ptimer_init(bh); | ||
| 137 | + s->irq = irq; | ||
| 138 | + m5206_timer_reset(s); | ||
| 139 | + return s; | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +/* UART */ | ||
| 143 | + | ||
| 144 | +typedef struct { | ||
| 145 | + uint8_t mr[2]; | ||
| 146 | + uint8_t sr; | ||
| 147 | + uint8_t isr; | ||
| 148 | + uint8_t imr; | ||
| 149 | + uint8_t bg1; | ||
| 150 | + uint8_t bg2; | ||
| 151 | + uint8_t fifo[4]; | ||
| 152 | + uint8_t tb; | ||
| 153 | + int current_mr; | ||
| 154 | + int fifo_len; | ||
| 155 | + int tx_enabled; | ||
| 156 | + int rx_enabled; | ||
| 157 | + qemu_irq irq; | ||
| 158 | + CharDriverState *chr; | ||
| 159 | +} m5206_uart_state; | ||
| 160 | + | ||
| 161 | +/* UART Status Register bits. */ | ||
| 162 | +#define M5206_UART_RxRDY 0x01 | ||
| 163 | +#define M5206_UART_FFULL 0x02 | ||
| 164 | +#define M5206_UART_TxRDY 0x04 | ||
| 165 | +#define M5206_UART_TxEMP 0x08 | ||
| 166 | +#define M5206_UART_OE 0x10 | ||
| 167 | +#define M5206_UART_PE 0x20 | ||
| 168 | +#define M5206_UART_FE 0x40 | ||
| 169 | +#define M5206_UART_RB 0x80 | ||
| 170 | + | ||
| 171 | +/* Interrupt flags. */ | ||
| 172 | +#define M5206_UART_TxINT 0x01 | ||
| 173 | +#define M5206_UART_RxINT 0x02 | ||
| 174 | +#define M5206_UART_DBINT 0x04 | ||
| 175 | +#define M5206_UART_COSINT 0x80 | ||
| 176 | + | ||
| 177 | +/* UMR1 flags. */ | ||
| 178 | +#define M5206_UART_BC0 0x01 | ||
| 179 | +#define M5206_UART_BC1 0x02 | ||
| 180 | +#define M5206_UART_PT 0x04 | ||
| 181 | +#define M5206_UART_PM0 0x08 | ||
| 182 | +#define M5206_UART_PM1 0x10 | ||
| 183 | +#define M5206_UART_ERR 0x20 | ||
| 184 | +#define M5206_UART_RxIRQ 0x40 | ||
| 185 | +#define M5206_UART_RxRTS 0x80 | ||
| 186 | + | ||
| 187 | +static void m5206_uart_update(m5206_uart_state *s) | ||
| 188 | +{ | ||
| 189 | + s->isr &= ~(M5206_UART_TxINT | M5206_UART_RxINT); | ||
| 190 | + if (s->sr & M5206_UART_TxRDY) | ||
| 191 | + s->isr |= M5206_UART_TxINT; | ||
| 192 | + if ((s->sr & ((s->mr[0] & M5206_UART_RxIRQ) | ||
| 193 | + ? M5206_UART_FFULL : M5206_UART_RxRDY)) != 0) | ||
| 194 | + s->isr |= M5206_UART_RxINT; | ||
| 195 | + | ||
| 196 | + qemu_set_irq(s->irq, (s->isr & s->imr) != 0); | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +static uint32_t m5206_uart_read(m5206_uart_state *s, uint32_t addr) | ||
| 200 | +{ | ||
| 201 | + switch (addr) { | ||
| 202 | + case 0x00: | ||
| 203 | + return s->mr[s->current_mr]; | ||
| 204 | + case 0x04: | ||
| 205 | + return s->sr; | ||
| 206 | + case 0x0c: | ||
| 207 | + { | ||
| 208 | + uint8_t val; | ||
| 209 | + int i; | ||
| 210 | + | ||
| 211 | + if (s->fifo_len == 0) | ||
| 212 | + return 0; | ||
| 213 | + | ||
| 214 | + val = s->fifo[0]; | ||
| 215 | + s->fifo_len--; | ||
| 216 | + for (i = 0; i < s->fifo_len; i++) | ||
| 217 | + s->fifo[i] = s->fifo[i + 1]; | ||
| 218 | + s->sr &= ~M5206_UART_FFULL; | ||
| 219 | + if (s->fifo_len == 0) | ||
| 220 | + s->sr &= ~M5206_UART_RxRDY; | ||
| 221 | + m5206_uart_update(s); | ||
| 222 | + return val; | ||
| 223 | + } | ||
| 224 | + case 0x10: | ||
| 225 | + /* TODO: Implement IPCR. */ | ||
| 226 | + return 0; | ||
| 227 | + case 0x14: | ||
| 228 | + return s->isr; | ||
| 229 | + case 0x18: | ||
| 230 | + return s->bg1; | ||
| 231 | + case 0x1c: | ||
| 232 | + return s->bg2; | ||
| 233 | + default: | ||
| 234 | + return 0; | ||
| 235 | + } | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +/* Update TxRDY flag and set data if present and enabled. */ | ||
| 239 | +static void m5206_uart_do_tx(m5206_uart_state *s) | ||
| 240 | +{ | ||
| 241 | + if (s->tx_enabled && (s->sr & M5206_UART_TxEMP) == 0) { | ||
| 242 | + if (s->chr) | ||
| 243 | + qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1); | ||
| 244 | + s->sr |= M5206_UART_TxEMP; | ||
| 245 | + } | ||
| 246 | + if (s->tx_enabled) { | ||
| 247 | + s->sr |= M5206_UART_TxRDY; | ||
| 248 | + } else { | ||
| 249 | + s->sr &= ~M5206_UART_TxRDY; | ||
| 250 | + } | ||
| 251 | +} | ||
| 252 | + | ||
| 253 | +static void m5206_do_command(m5206_uart_state *s, uint8_t cmd) | ||
| 254 | +{ | ||
| 255 | + /* Misc command. */ | ||
| 256 | + switch ((cmd >> 4) & 3) { | ||
| 257 | + case 0: /* No-op. */ | ||
| 258 | + break; | ||
| 259 | + case 1: /* Reset mode register pointer. */ | ||
| 260 | + s->current_mr = 0; | ||
| 261 | + break; | ||
| 262 | + case 2: /* Reset receiver. */ | ||
| 263 | + s->rx_enabled = 0; | ||
| 264 | + s->fifo_len = 0; | ||
| 265 | + s->sr &= ~(M5206_UART_RxRDY | M5206_UART_FFULL); | ||
| 266 | + break; | ||
| 267 | + case 3: /* Reset transmitter. */ | ||
| 268 | + s->tx_enabled = 0; | ||
| 269 | + s->sr |= M5206_UART_TxEMP; | ||
| 270 | + s->sr &= ~M5206_UART_TxRDY; | ||
| 271 | + break; | ||
| 272 | + case 4: /* Reset error status. */ | ||
| 273 | + break; | ||
| 274 | + case 5: /* Reset break-change interrupt. */ | ||
| 275 | + s->isr &= ~M5206_UART_DBINT; | ||
| 276 | + break; | ||
| 277 | + case 6: /* Start break. */ | ||
| 278 | + case 7: /* Stop break. */ | ||
| 279 | + break; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + /* Transmitter command. */ | ||
| 283 | + switch ((cmd >> 2) & 3) { | ||
| 284 | + case 0: /* No-op. */ | ||
| 285 | + break; | ||
| 286 | + case 1: /* Enable. */ | ||
| 287 | + s->tx_enabled = 1; | ||
| 288 | + m5206_uart_do_tx(s); | ||
| 289 | + break; | ||
| 290 | + case 2: /* Disable. */ | ||
| 291 | + s->tx_enabled = 0; | ||
| 292 | + m5206_uart_do_tx(s); | ||
| 293 | + break; | ||
| 294 | + case 3: /* Reserved. */ | ||
| 295 | + fprintf(stderr, "m5206_uart: Bad TX command\n"); | ||
| 296 | + break; | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + /* Receiver command. */ | ||
| 300 | + switch (cmd & 3) { | ||
| 301 | + case 0: /* No-op. */ | ||
| 302 | + break; | ||
| 303 | + case 1: /* Enable. */ | ||
| 304 | + s->rx_enabled = 1; | ||
| 305 | + break; | ||
| 306 | + case 2: | ||
| 307 | + s->rx_enabled = 0; | ||
| 308 | + break; | ||
| 309 | + case 3: /* Reserved. */ | ||
| 310 | + fprintf(stderr, "m5206_uart: Bad RX command\n"); | ||
| 311 | + break; | ||
| 312 | + } | ||
| 313 | +} | ||
| 314 | + | ||
| 315 | +static void m5206_uart_write(m5206_uart_state *s, uint32_t addr, uint32_t val) | ||
| 316 | +{ | ||
| 317 | + switch (addr) { | ||
| 318 | + case 0x00: | ||
| 319 | + s->mr[s->current_mr] = val; | ||
| 320 | + s->current_mr = 1; | ||
| 321 | + break; | ||
| 322 | + case 0x04: | ||
| 323 | + /* CSR is ignored. */ | ||
| 324 | + break; | ||
| 325 | + case 0x08: /* Command Register. */ | ||
| 326 | + m5206_do_command(s, val); | ||
| 327 | + break; | ||
| 328 | + case 0x0c: /* Transmit Buffer. */ | ||
| 329 | + s->sr &= ~M5206_UART_TxEMP; | ||
| 330 | + s->tb = val; | ||
| 331 | + m5206_uart_do_tx(s); | ||
| 332 | + break; | ||
| 333 | + case 0x10: | ||
| 334 | + /* ACR is ignored. */ | ||
| 335 | + break; | ||
| 336 | + case 0x14: | ||
| 337 | + s->imr = val; | ||
| 338 | + break; | ||
| 339 | + default: | ||
| 340 | + break; | ||
| 341 | + } | ||
| 342 | + m5206_uart_update(s); | ||
| 343 | +} | ||
| 344 | + | ||
| 345 | +static void m5206_uart_reset(m5206_uart_state *s) | ||
| 346 | +{ | ||
| 347 | + s->fifo_len = 0; | ||
| 348 | + s->mr[0] = 0; | ||
| 349 | + s->mr[1] = 0; | ||
| 350 | + s->sr = M5206_UART_TxEMP; | ||
| 351 | + s->tx_enabled = 0; | ||
| 352 | + s->rx_enabled = 0; | ||
| 353 | + s->isr = 0; | ||
| 354 | + s->imr = 0; | ||
| 355 | +} | ||
| 356 | + | ||
| 357 | +static void m5206_uart_push_byte(m5206_uart_state *s, uint8_t data) | ||
| 358 | +{ | ||
| 359 | + /* Break events overwrite the last byte if the fifo is full. */ | ||
| 360 | + if (s->fifo_len == 4) | ||
| 361 | + s->fifo_len--; | ||
| 362 | + | ||
| 363 | + s->fifo[s->fifo_len] = data; | ||
| 364 | + s->fifo_len++; | ||
| 365 | + s->sr |= M5206_UART_RxRDY; | ||
| 366 | + if (s->fifo_len == 4) | ||
| 367 | + s->sr |= M5206_UART_FFULL; | ||
| 368 | + | ||
| 369 | + m5206_uart_update(s); | ||
| 370 | +} | ||
| 371 | + | ||
| 372 | +static void m5206_uart_event(void *opaque, int event) | ||
| 373 | +{ | ||
| 374 | + m5206_uart_state *s = (m5206_uart_state *)opaque; | ||
| 375 | + | ||
| 376 | + switch (event) { | ||
| 377 | + case CHR_EVENT_BREAK: | ||
| 378 | + s->isr |= M5206_UART_DBINT; | ||
| 379 | + m5206_uart_push_byte(s, 0); | ||
| 380 | + break; | ||
| 381 | + default: | ||
| 382 | + break; | ||
| 383 | + } | ||
| 384 | +} | ||
| 385 | + | ||
| 386 | +static int m5206_uart_can_receive(void *opaque) | ||
| 387 | +{ | ||
| 388 | + m5206_uart_state *s = (m5206_uart_state *)opaque; | ||
| 389 | + | ||
| 390 | + return s->rx_enabled && (s->sr & M5206_UART_FFULL) == 0; | ||
| 391 | +} | ||
| 392 | + | ||
| 393 | +static void m5206_uart_receive(void *opaque, const uint8_t *buf, int size) | ||
| 394 | +{ | ||
| 395 | + m5206_uart_state *s = (m5206_uart_state *)opaque; | ||
| 396 | + | ||
| 397 | + m5206_uart_push_byte(s, buf[0]); | ||
| 398 | +} | ||
| 399 | + | ||
| 400 | +static m5206_uart_state *m5206_uart_init(qemu_irq irq, CharDriverState *chr) | ||
| 401 | +{ | ||
| 402 | + m5206_uart_state *s; | ||
| 403 | + | ||
| 404 | + s = qemu_mallocz(sizeof(m5206_uart_state)); | ||
| 405 | + s->chr = chr; | ||
| 406 | + s->irq = irq; | ||
| 407 | + if (chr) { | ||
| 408 | + qemu_chr_add_handlers(chr, m5206_uart_can_receive, m5206_uart_receive, | ||
| 409 | + m5206_uart_event, s); | ||
| 410 | + } | ||
| 411 | + m5206_uart_reset(s); | ||
| 412 | + return s; | ||
| 413 | +} | ||
| 414 | + | ||
| 415 | +/* System Integration Module. */ | ||
| 416 | + | ||
| 417 | +typedef struct { | ||
| 418 | + CPUState *env; | ||
| 419 | + m5206_timer_state *timer[2]; | ||
| 420 | + m5206_uart_state *uart[2]; | ||
| 421 | + uint8_t scr; | ||
| 422 | + uint8_t icr[14]; | ||
| 423 | + uint16_t imr; /* 1 == interrupt is masked. */ | ||
| 424 | + uint16_t ipr; | ||
| 425 | + uint8_t rsr; | ||
| 426 | + uint8_t swivr; | ||
| 427 | + uint8_t par; | ||
| 428 | + /* Include the UART vector registers here. */ | ||
| 429 | + uint8_t uivr[2]; | ||
| 430 | +} m5206_mbar_state; | ||
| 431 | + | ||
| 432 | +/* Interrupt controller. */ | ||
| 433 | + | ||
| 434 | +static int m5206_find_pending_irq(m5206_mbar_state *s) | ||
| 435 | +{ | ||
| 436 | + int level; | ||
| 437 | + int vector; | ||
| 438 | + uint16_t active; | ||
| 439 | + int i; | ||
| 440 | + | ||
| 441 | + level = 0; | ||
| 442 | + vector = 0; | ||
| 443 | + active = s->ipr & ~s->imr; | ||
| 444 | + if (!active) | ||
| 445 | + return 0; | ||
| 446 | + | ||
| 447 | + for (i = 1; i < 14; i++) { | ||
| 448 | + if (active & (1 << i)) { | ||
| 449 | + if ((s->icr[i] & 0x1f) > level) { | ||
| 450 | + level = s->icr[i] & 0x1f; | ||
| 451 | + vector = i; | ||
| 452 | + } | ||
| 453 | + } | ||
| 454 | + } | ||
| 455 | + | ||
| 456 | + if (level < 4) | ||
| 457 | + vector = 0; | ||
| 458 | + | ||
| 459 | + return vector; | ||
| 460 | +} | ||
| 461 | + | ||
| 462 | +static void m5206_mbar_update(m5206_mbar_state *s) | ||
| 463 | +{ | ||
| 464 | + int irq; | ||
| 465 | + int vector; | ||
| 466 | + int level; | ||
| 467 | + | ||
| 468 | + irq = m5206_find_pending_irq(s); | ||
| 469 | + if (irq) { | ||
| 470 | + int tmp; | ||
| 471 | + tmp = s->icr[irq]; | ||
| 472 | + level = (tmp >> 2) & 7; | ||
| 473 | + if (tmp & 0x80) { | ||
| 474 | + /* Autovector. */ | ||
| 475 | + vector = 24 + level; | ||
| 476 | + } else { | ||
| 477 | + switch (irq) { | ||
| 478 | + case 8: /* SWT */ | ||
| 479 | + vector = s->swivr; | ||
| 480 | + break; | ||
| 481 | + case 12: /* UART1 */ | ||
| 482 | + vector = s->uivr[0]; | ||
| 483 | + break; | ||
| 484 | + case 13: /* UART2 */ | ||
| 485 | + vector = s->uivr[1]; | ||
| 486 | + break; | ||
| 487 | + default: | ||
| 488 | + /* Unknown vector. */ | ||
| 489 | + fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); | ||
| 490 | + vector = 0xf; | ||
| 491 | + break; | ||
| 492 | + } | ||
| 493 | + } | ||
| 494 | + } else { | ||
| 495 | + level = 0; | ||
| 496 | + vector = 0; | ||
| 497 | + } | ||
| 498 | + m68k_set_irq_level(s->env, level, vector); | ||
| 499 | +} | ||
| 500 | + | ||
| 501 | +static void m5206_mbar_set_irq(void *opaque, int irq, int level) | ||
| 502 | +{ | ||
| 503 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 504 | + if (level) { | ||
| 505 | + s->ipr |= 1 << irq; | ||
| 506 | + } else { | ||
| 507 | + s->ipr &= ~(1 << irq); | ||
| 508 | + } | ||
| 509 | + m5206_mbar_update(s); | ||
| 510 | +} | ||
| 511 | + | ||
| 512 | +/* System Integration Module. */ | ||
| 513 | + | ||
| 514 | +static void m5206_mbar_reset(m5206_mbar_state *s) | ||
| 515 | +{ | ||
| 516 | + s->scr = 0xc0; | ||
| 517 | + s->icr[1] = 0x04; | ||
| 518 | + s->icr[2] = 0x08; | ||
| 519 | + s->icr[3] = 0x0c; | ||
| 520 | + s->icr[4] = 0x10; | ||
| 521 | + s->icr[5] = 0x14; | ||
| 522 | + s->icr[6] = 0x18; | ||
| 523 | + s->icr[7] = 0x1c; | ||
| 524 | + s->icr[8] = 0x1c; | ||
| 525 | + s->icr[9] = 0x80; | ||
| 526 | + s->icr[10] = 0x80; | ||
| 527 | + s->icr[11] = 0x80; | ||
| 528 | + s->icr[12] = 0x00; | ||
| 529 | + s->icr[13] = 0x00; | ||
| 530 | + s->imr = 0x3ffe; | ||
| 531 | + s->rsr = 0x80; | ||
| 532 | + s->swivr = 0x0f; | ||
| 533 | + s->par = 0; | ||
| 534 | +} | ||
| 535 | + | ||
| 536 | +static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset) | ||
| 537 | +{ | ||
| 538 | + if (offset >= 0x100 && offset < 0x120) { | ||
| 539 | + return m5206_timer_read(s->timer[0], offset - 0x100); | ||
| 540 | + } else if (offset >= 0x120 && offset < 0x140) { | ||
| 541 | + return m5206_timer_read(s->timer[1], offset - 0x120); | ||
| 542 | + } else if (offset >= 0x140 && offset < 0x160) { | ||
| 543 | + return m5206_uart_read(s->uart[0], offset - 0x140); | ||
| 544 | + } else if (offset >= 0x180 && offset < 0x1a0) { | ||
| 545 | + return m5206_uart_read(s->uart[1], offset - 0x180); | ||
| 546 | + } | ||
| 547 | + switch (offset) { | ||
| 548 | + case 0x03: return s->scr; | ||
| 549 | + case 0x14 ... 0x20: return s->icr[offset - 0x13]; | ||
| 550 | + case 0x36: return s->imr; | ||
| 551 | + case 0x3a: return s->ipr; | ||
| 552 | + case 0x40: return s->rsr; | ||
| 553 | + case 0x41: return 0; | ||
| 554 | + case 0x42: return s->swivr; | ||
| 555 | + case 0x50: | ||
| 556 | + /* DRAM mask register. */ | ||
| 557 | + /* FIXME: currently hardcoded to 128Mb. */ | ||
| 558 | + { | ||
| 559 | + uint32_t mask = ~0; | ||
| 560 | + while (mask > ram_size) | ||
| 561 | + mask >>= 1; | ||
| 562 | + return mask & 0x0ffe0000; | ||
| 563 | + } | ||
| 564 | + case 0x5c: return 1; /* DRAM bank 1 empty. */ | ||
| 565 | + case 0xcb: return s->par; | ||
| 566 | + case 0x170: return s->uivr[0]; | ||
| 567 | + case 0x1b0: return s->uivr[1]; | ||
| 568 | + } | ||
| 569 | + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); | ||
| 570 | + return 0; | ||
| 571 | +} | ||
| 572 | + | ||
| 573 | +static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, | ||
| 574 | + uint32_t value) | ||
| 575 | +{ | ||
| 576 | + if (offset >= 0x100 && offset < 0x120) { | ||
| 577 | + m5206_timer_write(s->timer[0], offset - 0x100, value); | ||
| 578 | + return; | ||
| 579 | + } else if (offset >= 0x120 && offset < 0x140) { | ||
| 580 | + m5206_timer_write(s->timer[1], offset - 0x120, value); | ||
| 581 | + return; | ||
| 582 | + } else if (offset >= 0x140 && offset < 0x160) { | ||
| 583 | + m5206_uart_write(s->uart[0], offset - 0x140, value); | ||
| 584 | + return; | ||
| 585 | + } else if (offset >= 0x180 && offset < 0x1a0) { | ||
| 586 | + m5206_uart_write(s->uart[1], offset - 0x180, value); | ||
| 587 | + return; | ||
| 588 | + } | ||
| 589 | + switch (offset) { | ||
| 590 | + case 0x03: | ||
| 591 | + s->scr = value; | ||
| 592 | + break; | ||
| 593 | + case 0x14 ... 0x20: | ||
| 594 | + s->icr[offset - 0x13] = value; | ||
| 595 | + m5206_mbar_update(s); | ||
| 596 | + break; | ||
| 597 | + case 0x36: | ||
| 598 | + s->imr = value; | ||
| 599 | + m5206_mbar_update(s); | ||
| 600 | + break; | ||
| 601 | + case 0x40: | ||
| 602 | + s->rsr &= ~value; | ||
| 603 | + break; | ||
| 604 | + case 0x41: | ||
| 605 | + /* TODO: implement watchdog. */ | ||
| 606 | + break; | ||
| 607 | + case 0x42: | ||
| 608 | + s->swivr = value; | ||
| 609 | + break; | ||
| 610 | + case 0xcb: | ||
| 611 | + s->par = value; | ||
| 612 | + break; | ||
| 613 | + case 0x170: | ||
| 614 | + s->uivr[0] = value; | ||
| 615 | + break; | ||
| 616 | + case 0x178: case 0x17c: case 0x1c8: case 0x1bc: | ||
| 617 | + /* Not implemented: UART Output port bits. */ | ||
| 618 | + break; | ||
| 619 | + case 0x1b0: | ||
| 620 | + s->uivr[1] = value; | ||
| 621 | + break; | ||
| 622 | + default: | ||
| 623 | + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); | ||
| 624 | + break; | ||
| 625 | + } | ||
| 626 | +} | ||
| 627 | + | ||
| 628 | +/* Internal peripherals use a variety of register widths. | ||
| 629 | + This lookup table allows a single routine to handle all of them. */ | ||
| 630 | +static const int m5206_mbar_width[] = | ||
| 631 | +{ | ||
| 632 | + /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, | ||
| 633 | + /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, | ||
| 634 | + /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, | ||
| 635 | + /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 636 | + /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, | ||
| 637 | + /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 638 | + /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 639 | + /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 640 | +}; | ||
| 641 | + | ||
| 642 | +static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset); | ||
| 643 | +static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset); | ||
| 644 | + | ||
| 645 | +static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) | ||
| 646 | +{ | ||
| 647 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 648 | + offset &= 0x3ff; | ||
| 649 | + if (offset > 0x200) { | ||
| 650 | + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); | ||
| 651 | + } | ||
| 652 | + if (m5206_mbar_width[offset >> 2] > 1) { | ||
| 653 | + uint16_t val; | ||
| 654 | + val = m5206_mbar_readw(opaque, offset & ~1); | ||
| 655 | + if ((offset & 1) == 0) { | ||
| 656 | + val >>= 8; | ||
| 657 | + } | ||
| 658 | + return val & 0xff; | ||
| 659 | + } | ||
| 660 | + return m5206_mbar_read(s, offset); | ||
| 661 | +} | ||
| 662 | + | ||
| 663 | +static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) | ||
| 664 | +{ | ||
| 665 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 666 | + int width; | ||
| 667 | + offset &= 0x3ff; | ||
| 668 | + if (offset > 0x200) { | ||
| 669 | + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); | ||
| 670 | + } | ||
| 671 | + width = m5206_mbar_width[offset >> 2]; | ||
| 672 | + if (width > 2) { | ||
| 673 | + uint32_t val; | ||
| 674 | + val = m5206_mbar_readl(opaque, offset & ~3); | ||
| 675 | + if ((offset & 3) == 0) | ||
| 676 | + val >>= 16; | ||
| 677 | + return val & 0xffff; | ||
| 678 | + } else if (width < 2) { | ||
| 679 | + uint16_t val; | ||
| 680 | + val = m5206_mbar_readb(opaque, offset) << 8; | ||
| 681 | + val |= m5206_mbar_readb(opaque, offset + 1); | ||
| 682 | + return val; | ||
| 683 | + } | ||
| 684 | + return m5206_mbar_read(s, offset); | ||
| 685 | +} | ||
| 686 | + | ||
| 687 | +static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) | ||
| 688 | +{ | ||
| 689 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 690 | + int width; | ||
| 691 | + offset &= 0x3ff; | ||
| 692 | + if (offset > 0x200) { | ||
| 693 | + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); | ||
| 694 | + } | ||
| 695 | + width = m5206_mbar_width[offset >> 2]; | ||
| 696 | + if (width < 4) { | ||
| 697 | + uint32_t val; | ||
| 698 | + val = m5206_mbar_readw(opaque, offset) << 16; | ||
| 699 | + val |= m5206_mbar_readw(opaque, offset + 2); | ||
| 700 | + return val; | ||
| 701 | + } | ||
| 702 | + return m5206_mbar_read(s, offset); | ||
| 703 | +} | ||
| 704 | + | ||
| 705 | +static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, | ||
| 706 | + uint32_t value); | ||
| 707 | +static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, | ||
| 708 | + uint32_t value); | ||
| 709 | + | ||
| 710 | +static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, | ||
| 711 | + uint32_t value) | ||
| 712 | +{ | ||
| 713 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 714 | + int width; | ||
| 715 | + offset &= 0x3ff; | ||
| 716 | + if (offset > 0x200) { | ||
| 717 | + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); | ||
| 718 | + } | ||
| 719 | + width = m5206_mbar_width[offset >> 2]; | ||
| 720 | + if (width > 1) { | ||
| 721 | + uint32_t tmp; | ||
| 722 | + tmp = m5206_mbar_readw(opaque, offset & ~1); | ||
| 723 | + if (offset & 1) { | ||
| 724 | + tmp = (tmp & 0xff00) | value; | ||
| 725 | + } else { | ||
| 726 | + tmp = (tmp & 0x00ff) | (value << 8); | ||
| 727 | + } | ||
| 728 | + m5206_mbar_writew(opaque, offset & ~1, tmp); | ||
| 729 | + return; | ||
| 730 | + } | ||
| 731 | + m5206_mbar_write(s, offset, value); | ||
| 732 | +} | ||
| 733 | + | ||
| 734 | +static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, | ||
| 735 | + uint32_t value) | ||
| 736 | +{ | ||
| 737 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 738 | + int width; | ||
| 739 | + offset &= 0x3ff; | ||
| 740 | + if (offset > 0x200) { | ||
| 741 | + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); | ||
| 742 | + } | ||
| 743 | + width = m5206_mbar_width[offset >> 2]; | ||
| 744 | + if (width > 2) { | ||
| 745 | + uint32_t tmp; | ||
| 746 | + tmp = m5206_mbar_readl(opaque, offset & ~3); | ||
| 747 | + if (offset & 3) { | ||
| 748 | + tmp = (tmp & 0xffff0000) | value; | ||
| 749 | + } else { | ||
| 750 | + tmp = (tmp & 0x0000ffff) | (value << 16); | ||
| 751 | + } | ||
| 752 | + m5206_mbar_writel(opaque, offset & ~3, tmp); | ||
| 753 | + return; | ||
| 754 | + } else if (width < 2) { | ||
| 755 | + m5206_mbar_writeb(opaque, offset, value >> 8); | ||
| 756 | + m5206_mbar_writeb(opaque, offset + 1, value & 0xff); | ||
| 757 | + return; | ||
| 758 | + } | ||
| 759 | + m5206_mbar_write(s, offset, value); | ||
| 760 | +} | ||
| 761 | + | ||
| 762 | +static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, | ||
| 763 | + uint32_t value) | ||
| 764 | +{ | ||
| 765 | + m5206_mbar_state *s = (m5206_mbar_state *)opaque; | ||
| 766 | + int width; | ||
| 767 | + offset &= 0x3ff; | ||
| 768 | + if (offset > 0x200) { | ||
| 769 | + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); | ||
| 770 | + } | ||
| 771 | + width = m5206_mbar_width[offset >> 2]; | ||
| 772 | + if (width < 4) { | ||
| 773 | + m5206_mbar_writew(opaque, offset, value >> 16); | ||
| 774 | + m5206_mbar_writew(opaque, offset + 2, value & 0xffff); | ||
| 775 | + return; | ||
| 776 | + } | ||
| 777 | + m5206_mbar_write(s, offset, value); | ||
| 778 | +} | ||
| 779 | + | ||
| 780 | +static CPUReadMemoryFunc *m5206_mbar_readfn[] = { | ||
| 781 | + m5206_mbar_readb, | ||
| 782 | + m5206_mbar_readw, | ||
| 783 | + m5206_mbar_readl | ||
| 784 | +}; | ||
| 785 | + | ||
| 786 | +static CPUWriteMemoryFunc *m5206_mbar_writefn[] = { | ||
| 787 | + m5206_mbar_writeb, | ||
| 788 | + m5206_mbar_writew, | ||
| 789 | + m5206_mbar_writel | ||
| 790 | +}; | ||
| 791 | + | ||
| 792 | +qemu_irq *mcf5206_init(uint32_t base, CPUState *env) | ||
| 793 | +{ | ||
| 794 | + m5206_mbar_state *s; | ||
| 795 | + qemu_irq *pic; | ||
| 796 | + int iomemtype; | ||
| 797 | + | ||
| 798 | + s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state)); | ||
| 799 | + iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn, | ||
| 800 | + m5206_mbar_writefn, s); | ||
| 801 | + cpu_register_physical_memory(base, 0x00000fff, iomemtype); | ||
| 802 | + | ||
| 803 | + pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); | ||
| 804 | + s->timer[0] = m5206_timer_init(pic[9]); | ||
| 805 | + s->timer[1] = m5206_timer_init(pic[10]); | ||
| 806 | + s->uart[0] = m5206_uart_init(pic[12], serial_hds[0]); | ||
| 807 | + s->uart[1] = m5206_uart_init(pic[13], serial_hds[1]); | ||
| 808 | + s->env = env; | ||
| 809 | + | ||
| 810 | + m5206_mbar_reset(s); | ||
| 811 | + return pic; | ||
| 812 | +} | ||
| 813 | + |
linux-user/main.c
| @@ -1977,13 +1977,12 @@ int main(int argc, char **argv) | @@ -1977,13 +1977,12 @@ int main(int argc, char **argv) | ||
| 1977 | } | 1977 | } |
| 1978 | #elif defined(TARGET_M68K) | 1978 | #elif defined(TARGET_M68K) |
| 1979 | { | 1979 | { |
| 1980 | - m68k_def_t *def; | ||
| 1981 | - def = m68k_find_by_name("cfv4e"); | ||
| 1982 | - if (def == NULL) { | 1980 | + if (cpu_model == NULL) |
| 1981 | + cpu_model = "cfv4e"; | ||
| 1982 | + if (cpu_m68k_set_model(env, cpu_model)) { | ||
| 1983 | cpu_abort(cpu_single_env, | 1983 | cpu_abort(cpu_single_env, |
| 1984 | "Unable to find m68k CPU definition\n"); | 1984 | "Unable to find m68k CPU definition\n"); |
| 1985 | } | 1985 | } |
| 1986 | - cpu_m68k_register(cpu_single_env, def); | ||
| 1987 | env->pc = regs->pc; | 1986 | env->pc = regs->pc; |
| 1988 | env->dregs[0] = regs->d0; | 1987 | env->dregs[0] = regs->d0; |
| 1989 | env->dregs[1] = regs->d1; | 1988 | env->dregs[1] = regs->d1; |
softmmu_header.h
| @@ -65,6 +65,8 @@ | @@ -65,6 +65,8 @@ | ||
| 65 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) | 65 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) |
| 66 | #elif defined (TARGET_ALPHA) | 66 | #elif defined (TARGET_ALPHA) |
| 67 | #define CPU_MEM_INDEX ((env->ps >> 3) & 3) | 67 | #define CPU_MEM_INDEX ((env->ps >> 3) & 3) |
| 68 | +#elif defined (TARGET_M68K) | ||
| 69 | +#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) | ||
| 68 | #else | 70 | #else |
| 69 | #error unsupported CPU | 71 | #error unsupported CPU |
| 70 | #endif | 72 | #endif |
| @@ -86,6 +88,8 @@ | @@ -86,6 +88,8 @@ | ||
| 86 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) | 88 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) |
| 87 | #elif defined (TARGET_ALPHA) | 89 | #elif defined (TARGET_ALPHA) |
| 88 | #define CPU_MEM_INDEX ((env->ps >> 3) & 3) | 90 | #define CPU_MEM_INDEX ((env->ps >> 3) & 3) |
| 91 | +#elif defined (TARGET_M68K) | ||
| 92 | +#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) | ||
| 89 | #else | 93 | #else |
| 90 | #error unsupported CPU | 94 | #error unsupported CPU |
| 91 | #endif | 95 | #endif |
target-m68k/cpu.h
| 1 | /* | 1 | /* |
| 2 | * m68k virtual CPU header | 2 | * m68k virtual CPU header |
| 3 | * | 3 | * |
| 4 | - * Copyright (c) 2005-2006 CodeSourcery | 4 | + * Copyright (c) 2005-2007 CodeSourcery |
| 5 | * Written by Paul Brook | 5 | * Written by Paul Brook |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
| @@ -50,6 +50,8 @@ | @@ -50,6 +50,8 @@ | ||
| 50 | #define EXCP_UNSUPPORTED 61 | 50 | #define EXCP_UNSUPPORTED 61 |
| 51 | #define EXCP_ICE 13 | 51 | #define EXCP_ICE 13 |
| 52 | 52 | ||
| 53 | +#define EXCP_RTE 0x100 | ||
| 54 | + | ||
| 53 | typedef struct CPUM68KState { | 55 | typedef struct CPUM68KState { |
| 54 | uint32_t dregs[8]; | 56 | uint32_t dregs[8]; |
| 55 | uint32_t aregs[8]; | 57 | uint32_t aregs[8]; |
| @@ -76,6 +78,12 @@ typedef struct CPUM68KState { | @@ -76,6 +78,12 @@ typedef struct CPUM68KState { | ||
| 76 | struct { | 78 | struct { |
| 77 | uint32_t ar; | 79 | uint32_t ar; |
| 78 | } mmu; | 80 | } mmu; |
| 81 | + | ||
| 82 | + /* Control registers. */ | ||
| 83 | + uint32_t vbr; | ||
| 84 | + uint32_t mbar; | ||
| 85 | + uint32_t rambar0; | ||
| 86 | + | ||
| 79 | /* ??? remove this. */ | 87 | /* ??? remove this. */ |
| 80 | uint32_t t1; | 88 | uint32_t t1; |
| 81 | 89 | ||
| @@ -84,7 +92,10 @@ typedef struct CPUM68KState { | @@ -84,7 +92,10 @@ typedef struct CPUM68KState { | ||
| 84 | int exception_index; | 92 | int exception_index; |
| 85 | int interrupt_request; | 93 | int interrupt_request; |
| 86 | int user_mode_only; | 94 | int user_mode_only; |
| 87 | - uint32_t address; | 95 | + int halted; |
| 96 | + | ||
| 97 | + int pending_vector; | ||
| 98 | + int pending_level; | ||
| 88 | 99 | ||
| 89 | uint32_t qregs[MAX_QREGS]; | 100 | uint32_t qregs[MAX_QREGS]; |
| 90 | 101 | ||
| @@ -94,6 +105,7 @@ typedef struct CPUM68KState { | @@ -94,6 +105,7 @@ typedef struct CPUM68KState { | ||
| 94 | CPUM68KState *cpu_m68k_init(void); | 105 | CPUM68KState *cpu_m68k_init(void); |
| 95 | int cpu_m68k_exec(CPUM68KState *s); | 106 | int cpu_m68k_exec(CPUM68KState *s); |
| 96 | void cpu_m68k_close(CPUM68KState *s); | 107 | void cpu_m68k_close(CPUM68KState *s); |
| 108 | +void do_interrupt(int is_hw); | ||
| 97 | /* you can call this signal handler from your SIGBUS and SIGSEGV | 109 | /* you can call this signal handler from your SIGBUS and SIGSEGV |
| 98 | signal handlers to inform the virtual CPU of exceptions. non zero | 110 | signal handlers to inform the virtual CPU of exceptions. non zero |
| 99 | is returned if the signal was handled by the virtual CPU. */ | 111 | is returned if the signal was handled by the virtual CPU. */ |
| @@ -120,12 +132,19 @@ enum { | @@ -120,12 +132,19 @@ enum { | ||
| 120 | #define CCF_V 0x02 | 132 | #define CCF_V 0x02 |
| 121 | #define CCF_Z 0x04 | 133 | #define CCF_Z 0x04 |
| 122 | #define CCF_N 0x08 | 134 | #define CCF_N 0x08 |
| 123 | -#define CCF_X 0x01 | 135 | +#define CCF_X 0x10 |
| 136 | + | ||
| 137 | +#define SR_I_SHIFT 8 | ||
| 138 | +#define SR_I 0x0700 | ||
| 139 | +#define SR_M 0x1000 | ||
| 140 | +#define SR_S 0x2000 | ||
| 141 | +#define SR_T 0x8000 | ||
| 124 | 142 | ||
| 125 | typedef struct m68k_def_t m68k_def_t; | 143 | typedef struct m68k_def_t m68k_def_t; |
| 126 | 144 | ||
| 127 | -m68k_def_t *m68k_find_by_name(const char *); | ||
| 128 | -void cpu_m68k_register(CPUM68KState *, m68k_def_t *); | 145 | +int cpu_m68k_set_model(CPUM68KState *env, const char * name); |
| 146 | + | ||
| 147 | +void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); | ||
| 129 | 148 | ||
| 130 | #define M68K_FPCR_PREC (1 << 6) | 149 | #define M68K_FPCR_PREC (1 << 6) |
| 131 | 150 |
target-m68k/exec.h
| @@ -40,8 +40,12 @@ static inline void regs_to_env(void) | @@ -40,8 +40,12 @@ static inline void regs_to_env(void) | ||
| 40 | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | 40 | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
| 41 | int is_user, int is_softmmu); | 41 | int is_user, int is_softmmu); |
| 42 | 42 | ||
| 43 | +#if !defined(CONFIG_USER_ONLY) | ||
| 44 | +#include "softmmu_exec.h" | ||
| 45 | +#endif | ||
| 43 | 46 | ||
| 44 | void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); | 47 | void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); |
| 45 | float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); | 48 | float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); |
| 49 | +void helper_movec(CPUM68KState *env, int reg, uint32_t val); | ||
| 46 | 50 | ||
| 47 | void cpu_loop_exit(void); | 51 | void cpu_loop_exit(void); |
target-m68k/helper.c
| 1 | /* | 1 | /* |
| 2 | * m68k op helpers | 2 | * m68k op helpers |
| 3 | * | 3 | * |
| 4 | - * Copyright (c) 2006 CodeSourcery | 4 | + * Copyright (c) 2006-2007 CodeSourcery |
| 5 | * Written by Paul Brook | 5 | * Written by Paul Brook |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * 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) | @@ -147,3 +147,65 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) | ||
| 147 | } | 147 | } |
| 148 | return res; | 148 | return res; |
| 149 | } | 149 | } |
| 150 | + | ||
| 151 | +void helper_movec(CPUM68KState *env, int reg, uint32_t val) | ||
| 152 | +{ | ||
| 153 | + switch (reg) { | ||
| 154 | + case 0x02: /* CACR */ | ||
| 155 | + /* Ignored. */ | ||
| 156 | + break; | ||
| 157 | + case 0x801: /* VBR */ | ||
| 158 | + env->vbr = val; | ||
| 159 | + break; | ||
| 160 | + /* TODO: Implement control registers. */ | ||
| 161 | + default: | ||
| 162 | + cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n", | ||
| 163 | + reg, val); | ||
| 164 | + } | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +/* MMU */ | ||
| 168 | + | ||
| 169 | +/* TODO: This will need fixing once the MMU is implemented. */ | ||
| 170 | +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 171 | +{ | ||
| 172 | + return addr; | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | +#if defined(CONFIG_USER_ONLY) | ||
| 176 | + | ||
| 177 | +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 178 | + int is_user, int is_softmmu) | ||
| 179 | +{ | ||
| 180 | + env->exception_index = EXCP_ACCESS; | ||
| 181 | + env->mmu.ar = address; | ||
| 182 | + return 1; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +#else | ||
| 186 | + | ||
| 187 | +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 188 | + int is_user, int is_softmmu) | ||
| 189 | +{ | ||
| 190 | + int prot; | ||
| 191 | + | ||
| 192 | + address &= TARGET_PAGE_MASK; | ||
| 193 | + prot = PAGE_READ | PAGE_WRITE; | ||
| 194 | + return tlb_set_page(env, address, address, prot, is_user, is_softmmu); | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +/* Notify CPU of a pending interrupt. Prioritization and vectoring should | ||
| 198 | + be handled by the interrupt controller. Real hardware only requests | ||
| 199 | + the vector when the interrupt is acknowledged by the CPU. For | ||
| 200 | + simplicitly we calculate it when the interrupt is signalled. */ | ||
| 201 | +void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector) | ||
| 202 | +{ | ||
| 203 | + env->pending_level = level; | ||
| 204 | + env->pending_vector = vector; | ||
| 205 | + if (level) | ||
| 206 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 207 | + else | ||
| 208 | + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +#endif |
target-m68k/op-hacks.h
| @@ -27,16 +27,38 @@ static inline int gen_im32(uint32_t i) | @@ -27,16 +27,38 @@ static inline int gen_im32(uint32_t i) | ||
| 27 | return qreg; | 27 | return qreg; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | -static inline void gen_op_ldf32(int dest, int addr) | 30 | +static inline void gen_op_ldf32_raw(int dest, int addr) |
| 31 | { | 31 | { |
| 32 | - gen_op_ld32(dest, addr); | 32 | + gen_op_ld32_raw(dest, addr); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | -static inline void gen_op_stf32(int addr, int dest) | 35 | +static inline void gen_op_stf32_raw(int addr, int dest) |
| 36 | { | 36 | { |
| 37 | - gen_op_st32(addr, dest); | 37 | + gen_op_st32_raw(addr, dest); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | +#if !defined(CONFIG_USER_ONLY) | ||
| 41 | +static inline void gen_op_ldf32_user(int dest, int addr) | ||
| 42 | +{ | ||
| 43 | + gen_op_ld32_user(dest, addr); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +static inline void gen_op_stf32_user(int addr, int dest) | ||
| 47 | +{ | ||
| 48 | + gen_op_st32_user(addr, dest); | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +static inline void gen_op_ldf32_kernel(int dest, int addr) | ||
| 52 | +{ | ||
| 53 | + gen_op_ld32_kernel(dest, addr); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +static inline void gen_op_stf32_kernel(int addr, int dest) | ||
| 57 | +{ | ||
| 58 | + gen_op_st32_kernel(addr, dest); | ||
| 59 | +} | ||
| 60 | +#endif | ||
| 61 | + | ||
| 40 | static inline void gen_op_pack_32_f32(int dest, int src) | 62 | static inline void gen_op_pack_32_f32(int dest, int src) |
| 41 | { | 63 | { |
| 42 | gen_op_mov32(dest, src); | 64 | gen_op_mov32(dest, src); |
target-m68k/op.c
| 1 | /* | 1 | /* |
| 2 | * m68k micro operations | 2 | * m68k micro operations |
| 3 | * | 3 | * |
| 4 | - * Copyright (c) 2006 CodeSourcery | 4 | + * Copyright (c) 2006-2007 CodeSourcery |
| 5 | * Written by Paul Brook | 5 | * Written by Paul Brook |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
| @@ -86,7 +86,7 @@ void set_opf64(int qreg, float64 val) | @@ -86,7 +86,7 @@ void set_opf64(int qreg, float64 val) | ||
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | -#define OP(name) void OPPROTO op_##name (void) | 89 | +#define OP(name) void OPPROTO glue(op_,name) (void) |
| 90 | 90 | ||
| 91 | OP(mov32) | 91 | OP(mov32) |
| 92 | { | 92 | { |
| @@ -316,77 +316,6 @@ OP(ext16s32) | @@ -316,77 +316,6 @@ OP(ext16s32) | ||
| 316 | FORCE_RET(); | 316 | FORCE_RET(); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | -/* Load/store ops. */ | ||
| 320 | -OP(ld8u32) | ||
| 321 | -{ | ||
| 322 | - uint32_t addr = get_op(PARAM2); | ||
| 323 | - set_op(PARAM1, ldub(addr)); | ||
| 324 | - FORCE_RET(); | ||
| 325 | -} | ||
| 326 | - | ||
| 327 | -OP(ld8s32) | ||
| 328 | -{ | ||
| 329 | - uint32_t addr = get_op(PARAM2); | ||
| 330 | - set_op(PARAM1, ldsb(addr)); | ||
| 331 | - FORCE_RET(); | ||
| 332 | -} | ||
| 333 | - | ||
| 334 | -OP(ld16u32) | ||
| 335 | -{ | ||
| 336 | - uint32_t addr = get_op(PARAM2); | ||
| 337 | - set_op(PARAM1, lduw(addr)); | ||
| 338 | - FORCE_RET(); | ||
| 339 | -} | ||
| 340 | - | ||
| 341 | -OP(ld16s32) | ||
| 342 | -{ | ||
| 343 | - uint32_t addr = get_op(PARAM2); | ||
| 344 | - set_op(PARAM1, ldsw(addr)); | ||
| 345 | - FORCE_RET(); | ||
| 346 | -} | ||
| 347 | - | ||
| 348 | -OP(ld32) | ||
| 349 | -{ | ||
| 350 | - uint32_t addr = get_op(PARAM2); | ||
| 351 | - set_op(PARAM1, ldl(addr)); | ||
| 352 | - FORCE_RET(); | ||
| 353 | -} | ||
| 354 | - | ||
| 355 | -OP(st8) | ||
| 356 | -{ | ||
| 357 | - uint32_t addr = get_op(PARAM1); | ||
| 358 | - stb(addr, get_op(PARAM2)); | ||
| 359 | - FORCE_RET(); | ||
| 360 | -} | ||
| 361 | - | ||
| 362 | -OP(st16) | ||
| 363 | -{ | ||
| 364 | - uint32_t addr = get_op(PARAM1); | ||
| 365 | - stw(addr, get_op(PARAM2)); | ||
| 366 | - FORCE_RET(); | ||
| 367 | -} | ||
| 368 | - | ||
| 369 | -OP(st32) | ||
| 370 | -{ | ||
| 371 | - uint32_t addr = get_op(PARAM1); | ||
| 372 | - stl(addr, get_op(PARAM2)); | ||
| 373 | - FORCE_RET(); | ||
| 374 | -} | ||
| 375 | - | ||
| 376 | -OP(ldf64) | ||
| 377 | -{ | ||
| 378 | - uint32_t addr = get_op(PARAM2); | ||
| 379 | - set_opf64(PARAM1, ldfq(addr)); | ||
| 380 | - FORCE_RET(); | ||
| 381 | -} | ||
| 382 | - | ||
| 383 | -OP(stf64) | ||
| 384 | -{ | ||
| 385 | - uint32_t addr = get_op(PARAM1); | ||
| 386 | - stfq(addr, get_opf64(PARAM2)); | ||
| 387 | - FORCE_RET(); | ||
| 388 | -} | ||
| 389 | - | ||
| 390 | OP(flush_flags) | 319 | OP(flush_flags) |
| 391 | { | 320 | { |
| 392 | int cc_op = PARAM1; | 321 | int cc_op = PARAM1; |
| @@ -454,6 +383,13 @@ OP(divs) | @@ -454,6 +383,13 @@ OP(divs) | ||
| 454 | FORCE_RET(); | 383 | FORCE_RET(); |
| 455 | } | 384 | } |
| 456 | 385 | ||
| 386 | +OP(halt) | ||
| 387 | +{ | ||
| 388 | + env->halted = 1; | ||
| 389 | + RAISE_EXCEPTION(EXCP_HLT); | ||
| 390 | + FORCE_RET(); | ||
| 391 | +} | ||
| 392 | + | ||
| 457 | OP(raise_exception) | 393 | OP(raise_exception) |
| 458 | { | 394 | { |
| 459 | RAISE_EXCEPTION(PARAM1); | 395 | RAISE_EXCEPTION(PARAM1); |
| @@ -679,3 +615,22 @@ OP(compare_quietf64) | @@ -679,3 +615,22 @@ OP(compare_quietf64) | ||
| 679 | set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); | 615 | set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); |
| 680 | FORCE_RET(); | 616 | FORCE_RET(); |
| 681 | } | 617 | } |
| 618 | + | ||
| 619 | +OP(movec) | ||
| 620 | +{ | ||
| 621 | + int op1 = get_op(PARAM1); | ||
| 622 | + uint32_t op2 = get_op(PARAM2); | ||
| 623 | + helper_movec(env, op1, op2); | ||
| 624 | +} | ||
| 625 | + | ||
| 626 | +/* Memory access. */ | ||
| 627 | + | ||
| 628 | +#define MEMSUFFIX _raw | ||
| 629 | +#include "op_mem.h" | ||
| 630 | + | ||
| 631 | +#if !defined(CONFIG_USER_ONLY) | ||
| 632 | +#define MEMSUFFIX _user | ||
| 633 | +#include "op_mem.h" | ||
| 634 | +#define MEMSUFFIX _kernel | ||
| 635 | +#include "op_mem.h" | ||
| 636 | +#endif |
target-m68k/op_helper.c
0 โ 100644
| 1 | +/* | ||
| 2 | + * M68K helper routines | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2007 CodeSourcery | ||
| 5 | + * | ||
| 6 | + * This library is free software; you can redistribute it and/or | ||
| 7 | + * modify it under the terms of the GNU Lesser General Public | ||
| 8 | + * License as published by the Free Software Foundation; either | ||
| 9 | + * version 2 of the License, or (at your option) any later version. | ||
| 10 | + * | ||
| 11 | + * This library is distributed in the hope that it will be useful, | ||
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | + * Lesser General Public License for more details. | ||
| 15 | + * | ||
| 16 | + * You should have received a copy of the GNU Lesser General Public | ||
| 17 | + * License along with this library; if not, write to the Free Software | ||
| 18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | + */ | ||
| 20 | +#include "exec.h" | ||
| 21 | + | ||
| 22 | +#if defined(CONFIG_USER_ONLY) | ||
| 23 | + | ||
| 24 | +void do_interrupt(int is_hw) | ||
| 25 | +{ | ||
| 26 | + env->exception_index = -1; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +#else | ||
| 30 | + | ||
| 31 | +#define MMUSUFFIX _mmu | ||
| 32 | +#define GETPC() (__builtin_return_address(0)) | ||
| 33 | + | ||
| 34 | +#define SHIFT 0 | ||
| 35 | +#include "softmmu_template.h" | ||
| 36 | + | ||
| 37 | +#define SHIFT 1 | ||
| 38 | +#include "softmmu_template.h" | ||
| 39 | + | ||
| 40 | +#define SHIFT 2 | ||
| 41 | +#include "softmmu_template.h" | ||
| 42 | + | ||
| 43 | +#define SHIFT 3 | ||
| 44 | +#include "softmmu_template.h" | ||
| 45 | + | ||
| 46 | +/* Try to fill the TLB and return an exception if error. If retaddr is | ||
| 47 | + NULL, it means that the function was called in C code (i.e. not | ||
| 48 | + from generated code or from helper.c) */ | ||
| 49 | +/* XXX: fix it to restore all registers */ | ||
| 50 | +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) | ||
| 51 | +{ | ||
| 52 | + TranslationBlock *tb; | ||
| 53 | + CPUState *saved_env; | ||
| 54 | + target_phys_addr_t pc; | ||
| 55 | + int ret; | ||
| 56 | + | ||
| 57 | + /* XXX: hack to restore env in all cases, even if not called from | ||
| 58 | + generated code */ | ||
| 59 | + saved_env = env; | ||
| 60 | + env = cpu_single_env; | ||
| 61 | + ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1); | ||
| 62 | + if (__builtin_expect(ret, 0)) { | ||
| 63 | + if (retaddr) { | ||
| 64 | + /* now we have a real cpu fault */ | ||
| 65 | + pc = (target_phys_addr_t)retaddr; | ||
| 66 | + tb = tb_find_pc(pc); | ||
| 67 | + if (tb) { | ||
| 68 | + /* the PC is inside the translated code. It means that we have | ||
| 69 | + a virtual CPU fault */ | ||
| 70 | + cpu_restore_state(tb, env, pc, NULL); | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + cpu_loop_exit(); | ||
| 74 | + } | ||
| 75 | + env = saved_env; | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +static void do_rte(void) | ||
| 79 | +{ | ||
| 80 | + uint32_t sp; | ||
| 81 | + uint32_t fmt; | ||
| 82 | + | ||
| 83 | + sp = env->aregs[7]; | ||
| 84 | + fmt = ldl_kernel(sp); | ||
| 85 | + env->pc = ldl_kernel(sp + 4); | ||
| 86 | + sp |= (fmt >> 28) & 3; | ||
| 87 | + env->sr = fmt & 0xffff; | ||
| 88 | + env->aregs[7] = sp + 8; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +void do_interrupt(int is_hw) | ||
| 92 | +{ | ||
| 93 | + uint32_t sp; | ||
| 94 | + uint32_t fmt; | ||
| 95 | + uint32_t retaddr; | ||
| 96 | + uint32_t vector; | ||
| 97 | + | ||
| 98 | + fmt = 0; | ||
| 99 | + retaddr = env->pc; | ||
| 100 | + | ||
| 101 | + if (!is_hw) { | ||
| 102 | + switch (env->exception_index) { | ||
| 103 | + case EXCP_RTE: | ||
| 104 | + /* Return from an exception. */ | ||
| 105 | + do_rte(); | ||
| 106 | + return; | ||
| 107 | + } | ||
| 108 | + if (env->exception_index >= EXCP_TRAP0 | ||
| 109 | + && env->exception_index <= EXCP_TRAP15) { | ||
| 110 | + /* Move the PC after the trap instruction. */ | ||
| 111 | + retaddr += 2; | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /* TODO: Implement USP. */ | ||
| 116 | + sp = env->aregs[7]; | ||
| 117 | + | ||
| 118 | + vector = env->exception_index << 2; | ||
| 119 | + | ||
| 120 | + fmt |= 0x40000000; | ||
| 121 | + fmt |= (sp & 3) << 28; | ||
| 122 | + fmt |= vector << 16; | ||
| 123 | + fmt |= env->sr; | ||
| 124 | + | ||
| 125 | + /* ??? This could cause MMU faults. */ | ||
| 126 | + sp &= ~3; | ||
| 127 | + sp -= 4; | ||
| 128 | + stl_kernel(sp, retaddr); | ||
| 129 | + sp -= 4; | ||
| 130 | + stl_kernel(sp, fmt); | ||
| 131 | + env->aregs[7] = sp; | ||
| 132 | + env->sr |= SR_S; | ||
| 133 | + if (is_hw) { | ||
| 134 | + env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); | ||
| 135 | + } | ||
| 136 | + /* Jump to vector. */ | ||
| 137 | + env->pc = ldl_kernel(env->vbr + vector); | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +#endif |
target-m68k/op_mem.h
0 โ 100644
| 1 | +/* Load/store ops. */ | ||
| 2 | +#define MEM_LD_OP(name,suffix) \ | ||
| 3 | +OP(glue(glue(ld,name),MEMSUFFIX)) \ | ||
| 4 | +{ \ | ||
| 5 | + uint32_t addr = get_op(PARAM2); \ | ||
| 6 | + set_op(PARAM1, glue(glue(ld,suffix),MEMSUFFIX)(addr)); \ | ||
| 7 | + FORCE_RET(); \ | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +MEM_LD_OP(8u32,ub) | ||
| 11 | +MEM_LD_OP(8s32,sb) | ||
| 12 | +MEM_LD_OP(16u32,uw) | ||
| 13 | +MEM_LD_OP(16s32,sw) | ||
| 14 | +MEM_LD_OP(32,l) | ||
| 15 | + | ||
| 16 | +#undef MEM_LD_OP | ||
| 17 | + | ||
| 18 | +#define MEM_ST_OP(name,suffix) \ | ||
| 19 | +OP(glue(glue(st,name),MEMSUFFIX)) \ | ||
| 20 | +{ \ | ||
| 21 | + uint32_t addr = get_op(PARAM1); \ | ||
| 22 | + glue(glue(st,suffix),MEMSUFFIX)(addr, get_op(PARAM2)); \ | ||
| 23 | + FORCE_RET(); \ | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +MEM_ST_OP(8,b) | ||
| 27 | +MEM_ST_OP(16,w) | ||
| 28 | +MEM_ST_OP(32,l) | ||
| 29 | + | ||
| 30 | +#undef MEM_ST_OP | ||
| 31 | + | ||
| 32 | +OP(glue(ldf64,MEMSUFFIX)) | ||
| 33 | +{ | ||
| 34 | + uint32_t addr = get_op(PARAM2); | ||
| 35 | + set_opf64(PARAM1, glue(ldfq,MEMSUFFIX)(addr)); | ||
| 36 | + FORCE_RET(); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +OP(glue(stf64,MEMSUFFIX)) | ||
| 40 | +{ | ||
| 41 | + uint32_t addr = get_op(PARAM1); | ||
| 42 | + glue(stfq,MEMSUFFIX)(addr, get_opf64(PARAM2)); | ||
| 43 | + FORCE_RET(); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +#undef MEMSUFFIX |
target-m68k/qregs.def
| @@ -24,6 +24,7 @@ DEFF64(F6, fregs[6]) | @@ -24,6 +24,7 @@ DEFF64(F6, fregs[6]) | ||
| 24 | DEFF64(F7, fregs[7]) | 24 | DEFF64(F7, fregs[7]) |
| 25 | DEFF64(FP_RESULT, fp_result) | 25 | DEFF64(FP_RESULT, fp_result) |
| 26 | DEFO32(PC, pc) | 26 | DEFO32(PC, pc) |
| 27 | +DEFO32(SR, sr) | ||
| 27 | DEFO32(CC_OP, cc_op) | 28 | DEFO32(CC_OP, cc_op) |
| 28 | DEFR(T0, AREG1, QMODE_I32) | 29 | DEFR(T0, AREG1, QMODE_I32) |
| 29 | DEFO32(CC_DEST, cc_dest) | 30 | DEFO32(CC_DEST, cc_dest) |
target-m68k/translate.c
| 1 | /* | 1 | /* |
| 2 | * m68k translation | 2 | * m68k translation |
| 3 | * | 3 | * |
| 4 | - * Copyright (c) 2005-2006 CodeSourcery | 4 | + * Copyright (c) 2005-2007 CodeSourcery |
| 5 | * Written by Paul Brook | 5 | * Written by Paul Brook |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
| @@ -30,6 +30,8 @@ | @@ -30,6 +30,8 @@ | ||
| 30 | #include "disas.h" | 30 | #include "disas.h" |
| 31 | #include "m68k-qreg.h" | 31 | #include "m68k-qreg.h" |
| 32 | 32 | ||
| 33 | +//#define DEBUG_DISPATCH 1 | ||
| 34 | + | ||
| 33 | static inline void qemu_assert(int cond, const char *msg) | 35 | static inline void qemu_assert(int cond, const char *msg) |
| 34 | { | 36 | { |
| 35 | if (!cond) { | 37 | if (!cond) { |
| @@ -43,6 +45,7 @@ typedef struct DisasContext { | @@ -43,6 +45,7 @@ typedef struct DisasContext { | ||
| 43 | target_ulong pc; | 45 | target_ulong pc; |
| 44 | int is_jmp; | 46 | int is_jmp; |
| 45 | int cc_op; | 47 | int cc_op; |
| 48 | + int user; | ||
| 46 | uint32_t fpcr; | 49 | uint32_t fpcr; |
| 47 | struct TranslationBlock *tb; | 50 | struct TranslationBlock *tb; |
| 48 | int singlestep_enabled; | 51 | int singlestep_enabled; |
| @@ -50,6 +53,12 @@ typedef struct DisasContext { | @@ -50,6 +53,12 @@ typedef struct DisasContext { | ||
| 50 | 53 | ||
| 51 | #define DISAS_JUMP_NEXT 4 | 54 | #define DISAS_JUMP_NEXT 4 |
| 52 | 55 | ||
| 56 | +#if defined(CONFIG_USER_ONLY) | ||
| 57 | +#define IS_USER(s) 1 | ||
| 58 | +#else | ||
| 59 | +#define IS_USER(s) s->user | ||
| 60 | +#endif | ||
| 61 | + | ||
| 53 | /* XXX: move that elsewhere */ | 62 | /* XXX: move that elsewhere */ |
| 54 | /* ??? Fix exceptions. */ | 63 | /* ??? Fix exceptions. */ |
| 55 | static void *gen_throws_exception; | 64 | static void *gen_throws_exception; |
| @@ -68,6 +77,25 @@ enum { | @@ -68,6 +77,25 @@ enum { | ||
| 68 | }; | 77 | }; |
| 69 | 78 | ||
| 70 | #include "gen-op.h" | 79 | #include "gen-op.h" |
| 80 | + | ||
| 81 | +#if defined(CONFIG_USER_ONLY) | ||
| 82 | +#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val) | ||
| 83 | +#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr) | ||
| 84 | +#else | ||
| 85 | +#define gen_st(s, name, addr, val) do { \ | ||
| 86 | + if (IS_USER(s)) \ | ||
| 87 | + gen_op_st##name##_user(addr, val); \ | ||
| 88 | + else \ | ||
| 89 | + gen_op_st##name##_kernel(addr, val); \ | ||
| 90 | + } while (0) | ||
| 91 | +#define gen_ld(s, name, val, addr) do { \ | ||
| 92 | + if (IS_USER(s)) \ | ||
| 93 | + gen_op_ld##name##_user(val, addr); \ | ||
| 94 | + else \ | ||
| 95 | + gen_op_ld##name##_kernel(val, addr); \ | ||
| 96 | + } while (0) | ||
| 97 | +#endif | ||
| 98 | + | ||
| 71 | #include "op-hacks.h" | 99 | #include "op-hacks.h" |
| 72 | 100 | ||
| 73 | #define OS_BYTE 0 | 101 | #define OS_BYTE 0 |
| @@ -101,40 +129,49 @@ static m68k_def_t m68k_cpu_defs[] = { | @@ -101,40 +129,49 @@ static m68k_def_t m68k_cpu_defs[] = { | ||
| 101 | 129 | ||
| 102 | typedef void (*disas_proc)(DisasContext *, uint16_t); | 130 | typedef void (*disas_proc)(DisasContext *, uint16_t); |
| 103 | 131 | ||
| 132 | +#ifdef DEBUG_DISPATCH | ||
| 133 | +#define DISAS_INSN(name) \ | ||
| 134 | + static void real_disas_##name (DisasContext *s, uint16_t insn); \ | ||
| 135 | + static void disas_##name (DisasContext *s, uint16_t insn) { \ | ||
| 136 | + if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \ | ||
| 137 | + real_disas_##name(s, insn); } \ | ||
| 138 | + static void real_disas_##name (DisasContext *s, uint16_t insn) | ||
| 139 | +#else | ||
| 104 | #define DISAS_INSN(name) \ | 140 | #define DISAS_INSN(name) \ |
| 105 | static void disas_##name (DisasContext *s, uint16_t insn) | 141 | static void disas_##name (DisasContext *s, uint16_t insn) |
| 142 | +#endif | ||
| 106 | 143 | ||
| 107 | /* Generate a load from the specified address. Narrow values are | 144 | /* Generate a load from the specified address. Narrow values are |
| 108 | sign extended to full register width. */ | 145 | sign extended to full register width. */ |
| 109 | -static inline int gen_load(int opsize, int addr, int sign) | 146 | +static inline int gen_load(DisasContext * s, int opsize, int addr, int sign) |
| 110 | { | 147 | { |
| 111 | int tmp; | 148 | int tmp; |
| 112 | switch(opsize) { | 149 | switch(opsize) { |
| 113 | case OS_BYTE: | 150 | case OS_BYTE: |
| 114 | tmp = gen_new_qreg(QMODE_I32); | 151 | tmp = gen_new_qreg(QMODE_I32); |
| 115 | if (sign) | 152 | if (sign) |
| 116 | - gen_op_ld8s32(tmp, addr); | 153 | + gen_ld(s, 8s32, tmp, addr); |
| 117 | else | 154 | else |
| 118 | - gen_op_ld8u32(tmp, addr); | 155 | + gen_ld(s, 8u32, tmp, addr); |
| 119 | break; | 156 | break; |
| 120 | case OS_WORD: | 157 | case OS_WORD: |
| 121 | tmp = gen_new_qreg(QMODE_I32); | 158 | tmp = gen_new_qreg(QMODE_I32); |
| 122 | if (sign) | 159 | if (sign) |
| 123 | - gen_op_ld16s32(tmp, addr); | 160 | + gen_ld(s, 16s32, tmp, addr); |
| 124 | else | 161 | else |
| 125 | - gen_op_ld16u32(tmp, addr); | 162 | + gen_ld(s, 16u32, tmp, addr); |
| 126 | break; | 163 | break; |
| 127 | case OS_LONG: | 164 | case OS_LONG: |
| 128 | tmp = gen_new_qreg(QMODE_I32); | 165 | tmp = gen_new_qreg(QMODE_I32); |
| 129 | - gen_op_ld32(tmp, addr); | 166 | + gen_ld(s, 32, tmp, addr); |
| 130 | break; | 167 | break; |
| 131 | case OS_SINGLE: | 168 | case OS_SINGLE: |
| 132 | tmp = gen_new_qreg(QMODE_F32); | 169 | tmp = gen_new_qreg(QMODE_F32); |
| 133 | - gen_op_ldf32(tmp, addr); | 170 | + gen_ld(s, f32, tmp, addr); |
| 134 | break; | 171 | break; |
| 135 | case OS_DOUBLE: | 172 | case OS_DOUBLE: |
| 136 | tmp = gen_new_qreg(QMODE_F64); | 173 | tmp = gen_new_qreg(QMODE_F64); |
| 137 | - gen_op_ldf64(tmp, addr); | 174 | + gen_ld(s, f64, tmp, addr); |
| 138 | break; | 175 | break; |
| 139 | default: | 176 | default: |
| 140 | qemu_assert(0, "bad load size"); | 177 | qemu_assert(0, "bad load size"); |
| @@ -144,23 +181,23 @@ static inline int gen_load(int opsize, int addr, int sign) | @@ -144,23 +181,23 @@ static inline int gen_load(int opsize, int addr, int sign) | ||
| 144 | } | 181 | } |
| 145 | 182 | ||
| 146 | /* Generate a store. */ | 183 | /* Generate a store. */ |
| 147 | -static inline void gen_store(int opsize, int addr, int val) | 184 | +static inline void gen_store(DisasContext *s, int opsize, int addr, int val) |
| 148 | { | 185 | { |
| 149 | switch(opsize) { | 186 | switch(opsize) { |
| 150 | case OS_BYTE: | 187 | case OS_BYTE: |
| 151 | - gen_op_st8(addr, val); | 188 | + gen_st(s, 8, addr, val); |
| 152 | break; | 189 | break; |
| 153 | case OS_WORD: | 190 | case OS_WORD: |
| 154 | - gen_op_st16(addr, val); | 191 | + gen_st(s, 16, addr, val); |
| 155 | break; | 192 | break; |
| 156 | case OS_LONG: | 193 | case OS_LONG: |
| 157 | - gen_op_st32(addr, val); | 194 | + gen_st(s, 32, addr, val); |
| 158 | break; | 195 | break; |
| 159 | case OS_SINGLE: | 196 | case OS_SINGLE: |
| 160 | - gen_op_stf32(addr, val); | 197 | + gen_st(s, f32, addr, val); |
| 161 | break; | 198 | break; |
| 162 | case OS_DOUBLE: | 199 | case OS_DOUBLE: |
| 163 | - gen_op_stf64(addr, val); | 200 | + gen_st(s, f64, addr, val); |
| 164 | break; | 201 | break; |
| 165 | default: | 202 | default: |
| 166 | qemu_assert(0, "bad store size"); | 203 | qemu_assert(0, "bad store size"); |
| @@ -170,13 +207,13 @@ static inline void gen_store(int opsize, int addr, int val) | @@ -170,13 +207,13 @@ static inline void gen_store(int opsize, int addr, int val) | ||
| 170 | 207 | ||
| 171 | /* Generate an unsigned load if VAL is 0 a signed load if val is -1, | 208 | /* Generate an unsigned load if VAL is 0 a signed load if val is -1, |
| 172 | otherwise generate a store. */ | 209 | otherwise generate a store. */ |
| 173 | -static int gen_ldst(int opsize, int addr, int val) | 210 | +static int gen_ldst(DisasContext *s, int opsize, int addr, int val) |
| 174 | { | 211 | { |
| 175 | if (val > 0) { | 212 | if (val > 0) { |
| 176 | - gen_store(opsize, addr, val); | 213 | + gen_store(s, opsize, addr, val); |
| 177 | return 0; | 214 | return 0; |
| 178 | } else { | 215 | } else { |
| 179 | - return gen_load(opsize, addr, val != 0); | 216 | + return gen_load(s, opsize, addr, val != 0); |
| 180 | } | 217 | } |
| 181 | } | 218 | } |
| 182 | 219 | ||
| @@ -191,7 +228,7 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) | @@ -191,7 +228,7 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) | ||
| 191 | int tmp; | 228 | int tmp; |
| 192 | 229 | ||
| 193 | offset = s->pc; | 230 | offset = s->pc; |
| 194 | - ext = lduw(s->pc); | 231 | + ext = lduw_code(s->pc); |
| 195 | s->pc += 2; | 232 | s->pc += 2; |
| 196 | tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); | 233 | tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); |
| 197 | /* ??? Check W/L bit. */ | 234 | /* ??? Check W/L bit. */ |
| @@ -216,9 +253,9 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) | @@ -216,9 +253,9 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) | ||
| 216 | static inline uint32_t read_im32(DisasContext *s) | 253 | static inline uint32_t read_im32(DisasContext *s) |
| 217 | { | 254 | { |
| 218 | uint32_t im; | 255 | uint32_t im; |
| 219 | - im = ((uint32_t)lduw(s->pc)) << 16; | 256 | + im = ((uint32_t)lduw_code(s->pc)) << 16; |
| 220 | s->pc += 2; | 257 | s->pc += 2; |
| 221 | - im |= lduw(s->pc); | 258 | + im |= lduw_code(s->pc); |
| 222 | s->pc += 2; | 259 | s->pc += 2; |
| 223 | return im; | 260 | return im; |
| 224 | } | 261 | } |
| @@ -343,7 +380,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | @@ -343,7 +380,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | ||
| 343 | case 5: /* Indirect displacement. */ | 380 | case 5: /* Indirect displacement. */ |
| 344 | reg += QREG_A0; | 381 | reg += QREG_A0; |
| 345 | tmp = gen_new_qreg(QMODE_I32); | 382 | tmp = gen_new_qreg(QMODE_I32); |
| 346 | - ext = lduw(s->pc); | 383 | + ext = lduw_code(s->pc); |
| 347 | s->pc += 2; | 384 | s->pc += 2; |
| 348 | gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); | 385 | gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); |
| 349 | return tmp; | 386 | return tmp; |
| @@ -353,7 +390,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | @@ -353,7 +390,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | ||
| 353 | case 7: /* Other */ | 390 | case 7: /* Other */ |
| 354 | switch (reg) { | 391 | switch (reg) { |
| 355 | case 0: /* Absolute short. */ | 392 | case 0: /* Absolute short. */ |
| 356 | - offset = ldsw(s->pc); | 393 | + offset = ldsw_code(s->pc); |
| 357 | s->pc += 2; | 394 | s->pc += 2; |
| 358 | return gen_im32(offset); | 395 | return gen_im32(offset); |
| 359 | case 1: /* Absolute long. */ | 396 | case 1: /* Absolute long. */ |
| @@ -362,7 +399,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | @@ -362,7 +399,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) | ||
| 362 | case 2: /* pc displacement */ | 399 | case 2: /* pc displacement */ |
| 363 | tmp = gen_new_qreg(QMODE_I32); | 400 | tmp = gen_new_qreg(QMODE_I32); |
| 364 | offset = s->pc; | 401 | offset = s->pc; |
| 365 | - offset += ldsw(s->pc); | 402 | + offset += ldsw_code(s->pc); |
| 366 | s->pc += 2; | 403 | s->pc += 2; |
| 367 | return gen_im32(offset); | 404 | return gen_im32(offset); |
| 368 | case 3: /* pc index+displacement. */ | 405 | case 3: /* pc index+displacement. */ |
| @@ -391,7 +428,7 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, | @@ -391,7 +428,7 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, | ||
| 391 | if (addrp) | 428 | if (addrp) |
| 392 | *addrp = tmp; | 429 | *addrp = tmp; |
| 393 | } | 430 | } |
| 394 | - return gen_ldst(opsize, tmp, val); | 431 | + return gen_ldst(s, opsize, tmp, val); |
| 395 | } | 432 | } |
| 396 | 433 | ||
| 397 | /* Generate code to load/store a value ito/from an EA. If VAL > 0 this is | 434 | /* 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, | @@ -424,10 +461,10 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, | ||
| 424 | } | 461 | } |
| 425 | case 2: /* Indirect register */ | 462 | case 2: /* Indirect register */ |
| 426 | reg += QREG_A0; | 463 | reg += QREG_A0; |
| 427 | - return gen_ldst(opsize, reg, val); | 464 | + return gen_ldst(s, opsize, reg, val); |
| 428 | case 3: /* Indirect postincrement. */ | 465 | case 3: /* Indirect postincrement. */ |
| 429 | reg += QREG_A0; | 466 | reg += QREG_A0; |
| 430 | - result = gen_ldst(opsize, reg, val); | 467 | + result = gen_ldst(s, opsize, reg, val); |
| 431 | /* ??? This is not exception safe. The instruction may still | 468 | /* ??? This is not exception safe. The instruction may still |
| 432 | fault after this point. */ | 469 | fault after this point. */ |
| 433 | if (val > 0 || !addrp) | 470 | if (val > 0 || !addrp) |
| @@ -443,7 +480,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, | @@ -443,7 +480,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, | ||
| 443 | if (addrp) | 480 | if (addrp) |
| 444 | *addrp = tmp; | 481 | *addrp = tmp; |
| 445 | } | 482 | } |
| 446 | - result = gen_ldst(opsize, tmp, val); | 483 | + result = gen_ldst(s, opsize, tmp, val); |
| 447 | /* ??? This is not exception safe. The instruction may still | 484 | /* ??? This is not exception safe. The instruction may still |
| 448 | fault after this point. */ | 485 | fault after this point. */ |
| 449 | if (val > 0 || !addrp) { | 486 | if (val > 0 || !addrp) { |
| @@ -467,16 +504,16 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, | @@ -467,16 +504,16 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, | ||
| 467 | switch (opsize) { | 504 | switch (opsize) { |
| 468 | case OS_BYTE: | 505 | case OS_BYTE: |
| 469 | if (val) | 506 | if (val) |
| 470 | - offset = ldsb(s->pc + 1); | 507 | + offset = ldsb_code(s->pc + 1); |
| 471 | else | 508 | else |
| 472 | - offset = ldub(s->pc + 1); | 509 | + offset = ldub_code(s->pc + 1); |
| 473 | s->pc += 2; | 510 | s->pc += 2; |
| 474 | break; | 511 | break; |
| 475 | case OS_WORD: | 512 | case OS_WORD: |
| 476 | if (val) | 513 | if (val) |
| 477 | - offset = ldsw(s->pc); | 514 | + offset = ldsw_code(s->pc); |
| 478 | else | 515 | else |
| 479 | - offset = lduw(s->pc); | 516 | + offset = lduw_code(s->pc); |
| 480 | s->pc += 2; | 517 | s->pc += 2; |
| 481 | break; | 518 | break; |
| 482 | case OS_LONG: | 519 | case OS_LONG: |
| @@ -622,6 +659,14 @@ DISAS_INSN(scc) | @@ -622,6 +659,14 @@ DISAS_INSN(scc) | ||
| 622 | gen_set_label(l1); | 659 | gen_set_label(l1); |
| 623 | } | 660 | } |
| 624 | 661 | ||
| 662 | +/* Force a TB lookup after an instruction that changes the CPU state. */ | ||
| 663 | +static void gen_lookup_tb(DisasContext *s) | ||
| 664 | +{ | ||
| 665 | + gen_flush_cc_op(s); | ||
| 666 | + gen_op_mov32(QREG_PC, gen_im32(s->pc)); | ||
| 667 | + s->is_jmp = DISAS_UPDATE; | ||
| 668 | +} | ||
| 669 | + | ||
| 625 | /* Generate a jump to to the address in qreg DEST. */ | 670 | /* Generate a jump to to the address in qreg DEST. */ |
| 626 | static void gen_jmp(DisasContext *s, int dest) | 671 | static void gen_jmp(DisasContext *s, int dest) |
| 627 | { | 672 | { |
| @@ -735,7 +780,7 @@ DISAS_INSN(divl) | @@ -735,7 +780,7 @@ DISAS_INSN(divl) | ||
| 735 | int reg; | 780 | int reg; |
| 736 | uint16_t ext; | 781 | uint16_t ext; |
| 737 | 782 | ||
| 738 | - ext = lduw(s->pc); | 783 | + ext = lduw_code(s->pc); |
| 739 | s->pc += 2; | 784 | s->pc += 2; |
| 740 | if (ext & 0x87f8) { | 785 | if (ext & 0x87f8) { |
| 741 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); | 786 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); |
| @@ -903,13 +948,13 @@ DISAS_INSN(sats) | @@ -903,13 +948,13 @@ DISAS_INSN(sats) | ||
| 903 | gen_logic_cc(s, tmp); | 948 | gen_logic_cc(s, tmp); |
| 904 | } | 949 | } |
| 905 | 950 | ||
| 906 | -static void gen_push(int val) | 951 | +static void gen_push(DisasContext *s, int val) |
| 907 | { | 952 | { |
| 908 | int tmp; | 953 | int tmp; |
| 909 | 954 | ||
| 910 | tmp = gen_new_qreg(QMODE_I32); | 955 | tmp = gen_new_qreg(QMODE_I32); |
| 911 | gen_op_sub32(tmp, QREG_SP, gen_im32(4)); | 956 | gen_op_sub32(tmp, QREG_SP, gen_im32(4)); |
| 912 | - gen_store(OS_LONG, tmp, val); | 957 | + gen_store(s, OS_LONG, tmp, val); |
| 913 | gen_op_mov32(QREG_SP, tmp); | 958 | gen_op_mov32(QREG_SP, tmp); |
| 914 | } | 959 | } |
| 915 | 960 | ||
| @@ -922,7 +967,7 @@ DISAS_INSN(movem) | @@ -922,7 +967,7 @@ DISAS_INSN(movem) | ||
| 922 | int tmp; | 967 | int tmp; |
| 923 | int is_load; | 968 | int is_load; |
| 924 | 969 | ||
| 925 | - mask = lduw(s->pc); | 970 | + mask = lduw_code(s->pc); |
| 926 | s->pc += 2; | 971 | s->pc += 2; |
| 927 | tmp = gen_lea(s, insn, OS_LONG); | 972 | tmp = gen_lea(s, insn, OS_LONG); |
| 928 | addr = gen_new_qreg(QMODE_I32); | 973 | addr = gen_new_qreg(QMODE_I32); |
| @@ -935,10 +980,10 @@ DISAS_INSN(movem) | @@ -935,10 +980,10 @@ DISAS_INSN(movem) | ||
| 935 | else | 980 | else |
| 936 | reg = AREG(i, 0); | 981 | reg = AREG(i, 0); |
| 937 | if (is_load) { | 982 | if (is_load) { |
| 938 | - tmp = gen_load(OS_LONG, addr, 0); | 983 | + tmp = gen_load(s, OS_LONG, addr, 0); |
| 939 | gen_op_mov32(reg, tmp); | 984 | gen_op_mov32(reg, tmp); |
| 940 | } else { | 985 | } else { |
| 941 | - gen_store(OS_LONG, addr, reg); | 986 | + gen_store(s, OS_LONG, addr, reg); |
| 942 | } | 987 | } |
| 943 | if (mask != 1) | 988 | if (mask != 1) |
| 944 | gen_op_add32(addr, addr, gen_im32(4)); | 989 | gen_op_add32(addr, addr, gen_im32(4)); |
| @@ -963,7 +1008,7 @@ DISAS_INSN(bitop_im) | @@ -963,7 +1008,7 @@ DISAS_INSN(bitop_im) | ||
| 963 | opsize = OS_LONG; | 1008 | opsize = OS_LONG; |
| 964 | op = (insn >> 6) & 3; | 1009 | op = (insn >> 6) & 3; |
| 965 | 1010 | ||
| 966 | - bitnum = lduw(s->pc); | 1011 | + bitnum = lduw_code(s->pc); |
| 967 | s->pc += 2; | 1012 | s->pc += 2; |
| 968 | if (bitnum & 0xff00) { | 1013 | if (bitnum & 0xff00) { |
| 969 | disas_undef(s, insn); | 1014 | disas_undef(s, insn); |
| @@ -1155,9 +1200,8 @@ DISAS_INSN(clr) | @@ -1155,9 +1200,8 @@ DISAS_INSN(clr) | ||
| 1155 | gen_logic_cc(s, gen_im32(0)); | 1200 | gen_logic_cc(s, gen_im32(0)); |
| 1156 | } | 1201 | } |
| 1157 | 1202 | ||
| 1158 | -DISAS_INSN(move_from_ccr) | 1203 | +static int gen_get_ccr(DisasContext *s) |
| 1159 | { | 1204 | { |
| 1160 | - int reg; | ||
| 1161 | int dest; | 1205 | int dest; |
| 1162 | 1206 | ||
| 1163 | gen_flush_flags(s); | 1207 | gen_flush_flags(s); |
| @@ -1165,8 +1209,17 @@ DISAS_INSN(move_from_ccr) | @@ -1165,8 +1209,17 @@ DISAS_INSN(move_from_ccr) | ||
| 1165 | gen_op_get_xflag(dest); | 1209 | gen_op_get_xflag(dest); |
| 1166 | gen_op_shl32(dest, dest, gen_im32(4)); | 1210 | gen_op_shl32(dest, dest, gen_im32(4)); |
| 1167 | gen_op_or32(dest, dest, QREG_CC_DEST); | 1211 | gen_op_or32(dest, dest, QREG_CC_DEST); |
| 1212 | + return dest; | ||
| 1213 | +} | ||
| 1214 | + | ||
| 1215 | +DISAS_INSN(move_from_ccr) | ||
| 1216 | +{ | ||
| 1217 | + int reg; | ||
| 1218 | + int ccr; | ||
| 1219 | + | ||
| 1220 | + ccr = gen_get_ccr(s); | ||
| 1168 | reg = DREG(insn, 0); | 1221 | reg = DREG(insn, 0); |
| 1169 | - gen_partset_reg(OS_WORD, reg, dest); | 1222 | + gen_partset_reg(OS_WORD, reg, ccr); |
| 1170 | } | 1223 | } |
| 1171 | 1224 | ||
| 1172 | DISAS_INSN(neg) | 1225 | DISAS_INSN(neg) |
| @@ -1184,7 +1237,16 @@ DISAS_INSN(neg) | @@ -1184,7 +1237,16 @@ DISAS_INSN(neg) | ||
| 1184 | s->cc_op = CC_OP_SUB; | 1237 | s->cc_op = CC_OP_SUB; |
| 1185 | } | 1238 | } |
| 1186 | 1239 | ||
| 1187 | -DISAS_INSN(move_to_ccr) | 1240 | +static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) |
| 1241 | +{ | ||
| 1242 | + gen_op_logic_cc(gen_im32(val & 0xf)); | ||
| 1243 | + gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); | ||
| 1244 | + if (!ccr_only) { | ||
| 1245 | + gen_op_mov32(QREG_SR, gen_im32(val & 0xff00)); | ||
| 1246 | + } | ||
| 1247 | +} | ||
| 1248 | + | ||
| 1249 | +static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) | ||
| 1188 | { | 1250 | { |
| 1189 | int src1; | 1251 | int src1; |
| 1190 | int reg; | 1252 | int reg; |
| @@ -1199,19 +1261,26 @@ DISAS_INSN(move_to_ccr) | @@ -1199,19 +1261,26 @@ DISAS_INSN(move_to_ccr) | ||
| 1199 | gen_op_shr32(src1, reg, gen_im32(4)); | 1261 | gen_op_shr32(src1, reg, gen_im32(4)); |
| 1200 | gen_op_and32(src1, src1, gen_im32(1)); | 1262 | gen_op_and32(src1, src1, gen_im32(1)); |
| 1201 | gen_op_update_xflag_tst(src1); | 1263 | gen_op_update_xflag_tst(src1); |
| 1264 | + if (!ccr_only) { | ||
| 1265 | + gen_op_and32(QREG_SR, reg, gen_im32(0xff00)); | ||
| 1266 | + } | ||
| 1202 | } | 1267 | } |
| 1203 | - else if ((insn & 0x3f) != 0x3c) | 1268 | + else if ((insn & 0x3f) == 0x3c) |
| 1204 | { | 1269 | { |
| 1205 | - uint8_t val; | ||
| 1206 | - val = ldsb(s->pc); | 1270 | + uint16_t val; |
| 1271 | + val = lduw_code(s->pc); | ||
| 1207 | s->pc += 2; | 1272 | s->pc += 2; |
| 1208 | - gen_op_logic_cc(gen_im32(val & 0xf)); | ||
| 1209 | - gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); | 1273 | + gen_set_sr_im(s, val, ccr_only); |
| 1210 | } | 1274 | } |
| 1211 | else | 1275 | else |
| 1212 | disas_undef(s, insn); | 1276 | disas_undef(s, insn); |
| 1213 | } | 1277 | } |
| 1214 | 1278 | ||
| 1279 | +DISAS_INSN(move_to_ccr) | ||
| 1280 | +{ | ||
| 1281 | + gen_set_sr(s, insn, 1); | ||
| 1282 | +} | ||
| 1283 | + | ||
| 1215 | DISAS_INSN(not) | 1284 | DISAS_INSN(not) |
| 1216 | { | 1285 | { |
| 1217 | int reg; | 1286 | int reg; |
| @@ -1244,7 +1313,7 @@ DISAS_INSN(pea) | @@ -1244,7 +1313,7 @@ DISAS_INSN(pea) | ||
| 1244 | int tmp; | 1313 | int tmp; |
| 1245 | 1314 | ||
| 1246 | tmp = gen_lea(s, insn, OS_LONG); | 1315 | tmp = gen_lea(s, insn, OS_LONG); |
| 1247 | - gen_push(tmp); | 1316 | + gen_push(s, tmp); |
| 1248 | } | 1317 | } |
| 1249 | 1318 | ||
| 1250 | DISAS_INSN(ext) | 1319 | DISAS_INSN(ext) |
| @@ -1322,7 +1391,7 @@ DISAS_INSN(mull) | @@ -1322,7 +1391,7 @@ DISAS_INSN(mull) | ||
| 1322 | 1391 | ||
| 1323 | /* The upper 32 bits of the product are discarded, so | 1392 | /* The upper 32 bits of the product are discarded, so |
| 1324 | muls.l and mulu.l are functionally equivalent. */ | 1393 | muls.l and mulu.l are functionally equivalent. */ |
| 1325 | - ext = lduw(s->pc); | 1394 | + ext = lduw_code(s->pc); |
| 1326 | s->pc += 2; | 1395 | s->pc += 2; |
| 1327 | if (ext & 0x87ff) { | 1396 | if (ext & 0x87ff) { |
| 1328 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); | 1397 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); |
| @@ -1343,12 +1412,12 @@ DISAS_INSN(link) | @@ -1343,12 +1412,12 @@ DISAS_INSN(link) | ||
| 1343 | int reg; | 1412 | int reg; |
| 1344 | int tmp; | 1413 | int tmp; |
| 1345 | 1414 | ||
| 1346 | - offset = ldsw(s->pc); | 1415 | + offset = ldsw_code(s->pc); |
| 1347 | s->pc += 2; | 1416 | s->pc += 2; |
| 1348 | reg = AREG(insn, 0); | 1417 | reg = AREG(insn, 0); |
| 1349 | tmp = gen_new_qreg(QMODE_I32); | 1418 | tmp = gen_new_qreg(QMODE_I32); |
| 1350 | gen_op_sub32(tmp, QREG_SP, gen_im32(4)); | 1419 | gen_op_sub32(tmp, QREG_SP, gen_im32(4)); |
| 1351 | - gen_store(OS_LONG, tmp, reg); | 1420 | + gen_store(s, OS_LONG, tmp, reg); |
| 1352 | if (reg != QREG_SP) | 1421 | if (reg != QREG_SP) |
| 1353 | gen_op_mov32(reg, tmp); | 1422 | gen_op_mov32(reg, tmp); |
| 1354 | gen_op_add32(QREG_SP, tmp, gen_im32(offset)); | 1423 | gen_op_add32(QREG_SP, tmp, gen_im32(offset)); |
| @@ -1363,7 +1432,7 @@ DISAS_INSN(unlk) | @@ -1363,7 +1432,7 @@ DISAS_INSN(unlk) | ||
| 1363 | src = gen_new_qreg(QMODE_I32); | 1432 | src = gen_new_qreg(QMODE_I32); |
| 1364 | reg = AREG(insn, 0); | 1433 | reg = AREG(insn, 0); |
| 1365 | gen_op_mov32(src, reg); | 1434 | gen_op_mov32(src, reg); |
| 1366 | - tmp = gen_load(OS_LONG, src, 0); | 1435 | + tmp = gen_load(s, OS_LONG, src, 0); |
| 1367 | gen_op_mov32(reg, tmp); | 1436 | gen_op_mov32(reg, tmp); |
| 1368 | gen_op_add32(QREG_SP, src, gen_im32(4)); | 1437 | gen_op_add32(QREG_SP, src, gen_im32(4)); |
| 1369 | } | 1438 | } |
| @@ -1376,7 +1445,7 @@ DISAS_INSN(rts) | @@ -1376,7 +1445,7 @@ DISAS_INSN(rts) | ||
| 1376 | { | 1445 | { |
| 1377 | int tmp; | 1446 | int tmp; |
| 1378 | 1447 | ||
| 1379 | - tmp = gen_load(OS_LONG, QREG_SP, 0); | 1448 | + tmp = gen_load(s, OS_LONG, QREG_SP, 0); |
| 1380 | gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); | 1449 | gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); |
| 1381 | gen_jmp(s, tmp); | 1450 | gen_jmp(s, tmp); |
| 1382 | } | 1451 | } |
| @@ -1390,7 +1459,7 @@ DISAS_INSN(jump) | @@ -1390,7 +1459,7 @@ DISAS_INSN(jump) | ||
| 1390 | tmp = gen_lea(s, insn, OS_LONG); | 1459 | tmp = gen_lea(s, insn, OS_LONG); |
| 1391 | if ((insn & 0x40) == 0) { | 1460 | if ((insn & 0x40) == 0) { |
| 1392 | /* jsr */ | 1461 | /* jsr */ |
| 1393 | - gen_push(gen_im32(s->pc)); | 1462 | + gen_push(s, gen_im32(s->pc)); |
| 1394 | } | 1463 | } |
| 1395 | gen_jmp(s, tmp); | 1464 | gen_jmp(s, tmp); |
| 1396 | } | 1465 | } |
| @@ -1460,14 +1529,14 @@ DISAS_INSN(branch) | @@ -1460,14 +1529,14 @@ DISAS_INSN(branch) | ||
| 1460 | op = (insn >> 8) & 0xf; | 1529 | op = (insn >> 8) & 0xf; |
| 1461 | offset = (int8_t)insn; | 1530 | offset = (int8_t)insn; |
| 1462 | if (offset == 0) { | 1531 | if (offset == 0) { |
| 1463 | - offset = ldsw(s->pc); | 1532 | + offset = ldsw_code(s->pc); |
| 1464 | s->pc += 2; | 1533 | s->pc += 2; |
| 1465 | } else if (offset == -1) { | 1534 | } else if (offset == -1) { |
| 1466 | offset = read_im32(s); | 1535 | offset = read_im32(s); |
| 1467 | } | 1536 | } |
| 1468 | if (op == 1) { | 1537 | if (op == 1) { |
| 1469 | /* bsr */ | 1538 | /* bsr */ |
| 1470 | - gen_push(gen_im32(s->pc)); | 1539 | + gen_push(s, gen_im32(s->pc)); |
| 1471 | } | 1540 | } |
| 1472 | gen_flush_cc_op(s); | 1541 | gen_flush_cc_op(s); |
| 1473 | if (op > 1) { | 1542 | if (op > 1) { |
| @@ -1752,68 +1821,154 @@ DISAS_INSN(ff1) | @@ -1752,68 +1821,154 @@ DISAS_INSN(ff1) | ||
| 1752 | cpu_abort(NULL, "Unimplemented insn: ff1"); | 1821 | cpu_abort(NULL, "Unimplemented insn: ff1"); |
| 1753 | } | 1822 | } |
| 1754 | 1823 | ||
| 1824 | +static int gen_get_sr(DisasContext *s) | ||
| 1825 | +{ | ||
| 1826 | + int ccr; | ||
| 1827 | + int sr; | ||
| 1828 | + | ||
| 1829 | + ccr = gen_get_ccr(s); | ||
| 1830 | + sr = gen_new_qreg(QMODE_I32); | ||
| 1831 | + gen_op_and32(sr, QREG_SR, gen_im32(0xffe0)); | ||
| 1832 | + gen_op_or32(sr, sr, ccr); | ||
| 1833 | + return sr; | ||
| 1834 | +} | ||
| 1835 | + | ||
| 1755 | DISAS_INSN(strldsr) | 1836 | DISAS_INSN(strldsr) |
| 1756 | { | 1837 | { |
| 1757 | uint16_t ext; | 1838 | uint16_t ext; |
| 1758 | uint32_t addr; | 1839 | uint32_t addr; |
| 1759 | 1840 | ||
| 1760 | addr = s->pc - 2; | 1841 | addr = s->pc - 2; |
| 1761 | - ext = lduw(s->pc); | 1842 | + ext = lduw_code(s->pc); |
| 1762 | s->pc += 2; | 1843 | s->pc += 2; |
| 1763 | - if (ext != 0x46FC) | 1844 | + if (ext != 0x46FC) { |
| 1764 | gen_exception(s, addr, EXCP_UNSUPPORTED); | 1845 | gen_exception(s, addr, EXCP_UNSUPPORTED); |
| 1765 | - else | 1846 | + return; |
| 1847 | + } | ||
| 1848 | + ext = lduw_code(s->pc); | ||
| 1849 | + s->pc += 2; | ||
| 1850 | + if (IS_USER(s) || (ext & SR_S) == 0) { | ||
| 1766 | gen_exception(s, addr, EXCP_PRIVILEGE); | 1851 | gen_exception(s, addr, EXCP_PRIVILEGE); |
| 1852 | + return; | ||
| 1853 | + } | ||
| 1854 | + gen_push(s, gen_get_sr(s)); | ||
| 1855 | + gen_set_sr_im(s, ext, 0); | ||
| 1767 | } | 1856 | } |
| 1768 | 1857 | ||
| 1769 | DISAS_INSN(move_from_sr) | 1858 | DISAS_INSN(move_from_sr) |
| 1770 | { | 1859 | { |
| 1771 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1860 | + int reg; |
| 1861 | + int sr; | ||
| 1862 | + | ||
| 1863 | + if (IS_USER(s)) { | ||
| 1864 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1865 | + return; | ||
| 1866 | + } | ||
| 1867 | + sr = gen_get_sr(s); | ||
| 1868 | + reg = DREG(insn, 0); | ||
| 1869 | + gen_partset_reg(OS_WORD, reg, sr); | ||
| 1772 | } | 1870 | } |
| 1773 | 1871 | ||
| 1774 | DISAS_INSN(move_to_sr) | 1872 | DISAS_INSN(move_to_sr) |
| 1775 | { | 1873 | { |
| 1776 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1874 | + if (IS_USER(s)) { |
| 1875 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1876 | + return; | ||
| 1877 | + } | ||
| 1878 | + gen_set_sr(s, insn, 0); | ||
| 1879 | + gen_lookup_tb(s); | ||
| 1777 | } | 1880 | } |
| 1778 | 1881 | ||
| 1779 | DISAS_INSN(move_from_usp) | 1882 | DISAS_INSN(move_from_usp) |
| 1780 | { | 1883 | { |
| 1781 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1884 | + if (IS_USER(s)) { |
| 1885 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1886 | + return; | ||
| 1887 | + } | ||
| 1888 | + /* TODO: Implement USP. */ | ||
| 1889 | + gen_exception(s, s->pc - 2, EXCP_ILLEGAL); | ||
| 1782 | } | 1890 | } |
| 1783 | 1891 | ||
| 1784 | DISAS_INSN(move_to_usp) | 1892 | DISAS_INSN(move_to_usp) |
| 1785 | { | 1893 | { |
| 1786 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1894 | + if (IS_USER(s)) { |
| 1895 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1896 | + return; | ||
| 1897 | + } | ||
| 1898 | + /* TODO: Implement USP. */ | ||
| 1899 | + gen_exception(s, s->pc - 2, EXCP_ILLEGAL); | ||
| 1787 | } | 1900 | } |
| 1788 | 1901 | ||
| 1789 | DISAS_INSN(halt) | 1902 | DISAS_INSN(halt) |
| 1790 | { | 1903 | { |
| 1791 | - gen_exception(s, s->pc, EXCP_HLT); | 1904 | + gen_flush_cc_op(s); |
| 1905 | + gen_jmp(s, gen_im32(s->pc)); | ||
| 1906 | + gen_op_halt(); | ||
| 1792 | } | 1907 | } |
| 1793 | 1908 | ||
| 1794 | DISAS_INSN(stop) | 1909 | DISAS_INSN(stop) |
| 1795 | { | 1910 | { |
| 1796 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1911 | + uint16_t ext; |
| 1912 | + | ||
| 1913 | + if (IS_USER(s)) { | ||
| 1914 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1915 | + return; | ||
| 1916 | + } | ||
| 1917 | + | ||
| 1918 | + ext = lduw_code(s->pc); | ||
| 1919 | + s->pc += 2; | ||
| 1920 | + | ||
| 1921 | + gen_set_sr_im(s, ext, 0); | ||
| 1922 | + disas_halt(s, insn); | ||
| 1797 | } | 1923 | } |
| 1798 | 1924 | ||
| 1799 | DISAS_INSN(rte) | 1925 | DISAS_INSN(rte) |
| 1800 | { | 1926 | { |
| 1801 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1927 | + if (IS_USER(s)) { |
| 1928 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1929 | + return; | ||
| 1930 | + } | ||
| 1931 | + gen_exception(s, s->pc - 2, EXCP_RTE); | ||
| 1802 | } | 1932 | } |
| 1803 | 1933 | ||
| 1804 | DISAS_INSN(movec) | 1934 | DISAS_INSN(movec) |
| 1805 | { | 1935 | { |
| 1806 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1936 | + uint16_t ext; |
| 1937 | + int reg; | ||
| 1938 | + | ||
| 1939 | + if (IS_USER(s)) { | ||
| 1940 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1941 | + return; | ||
| 1942 | + } | ||
| 1943 | + | ||
| 1944 | + ext = lduw_code(s->pc); | ||
| 1945 | + s->pc += 2; | ||
| 1946 | + | ||
| 1947 | + if (ext & 0x8000) { | ||
| 1948 | + reg = AREG(ext, 12); | ||
| 1949 | + } else { | ||
| 1950 | + reg = DREG(ext, 12); | ||
| 1951 | + } | ||
| 1952 | + gen_op_movec(gen_im32(ext & 0xfff), reg); | ||
| 1953 | + gen_lookup_tb(s); | ||
| 1807 | } | 1954 | } |
| 1808 | 1955 | ||
| 1809 | DISAS_INSN(intouch) | 1956 | DISAS_INSN(intouch) |
| 1810 | { | 1957 | { |
| 1811 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1958 | + if (IS_USER(s)) { |
| 1959 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1960 | + return; | ||
| 1961 | + } | ||
| 1962 | + /* ICache fetch. Implement as no-op. */ | ||
| 1812 | } | 1963 | } |
| 1813 | 1964 | ||
| 1814 | DISAS_INSN(cpushl) | 1965 | DISAS_INSN(cpushl) |
| 1815 | { | 1966 | { |
| 1816 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1967 | + if (IS_USER(s)) { |
| 1968 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1969 | + return; | ||
| 1970 | + } | ||
| 1971 | + /* Cache push/invalidate. Implement as no-op. */ | ||
| 1817 | } | 1972 | } |
| 1818 | 1973 | ||
| 1819 | DISAS_INSN(wddata) | 1974 | DISAS_INSN(wddata) |
| @@ -1823,7 +1978,12 @@ DISAS_INSN(wddata) | @@ -1823,7 +1978,12 @@ DISAS_INSN(wddata) | ||
| 1823 | 1978 | ||
| 1824 | DISAS_INSN(wdebug) | 1979 | DISAS_INSN(wdebug) |
| 1825 | { | 1980 | { |
| 1826 | - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | 1981 | + if (IS_USER(s)) { |
| 1982 | + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); | ||
| 1983 | + return; | ||
| 1984 | + } | ||
| 1985 | + /* TODO: Implement wdebug. */ | ||
| 1986 | + qemu_assert(0, "WDEBUG not implemented"); | ||
| 1827 | } | 1987 | } |
| 1828 | 1988 | ||
| 1829 | DISAS_INSN(trap) | 1989 | DISAS_INSN(trap) |
| @@ -1843,7 +2003,7 @@ DISAS_INSN(fpu) | @@ -1843,7 +2003,7 @@ DISAS_INSN(fpu) | ||
| 1843 | int round; | 2003 | int round; |
| 1844 | int opsize; | 2004 | int opsize; |
| 1845 | 2005 | ||
| 1846 | - ext = lduw(s->pc); | 2006 | + ext = lduw_code(s->pc); |
| 1847 | s->pc += 2; | 2007 | s->pc += 2; |
| 1848 | opmode = ext & 0x7f; | 2008 | opmode = ext & 0x7f; |
| 1849 | switch ((ext >> 13) & 7) { | 2009 | switch ((ext >> 13) & 7) { |
| @@ -1928,10 +2088,10 @@ DISAS_INSN(fpu) | @@ -1928,10 +2088,10 @@ DISAS_INSN(fpu) | ||
| 1928 | if (ext & mask) { | 2088 | if (ext & mask) { |
| 1929 | if (ext & (1 << 13)) { | 2089 | if (ext & (1 << 13)) { |
| 1930 | /* store */ | 2090 | /* store */ |
| 1931 | - gen_op_stf64(addr, dest); | 2091 | + gen_st(s, f64, addr, dest); |
| 1932 | } else { | 2092 | } else { |
| 1933 | /* load */ | 2093 | /* load */ |
| 1934 | - gen_op_ldf64(dest, addr); | 2094 | + gen_ld(s, f64, dest, addr); |
| 1935 | } | 2095 | } |
| 1936 | if (ext & (mask - 1)) | 2096 | if (ext & (mask - 1)) |
| 1937 | gen_op_add32(addr, addr, gen_im32(8)); | 2097 | gen_op_add32(addr, addr, gen_im32(8)); |
| @@ -2060,10 +2220,10 @@ DISAS_INSN(fbcc) | @@ -2060,10 +2220,10 @@ DISAS_INSN(fbcc) | ||
| 2060 | int l1; | 2220 | int l1; |
| 2061 | 2221 | ||
| 2062 | addr = s->pc; | 2222 | addr = s->pc; |
| 2063 | - offset = ldsw(s->pc); | 2223 | + offset = ldsw_code(s->pc); |
| 2064 | s->pc += 2; | 2224 | s->pc += 2; |
| 2065 | if (insn & (1 << 6)) { | 2225 | if (insn & (1 << 6)) { |
| 2066 | - offset = (offset << 16) | lduw(s->pc); | 2226 | + offset = (offset << 16) | lduw_code(s->pc); |
| 2067 | s->pc += 2; | 2227 | s->pc += 2; |
| 2068 | } | 2228 | } |
| 2069 | 2229 | ||
| @@ -2143,6 +2303,18 @@ DISAS_INSN(fbcc) | @@ -2143,6 +2303,18 @@ DISAS_INSN(fbcc) | ||
| 2143 | gen_jmp_tb(s, 1, addr + offset); | 2303 | gen_jmp_tb(s, 1, addr + offset); |
| 2144 | } | 2304 | } |
| 2145 | 2305 | ||
| 2306 | +DISAS_INSN(frestore) | ||
| 2307 | +{ | ||
| 2308 | + /* TODO: Implement frestore. */ | ||
| 2309 | + qemu_assert(0, "FRESTORE not implemented"); | ||
| 2310 | +} | ||
| 2311 | + | ||
| 2312 | +DISAS_INSN(fsave) | ||
| 2313 | +{ | ||
| 2314 | + /* TODO: Implement fsave. */ | ||
| 2315 | + qemu_assert(0, "FSAVE not implemented"); | ||
| 2316 | +} | ||
| 2317 | + | ||
| 2146 | static disas_proc opcode_table[65536]; | 2318 | static disas_proc opcode_table[65536]; |
| 2147 | 2319 | ||
| 2148 | static void | 2320 | static void |
| @@ -2168,11 +2340,10 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) | @@ -2168,11 +2340,10 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) | ||
| 2168 | i <<= 1; | 2340 | i <<= 1; |
| 2169 | from = opcode & ~(i - 1); | 2341 | from = opcode & ~(i - 1); |
| 2170 | to = from + i; | 2342 | to = from + i; |
| 2171 | - for (i = from; i < to; i++) | ||
| 2172 | - { | 2343 | + for (i = from; i < to; i++) { |
| 2173 | if ((i & mask) == opcode) | 2344 | if ((i & mask) == opcode) |
| 2174 | opcode_table[i] = proc; | 2345 | opcode_table[i] = proc; |
| 2175 | - } | 2346 | + } |
| 2176 | } | 2347 | } |
| 2177 | 2348 | ||
| 2178 | /* Register m68k opcode handlers. Order is important. | 2349 | /* Register m68k opcode handlers. Order is important. |
| @@ -2274,6 +2445,8 @@ register_m68k_insns (m68k_def_t *def) | @@ -2274,6 +2445,8 @@ register_m68k_insns (m68k_def_t *def) | ||
| 2274 | INSN(undef_fpu, f000, f000, CF_A); | 2445 | INSN(undef_fpu, f000, f000, CF_A); |
| 2275 | INSN(fpu, f200, ffc0, CF_FPU); | 2446 | INSN(fpu, f200, ffc0, CF_FPU); |
| 2276 | INSN(fbcc, f280, ffc0, CF_FPU); | 2447 | INSN(fbcc, f280, ffc0, CF_FPU); |
| 2448 | + INSN(frestore, f340, ffc0, CF_FPU); | ||
| 2449 | + INSN(fsave, f340, ffc0, CF_FPU); | ||
| 2277 | INSN(intouch, f340, ffc0, CF_A); | 2450 | INSN(intouch, f340, ffc0, CF_A); |
| 2278 | INSN(cpushl, f428, ff38, CF_A); | 2451 | INSN(cpushl, f428, ff38, CF_A); |
| 2279 | INSN(wddata, fb00, ff00, CF_A); | 2452 | INSN(wddata, fb00, ff00, CF_A); |
| @@ -2287,7 +2460,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s) | @@ -2287,7 +2460,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s) | ||
| 2287 | { | 2460 | { |
| 2288 | uint16_t insn; | 2461 | uint16_t insn; |
| 2289 | 2462 | ||
| 2290 | - insn = lduw(s->pc); | 2463 | + insn = lduw_code(s->pc); |
| 2291 | s->pc += 2; | 2464 | s->pc += 2; |
| 2292 | 2465 | ||
| 2293 | opcode_table[insn](s, insn); | 2466 | opcode_table[insn](s, insn); |
| @@ -2576,6 +2749,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2576,6 +2749,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2576 | dc->cc_op = CC_OP_DYNAMIC; | 2749 | dc->cc_op = CC_OP_DYNAMIC; |
| 2577 | dc->singlestep_enabled = env->singlestep_enabled; | 2750 | dc->singlestep_enabled = env->singlestep_enabled; |
| 2578 | dc->fpcr = env->fpcr; | 2751 | dc->fpcr = env->fpcr; |
| 2752 | + dc->user = (env->sr & SR_S) == 0; | ||
| 2579 | nb_gen_labels = 0; | 2753 | nb_gen_labels = 0; |
| 2580 | lj = -1; | 2754 | lj = -1; |
| 2581 | do { | 2755 | do { |
| @@ -2675,6 +2849,19 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) | @@ -2675,6 +2849,19 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) | ||
| 2675 | return gen_intermediate_code_internal(env, tb, 1); | 2849 | return gen_intermediate_code_internal(env, tb, 1); |
| 2676 | } | 2850 | } |
| 2677 | 2851 | ||
| 2852 | +void cpu_reset(CPUM68KState *env) | ||
| 2853 | +{ | ||
| 2854 | + memset(env, 0, offsetof(CPUM68KState, breakpoints)); | ||
| 2855 | +#if !defined (CONFIG_USER_ONLY) | ||
| 2856 | + env->sr = 0x2700; | ||
| 2857 | +#endif | ||
| 2858 | + /* ??? FP regs should be initialized to NaN. */ | ||
| 2859 | + env->cc_op = CC_OP_FLAGS; | ||
| 2860 | + /* TODO: We should set PC from the interrupt vector. */ | ||
| 2861 | + env->pc = 0; | ||
| 2862 | + tlb_flush(env, 1); | ||
| 2863 | +} | ||
| 2864 | + | ||
| 2678 | CPUM68KState *cpu_m68k_init(void) | 2865 | CPUM68KState *cpu_m68k_init(void) |
| 2679 | { | 2866 | { |
| 2680 | CPUM68KState *env; | 2867 | CPUM68KState *env; |
| @@ -2684,10 +2871,7 @@ CPUM68KState *cpu_m68k_init(void) | @@ -2684,10 +2871,7 @@ CPUM68KState *cpu_m68k_init(void) | ||
| 2684 | return NULL; | 2871 | return NULL; |
| 2685 | cpu_exec_init(env); | 2872 | cpu_exec_init(env); |
| 2686 | 2873 | ||
| 2687 | - memset(env, 0, sizeof(CPUM68KState)); | ||
| 2688 | - /* ??? FP regs should be initialized to NaN. */ | ||
| 2689 | - cpu_single_env = env; | ||
| 2690 | - env->cc_op = CC_OP_FLAGS; | 2874 | + cpu_reset(env); |
| 2691 | return env; | 2875 | return env; |
| 2692 | } | 2876 | } |
| 2693 | 2877 | ||
| @@ -2696,23 +2880,20 @@ void cpu_m68k_close(CPUM68KState *env) | @@ -2696,23 +2880,20 @@ void cpu_m68k_close(CPUM68KState *env) | ||
| 2696 | free(env); | 2880 | free(env); |
| 2697 | } | 2881 | } |
| 2698 | 2882 | ||
| 2699 | -m68k_def_t *m68k_find_by_name(const char *name) | 2883 | +int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
| 2700 | { | 2884 | { |
| 2701 | m68k_def_t *def; | 2885 | m68k_def_t *def; |
| 2702 | 2886 | ||
| 2703 | - def = m68k_cpu_defs; | ||
| 2704 | - while (def->name) | ||
| 2705 | - { | 2887 | + for (def = m68k_cpu_defs; def->name; def++) { |
| 2706 | if (strcmp(def->name, name) == 0) | 2888 | if (strcmp(def->name, name) == 0) |
| 2707 | - return def; | ||
| 2708 | - def++; | ||
| 2709 | - } | ||
| 2710 | - return NULL; | ||
| 2711 | -} | 2889 | + break; |
| 2890 | + } | ||
| 2891 | + if (!def->name) | ||
| 2892 | + return 1; | ||
| 2712 | 2893 | ||
| 2713 | -void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def) | ||
| 2714 | -{ | ||
| 2715 | register_m68k_insns(def); | 2894 | register_m68k_insns(def); |
| 2895 | + | ||
| 2896 | + return 0; | ||
| 2716 | } | 2897 | } |
| 2717 | 2898 | ||
| 2718 | void cpu_dump_state(CPUState *env, FILE *f, | 2899 | void cpu_dump_state(CPUState *env, FILE *f, |
| @@ -2737,24 +2918,3 @@ void cpu_dump_state(CPUState *env, FILE *f, | @@ -2737,24 +2918,3 @@ void cpu_dump_state(CPUState *env, FILE *f, | ||
| 2737 | cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result); | 2918 | cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result); |
| 2738 | } | 2919 | } |
| 2739 | 2920 | ||
| 2740 | -/* ??? */ | ||
| 2741 | -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 2742 | -{ | ||
| 2743 | - return addr; | ||
| 2744 | -} | ||
| 2745 | - | ||
| 2746 | -#if defined(CONFIG_USER_ONLY) | ||
| 2747 | - | ||
| 2748 | -int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 2749 | - int is_user, int is_softmmu) | ||
| 2750 | -{ | ||
| 2751 | - env->exception_index = EXCP_ACCESS; | ||
| 2752 | - env->mmu.ar = address; | ||
| 2753 | - return 1; | ||
| 2754 | -} | ||
| 2755 | - | ||
| 2756 | -#else | ||
| 2757 | - | ||
| 2758 | -#error not implemented | ||
| 2759 | - | ||
| 2760 | -#endif |
vl.c
| @@ -6833,6 +6833,8 @@ void register_machines(void) | @@ -6833,6 +6833,8 @@ void register_machines(void) | ||
| 6833 | qemu_register_machine(&shix_machine); | 6833 | qemu_register_machine(&shix_machine); |
| 6834 | #elif defined(TARGET_ALPHA) | 6834 | #elif defined(TARGET_ALPHA) |
| 6835 | /* XXX: TODO */ | 6835 | /* XXX: TODO */ |
| 6836 | +#elif defined(TARGET_M68K) | ||
| 6837 | + qemu_register_machine(&an5206_machine); | ||
| 6836 | #else | 6838 | #else |
| 6837 | #error unsupported CPU | 6839 | #error unsupported CPU |
| 6838 | #endif | 6840 | #endif |
vl.h
| @@ -1597,6 +1597,12 @@ void ptimer_stop(ptimer_state *s); | @@ -1597,6 +1597,12 @@ void ptimer_stop(ptimer_state *s); | ||
| 1597 | 1597 | ||
| 1598 | #include "hw/pxa.h" | 1598 | #include "hw/pxa.h" |
| 1599 | 1599 | ||
| 1600 | +/* mcf5206.c */ | ||
| 1601 | +qemu_irq *mcf5206_init(uint32_t base, CPUState *env); | ||
| 1602 | + | ||
| 1603 | +/* an5206.c */ | ||
| 1604 | +extern QEMUMachine an5206_machine; | ||
| 1605 | + | ||
| 1600 | #include "gdbstub.h" | 1606 | #include "gdbstub.h" |
| 1601 | 1607 | ||
| 1602 | #endif /* defined(QEMU_TOOL) */ | 1608 | #endif /* defined(QEMU_TOOL) */ |