Commit 20dcee9483361ee0621cf6d68d271ecde686fd9c
1 parent
62ea5b0b
MCF5208 emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2924 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
13 changed files
with
833 additions
and
296 deletions
Makefile.target
... | ... | @@ -467,7 +467,7 @@ ifeq ($(TARGET_BASE_ARCH), sh4) |
467 | 467 | VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o |
468 | 468 | endif |
469 | 469 | ifeq ($(TARGET_BASE_ARCH), m68k) |
470 | -VL_OBJS+= an5206.o mcf5206.o ptimer.o | |
470 | +VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o | |
471 | 471 | VL_OBJS+= m68k-semi.o |
472 | 472 | endif |
473 | 473 | ifdef CONFIG_GDBSTUB | ... | ... |
hw/an5206.c
... | ... | @@ -40,7 +40,9 @@ static void an5206_init(int ram_size, int vga_ram_size, int boot_device, |
40 | 40 | env = cpu_init(); |
41 | 41 | if (!cpu_model) |
42 | 42 | cpu_model = "m5206"; |
43 | - cpu_m68k_set_model(env, cpu_model); | |
43 | + if (cpu_m68k_set_model(env, cpu_model)) { | |
44 | + cpu_abort(env, "Unable to find m68k CPU definition\n"); | |
45 | + } | |
44 | 46 | |
45 | 47 | /* Initialize CPU registers. */ |
46 | 48 | env->vbr = 0; | ... | ... |
hw/mcf5206.c
... | ... | @@ -139,285 +139,12 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) |
139 | 139 | return s; |
140 | 140 | } |
141 | 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 | 142 | /* System Integration Module. */ |
416 | 143 | |
417 | 144 | typedef struct { |
418 | 145 | CPUState *env; |
419 | 146 | m5206_timer_state *timer[2]; |
420 | - m5206_uart_state *uart[2]; | |
147 | + void *uart[2]; | |
421 | 148 | uint8_t scr; |
422 | 149 | uint8_t icr[14]; |
423 | 150 | uint16_t imr; /* 1 == interrupt is masked. */ |
... | ... | @@ -540,9 +267,9 @@ static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset) |
540 | 267 | } else if (offset >= 0x120 && offset < 0x140) { |
541 | 268 | return m5206_timer_read(s->timer[1], offset - 0x120); |
542 | 269 | } else if (offset >= 0x140 && offset < 0x160) { |
543 | - return m5206_uart_read(s->uart[0], offset - 0x140); | |
270 | + return mcf_uart_read(s->uart[0], offset - 0x140); | |
544 | 271 | } else if (offset >= 0x180 && offset < 0x1a0) { |
545 | - return m5206_uart_read(s->uart[1], offset - 0x180); | |
272 | + return mcf_uart_read(s->uart[1], offset - 0x180); | |
546 | 273 | } |
547 | 274 | switch (offset) { |
548 | 275 | case 0x03: return s->scr; |
... | ... | @@ -580,10 +307,10 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, |
580 | 307 | m5206_timer_write(s->timer[1], offset - 0x120, value); |
581 | 308 | return; |
582 | 309 | } else if (offset >= 0x140 && offset < 0x160) { |
583 | - m5206_uart_write(s->uart[0], offset - 0x140, value); | |
310 | + mcf_uart_write(s->uart[0], offset - 0x140, value); | |
584 | 311 | return; |
585 | 312 | } else if (offset >= 0x180 && offset < 0x1a0) { |
586 | - m5206_uart_write(s->uart[1], offset - 0x180, value); | |
313 | + mcf_uart_write(s->uart[1], offset - 0x180, value); | |
587 | 314 | return; |
588 | 315 | } |
589 | 316 | switch (offset) { |
... | ... | @@ -798,13 +525,13 @@ qemu_irq *mcf5206_init(uint32_t base, CPUState *env) |
798 | 525 | s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state)); |
799 | 526 | iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn, |
800 | 527 | m5206_mbar_writefn, s); |
801 | - cpu_register_physical_memory(base, 0x00000fff, iomemtype); | |
528 | + cpu_register_physical_memory(base, 0x00001000, iomemtype); | |
802 | 529 | |
803 | 530 | pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); |
804 | 531 | s->timer[0] = m5206_timer_init(pic[9]); |
805 | 532 | 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]); | |
533 | + s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); | |
534 | + s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); | |
808 | 535 | s->env = env; |
809 | 536 | |
810 | 537 | m5206_mbar_reset(s); | ... | ... |
hw/mcf5208.c
0 โ 100644
1 | +/* | |
2 | + * Motorola ColdFire MCF5208 SoC emulation. | |
3 | + * | |
4 | + * Copyright (c) 2007 CodeSourcery. | |
5 | + * | |
6 | + * This code is licenced under the GPL | |
7 | + */ | |
8 | +#include "vl.h" | |
9 | + | |
10 | +#define SYS_FREQ 66000000 | |
11 | + | |
12 | +#define PCSR_EN 0x0001 | |
13 | +#define PCSR_RLD 0x0002 | |
14 | +#define PCSR_PIF 0x0004 | |
15 | +#define PCSR_PIE 0x0008 | |
16 | +#define PCSR_OVW 0x0010 | |
17 | +#define PCSR_DBG 0x0020 | |
18 | +#define PCSR_DOZE 0x0040 | |
19 | +#define PCSR_PRE_SHIFT 8 | |
20 | +#define PCSR_PRE_MASK 0x0f00 | |
21 | + | |
22 | +typedef struct { | |
23 | + qemu_irq irq; | |
24 | + ptimer_state *timer; | |
25 | + uint16_t pcsr; | |
26 | + uint16_t pmr; | |
27 | + uint16_t pcntr; | |
28 | +} m5208_timer_state; | |
29 | + | |
30 | +static void m5208_timer_update(m5208_timer_state *s) | |
31 | +{ | |
32 | + if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF)) | |
33 | + qemu_irq_raise(s->irq); | |
34 | + else | |
35 | + qemu_irq_lower(s->irq); | |
36 | +} | |
37 | + | |
38 | +static void m5208_timer_write(m5208_timer_state *s, int offset, | |
39 | + uint32_t value) | |
40 | +{ | |
41 | + int prescale; | |
42 | + int limit; | |
43 | + switch (offset) { | |
44 | + case 0: | |
45 | + /* The PIF bit is set-to-clear. */ | |
46 | + if (value & PCSR_PIF) { | |
47 | + s->pcsr &= ~PCSR_PIF; | |
48 | + value &= ~PCSR_PIF; | |
49 | + } | |
50 | + /* Avoid frobbing the timer if we're just twiddling IRQ bits. */ | |
51 | + if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) { | |
52 | + s->pcsr = value; | |
53 | + m5208_timer_update(s); | |
54 | + return; | |
55 | + } | |
56 | + | |
57 | + if (s->pcsr & PCSR_EN) | |
58 | + ptimer_stop(s->timer); | |
59 | + | |
60 | + s->pcsr = value; | |
61 | + | |
62 | + prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT); | |
63 | + ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale); | |
64 | + if (s->pcsr & PCSR_RLD) | |
65 | + limit = 0xffff; | |
66 | + else | |
67 | + limit = s->pmr; | |
68 | + ptimer_set_limit(s->timer, limit, 0); | |
69 | + | |
70 | + if (s->pcsr & PCSR_EN) | |
71 | + ptimer_run(s->timer, 0); | |
72 | + break; | |
73 | + case 2: | |
74 | + s->pmr = value; | |
75 | + s->pcsr &= ~PCSR_PIF; | |
76 | + if (s->pcsr & PCSR_RLD) | |
77 | + value = 0xffff; | |
78 | + ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); | |
79 | + break; | |
80 | + case 4: | |
81 | + break; | |
82 | + default: | |
83 | + /* Should never happen. */ | |
84 | + abort(); | |
85 | + } | |
86 | + m5208_timer_update(s); | |
87 | +} | |
88 | + | |
89 | +static void m5208_timer_trigger(void *opaque) | |
90 | +{ | |
91 | + m5208_timer_state *s = (m5208_timer_state *)opaque; | |
92 | + s->pcsr |= PCSR_PIF; | |
93 | + m5208_timer_update(s); | |
94 | +} | |
95 | + | |
96 | +typedef struct { | |
97 | + m5208_timer_state timer[2]; | |
98 | +} m5208_sys_state; | |
99 | + | |
100 | +static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr) | |
101 | +{ | |
102 | + m5208_sys_state *s = (m5208_sys_state *)opaque; | |
103 | + switch (addr) { | |
104 | + /* PIT0 */ | |
105 | + case 0xfc080000: | |
106 | + return s->timer[0].pcsr; | |
107 | + case 0xfc080002: | |
108 | + return s->timer[0].pmr; | |
109 | + case 0xfc080004: | |
110 | + return ptimer_get_count(s->timer[0].timer); | |
111 | + /* PIT1 */ | |
112 | + case 0xfc084000: | |
113 | + return s->timer[1].pcsr; | |
114 | + case 0xfc084002: | |
115 | + return s->timer[1].pmr; | |
116 | + case 0xfc084004: | |
117 | + return ptimer_get_count(s->timer[1].timer); | |
118 | + | |
119 | + /* SDRAM Controller. */ | |
120 | + case 0xfc0a8110: /* SDCS0 */ | |
121 | + { | |
122 | + int n; | |
123 | + for (n = 0; n < 32; n++) { | |
124 | + if (ram_size < (2u << n)) | |
125 | + break; | |
126 | + } | |
127 | + return (n - 1) | 0x40000000; | |
128 | + } | |
129 | + case 0xfc0a8114: /* SDCS1 */ | |
130 | + return 0; | |
131 | + | |
132 | + default: | |
133 | + cpu_abort(cpu_single_env, "m5208_sys_read: Bad offset 0x%x\n", | |
134 | + (int)addr); | |
135 | + return 0; | |
136 | + } | |
137 | +} | |
138 | + | |
139 | +static void m5208_sys_write(void *opaque, target_phys_addr_t addr, | |
140 | + uint32_t value) | |
141 | +{ | |
142 | + m5208_sys_state *s = (m5208_sys_state *)opaque; | |
143 | + switch (addr) { | |
144 | + /* PIT0 */ | |
145 | + case 0xfc080000: | |
146 | + case 0xfc080002: | |
147 | + case 0xfc080004: | |
148 | + m5208_timer_write(&s->timer[0], addr & 0xf, value); | |
149 | + return; | |
150 | + /* PIT1 */ | |
151 | + case 0xfc084000: | |
152 | + case 0xfc084002: | |
153 | + case 0xfc084004: | |
154 | + m5208_timer_write(&s->timer[1], addr & 0xf, value); | |
155 | + return; | |
156 | + default: | |
157 | + cpu_abort(cpu_single_env, "m5208_sys_write: Bad offset 0x%x\n", | |
158 | + (int)addr); | |
159 | + break; | |
160 | + } | |
161 | +} | |
162 | + | |
163 | +static CPUReadMemoryFunc *m5208_sys_readfn[] = { | |
164 | + m5208_sys_read, | |
165 | + m5208_sys_read, | |
166 | + m5208_sys_read | |
167 | +}; | |
168 | + | |
169 | +static CPUWriteMemoryFunc *m5208_sys_writefn[] = { | |
170 | + m5208_sys_write, | |
171 | + m5208_sys_write, | |
172 | + m5208_sys_write | |
173 | +}; | |
174 | + | |
175 | +static void mcf5208_sys_init(qemu_irq *pic) | |
176 | +{ | |
177 | + int iomemtype; | |
178 | + m5208_sys_state *s; | |
179 | + QEMUBH *bh; | |
180 | + int i; | |
181 | + | |
182 | + s = (m5208_sys_state *)qemu_mallocz(sizeof(m5208_sys_state)); | |
183 | + iomemtype = cpu_register_io_memory(0, m5208_sys_readfn, | |
184 | + m5208_sys_writefn, s); | |
185 | + /* SDRAMC. */ | |
186 | + cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype); | |
187 | + /* Timers. */ | |
188 | + for (i = 0; i < 2; i++) { | |
189 | + bh = qemu_bh_new(m5208_timer_trigger, &s->timer[i]); | |
190 | + s->timer[i].timer = ptimer_init(bh); | |
191 | + cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000, | |
192 | + iomemtype); | |
193 | + s->timer[i].irq = pic[4 + i]; | |
194 | + } | |
195 | +} | |
196 | + | |
197 | +static void mcf5208evb_init(int ram_size, int vga_ram_size, int boot_device, | |
198 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
199 | + const char *kernel_filename, const char *kernel_cmdline, | |
200 | + const char *initrd_filename, const char *cpu_model) | |
201 | +{ | |
202 | + CPUState *env; | |
203 | + int kernel_size; | |
204 | + uint64_t elf_entry; | |
205 | + target_ulong entry; | |
206 | + qemu_irq *pic; | |
207 | + | |
208 | + env = cpu_init(); | |
209 | + if (!cpu_model) | |
210 | + cpu_model = "m5208"; | |
211 | + if (cpu_m68k_set_model(env, cpu_model)) { | |
212 | + cpu_abort(env, "Unable to find m68k CPU definition\n"); | |
213 | + } | |
214 | + | |
215 | + /* Initialize CPU registers. */ | |
216 | + env->vbr = 0; | |
217 | + /* TODO: Configure BARs. */ | |
218 | + | |
219 | + /* DRAM at 0x20000000 */ | |
220 | + cpu_register_physical_memory(0x40000000, ram_size, | |
221 | + qemu_ram_alloc(ram_size) | IO_MEM_RAM); | |
222 | + | |
223 | + /* Internal SRAM. */ | |
224 | + cpu_register_physical_memory(0x80000000, 16384, | |
225 | + qemu_ram_alloc(16384) | IO_MEM_RAM); | |
226 | + | |
227 | + /* Internal peripherals. */ | |
228 | + pic = mcf_intc_init(0xfc048000, env); | |
229 | + | |
230 | + mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]); | |
231 | + mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]); | |
232 | + mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]); | |
233 | + | |
234 | + mcf5208_sys_init(pic); | |
235 | + | |
236 | + /* 0xfc000000 SCM. */ | |
237 | + /* 0xfc004000 XBS. */ | |
238 | + /* 0xfc008000 FlexBus CS. */ | |
239 | + /* 0xfc030000 FEC. */ | |
240 | + /* 0xfc040000 SCM + Power management. */ | |
241 | + /* 0xfc044000 eDMA. */ | |
242 | + /* 0xfc048000 INTC. */ | |
243 | + /* 0xfc058000 I2C. */ | |
244 | + /* 0xfc05c000 QSPI. */ | |
245 | + /* 0xfc060000 UART0. */ | |
246 | + /* 0xfc064000 UART0. */ | |
247 | + /* 0xfc068000 UART0. */ | |
248 | + /* 0xfc070000 DMA timers. */ | |
249 | + /* 0xfc080000 PIT0. */ | |
250 | + /* 0xfc084000 PIT1. */ | |
251 | + /* 0xfc088000 EPORT. */ | |
252 | + /* 0xfc08c000 Watchdog. */ | |
253 | + /* 0xfc090000 clock module. */ | |
254 | + /* 0xfc0a0000 CCM + reset. */ | |
255 | + /* 0xfc0a4000 GPIO. */ | |
256 | + /* 0xfc0a8000 SDRAM controller. */ | |
257 | + | |
258 | + /* Load kernel. */ | |
259 | + if (!kernel_filename) { | |
260 | + fprintf(stderr, "Kernel image must be specified\n"); | |
261 | + exit(1); | |
262 | + } | |
263 | + | |
264 | + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); | |
265 | + entry = elf_entry; | |
266 | + if (kernel_size < 0) { | |
267 | + kernel_size = load_uboot(kernel_filename, &entry, NULL); | |
268 | + } | |
269 | + if (kernel_size < 0) { | |
270 | + kernel_size = load_image(kernel_filename, phys_ram_base); | |
271 | + entry = 0x20000000; | |
272 | + } | |
273 | + if (kernel_size < 0) { | |
274 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); | |
275 | + exit(1); | |
276 | + } | |
277 | + | |
278 | + env->pc = entry; | |
279 | +} | |
280 | + | |
281 | +QEMUMachine mcf5208evb_machine = { | |
282 | + "mcf5208evb", | |
283 | + "MCF5206EVB", | |
284 | + mcf5208evb_init, | |
285 | +}; | ... | ... |
hw/mcf_intc.c
0 โ 100644
1 | +/* | |
2 | + * ColdFire Interrupt Controller emulation. | |
3 | + * | |
4 | + * Copyright (c) 2007 CodeSourcery. | |
5 | + * | |
6 | + * This code is licenced under the GPL | |
7 | + */ | |
8 | +#include "vl.h" | |
9 | + | |
10 | +typedef struct { | |
11 | + uint64_t ipr; | |
12 | + uint64_t imr; | |
13 | + uint64_t ifr; | |
14 | + uint64_t enabled; | |
15 | + uint8_t icr[64]; | |
16 | + CPUState *env; | |
17 | + int active_vector; | |
18 | +} mcf_intc_state; | |
19 | + | |
20 | +static void mcf_intc_update(mcf_intc_state *s) | |
21 | +{ | |
22 | + uint64_t active; | |
23 | + int i; | |
24 | + int best; | |
25 | + int best_level; | |
26 | + | |
27 | + active = (s->ipr | s->ifr) & s->enabled & ~s->imr; | |
28 | + best_level = 0; | |
29 | + best = 64; | |
30 | + if (active) { | |
31 | + for (i = 0; i < 64; i++) { | |
32 | + if ((active & 1) != 0 && s->icr[i] >= best_level) { | |
33 | + best_level = s->icr[i]; | |
34 | + best = i; | |
35 | + } | |
36 | + active >>= 1; | |
37 | + } | |
38 | + } | |
39 | + s->active_vector = ((best == 64) ? 24 : (best + 64)); | |
40 | + m68k_set_irq_level(s->env, best_level, s->active_vector); | |
41 | +} | |
42 | + | |
43 | +static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr) | |
44 | +{ | |
45 | + int offset; | |
46 | + mcf_intc_state *s = (mcf_intc_state *)opaque; | |
47 | + offset = addr & 0xff; | |
48 | + if (offset >= 0x40 && offset < 0x80) { | |
49 | + return s->icr[offset - 0x40]; | |
50 | + } | |
51 | + switch (offset) { | |
52 | + case 0x00: | |
53 | + return (uint32_t)(s->ipr >> 32); | |
54 | + case 0x04: | |
55 | + return (uint32_t)s->ipr; | |
56 | + case 0x08: | |
57 | + return (uint32_t)(s->imr >> 32); | |
58 | + case 0x0c: | |
59 | + return (uint32_t)s->imr; | |
60 | + case 0x10: | |
61 | + return (uint32_t)(s->ifr >> 32); | |
62 | + case 0x14: | |
63 | + return (uint32_t)s->ifr; | |
64 | + case 0xe0: /* SWIACK. */ | |
65 | + return s->active_vector; | |
66 | + case 0xe1: case 0xe2: case 0xe3: case 0xe4: | |
67 | + case 0xe5: case 0xe6: case 0xe7: | |
68 | + /* LnIACK */ | |
69 | + cpu_abort(cpu_single_env, "mcf_intc_read: LnIACK not implemented\n"); | |
70 | + default: | |
71 | + return 0; | |
72 | + } | |
73 | +} | |
74 | + | |
75 | +static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val) | |
76 | +{ | |
77 | + int offset; | |
78 | + mcf_intc_state *s = (mcf_intc_state *)opaque; | |
79 | + offset = addr & 0xff; | |
80 | + if (offset >= 0x40 && offset < 0x80) { | |
81 | + int n = offset - 0x40; | |
82 | + s->icr[n] = val; | |
83 | + if (val == 0) | |
84 | + s->enabled &= ~(1ull << n); | |
85 | + else | |
86 | + s->enabled |= (1ull << n); | |
87 | + mcf_intc_update(s); | |
88 | + return; | |
89 | + } | |
90 | + switch (offset) { | |
91 | + case 0x00: case 0x04: | |
92 | + /* Ignore IPR writes. */ | |
93 | + return; | |
94 | + case 0x08: | |
95 | + s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); | |
96 | + break; | |
97 | + case 0x0c: | |
98 | + s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; | |
99 | + break; | |
100 | + default: | |
101 | + cpu_abort(cpu_single_env, "mcf_intc_write: Bad write offset %d\n", | |
102 | + offset); | |
103 | + break; | |
104 | + } | |
105 | + mcf_intc_update(s); | |
106 | +} | |
107 | + | |
108 | +static void mcf_intc_set_irq(void *opaque, int irq, int level) | |
109 | +{ | |
110 | + mcf_intc_state *s = (mcf_intc_state *)opaque; | |
111 | + if (irq >= 64) | |
112 | + return; | |
113 | + if (level) | |
114 | + s->ipr |= 1ull << irq; | |
115 | + else | |
116 | + s->ipr &= ~(1ull << irq); | |
117 | + mcf_intc_update(s); | |
118 | +} | |
119 | + | |
120 | +static void mcf_intc_reset(mcf_intc_state *s) | |
121 | +{ | |
122 | + s->imr = ~0ull; | |
123 | + s->ipr = 0; | |
124 | + s->ifr = 0; | |
125 | + s->enabled = 0; | |
126 | + memset(s->icr, 0, 64); | |
127 | + s->active_vector = 24; | |
128 | +} | |
129 | + | |
130 | +static CPUReadMemoryFunc *mcf_intc_readfn[] = { | |
131 | + mcf_intc_read, | |
132 | + mcf_intc_read, | |
133 | + mcf_intc_read | |
134 | +}; | |
135 | + | |
136 | +static CPUWriteMemoryFunc *mcf_intc_writefn[] = { | |
137 | + mcf_intc_write, | |
138 | + mcf_intc_write, | |
139 | + mcf_intc_write | |
140 | +}; | |
141 | + | |
142 | +qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env) | |
143 | +{ | |
144 | + mcf_intc_state *s; | |
145 | + int iomemtype; | |
146 | + | |
147 | + s = qemu_mallocz(sizeof(mcf_intc_state)); | |
148 | + s->env = env; | |
149 | + mcf_intc_reset(s); | |
150 | + | |
151 | + iomemtype = cpu_register_io_memory(0, mcf_intc_readfn, | |
152 | + mcf_intc_writefn, s); | |
153 | + cpu_register_physical_memory(base, 0x100, iomemtype); | |
154 | + | |
155 | + return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); | |
156 | +} | ... | ... |
hw/mcf_uart.c
0 โ 100644
1 | +/* | |
2 | + * ColdFire UART emulation. | |
3 | + * | |
4 | + * Copyright (c) 2007 CodeSourcery. | |
5 | + * | |
6 | + * This code is licenced under the GPL | |
7 | + */ | |
8 | +#include "vl.h" | |
9 | + | |
10 | +typedef struct { | |
11 | + uint8_t mr[2]; | |
12 | + uint8_t sr; | |
13 | + uint8_t isr; | |
14 | + uint8_t imr; | |
15 | + uint8_t bg1; | |
16 | + uint8_t bg2; | |
17 | + uint8_t fifo[4]; | |
18 | + uint8_t tb; | |
19 | + int current_mr; | |
20 | + int fifo_len; | |
21 | + int tx_enabled; | |
22 | + int rx_enabled; | |
23 | + qemu_irq irq; | |
24 | + CharDriverState *chr; | |
25 | +} mcf_uart_state; | |
26 | + | |
27 | +/* UART Status Register bits. */ | |
28 | +#define MCF_UART_RxRDY 0x01 | |
29 | +#define MCF_UART_FFULL 0x02 | |
30 | +#define MCF_UART_TxRDY 0x04 | |
31 | +#define MCF_UART_TxEMP 0x08 | |
32 | +#define MCF_UART_OE 0x10 | |
33 | +#define MCF_UART_PE 0x20 | |
34 | +#define MCF_UART_FE 0x40 | |
35 | +#define MCF_UART_RB 0x80 | |
36 | + | |
37 | +/* Interrupt flags. */ | |
38 | +#define MCF_UART_TxINT 0x01 | |
39 | +#define MCF_UART_RxINT 0x02 | |
40 | +#define MCF_UART_DBINT 0x04 | |
41 | +#define MCF_UART_COSINT 0x80 | |
42 | + | |
43 | +/* UMR1 flags. */ | |
44 | +#define MCF_UART_BC0 0x01 | |
45 | +#define MCF_UART_BC1 0x02 | |
46 | +#define MCF_UART_PT 0x04 | |
47 | +#define MCF_UART_PM0 0x08 | |
48 | +#define MCF_UART_PM1 0x10 | |
49 | +#define MCF_UART_ERR 0x20 | |
50 | +#define MCF_UART_RxIRQ 0x40 | |
51 | +#define MCF_UART_RxRTS 0x80 | |
52 | + | |
53 | +static void mcf_uart_update(mcf_uart_state *s) | |
54 | +{ | |
55 | + s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); | |
56 | + if (s->sr & MCF_UART_TxRDY) | |
57 | + s->isr |= MCF_UART_TxINT; | |
58 | + if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) | |
59 | + ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) | |
60 | + s->isr |= MCF_UART_RxINT; | |
61 | + | |
62 | + qemu_set_irq(s->irq, (s->isr & s->imr) != 0); | |
63 | +} | |
64 | + | |
65 | +uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr) | |
66 | +{ | |
67 | + mcf_uart_state *s = (mcf_uart_state *)opaque; | |
68 | + switch (addr & 0x3f) { | |
69 | + case 0x00: | |
70 | + return s->mr[s->current_mr]; | |
71 | + case 0x04: | |
72 | + return s->sr; | |
73 | + case 0x0c: | |
74 | + { | |
75 | + uint8_t val; | |
76 | + int i; | |
77 | + | |
78 | + if (s->fifo_len == 0) | |
79 | + return 0; | |
80 | + | |
81 | + val = s->fifo[0]; | |
82 | + s->fifo_len--; | |
83 | + for (i = 0; i < s->fifo_len; i++) | |
84 | + s->fifo[i] = s->fifo[i + 1]; | |
85 | + s->sr &= ~MCF_UART_FFULL; | |
86 | + if (s->fifo_len == 0) | |
87 | + s->sr &= ~MCF_UART_RxRDY; | |
88 | + mcf_uart_update(s); | |
89 | + return val; | |
90 | + } | |
91 | + case 0x10: | |
92 | + /* TODO: Implement IPCR. */ | |
93 | + return 0; | |
94 | + case 0x14: | |
95 | + return s->isr; | |
96 | + case 0x18: | |
97 | + return s->bg1; | |
98 | + case 0x1c: | |
99 | + return s->bg2; | |
100 | + default: | |
101 | + return 0; | |
102 | + } | |
103 | +} | |
104 | + | |
105 | +/* Update TxRDY flag and set data if present and enabled. */ | |
106 | +static void mcf_uart_do_tx(mcf_uart_state *s) | |
107 | +{ | |
108 | + if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { | |
109 | + if (s->chr) | |
110 | + qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1); | |
111 | + s->sr |= MCF_UART_TxEMP; | |
112 | + } | |
113 | + if (s->tx_enabled) { | |
114 | + s->sr |= MCF_UART_TxRDY; | |
115 | + } else { | |
116 | + s->sr &= ~MCF_UART_TxRDY; | |
117 | + } | |
118 | +} | |
119 | + | |
120 | +static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) | |
121 | +{ | |
122 | + /* Misc command. */ | |
123 | + switch ((cmd >> 4) & 3) { | |
124 | + case 0: /* No-op. */ | |
125 | + break; | |
126 | + case 1: /* Reset mode register pointer. */ | |
127 | + s->current_mr = 0; | |
128 | + break; | |
129 | + case 2: /* Reset receiver. */ | |
130 | + s->rx_enabled = 0; | |
131 | + s->fifo_len = 0; | |
132 | + s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); | |
133 | + break; | |
134 | + case 3: /* Reset transmitter. */ | |
135 | + s->tx_enabled = 0; | |
136 | + s->sr |= MCF_UART_TxEMP; | |
137 | + s->sr &= ~MCF_UART_TxRDY; | |
138 | + break; | |
139 | + case 4: /* Reset error status. */ | |
140 | + break; | |
141 | + case 5: /* Reset break-change interrupt. */ | |
142 | + s->isr &= ~MCF_UART_DBINT; | |
143 | + break; | |
144 | + case 6: /* Start break. */ | |
145 | + case 7: /* Stop break. */ | |
146 | + break; | |
147 | + } | |
148 | + | |
149 | + /* Transmitter command. */ | |
150 | + switch ((cmd >> 2) & 3) { | |
151 | + case 0: /* No-op. */ | |
152 | + break; | |
153 | + case 1: /* Enable. */ | |
154 | + s->tx_enabled = 1; | |
155 | + mcf_uart_do_tx(s); | |
156 | + break; | |
157 | + case 2: /* Disable. */ | |
158 | + s->tx_enabled = 0; | |
159 | + mcf_uart_do_tx(s); | |
160 | + break; | |
161 | + case 3: /* Reserved. */ | |
162 | + fprintf(stderr, "mcf_uart: Bad TX command\n"); | |
163 | + break; | |
164 | + } | |
165 | + | |
166 | + /* Receiver command. */ | |
167 | + switch (cmd & 3) { | |
168 | + case 0: /* No-op. */ | |
169 | + break; | |
170 | + case 1: /* Enable. */ | |
171 | + s->rx_enabled = 1; | |
172 | + break; | |
173 | + case 2: | |
174 | + s->rx_enabled = 0; | |
175 | + break; | |
176 | + case 3: /* Reserved. */ | |
177 | + fprintf(stderr, "mcf_uart: Bad RX command\n"); | |
178 | + break; | |
179 | + } | |
180 | +} | |
181 | + | |
182 | +void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val) | |
183 | +{ | |
184 | + mcf_uart_state *s = (mcf_uart_state *)opaque; | |
185 | + switch (addr & 0x3f) { | |
186 | + case 0x00: | |
187 | + s->mr[s->current_mr] = val; | |
188 | + s->current_mr = 1; | |
189 | + break; | |
190 | + case 0x04: | |
191 | + /* CSR is ignored. */ | |
192 | + break; | |
193 | + case 0x08: /* Command Register. */ | |
194 | + mcf_do_command(s, val); | |
195 | + break; | |
196 | + case 0x0c: /* Transmit Buffer. */ | |
197 | + s->sr &= ~MCF_UART_TxEMP; | |
198 | + s->tb = val; | |
199 | + mcf_uart_do_tx(s); | |
200 | + break; | |
201 | + case 0x10: | |
202 | + /* ACR is ignored. */ | |
203 | + break; | |
204 | + case 0x14: | |
205 | + s->imr = val; | |
206 | + break; | |
207 | + default: | |
208 | + break; | |
209 | + } | |
210 | + mcf_uart_update(s); | |
211 | +} | |
212 | + | |
213 | +static void mcf_uart_reset(mcf_uart_state *s) | |
214 | +{ | |
215 | + s->fifo_len = 0; | |
216 | + s->mr[0] = 0; | |
217 | + s->mr[1] = 0; | |
218 | + s->sr = MCF_UART_TxEMP; | |
219 | + s->tx_enabled = 0; | |
220 | + s->rx_enabled = 0; | |
221 | + s->isr = 0; | |
222 | + s->imr = 0; | |
223 | +} | |
224 | + | |
225 | +static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) | |
226 | +{ | |
227 | + /* Break events overwrite the last byte if the fifo is full. */ | |
228 | + if (s->fifo_len == 4) | |
229 | + s->fifo_len--; | |
230 | + | |
231 | + s->fifo[s->fifo_len] = data; | |
232 | + s->fifo_len++; | |
233 | + s->sr |= MCF_UART_RxRDY; | |
234 | + if (s->fifo_len == 4) | |
235 | + s->sr |= MCF_UART_FFULL; | |
236 | + | |
237 | + mcf_uart_update(s); | |
238 | +} | |
239 | + | |
240 | +static void mcf_uart_event(void *opaque, int event) | |
241 | +{ | |
242 | + mcf_uart_state *s = (mcf_uart_state *)opaque; | |
243 | + | |
244 | + switch (event) { | |
245 | + case CHR_EVENT_BREAK: | |
246 | + s->isr |= MCF_UART_DBINT; | |
247 | + mcf_uart_push_byte(s, 0); | |
248 | + break; | |
249 | + default: | |
250 | + break; | |
251 | + } | |
252 | +} | |
253 | + | |
254 | +static int mcf_uart_can_receive(void *opaque) | |
255 | +{ | |
256 | + mcf_uart_state *s = (mcf_uart_state *)opaque; | |
257 | + | |
258 | + return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; | |
259 | +} | |
260 | + | |
261 | +static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) | |
262 | +{ | |
263 | + mcf_uart_state *s = (mcf_uart_state *)opaque; | |
264 | + | |
265 | + mcf_uart_push_byte(s, buf[0]); | |
266 | +} | |
267 | + | |
268 | +void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) | |
269 | +{ | |
270 | + mcf_uart_state *s; | |
271 | + | |
272 | + s = qemu_mallocz(sizeof(mcf_uart_state)); | |
273 | + s->chr = chr; | |
274 | + s->irq = irq; | |
275 | + if (chr) { | |
276 | + qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, | |
277 | + mcf_uart_event, s); | |
278 | + } | |
279 | + mcf_uart_reset(s); | |
280 | + return s; | |
281 | +} | |
282 | + | |
283 | + | |
284 | +static CPUReadMemoryFunc *mcf_uart_readfn[] = { | |
285 | + mcf_uart_read, | |
286 | + mcf_uart_read, | |
287 | + mcf_uart_read | |
288 | +}; | |
289 | + | |
290 | +static CPUWriteMemoryFunc *mcf_uart_writefn[] = { | |
291 | + mcf_uart_write, | |
292 | + mcf_uart_write, | |
293 | + mcf_uart_write | |
294 | +}; | |
295 | + | |
296 | +void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, | |
297 | + CharDriverState *chr) | |
298 | +{ | |
299 | + mcf_uart_state *s; | |
300 | + int iomemtype; | |
301 | + | |
302 | + s = mcf_uart_init(irq, chr); | |
303 | + iomemtype = cpu_register_io_memory(0, mcf_uart_readfn, | |
304 | + mcf_uart_writefn, s); | |
305 | + cpu_register_physical_memory(base, 0x40, iomemtype); | |
306 | +} | ... | ... |
target-m68k/cpu.h
... | ... | @@ -59,6 +59,10 @@ typedef struct CPUM68KState { |
59 | 59 | uint32_t pc; |
60 | 60 | uint32_t sr; |
61 | 61 | |
62 | + /* SSP and USP. The current_sp is stored in aregs[7], the other here. */ | |
63 | + int current_sp; | |
64 | + uint32_t sp[2]; | |
65 | + | |
62 | 66 | /* Condition flags. */ |
63 | 67 | uint32_t cc_op; |
64 | 68 | uint32_t cc_dest; |
... | ... | @@ -92,6 +96,7 @@ typedef struct CPUM68KState { |
92 | 96 | uint32_t vbr; |
93 | 97 | uint32_t mbar; |
94 | 98 | uint32_t rambar0; |
99 | + uint32_t cacr; | |
95 | 100 | |
96 | 101 | uint32_t features; |
97 | 102 | |
... | ... | @@ -151,6 +156,12 @@ enum { |
151 | 156 | #define SR_S 0x2000 |
152 | 157 | #define SR_T 0x8000 |
153 | 158 | |
159 | +#define M68K_SSP 0 | |
160 | +#define M68K_USP 1 | |
161 | + | |
162 | +/* CACR fields are implementation defined, but some bits are common. */ | |
163 | +#define M68K_CACR_EUSP 0x10 | |
164 | + | |
154 | 165 | #define MACSR_PAV0 0x100 |
155 | 166 | #define MACSR_OMC 0x080 |
156 | 167 | #define MACSR_SU 0x040 |
... | ... | @@ -167,6 +178,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name); |
167 | 178 | |
168 | 179 | void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); |
169 | 180 | void m68k_set_macsr(CPUM68KState *env, uint32_t val); |
181 | +void m68k_switch_sp(CPUM68KState *env); | |
170 | 182 | |
171 | 183 | #define M68K_FPCR_PREC (1 << 6) |
172 | 184 | |
... | ... | @@ -179,6 +191,7 @@ enum m68k_features { |
179 | 191 | M68K_FEATURE_CF_FPU, |
180 | 192 | M68K_FEATURE_CF_MAC, |
181 | 193 | M68K_FEATURE_CF_EMAC, |
194 | + M68K_FEATURE_USP, | |
182 | 195 | M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ |
183 | 196 | M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ |
184 | 197 | }; | ... | ... |
target-m68k/helper.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | |
29 | 29 | enum m68k_cpuid { |
30 | 30 | M68K_CPUID_M5206, |
31 | + M68K_CPUID_M5208, | |
31 | 32 | M68K_CPUID_CFV4E, |
32 | 33 | M68K_CPUID_ANY, |
33 | 34 | }; |
... | ... | @@ -39,6 +40,7 @@ struct m68k_def_t { |
39 | 40 | |
40 | 41 | static m68k_def_t m68k_cpu_defs[] = { |
41 | 42 | {"m5206", M68K_CPUID_M5206}, |
43 | + {"m5208", M68K_CPUID_M5208}, | |
42 | 44 | {"cfv4e", M68K_CPUID_CFV4E}, |
43 | 45 | {"any", M68K_CPUID_ANY}, |
44 | 46 | {NULL, 0}, |
... | ... | @@ -64,12 +66,18 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
64 | 66 | case M68K_CPUID_M5206: |
65 | 67 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
66 | 68 | break; |
69 | + case M68K_CPUID_M5208: | |
70 | + m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); | |
71 | + m68k_set_feature(env, M68K_FEATURE_CF_EMAC); | |
72 | + m68k_set_feature(env, M68K_FEATURE_USP); | |
73 | + break; | |
67 | 74 | case M68K_CPUID_CFV4E: |
68 | 75 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
69 | 76 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
70 | 77 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
71 | 78 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
72 | 79 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
80 | + m68k_set_feature(env, M68K_FEATURE_USP); | |
73 | 81 | break; |
74 | 82 | case M68K_CPUID_ANY: |
75 | 83 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
... | ... | @@ -79,6 +87,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
79 | 87 | /* MAC and EMAC are mututally exclusive, so pick EMAC. |
80 | 88 | It's mostly backwards compatible. */ |
81 | 89 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
90 | + m68k_set_feature(env, M68K_FEATURE_USP); | |
82 | 91 | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); |
83 | 92 | break; |
84 | 93 | } |
... | ... | @@ -215,7 +224,11 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val) |
215 | 224 | { |
216 | 225 | switch (reg) { |
217 | 226 | case 0x02: /* CACR */ |
218 | - /* Ignored. */ | |
227 | + env->cacr = val; | |
228 | + m68k_switch_sp(env); | |
229 | + break; | |
230 | + case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ | |
231 | + /* TODO: Implement Access Control Registers. */ | |
219 | 232 | break; |
220 | 233 | case 0x801: /* VBR */ |
221 | 234 | env->vbr = val; |
... | ... | @@ -261,6 +274,17 @@ void m68k_set_macsr(CPUM68KState *env, uint32_t val) |
261 | 274 | env->macsr = val; |
262 | 275 | } |
263 | 276 | |
277 | +void m68k_switch_sp(CPUM68KState *env) | |
278 | +{ | |
279 | + int new_sp; | |
280 | + | |
281 | + env->sp[env->current_sp] = env->aregs[7]; | |
282 | + new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) | |
283 | + ? M68K_SSP : M68K_USP; | |
284 | + env->aregs[7] = env->sp[new_sp]; | |
285 | + env->current_sp = new_sp; | |
286 | +} | |
287 | + | |
264 | 288 | /* MMU */ |
265 | 289 | |
266 | 290 | /* TODO: This will need fixing once the MMU is implemented. */ | ... | ... |
target-m68k/op.c
target-m68k/op_helper.c
... | ... | @@ -87,6 +87,7 @@ static void do_rte(void) |
87 | 87 | env->pc = ldl_kernel(sp + 4); |
88 | 88 | sp |= (fmt >> 28) & 3; |
89 | 89 | env->sr = fmt & 0xffff; |
90 | + m68k_switch_sp(env); | |
90 | 91 | env->aregs[7] = sp + 8; |
91 | 92 | } |
92 | 93 | |
... | ... | @@ -128,9 +129,6 @@ void do_interrupt(int is_hw) |
128 | 129 | } |
129 | 130 | } |
130 | 131 | |
131 | - /* TODO: Implement USP. */ | |
132 | - sp = env->aregs[7]; | |
133 | - | |
134 | 132 | vector = env->exception_index << 2; |
135 | 133 | |
136 | 134 | fmt |= 0x40000000; |
... | ... | @@ -138,6 +136,15 @@ void do_interrupt(int is_hw) |
138 | 136 | fmt |= vector << 16; |
139 | 137 | fmt |= env->sr; |
140 | 138 | |
139 | + env->sr |= SR_S; | |
140 | + if (is_hw) { | |
141 | + env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); | |
142 | + env->sr &= ~SR_M; | |
143 | + } | |
144 | + m68k_switch_sp(env); | |
145 | + | |
146 | + sp = env->aregs[7]; | |
147 | + | |
141 | 148 | /* ??? This could cause MMU faults. */ |
142 | 149 | sp &= ~3; |
143 | 150 | sp -= 4; |
... | ... | @@ -145,11 +152,6 @@ void do_interrupt(int is_hw) |
145 | 152 | sp -= 4; |
146 | 153 | stl_kernel(sp, fmt); |
147 | 154 | env->aregs[7] = sp; |
148 | - env->sr |= SR_S; | |
149 | - if (is_hw) { | |
150 | - env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); | |
151 | - env->sr &= ~SR_M; | |
152 | - } | |
153 | 155 | /* Jump to vector. */ |
154 | 156 | env->pc = ldl_kernel(env->vbr + vector); |
155 | 157 | } | ... | ... |
target-m68k/translate.c
... | ... | @@ -1345,7 +1345,7 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) |
1345 | 1345 | gen_op_logic_cc(gen_im32(val & 0xf)); |
1346 | 1346 | gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); |
1347 | 1347 | if (!ccr_only) { |
1348 | - gen_op_mov32(QREG_SR, gen_im32(val & 0xff00)); | |
1348 | + gen_op_set_sr(gen_im32(val & 0xff00)); | |
1349 | 1349 | } |
1350 | 1350 | } |
1351 | 1351 | |
... | ... | @@ -1365,7 +1365,7 @@ static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) |
1365 | 1365 | gen_op_and32(src1, src1, gen_im32(1)); |
1366 | 1366 | gen_op_update_xflag_tst(src1); |
1367 | 1367 | if (!ccr_only) { |
1368 | - gen_op_and32(QREG_SR, reg, gen_im32(0xff00)); | |
1368 | + gen_op_set_sr(reg); | |
1369 | 1369 | } |
1370 | 1370 | } |
1371 | 1371 | else if ((insn & 0x3f) == 0x3c) |
... | ... | @@ -2797,8 +2797,8 @@ void register_m68k_insns (CPUM68KState *env) |
2797 | 2797 | INSN(trap, 4e40, fff0, CF_ISA_A); |
2798 | 2798 | INSN(link, 4e50, fff8, CF_ISA_A); |
2799 | 2799 | INSN(unlk, 4e58, fff8, CF_ISA_A); |
2800 | - INSN(move_to_usp, 4e60, fff8, CF_ISA_B); | |
2801 | - INSN(move_from_usp, 4e68, fff8, CF_ISA_B); | |
2800 | + INSN(move_to_usp, 4e60, fff8, USP); | |
2801 | + INSN(move_from_usp, 4e68, fff8, USP); | |
2802 | 2802 | INSN(nop, 4e71, ffff, CF_ISA_A); |
2803 | 2803 | INSN(stop, 4e72, ffff, CF_ISA_A); |
2804 | 2804 | INSN(rte, 4e73, ffff, CF_ISA_A); |
... | ... | @@ -3261,6 +3261,7 @@ void cpu_reset(CPUM68KState *env) |
3261 | 3261 | #if !defined (CONFIG_USER_ONLY) |
3262 | 3262 | env->sr = 0x2700; |
3263 | 3263 | #endif |
3264 | + m68k_switch_sp(env); | |
3264 | 3265 | /* ??? FP regs should be initialized to NaN. */ |
3265 | 3266 | env->cc_op = CC_OP_FLAGS; |
3266 | 3267 | /* TODO: We should set PC from the interrupt vector. */ | ... | ... |
vl.c
... | ... | @@ -6972,6 +6972,7 @@ void register_machines(void) |
6972 | 6972 | #elif defined(TARGET_ALPHA) |
6973 | 6973 | /* XXX: TODO */ |
6974 | 6974 | #elif defined(TARGET_M68K) |
6975 | + qemu_register_machine(&mcf5208evb_machine); | |
6975 | 6976 | qemu_register_machine(&an5206_machine); |
6976 | 6977 | #else |
6977 | 6978 | #error unsupported CPU | ... | ... |
vl.h
... | ... | @@ -1593,12 +1593,25 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); |
1593 | 1593 | |
1594 | 1594 | #include "hw/pxa.h" |
1595 | 1595 | |
1596 | +/* mcf_uart.c */ | |
1597 | +uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); | |
1598 | +void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); | |
1599 | +void *mcf_uart_init(qemu_irq irq, CharDriverState *chr); | |
1600 | +void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, | |
1601 | + CharDriverState *chr); | |
1602 | + | |
1603 | +/* mcf_intc.c */ | |
1604 | +qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env); | |
1605 | + | |
1596 | 1606 | /* mcf5206.c */ |
1597 | 1607 | qemu_irq *mcf5206_init(uint32_t base, CPUState *env); |
1598 | 1608 | |
1599 | 1609 | /* an5206.c */ |
1600 | 1610 | extern QEMUMachine an5206_machine; |
1601 | 1611 | |
1612 | +/* mcf5208.c */ | |
1613 | +extern QEMUMachine mcf5208evb_machine; | |
1614 | + | |
1602 | 1615 | #include "gdbstub.h" |
1603 | 1616 | |
1604 | 1617 | #endif /* defined(QEMU_TOOL) */ | ... | ... |