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