fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 554 lines 12 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/simarm/simarm.c * 7 * Created: 2004-11-04 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2004-2011 Hampa Hug <hampa@hampa.ch> * 9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> * 10 *****************************************************************************/ 11 12/***************************************************************************** 13 * This program is free software. You can redistribute it and / or modify it * 14 * under the terms of the GNU General Public License version 2 as published * 15 * by the Free Software Foundation. * 16 * * 17 * This program is distributed in the hope that it will be useful, but * 18 * WITHOUT ANY WARRANTY, without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 20 * Public License for more details. * 21 *****************************************************************************/ 22 23/***************************************************************************** 24 * This software was developed at the Computer Engineering and Networks * 25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. * 26 *****************************************************************************/ 27 28 29#include "main.h" 30#include "intc.h" 31#include "pci.h" 32#include "sercons.h" 33#include "simarm.h" 34#include "timer.h" 35 36#include <stdlib.h> 37#include <string.h> 38 39#include <lib/iniata.h> 40#include <lib/inidsk.h> 41#include <lib/iniram.h> 42#include <lib/load.h> 43#include <lib/log.h> 44#include <lib/msg.h> 45#include <lib/sysdep.h> 46 47 48void sarm_break (simarm_t *sim, unsigned char val); 49 50 51static 52void sarm_setup_cpu (simarm_t *sim, ini_sct_t *ini) 53{ 54 ini_sct_t *sct; 55 const char *model; 56 unsigned long id; 57 58 sct = ini_next_sct (ini, NULL, "cpu"); 59 60 ini_get_string (sct, "model", &model, "armv5"); 61 ini_get_bool (sct, "bigendian", &sim->bigendian, 1); 62 63 if (strcmp (model, "xscale") == 0) { 64 id = 0x69052000; 65 } 66 else if (strcmp (model, "ixp2400") == 0) { 67 id = 0x69054190; 68 } 69 else { 70 id = 0x69054190; 71 } 72 73 ini_get_uint32 (sct, "id", &id, id); 74 75 pce_log_tag (MSG_INF, "CPU:", "model=%s id=0x%08lx endian=%s\n", 76 model, id, sim->bigendian ? "big" : "little" 77 ); 78 79 sim->cpu = arm_new(); 80 if (sim->cpu == NULL) { 81 return; 82 } 83 84 arm_set_flags (sim->cpu, ARM_FLAG_XSCALE, 1); 85 arm_set_flags (sim->cpu, ARM_FLAG_BIGENDIAN, sim->bigendian); 86 87 arm_set_id (sim->cpu, id); 88 89 if (sim->bigendian) { 90 arm_set_mem_fct (sim->cpu, sim->mem, 91 &mem_get_uint8, 92 &mem_get_uint16_be, 93 &mem_get_uint32_be, 94 &mem_set_uint8, 95 &mem_set_uint16_be, 96 &mem_set_uint32_be 97 ); 98 } 99 else { 100 arm_set_mem_fct (sim->cpu, sim->mem, 101 &mem_get_uint8, 102 &mem_get_uint16_le, 103 &mem_get_uint32_le, 104 &mem_set_uint8, 105 &mem_set_uint16_le, 106 &mem_set_uint32_le 107 ); 108 } 109 110 if (sim->ram != NULL) { 111 arm_set_ram (sim->cpu, mem_blk_get_data (sim->ram), mem_blk_get_size (sim->ram)); 112 } 113} 114 115static 116void sarm_setup_intc (simarm_t *sim, ini_sct_t *ini) 117{ 118 unsigned long addr; 119 ini_sct_t *sct; 120 121 sct = ini_next_sct (ini, NULL, "intc"); 122 123 ini_get_uint32 (sct, "address", &addr, 0xd6000000); 124 125 sim->intc = ict_new (addr); 126 if (sim->intc == NULL) { 127 return; 128 } 129 130 ict_set_fiq_f (sim->intc, arm_set_fiq, sim->cpu); 131 ict_set_irq_f (sim->intc, arm_set_irq, sim->cpu); 132 133 mem_add_blk (sim->mem, ict_get_io (sim->intc, 0), 0); 134 135 pce_log_tag (MSG_INF, "INTC:", "addr=0x%08lx\n", addr); 136} 137 138static 139void sarm_setup_timer (simarm_t *sim, ini_sct_t *ini) 140{ 141 unsigned long addr; 142 ini_sct_t *sct; 143 144 sct = ini_next_sct (ini, NULL, "timer"); 145 146 ini_get_uint32 (sct, "address", &addr, 0xc0020000); 147 148 sim->timer = tmr_new (addr); 149 if (sim->timer == NULL) { 150 return; 151 } 152 153 tmr_set_irq_f (sim->timer, 0, ict_set_irq4, sim->intc); 154 tmr_set_irq_f (sim->timer, 1, ict_set_irq5, sim->intc); 155 tmr_set_irq_f (sim->timer, 2, ict_set_irq6, sim->intc); 156 tmr_set_irq_f (sim->timer, 3, ict_set_irq7, sim->intc); 157 158 mem_add_blk (sim->mem, tmr_get_io (sim->timer, 0), 0); 159 160 sim->rclk_interval = 0; 161 162 pce_log_tag (MSG_INF, "TIMER:", "addr=0x%08lx\n", addr); 163} 164 165static 166void sarm_setup_serport (simarm_t *sim, ini_sct_t *ini) 167{ 168 unsigned i; 169 unsigned long addr; 170 unsigned irq; 171 unsigned multichar; 172 const char *driver; 173 const char *chip; 174 ini_sct_t *sct; 175 serport_t *ser; 176 e8250_t *uart; 177 178 sim->serport[0] = NULL; 179 sim->serport[1] = NULL; 180 181 i = 0; 182 sct = NULL; 183 184 while ((i < 2) && (sct = ini_next_sct (ini, sct, "serial")) != NULL) { 185 ini_get_uint32 (sct, "address", &addr, 0xc0030000); 186 ini_get_uint16 (sct, "irq", &irq, 2); 187 ini_get_uint16 (sct, "multichar", &multichar, 1); 188 ini_get_string (sct, "uart", &chip, "8250"); 189 ini_get_string (sct, "driver", &driver, NULL); 190 191 pce_log_tag (MSG_INF, "UART:", 192 "n=%u addr=0x%08lx irq=%u uart=%s multi=%u driver=%s\n", 193 i, addr, irq, chip, multichar, 194 (driver == NULL) ? "<none>" : driver 195 ); 196 197 ser = ser_new (addr, 2); 198 199 if (ser == NULL) { 200 pce_log (MSG_ERR, 201 "*** serial port setup failed [%08lX/%u -> %s]\n", 202 addr, irq, (driver == NULL) ? "<none>" : driver 203 ); 204 } 205 else { 206 sim->serport[i] = ser; 207 208 uart = ser_get_uart (ser); 209 210 if (driver != NULL) { 211 if (ser_set_driver (ser, driver)) { 212 pce_log (MSG_ERR, 213 "*** can't open driver (%s)\n", 214 driver 215 ); 216 } 217 } 218 219 e8250_set_buf_size (uart, 256, 256); 220 e8250_set_multichar (uart, multichar, multichar); 221 222 if (e8250_set_chip_str (uart, chip)) { 223 pce_log (MSG_ERR, 224 "*** unknown UART chip (%s)\n", chip 225 ); 226 } 227 228 e8250_set_irq_fct (uart, 229 sim->intc, ict_get_irq_f (sim->intc, irq) 230 ); 231 232 mem_add_blk (sim->mem, ser_get_reg (ser), 0); 233 234 i += 1; 235 } 236 } 237} 238 239static 240void sarm_setup_console (simarm_t *sim, ini_sct_t *ini) 241{ 242 unsigned ser; 243 ini_sct_t *sct; 244 245 sct = ini_next_sct (ini, NULL, "console"); 246 247 if (sct == NULL) { 248 ser = 0; 249 } 250 else { 251 ini_get_uint16 (sct, "serial", &ser, 0); 252 } 253 254 pce_log_tag (MSG_INF, "CONSOLE:", "serport=%u\n", ser); 255 256 if ((ser >= 2) || (sim->serport[ser] == NULL)) { 257 pce_log (MSG_ERR, "*** no serial port (%u)\n", ser); 258 return; 259 } 260 261 sim->sercons = ser; 262} 263 264static 265void sarm_setup_disks (simarm_t *sim, ini_sct_t *ini) 266{ 267 sim->dsks = ini_get_disks (ini); 268} 269 270static 271void sarm_setup_pci (simarm_t *sim, ini_sct_t *ini) 272{ 273 unsigned irq; 274 ini_sct_t *sct; 275 276 sct = ini_next_sct (ini, NULL, "pci"); 277 278 ini_get_uint16 (sct, "irq", &irq, 15); 279 280 pce_log_tag (MSG_INF, "PCI:", "irq=%u\n", irq); 281 282 sim->pci = pci_ixp_new(); 283 284 pci_ixp_set_endian (sim->pci, sim->bigendian); 285 286 pci_ixp_set_irq_fct (sim->pci, sim->intc, ict_get_irq_f (sim->intc, irq)); 287 288 mem_add_blk (sim->mem, pci_ixp_get_mem_io (sim->pci), 0); 289 mem_add_blk (sim->mem, pci_ixp_get_mem_cfg (sim->pci), 0); 290 mem_add_blk (sim->mem, pci_ixp_get_mem_special (sim->pci), 0); 291 mem_add_blk (sim->mem, pci_ixp_get_mem_pcicfg (sim->pci), 0); 292 mem_add_blk (sim->mem, pci_ixp_get_mem_csr (sim->pci), 0); 293 mem_add_blk (sim->mem, pci_ixp_get_mem_mem (sim->pci), 0); 294} 295 296static 297void sarm_setup_ata (simarm_t *sim, ini_sct_t *ini) 298{ 299 unsigned dev, irq; 300 ini_sct_t *sct; 301 302 pci_ata_init (&sim->pciata); 303 304 sct = ini_next_sct (ini, NULL, "pci_ata"); 305 306 if (sct == NULL) { 307 return; 308 } 309 310 ini_get_uint16 (sct, "pci_device", &dev, 1); 311 ini_get_uint16 (sct, "pci_irq", &irq, 255); 312 313 pce_log_tag (MSG_INF, "PCI-ATA:", "device=%u\n", dev); 314 315 if (irq < 32) { 316 pce_log_tag (MSG_INF, "PCI-ATA:", "irq=%u\n", irq); 317 } 318 319 pci_ixp_add_device (sim->pci, &sim->pciata.pci); 320 pci_set_device (&sim->pci->bus, &sim->pciata.pci, dev); 321 322 /* 323 * If an irq is specified, the ATA PCI interrupt is connected 324 * directly to the interrupt controller instead of PCI INT A. 325 * This is a hack and should not be used. 326 */ 327 if (irq < 32) { 328 pci_dev_set_intr_fct (&sim->pciata.pci, 0, 329 sim->intc, ict_get_irq_f (sim->intc, irq) 330 ); 331 } 332 else { 333 pci_dev_set_intr_fct (&sim->pciata.pci, 0, 334 sim->pci, pci_ixp_set_int_a 335 ); 336 } 337 338 ini_get_pci_ata (&sim->pciata, sim->dsks, sct); 339} 340 341simarm_t *sarm_new (ini_sct_t *ini) 342{ 343 unsigned i; 344 simarm_t *sim; 345 346 sim = malloc (sizeof (simarm_t)); 347 if (sim == NULL) { 348 return (NULL); 349 } 350 351 sim->ram = NULL; 352 sim->brk = 0; 353 sim->clk_cnt = 0; 354 355 sim->sercons = 0; 356 357 for (i = 0; i < 4; i++) { 358 sim->clk_div[i] = 0; 359 } 360 361 sim->cfg = ini; 362 363 bps_init (&sim->bps); 364 365 sim->mem = mem_new(); 366 367 ini_get_ram (sim->mem, ini, &sim->ram); 368 ini_get_rom (sim->mem, ini); 369 370 sarm_setup_cpu (sim, ini); 371 sarm_setup_intc (sim, ini); 372 sarm_setup_timer (sim, ini); 373 sarm_setup_serport (sim, ini); 374 sarm_setup_console (sim, ini); 375 sarm_setup_disks (sim, ini); 376 sarm_setup_pci (sim, ini); 377 sarm_setup_ata (sim, ini); 378 379 pce_load_mem_ini (sim->mem, ini); 380 381 return (sim); 382} 383 384void sarm_del (simarm_t *sim) 385{ 386 if (sim == NULL) { 387 return; 388 } 389 390 pci_ata_free (&sim->pciata); 391 pci_ixp_del (sim->pci); 392 393 dsks_del (sim->dsks); 394 395 ser_del (sim->serport[1]); 396 ser_del (sim->serport[0]); 397 398 tmr_del (sim->timer); 399 ict_del (sim->intc); 400 401 arm_del (sim->cpu); 402 403 mem_del (sim->mem); 404 405 bps_free (&sim->bps); 406 407 free (sim); 408} 409 410unsigned long long sarm_get_clkcnt (simarm_t *sim) 411{ 412 return (sim->clk_cnt); 413} 414 415void sarm_break (simarm_t *sim, unsigned char val) 416{ 417 if ((val == PCE_BRK_STOP) || (val == PCE_BRK_ABORT)) { 418 sim->brk = val; 419 } 420} 421 422void sarm_set_keycode (simarm_t *sim, unsigned char val) 423{ 424 if (sim->serport[sim->sercons] != NULL) { 425 ser_receive (sim->serport[sim->sercons], val); 426 } 427} 428 429void sarm_clock_discontinuity (simarm_t *sim) 430{ 431 pce_get_interval_us (&sim->rclk_interval); 432} 433 434void sarm_reset (simarm_t *sim) 435{ 436 arm_reset (sim->cpu); 437} 438 439void sarm_clock (simarm_t *sim, unsigned n) 440{ 441 unsigned long clk, rclk; 442 443 arm_clock (sim->cpu, n); 444 445 sim->clk_cnt += n; 446 sim->clk_div[0] += n; 447 448 if (sim->clk_div[0] < 256) { 449 return; 450 } 451 452 clk = sim->clk_div[0] & ~255UL; 453 sim->clk_div[1] += clk; 454 sim->clk_div[0] &= 255; 455 456 if (sim->serport[0] != NULL) { 457 e8250_clock (&sim->serport[0]->uart, clk / 4); 458 } 459 460 if (sim->serport[1] != NULL) { 461 e8250_clock (&sim->serport[1]->uart, clk / 4); 462 } 463 464 if (sim->clk_div[1] < 4096) { 465 return; 466 } 467 468 clk = sim->clk_div[1] & ~4095UL; 469 sim->clk_div[2] += clk; 470 sim->clk_div[1] &= 4095; 471 472 rclk = pce_get_interval_us (&sim->rclk_interval); 473 474 tmr_clock (sim->timer, 50 * rclk); 475 476 if (sim->serport[0] != NULL) { 477 ser_clock (sim->serport[0], clk); 478 } 479 480 if (sim->serport[1] != NULL) { 481 ser_clock (sim->serport[1], clk); 482 } 483 484 if (sim->clk_div[2] < 16384) { 485 return; 486 } 487 488 sim->clk_div[2] &= 16383; 489 490 scon_check (sim); 491} 492 493int sarm_set_msg (simarm_t *sim, const char *msg, const char *val) 494{ 495 /* a hack, for debugging only */ 496 if (sim == NULL) { 497 sim = par_sim; 498 } 499 500 if (msg == NULL) { 501 msg = ""; 502 } 503 504 if (val == NULL) { 505 val = ""; 506 } 507 508 if (msg_is_prefix ("term", msg)) { 509 return (1); 510 } 511 512 if (msg_is_message ("emu.stop", msg)) { 513 sim->brk = PCE_BRK_STOP; 514 return (0); 515 } 516 else if (strcmp (msg, "emu.exit") == 0) { 517 sim->brk = PCE_BRK_ABORT; 518 return (0); 519 } 520 521 pce_log (MSG_DEB, "msg (\"%s\", \"%s\")\n", msg, val); 522 523 if (msg_is_message ("disk.commit", msg)) { 524 if (strcmp (val, "") == 0) { 525 if (dsks_commit (sim->dsks)) { 526 pce_log (MSG_ERR, "commit failed for at least one disk\n"); 527 return (1); 528 } 529 } 530 else { 531 unsigned d; 532 533 d = strtoul (val, NULL, 0); 534 535 if (dsks_set_msg (sim->dsks, d, "commit", NULL)) { 536 pce_log (MSG_ERR, "commit failed (%s)\n", val); 537 return (1); 538 } 539 } 540 541 return (0); 542 } 543 else if (msg_is_message ("emu.config.save", msg)) { 544 if (ini_write (val, sim->cfg)) { 545 return (1); 546 } 547 548 return (0); 549 } 550 551 pce_log (MSG_INF, "unhandled message (\"%s\", \"%s\")\n", msg, val); 552 553 return (1); 554}