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