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 | 308 | endif |
| 309 | 309 | |
| 310 | 310 | ifeq ($(TARGET_BASE_ARCH), m68k) |
| 311 | -LIBOBJS+= helper.o | |
| 311 | +LIBOBJS+= op_helper.o helper.o | |
| 312 | 312 | endif |
| 313 | 313 | |
| 314 | 314 | ifeq ($(TARGET_BASE_ARCH), alpha) |
| ... | ... | @@ -466,6 +466,9 @@ endif |
| 466 | 466 | ifeq ($(TARGET_BASE_ARCH), sh4) |
| 467 | 467 | VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o |
| 468 | 468 | endif |
| 469 | +ifeq ($(TARGET_BASE_ARCH), m68k) | |
| 470 | +VL_OBJS+= an5206.o mcf5206.o ptimer.o | |
| 471 | +endif | |
| 469 | 472 | ifdef CONFIG_GDBSTUB |
| 470 | 473 | VL_OBJS+=gdbstub.o |
| 471 | 474 | endif | ... | ... |
configure
| ... | ... | @@ -467,7 +467,7 @@ fi |
| 467 | 467 | if test -z "$target_list" ; then |
| 468 | 468 | # these targets are portable |
| 469 | 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 | 471 | fi |
| 472 | 472 | # the following are Linux specific |
| 473 | 473 | if [ "$linux_user" = "yes" ] ; then | ... | ... |
cpu-exec.c
| ... | ... | @@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void) |
| 196 | 196 | cs_base = 0; |
| 197 | 197 | pc = env->PC; |
| 198 | 198 | #elif defined(TARGET_M68K) |
| 199 | - flags = env->fpcr & M68K_FPCR_PREC; | |
| 199 | + flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S); | |
| 200 | 200 | cs_base = 0; |
| 201 | 201 | pc = env->pc; |
| 202 | 202 | #elif defined(TARGET_SH4) |
| ... | ... | @@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1) |
| 297 | 297 | return EXCP_HALTED; |
| 298 | 298 | } |
| 299 | 299 | } |
| 300 | -#elif defined(TARGET_ALPHA) | |
| 300 | +#elif defined(TARGET_ALPHA) || defined(TARGET_M68K) | |
| 301 | 301 | if (env1->halted) { |
| 302 | 302 | if (env1->interrupt_request & CPU_INTERRUPT_HARD) { |
| 303 | 303 | env1->halted = 0; |
| ... | ... | @@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1) |
| 390 | 390 | do_interrupt(env); |
| 391 | 391 | #elif defined(TARGET_ALPHA) |
| 392 | 392 | do_interrupt(env); |
| 393 | +#elif defined(TARGET_M68K) | |
| 394 | + do_interrupt(0); | |
| 393 | 395 | #endif |
| 394 | 396 | } |
| 395 | 397 | env->exception_index = -1; |
| ... | ... | @@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1) |
| 542 | 544 | if (interrupt_request & CPU_INTERRUPT_HARD) { |
| 543 | 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 | 559 | #endif |
| 546 | 560 | /* Don't use the cached interupt_request value, |
| 547 | 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 | 584 | is_user = ((env->sr & SR_MD) == 0); |
| 585 | 585 | #elif defined (TARGET_ALPHA) |
| 586 | 586 | is_user = ((env->ps >> 3) & 3); |
| 587 | +#elif defined (TARGET_M68K) | |
| 588 | + is_user = ((env->sr & SR_S) == 0); | |
| 587 | 589 | #else |
| 588 | 590 | #error unimplemented CPU |
| 589 | 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 | 1977 | } |
| 1978 | 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 | 1983 | cpu_abort(cpu_single_env, |
| 1984 | 1984 | "Unable to find m68k CPU definition\n"); |
| 1985 | 1985 | } |
| 1986 | - cpu_m68k_register(cpu_single_env, def); | |
| 1987 | 1986 | env->pc = regs->pc; |
| 1988 | 1987 | env->dregs[0] = regs->d0; |
| 1989 | 1988 | env->dregs[1] = regs->d1; | ... | ... |
softmmu_header.h
| ... | ... | @@ -65,6 +65,8 @@ |
| 65 | 65 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) |
| 66 | 66 | #elif defined (TARGET_ALPHA) |
| 67 | 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 | 70 | #else |
| 69 | 71 | #error unsupported CPU |
| 70 | 72 | #endif |
| ... | ... | @@ -86,6 +88,8 @@ |
| 86 | 88 | #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) |
| 87 | 89 | #elif defined (TARGET_ALPHA) |
| 88 | 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 | 93 | #else |
| 90 | 94 | #error unsupported CPU |
| 91 | 95 | #endif | ... | ... |
target-m68k/cpu.h
| 1 | 1 | /* |
| 2 | 2 | * m68k virtual CPU header |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2005-2006 CodeSourcery | |
| 4 | + * Copyright (c) 2005-2007 CodeSourcery | |
| 5 | 5 | * Written by Paul Brook |
| 6 | 6 | * |
| 7 | 7 | * This library is free software; you can redistribute it and/or |
| ... | ... | @@ -50,6 +50,8 @@ |
| 50 | 50 | #define EXCP_UNSUPPORTED 61 |
| 51 | 51 | #define EXCP_ICE 13 |
| 52 | 52 | |
| 53 | +#define EXCP_RTE 0x100 | |
| 54 | + | |
| 53 | 55 | typedef struct CPUM68KState { |
| 54 | 56 | uint32_t dregs[8]; |
| 55 | 57 | uint32_t aregs[8]; |
| ... | ... | @@ -76,6 +78,12 @@ typedef struct CPUM68KState { |
| 76 | 78 | struct { |
| 77 | 79 | uint32_t ar; |
| 78 | 80 | } mmu; |
| 81 | + | |
| 82 | + /* Control registers. */ | |
| 83 | + uint32_t vbr; | |
| 84 | + uint32_t mbar; | |
| 85 | + uint32_t rambar0; | |
| 86 | + | |
| 79 | 87 | /* ??? remove this. */ |
| 80 | 88 | uint32_t t1; |
| 81 | 89 | |
| ... | ... | @@ -84,7 +92,10 @@ typedef struct CPUM68KState { |
| 84 | 92 | int exception_index; |
| 85 | 93 | int interrupt_request; |
| 86 | 94 | int user_mode_only; |
| 87 | - uint32_t address; | |
| 95 | + int halted; | |
| 96 | + | |
| 97 | + int pending_vector; | |
| 98 | + int pending_level; | |
| 88 | 99 | |
| 89 | 100 | uint32_t qregs[MAX_QREGS]; |
| 90 | 101 | |
| ... | ... | @@ -94,6 +105,7 @@ typedef struct CPUM68KState { |
| 94 | 105 | CPUM68KState *cpu_m68k_init(void); |
| 95 | 106 | int cpu_m68k_exec(CPUM68KState *s); |
| 96 | 107 | void cpu_m68k_close(CPUM68KState *s); |
| 108 | +void do_interrupt(int is_hw); | |
| 97 | 109 | /* you can call this signal handler from your SIGBUS and SIGSEGV |
| 98 | 110 | signal handlers to inform the virtual CPU of exceptions. non zero |
| 99 | 111 | is returned if the signal was handled by the virtual CPU. */ |
| ... | ... | @@ -120,12 +132,19 @@ enum { |
| 120 | 132 | #define CCF_V 0x02 |
| 121 | 133 | #define CCF_Z 0x04 |
| 122 | 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 | 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 | 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 | 40 | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
| 41 | 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 | 47 | void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); |
| 45 | 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 | 51 | void cpu_loop_exit(void); | ... | ... |
target-m68k/helper.c
| 1 | 1 | /* |
| 2 | 2 | * m68k op helpers |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2006 CodeSourcery | |
| 4 | + * Copyright (c) 2006-2007 CodeSourcery | |
| 5 | 5 | * Written by Paul Brook |
| 6 | 6 | * |
| 7 | 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 | 147 | } |
| 148 | 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 | 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 | 62 | static inline void gen_op_pack_32_f32(int dest, int src) |
| 41 | 63 | { |
| 42 | 64 | gen_op_mov32(dest, src); | ... | ... |
target-m68k/op.c
| 1 | 1 | /* |
| 2 | 2 | * m68k micro operations |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2006 CodeSourcery | |
| 4 | + * Copyright (c) 2006-2007 CodeSourcery | |
| 5 | 5 | * Written by Paul Brook |
| 6 | 6 | * |
| 7 | 7 | * This library is free software; you can redistribute it and/or |
| ... | ... | @@ -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 | 91 | OP(mov32) |
| 92 | 92 | { |
| ... | ... | @@ -316,77 +316,6 @@ OP(ext16s32) |
| 316 | 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 | 319 | OP(flush_flags) |
| 391 | 320 | { |
| 392 | 321 | int cc_op = PARAM1; |
| ... | ... | @@ -454,6 +383,13 @@ OP(divs) |
| 454 | 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 | 393 | OP(raise_exception) |
| 458 | 394 | { |
| 459 | 395 | RAISE_EXCEPTION(PARAM1); |
| ... | ... | @@ -679,3 +615,22 @@ OP(compare_quietf64) |
| 679 | 615 | set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); |
| 680 | 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
target-m68k/translate.c
| 1 | 1 | /* |
| 2 | 2 | * m68k translation |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2005-2006 CodeSourcery | |
| 4 | + * Copyright (c) 2005-2007 CodeSourcery | |
| 5 | 5 | * Written by Paul Brook |
| 6 | 6 | * |
| 7 | 7 | * This library is free software; you can redistribute it and/or |
| ... | ... | @@ -30,6 +30,8 @@ |
| 30 | 30 | #include "disas.h" |
| 31 | 31 | #include "m68k-qreg.h" |
| 32 | 32 | |
| 33 | +//#define DEBUG_DISPATCH 1 | |
| 34 | + | |
| 33 | 35 | static inline void qemu_assert(int cond, const char *msg) |
| 34 | 36 | { |
| 35 | 37 | if (!cond) { |
| ... | ... | @@ -43,6 +45,7 @@ typedef struct DisasContext { |
| 43 | 45 | target_ulong pc; |
| 44 | 46 | int is_jmp; |
| 45 | 47 | int cc_op; |
| 48 | + int user; | |
| 46 | 49 | uint32_t fpcr; |
| 47 | 50 | struct TranslationBlock *tb; |
| 48 | 51 | int singlestep_enabled; |
| ... | ... | @@ -50,6 +53,12 @@ typedef struct DisasContext { |
| 50 | 53 | |
| 51 | 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 | 62 | /* XXX: move that elsewhere */ |
| 54 | 63 | /* ??? Fix exceptions. */ |
| 55 | 64 | static void *gen_throws_exception; |
| ... | ... | @@ -68,6 +77,25 @@ enum { |
| 68 | 77 | }; |
| 69 | 78 | |
| 70 | 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 | 99 | #include "op-hacks.h" |
| 72 | 100 | |
| 73 | 101 | #define OS_BYTE 0 |
| ... | ... | @@ -101,40 +129,49 @@ static m68k_def_t m68k_cpu_defs[] = { |
| 101 | 129 | |
| 102 | 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 | 140 | #define DISAS_INSN(name) \ |
| 105 | 141 | static void disas_##name (DisasContext *s, uint16_t insn) |
| 142 | +#endif | |
| 106 | 143 | |
| 107 | 144 | /* Generate a load from the specified address. Narrow values are |
| 108 | 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 | 148 | int tmp; |
| 112 | 149 | switch(opsize) { |
| 113 | 150 | case OS_BYTE: |
| 114 | 151 | tmp = gen_new_qreg(QMODE_I32); |
| 115 | 152 | if (sign) |
| 116 | - gen_op_ld8s32(tmp, addr); | |
| 153 | + gen_ld(s, 8s32, tmp, addr); | |
| 117 | 154 | else |
| 118 | - gen_op_ld8u32(tmp, addr); | |
| 155 | + gen_ld(s, 8u32, tmp, addr); | |
| 119 | 156 | break; |
| 120 | 157 | case OS_WORD: |
| 121 | 158 | tmp = gen_new_qreg(QMODE_I32); |
| 122 | 159 | if (sign) |
| 123 | - gen_op_ld16s32(tmp, addr); | |
| 160 | + gen_ld(s, 16s32, tmp, addr); | |
| 124 | 161 | else |
| 125 | - gen_op_ld16u32(tmp, addr); | |
| 162 | + gen_ld(s, 16u32, tmp, addr); | |
| 126 | 163 | break; |
| 127 | 164 | case OS_LONG: |
| 128 | 165 | tmp = gen_new_qreg(QMODE_I32); |
| 129 | - gen_op_ld32(tmp, addr); | |
| 166 | + gen_ld(s, 32, tmp, addr); | |
| 130 | 167 | break; |
| 131 | 168 | case OS_SINGLE: |
| 132 | 169 | tmp = gen_new_qreg(QMODE_F32); |
| 133 | - gen_op_ldf32(tmp, addr); | |
| 170 | + gen_ld(s, f32, tmp, addr); | |
| 134 | 171 | break; |
| 135 | 172 | case OS_DOUBLE: |
| 136 | 173 | tmp = gen_new_qreg(QMODE_F64); |
| 137 | - gen_op_ldf64(tmp, addr); | |
| 174 | + gen_ld(s, f64, tmp, addr); | |
| 138 | 175 | break; |
| 139 | 176 | default: |
| 140 | 177 | qemu_assert(0, "bad load size"); |
| ... | ... | @@ -144,23 +181,23 @@ static inline int gen_load(int opsize, int addr, int sign) |
| 144 | 181 | } |
| 145 | 182 | |
| 146 | 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 | 186 | switch(opsize) { |
| 150 | 187 | case OS_BYTE: |
| 151 | - gen_op_st8(addr, val); | |
| 188 | + gen_st(s, 8, addr, val); | |
| 152 | 189 | break; |
| 153 | 190 | case OS_WORD: |
| 154 | - gen_op_st16(addr, val); | |
| 191 | + gen_st(s, 16, addr, val); | |
| 155 | 192 | break; |
| 156 | 193 | case OS_LONG: |
| 157 | - gen_op_st32(addr, val); | |
| 194 | + gen_st(s, 32, addr, val); | |
| 158 | 195 | break; |
| 159 | 196 | case OS_SINGLE: |
| 160 | - gen_op_stf32(addr, val); | |
| 197 | + gen_st(s, f32, addr, val); | |
| 161 | 198 | break; |
| 162 | 199 | case OS_DOUBLE: |
| 163 | - gen_op_stf64(addr, val); | |
| 200 | + gen_st(s, f64, addr, val); | |
| 164 | 201 | break; |
| 165 | 202 | default: |
| 166 | 203 | qemu_assert(0, "bad store size"); |
| ... | ... | @@ -170,13 +207,13 @@ static inline void gen_store(int opsize, int addr, int val) |
| 170 | 207 | |
| 171 | 208 | /* Generate an unsigned load if VAL is 0 a signed load if val is -1, |
| 172 | 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 | 212 | if (val > 0) { |
| 176 | - gen_store(opsize, addr, val); | |
| 213 | + gen_store(s, opsize, addr, val); | |
| 177 | 214 | return 0; |
| 178 | 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 | 228 | int tmp; |
| 192 | 229 | |
| 193 | 230 | offset = s->pc; |
| 194 | - ext = lduw(s->pc); | |
| 231 | + ext = lduw_code(s->pc); | |
| 195 | 232 | s->pc += 2; |
| 196 | 233 | tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); |
| 197 | 234 | /* ??? Check W/L bit. */ |
| ... | ... | @@ -216,9 +253,9 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) |
| 216 | 253 | static inline uint32_t read_im32(DisasContext *s) |
| 217 | 254 | { |
| 218 | 255 | uint32_t im; |
| 219 | - im = ((uint32_t)lduw(s->pc)) << 16; | |
| 256 | + im = ((uint32_t)lduw_code(s->pc)) << 16; | |
| 220 | 257 | s->pc += 2; |
| 221 | - im |= lduw(s->pc); | |
| 258 | + im |= lduw_code(s->pc); | |
| 222 | 259 | s->pc += 2; |
| 223 | 260 | return im; |
| 224 | 261 | } |
| ... | ... | @@ -343,7 +380,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) |
| 343 | 380 | case 5: /* Indirect displacement. */ |
| 344 | 381 | reg += QREG_A0; |
| 345 | 382 | tmp = gen_new_qreg(QMODE_I32); |
| 346 | - ext = lduw(s->pc); | |
| 383 | + ext = lduw_code(s->pc); | |
| 347 | 384 | s->pc += 2; |
| 348 | 385 | gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); |
| 349 | 386 | return tmp; |
| ... | ... | @@ -353,7 +390,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) |
| 353 | 390 | case 7: /* Other */ |
| 354 | 391 | switch (reg) { |
| 355 | 392 | case 0: /* Absolute short. */ |
| 356 | - offset = ldsw(s->pc); | |
| 393 | + offset = ldsw_code(s->pc); | |
| 357 | 394 | s->pc += 2; |
| 358 | 395 | return gen_im32(offset); |
| 359 | 396 | case 1: /* Absolute long. */ |
| ... | ... | @@ -362,7 +399,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) |
| 362 | 399 | case 2: /* pc displacement */ |
| 363 | 400 | tmp = gen_new_qreg(QMODE_I32); |
| 364 | 401 | offset = s->pc; |
| 365 | - offset += ldsw(s->pc); | |
| 402 | + offset += ldsw_code(s->pc); | |
| 366 | 403 | s->pc += 2; |
| 367 | 404 | return gen_im32(offset); |
| 368 | 405 | case 3: /* pc index+displacement. */ |
| ... | ... | @@ -391,7 +428,7 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, |
| 391 | 428 | if (addrp) |
| 392 | 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 | 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 | 461 | } |
| 425 | 462 | case 2: /* Indirect register */ |
| 426 | 463 | reg += QREG_A0; |
| 427 | - return gen_ldst(opsize, reg, val); | |
| 464 | + return gen_ldst(s, opsize, reg, val); | |
| 428 | 465 | case 3: /* Indirect postincrement. */ |
| 429 | 466 | reg += QREG_A0; |
| 430 | - result = gen_ldst(opsize, reg, val); | |
| 467 | + result = gen_ldst(s, opsize, reg, val); | |
| 431 | 468 | /* ??? This is not exception safe. The instruction may still |
| 432 | 469 | fault after this point. */ |
| 433 | 470 | if (val > 0 || !addrp) |
| ... | ... | @@ -443,7 +480,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, |
| 443 | 480 | if (addrp) |
| 444 | 481 | *addrp = tmp; |
| 445 | 482 | } |
| 446 | - result = gen_ldst(opsize, tmp, val); | |
| 483 | + result = gen_ldst(s, opsize, tmp, val); | |
| 447 | 484 | /* ??? This is not exception safe. The instruction may still |
| 448 | 485 | fault after this point. */ |
| 449 | 486 | if (val > 0 || !addrp) { |
| ... | ... | @@ -467,16 +504,16 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, |
| 467 | 504 | switch (opsize) { |
| 468 | 505 | case OS_BYTE: |
| 469 | 506 | if (val) |
| 470 | - offset = ldsb(s->pc + 1); | |
| 507 | + offset = ldsb_code(s->pc + 1); | |
| 471 | 508 | else |
| 472 | - offset = ldub(s->pc + 1); | |
| 509 | + offset = ldub_code(s->pc + 1); | |
| 473 | 510 | s->pc += 2; |
| 474 | 511 | break; |
| 475 | 512 | case OS_WORD: |
| 476 | 513 | if (val) |
| 477 | - offset = ldsw(s->pc); | |
| 514 | + offset = ldsw_code(s->pc); | |
| 478 | 515 | else |
| 479 | - offset = lduw(s->pc); | |
| 516 | + offset = lduw_code(s->pc); | |
| 480 | 517 | s->pc += 2; |
| 481 | 518 | break; |
| 482 | 519 | case OS_LONG: |
| ... | ... | @@ -622,6 +659,14 @@ DISAS_INSN(scc) |
| 622 | 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 | 670 | /* Generate a jump to to the address in qreg DEST. */ |
| 626 | 671 | static void gen_jmp(DisasContext *s, int dest) |
| 627 | 672 | { |
| ... | ... | @@ -735,7 +780,7 @@ DISAS_INSN(divl) |
| 735 | 780 | int reg; |
| 736 | 781 | uint16_t ext; |
| 737 | 782 | |
| 738 | - ext = lduw(s->pc); | |
| 783 | + ext = lduw_code(s->pc); | |
| 739 | 784 | s->pc += 2; |
| 740 | 785 | if (ext & 0x87f8) { |
| 741 | 786 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); |
| ... | ... | @@ -903,13 +948,13 @@ DISAS_INSN(sats) |
| 903 | 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 | 953 | int tmp; |
| 909 | 954 | |
| 910 | 955 | tmp = gen_new_qreg(QMODE_I32); |
| 911 | 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 | 958 | gen_op_mov32(QREG_SP, tmp); |
| 914 | 959 | } |
| 915 | 960 | |
| ... | ... | @@ -922,7 +967,7 @@ DISAS_INSN(movem) |
| 922 | 967 | int tmp; |
| 923 | 968 | int is_load; |
| 924 | 969 | |
| 925 | - mask = lduw(s->pc); | |
| 970 | + mask = lduw_code(s->pc); | |
| 926 | 971 | s->pc += 2; |
| 927 | 972 | tmp = gen_lea(s, insn, OS_LONG); |
| 928 | 973 | addr = gen_new_qreg(QMODE_I32); |
| ... | ... | @@ -935,10 +980,10 @@ DISAS_INSN(movem) |
| 935 | 980 | else |
| 936 | 981 | reg = AREG(i, 0); |
| 937 | 982 | if (is_load) { |
| 938 | - tmp = gen_load(OS_LONG, addr, 0); | |
| 983 | + tmp = gen_load(s, OS_LONG, addr, 0); | |
| 939 | 984 | gen_op_mov32(reg, tmp); |
| 940 | 985 | } else { |
| 941 | - gen_store(OS_LONG, addr, reg); | |
| 986 | + gen_store(s, OS_LONG, addr, reg); | |
| 942 | 987 | } |
| 943 | 988 | if (mask != 1) |
| 944 | 989 | gen_op_add32(addr, addr, gen_im32(4)); |
| ... | ... | @@ -963,7 +1008,7 @@ DISAS_INSN(bitop_im) |
| 963 | 1008 | opsize = OS_LONG; |
| 964 | 1009 | op = (insn >> 6) & 3; |
| 965 | 1010 | |
| 966 | - bitnum = lduw(s->pc); | |
| 1011 | + bitnum = lduw_code(s->pc); | |
| 967 | 1012 | s->pc += 2; |
| 968 | 1013 | if (bitnum & 0xff00) { |
| 969 | 1014 | disas_undef(s, insn); |
| ... | ... | @@ -1155,9 +1200,8 @@ DISAS_INSN(clr) |
| 1155 | 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 | 1205 | int dest; |
| 1162 | 1206 | |
| 1163 | 1207 | gen_flush_flags(s); |
| ... | ... | @@ -1165,8 +1209,17 @@ DISAS_INSN(move_from_ccr) |
| 1165 | 1209 | gen_op_get_xflag(dest); |
| 1166 | 1210 | gen_op_shl32(dest, dest, gen_im32(4)); |
| 1167 | 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 | 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 | 1225 | DISAS_INSN(neg) |
| ... | ... | @@ -1184,7 +1237,16 @@ DISAS_INSN(neg) |
| 1184 | 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 | 1251 | int src1; |
| 1190 | 1252 | int reg; |
| ... | ... | @@ -1199,19 +1261,26 @@ DISAS_INSN(move_to_ccr) |
| 1199 | 1261 | gen_op_shr32(src1, reg, gen_im32(4)); |
| 1200 | 1262 | gen_op_and32(src1, src1, gen_im32(1)); |
| 1201 | 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 | 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 | 1275 | else |
| 1212 | 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 | 1284 | DISAS_INSN(not) |
| 1216 | 1285 | { |
| 1217 | 1286 | int reg; |
| ... | ... | @@ -1244,7 +1313,7 @@ DISAS_INSN(pea) |
| 1244 | 1313 | int tmp; |
| 1245 | 1314 | |
| 1246 | 1315 | tmp = gen_lea(s, insn, OS_LONG); |
| 1247 | - gen_push(tmp); | |
| 1316 | + gen_push(s, tmp); | |
| 1248 | 1317 | } |
| 1249 | 1318 | |
| 1250 | 1319 | DISAS_INSN(ext) |
| ... | ... | @@ -1322,7 +1391,7 @@ DISAS_INSN(mull) |
| 1322 | 1391 | |
| 1323 | 1392 | /* The upper 32 bits of the product are discarded, so |
| 1324 | 1393 | muls.l and mulu.l are functionally equivalent. */ |
| 1325 | - ext = lduw(s->pc); | |
| 1394 | + ext = lduw_code(s->pc); | |
| 1326 | 1395 | s->pc += 2; |
| 1327 | 1396 | if (ext & 0x87ff) { |
| 1328 | 1397 | gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); |
| ... | ... | @@ -1343,12 +1412,12 @@ DISAS_INSN(link) |
| 1343 | 1412 | int reg; |
| 1344 | 1413 | int tmp; |
| 1345 | 1414 | |
| 1346 | - offset = ldsw(s->pc); | |
| 1415 | + offset = ldsw_code(s->pc); | |
| 1347 | 1416 | s->pc += 2; |
| 1348 | 1417 | reg = AREG(insn, 0); |
| 1349 | 1418 | tmp = gen_new_qreg(QMODE_I32); |
| 1350 | 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 | 1421 | if (reg != QREG_SP) |
| 1353 | 1422 | gen_op_mov32(reg, tmp); |
| 1354 | 1423 | gen_op_add32(QREG_SP, tmp, gen_im32(offset)); |
| ... | ... | @@ -1363,7 +1432,7 @@ DISAS_INSN(unlk) |
| 1363 | 1432 | src = gen_new_qreg(QMODE_I32); |
| 1364 | 1433 | reg = AREG(insn, 0); |
| 1365 | 1434 | gen_op_mov32(src, reg); |
| 1366 | - tmp = gen_load(OS_LONG, src, 0); | |
| 1435 | + tmp = gen_load(s, OS_LONG, src, 0); | |
| 1367 | 1436 | gen_op_mov32(reg, tmp); |
| 1368 | 1437 | gen_op_add32(QREG_SP, src, gen_im32(4)); |
| 1369 | 1438 | } |
| ... | ... | @@ -1376,7 +1445,7 @@ DISAS_INSN(rts) |
| 1376 | 1445 | { |
| 1377 | 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 | 1449 | gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); |
| 1381 | 1450 | gen_jmp(s, tmp); |
| 1382 | 1451 | } |
| ... | ... | @@ -1390,7 +1459,7 @@ DISAS_INSN(jump) |
| 1390 | 1459 | tmp = gen_lea(s, insn, OS_LONG); |
| 1391 | 1460 | if ((insn & 0x40) == 0) { |
| 1392 | 1461 | /* jsr */ |
| 1393 | - gen_push(gen_im32(s->pc)); | |
| 1462 | + gen_push(s, gen_im32(s->pc)); | |
| 1394 | 1463 | } |
| 1395 | 1464 | gen_jmp(s, tmp); |
| 1396 | 1465 | } |
| ... | ... | @@ -1460,14 +1529,14 @@ DISAS_INSN(branch) |
| 1460 | 1529 | op = (insn >> 8) & 0xf; |
| 1461 | 1530 | offset = (int8_t)insn; |
| 1462 | 1531 | if (offset == 0) { |
| 1463 | - offset = ldsw(s->pc); | |
| 1532 | + offset = ldsw_code(s->pc); | |
| 1464 | 1533 | s->pc += 2; |
| 1465 | 1534 | } else if (offset == -1) { |
| 1466 | 1535 | offset = read_im32(s); |
| 1467 | 1536 | } |
| 1468 | 1537 | if (op == 1) { |
| 1469 | 1538 | /* bsr */ |
| 1470 | - gen_push(gen_im32(s->pc)); | |
| 1539 | + gen_push(s, gen_im32(s->pc)); | |
| 1471 | 1540 | } |
| 1472 | 1541 | gen_flush_cc_op(s); |
| 1473 | 1542 | if (op > 1) { |
| ... | ... | @@ -1752,68 +1821,154 @@ DISAS_INSN(ff1) |
| 1752 | 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 | 1836 | DISAS_INSN(strldsr) |
| 1756 | 1837 | { |
| 1757 | 1838 | uint16_t ext; |
| 1758 | 1839 | uint32_t addr; |
| 1759 | 1840 | |
| 1760 | 1841 | addr = s->pc - 2; |
| 1761 | - ext = lduw(s->pc); | |
| 1842 | + ext = lduw_code(s->pc); | |
| 1762 | 1843 | s->pc += 2; |
| 1763 | - if (ext != 0x46FC) | |
| 1844 | + if (ext != 0x46FC) { | |
| 1764 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 1974 | DISAS_INSN(wddata) |
| ... | ... | @@ -1823,7 +1978,12 @@ DISAS_INSN(wddata) |
| 1823 | 1978 | |
| 1824 | 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 | 1989 | DISAS_INSN(trap) |
| ... | ... | @@ -1843,7 +2003,7 @@ DISAS_INSN(fpu) |
| 1843 | 2003 | int round; |
| 1844 | 2004 | int opsize; |
| 1845 | 2005 | |
| 1846 | - ext = lduw(s->pc); | |
| 2006 | + ext = lduw_code(s->pc); | |
| 1847 | 2007 | s->pc += 2; |
| 1848 | 2008 | opmode = ext & 0x7f; |
| 1849 | 2009 | switch ((ext >> 13) & 7) { |
| ... | ... | @@ -1928,10 +2088,10 @@ DISAS_INSN(fpu) |
| 1928 | 2088 | if (ext & mask) { |
| 1929 | 2089 | if (ext & (1 << 13)) { |
| 1930 | 2090 | /* store */ |
| 1931 | - gen_op_stf64(addr, dest); | |
| 2091 | + gen_st(s, f64, addr, dest); | |
| 1932 | 2092 | } else { |
| 1933 | 2093 | /* load */ |
| 1934 | - gen_op_ldf64(dest, addr); | |
| 2094 | + gen_ld(s, f64, dest, addr); | |
| 1935 | 2095 | } |
| 1936 | 2096 | if (ext & (mask - 1)) |
| 1937 | 2097 | gen_op_add32(addr, addr, gen_im32(8)); |
| ... | ... | @@ -2060,10 +2220,10 @@ DISAS_INSN(fbcc) |
| 2060 | 2220 | int l1; |
| 2061 | 2221 | |
| 2062 | 2222 | addr = s->pc; |
| 2063 | - offset = ldsw(s->pc); | |
| 2223 | + offset = ldsw_code(s->pc); | |
| 2064 | 2224 | s->pc += 2; |
| 2065 | 2225 | if (insn & (1 << 6)) { |
| 2066 | - offset = (offset << 16) | lduw(s->pc); | |
| 2226 | + offset = (offset << 16) | lduw_code(s->pc); | |
| 2067 | 2227 | s->pc += 2; |
| 2068 | 2228 | } |
| 2069 | 2229 | |
| ... | ... | @@ -2143,6 +2303,18 @@ DISAS_INSN(fbcc) |
| 2143 | 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 | 2318 | static disas_proc opcode_table[65536]; |
| 2147 | 2319 | |
| 2148 | 2320 | static void |
| ... | ... | @@ -2168,11 +2340,10 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) |
| 2168 | 2340 | i <<= 1; |
| 2169 | 2341 | from = opcode & ~(i - 1); |
| 2170 | 2342 | to = from + i; |
| 2171 | - for (i = from; i < to; i++) | |
| 2172 | - { | |
| 2343 | + for (i = from; i < to; i++) { | |
| 2173 | 2344 | if ((i & mask) == opcode) |
| 2174 | 2345 | opcode_table[i] = proc; |
| 2175 | - } | |
| 2346 | + } | |
| 2176 | 2347 | } |
| 2177 | 2348 | |
| 2178 | 2349 | /* Register m68k opcode handlers. Order is important. |
| ... | ... | @@ -2274,6 +2445,8 @@ register_m68k_insns (m68k_def_t *def) |
| 2274 | 2445 | INSN(undef_fpu, f000, f000, CF_A); |
| 2275 | 2446 | INSN(fpu, f200, ffc0, CF_FPU); |
| 2276 | 2447 | INSN(fbcc, f280, ffc0, CF_FPU); |
| 2448 | + INSN(frestore, f340, ffc0, CF_FPU); | |
| 2449 | + INSN(fsave, f340, ffc0, CF_FPU); | |
| 2277 | 2450 | INSN(intouch, f340, ffc0, CF_A); |
| 2278 | 2451 | INSN(cpushl, f428, ff38, CF_A); |
| 2279 | 2452 | INSN(wddata, fb00, ff00, CF_A); |
| ... | ... | @@ -2287,7 +2460,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s) |
| 2287 | 2460 | { |
| 2288 | 2461 | uint16_t insn; |
| 2289 | 2462 | |
| 2290 | - insn = lduw(s->pc); | |
| 2463 | + insn = lduw_code(s->pc); | |
| 2291 | 2464 | s->pc += 2; |
| 2292 | 2465 | |
| 2293 | 2466 | opcode_table[insn](s, insn); |
| ... | ... | @@ -2576,6 +2749,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, |
| 2576 | 2749 | dc->cc_op = CC_OP_DYNAMIC; |
| 2577 | 2750 | dc->singlestep_enabled = env->singlestep_enabled; |
| 2578 | 2751 | dc->fpcr = env->fpcr; |
| 2752 | + dc->user = (env->sr & SR_S) == 0; | |
| 2579 | 2753 | nb_gen_labels = 0; |
| 2580 | 2754 | lj = -1; |
| 2581 | 2755 | do { |
| ... | ... | @@ -2675,6 +2849,19 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) |
| 2675 | 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 | 2865 | CPUM68KState *cpu_m68k_init(void) |
| 2679 | 2866 | { |
| 2680 | 2867 | CPUM68KState *env; |
| ... | ... | @@ -2684,10 +2871,7 @@ CPUM68KState *cpu_m68k_init(void) |
| 2684 | 2871 | return NULL; |
| 2685 | 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 | 2875 | return env; |
| 2692 | 2876 | } |
| 2693 | 2877 | |
| ... | ... | @@ -2696,23 +2880,20 @@ void cpu_m68k_close(CPUM68KState *env) |
| 2696 | 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 | 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 | 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 | 2894 | register_m68k_insns(def); |
| 2895 | + | |
| 2896 | + return 0; | |
| 2716 | 2897 | } |
| 2717 | 2898 | |
| 2718 | 2899 | void cpu_dump_state(CPUState *env, FILE *f, |
| ... | ... | @@ -2737,24 +2918,3 @@ void cpu_dump_state(CPUState *env, FILE *f, |
| 2737 | 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 | 6833 | qemu_register_machine(&shix_machine); |
| 6834 | 6834 | #elif defined(TARGET_ALPHA) |
| 6835 | 6835 | /* XXX: TODO */ |
| 6836 | +#elif defined(TARGET_M68K) | |
| 6837 | + qemu_register_machine(&an5206_machine); | |
| 6836 | 6838 | #else |
| 6837 | 6839 | #error unsupported CPU |
| 6838 | 6840 | #endif | ... | ... |
vl.h
| ... | ... | @@ -1597,6 +1597,12 @@ void ptimer_stop(ptimer_state *s); |
| 1597 | 1597 | |
| 1598 | 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 | 1606 | #include "gdbstub.h" |
| 1601 | 1607 | |
| 1602 | 1608 | #endif /* defined(QEMU_TOOL) */ | ... | ... |