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) */ | ... | ... |