fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 731 lines 16 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/sim405/sim405.c * 7 * Created: 2004-06-01 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2004-2018 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 31#include <stdlib.h> 32 33#include "hook.h" 34#include "msg.h" 35#include "pci.h" 36#include "sercons.h" 37#include "sim405.h" 38 39#include <chipset/clock/ds1743.h> 40 41#include <chipset/82xx/e8250.h> 42 43#include <cpu/ppc405/ppc405.h> 44 45#include <devices/clock/ds1743.h> 46#include <devices/pci.h> 47#include <devices/serport.h> 48#include <devices/slip.h> 49 50#include <lib/brkpt.h> 51#include <lib/log.h> 52#include <lib/iniata.h> 53#include <lib/inidsk.h> 54#include <lib/iniram.h> 55#include <lib/load.h> 56#include <lib/sysdep.h> 57 58#include <libini/libini.h> 59 60 61#define S405_CLOCK (200UL * 1000UL * 1000UL) 62 63 64static unsigned long s405_get_dcr (void *ext, unsigned long dcrn); 65static void s405_set_dcr (void *ext, unsigned long dcrn, unsigned long val); 66 67void s405_break (sim405_t *sim, unsigned char val); 68 69 70static 71void s405_setup_system (sim405_t *sim, ini_sct_t *ini) 72{ 73 ini_sct_t *sct; 74 const char *model; 75 unsigned long uicinv; 76 unsigned long serial_clock; 77 int sync_time_base; 78 79 sct = ini_next_sct (ini, NULL, "system"); 80 81 if (sct == NULL) { 82 sct = ini_next_sct (ini, NULL, "powerpc"); 83 } 84 85 ini_get_string (sct, "model", &model, "ppc405"); 86 ini_get_uint32 (sct, "uic_invert", &uicinv, 0x0000007f); 87 ini_get_uint32 (sct, "serial_clock", &serial_clock, 115200); 88 ini_get_bool (sct, "sync_time_base", &sync_time_base, 1); 89 90 pce_log_tag (MSG_INF, "CPU:", "model=%s uic-inv=%08lX sync_time_base=%d\n", 91 model, uicinv, sync_time_base 92 ); 93 94 sim->ppc = p405_new (); 95 96 sim->sync_time_base = (sync_time_base != 0); 97 98 p405_set_mem_fct (sim->ppc, sim->mem, 99 &mem_get_uint8, 100 &mem_get_uint16_be, 101 &mem_get_uint32_be, 102 &mem_set_uint8, 103 &mem_set_uint16_be, 104 &mem_set_uint32_be 105 ); 106 107 if (sim->ram != NULL) { 108 p405_set_ram (sim->ppc, mem_blk_get_data (sim->ram), mem_blk_get_size (sim->ram)); 109 } 110 111 p405_set_dcr_fct (sim->ppc, sim, &s405_get_dcr, &s405_set_dcr); 112 113 p405uic_init (&sim->uic); 114 p405uic_set_invert (&sim->uic, uicinv); 115 p405uic_set_nint_fct (&sim->uic, sim->ppc, p405_interrupt); 116 117 if (serial_clock > 0) { 118 pce_log_tag (MSG_INF, "SERIAL:", "clock=%lu (%lu)\n", 119 serial_clock, 16 * serial_clock 120 ); 121 122 sim->serial_clock = 16 * serial_clock; 123 } 124} 125 126static 127void s405_setup_serport (sim405_t *sim, ini_sct_t *ini) 128{ 129 unsigned i; 130 unsigned long addr; 131 unsigned irq; 132 unsigned multichar, clock_mul; 133 const char *driver; 134 const char *chip; 135 ini_sct_t *sct; 136 137 static unsigned long defbase[2] = { 0xef600300, 0xef600400 }; 138 static unsigned defirq[2] = { 0, 1 }; 139 140 141 sim->serport[0] = NULL; 142 sim->serport[1] = NULL; 143 144 i = 0; 145 sct = NULL; 146 while ((sct = ini_next_sct (ini, sct, "serial")) != NULL) { 147 if (i >= 2) { 148 break; 149 } 150 151 ini_get_uint32 (sct, "address", &addr, defbase[i]); 152 ini_get_uint16 (sct, "irq", &irq, defirq[i]); 153 ini_get_string (sct, "uart", &chip, "8250"); 154 ini_get_uint16 (sct, "multichar", &multichar, 1); 155 ini_get_uint16 (sct, "clock_mul", &clock_mul, 1); 156 ini_get_string (sct, "driver", &driver, NULL); 157 158 pce_log_tag (MSG_INF, "UART:", 159 "n=%u addr=0x%08lx irq=%u uart=%s multi=%u clock_mul=%u driver=%s\n", 160 i, addr, irq, chip, multichar, clock_mul, 161 (driver == NULL) ? "<none>" : driver 162 ); 163 164 sim->serport[i] = ser_new (addr, 0); 165 166 if (sim->serport[i] == NULL) { 167 pce_log (MSG_ERR, 168 "*** serial port setup failed [%08lX/%u -> %s]\n", 169 addr, irq, (driver == NULL) ? "<none>" : driver 170 ); 171 } 172 else { 173 e8250_t *uart; 174 175 if (driver != NULL) { 176 if (ser_set_driver (sim->serport[i], driver)) { 177 pce_log (MSG_ERR, "*** can't open driver (%s)\n", driver); 178 } 179 } 180 181 uart = &sim->serport[i]->uart; 182 183 e8250_set_buf_size (uart, 256, 256); 184 e8250_set_multichar (uart, multichar, multichar); 185 e8250_set_clock_mul (uart, clock_mul); 186 e8250_set_bit_clk_div (uart, (S405_CLOCK / 16) / sim->serial_clock); 187 188 if (e8250_set_chip_str (uart, chip)) { 189 pce_log (MSG_ERR, "*** unknown UART chip (%s)\n", chip); 190 } 191 192 e8250_set_irq_fct (uart, 193 &sim->uic, p405uic_get_irq_fct (&sim->uic, irq) 194 ); 195 196 p405uic_set_force_polarity (&sim->uic, irq, 1); 197 198 mem_add_blk (sim->mem, ser_get_reg (sim->serport[i]), 0); 199 200 i += 1; 201 } 202 } 203} 204 205static 206void s405_setup_sercons (sim405_t *sim, ini_sct_t *ini) 207{ 208 ini_sct_t *sct; 209 unsigned ser; 210 211 sct = ini_next_sct (ini, NULL, "sercons"); 212 213 if (sct == NULL) { 214 ser = 0; 215 } 216 else { 217 ini_get_uint16 (sct, "serial", &ser, 0); 218 } 219 220 pce_log_tag (MSG_INF, "CONSOLE:", "serport=%u\n", ser); 221 222 if (ser >= 2) { 223 return; 224 } 225 226 sim->sercons = ser; 227} 228 229static 230void s405_setup_slip (sim405_t *sim, ini_sct_t *ini) 231{ 232 ini_sct_t *sct; 233 unsigned ser; 234 const char *name; 235 e8250_t *uart; 236 237 sct = ini_next_sct (ini, NULL, "slip"); 238 if (sct == NULL) { 239 return; 240 } 241 242 ini_get_uint16 (sct, "serial", &ser, 0); 243 ini_get_string (sct, "interface", &name, "tun0"); 244 245 pce_log_tag (MSG_INF, "SLIP:", "serport=%u interface=%s\n", ser, name); 246 247 if (ser >= 2) { 248 return; 249 } 250 251 if (sim->serport[ser] == NULL) { 252 return; 253 } 254 255 sim->slip = slip_new(); 256 if (sim->slip == NULL) { 257 return; 258 } 259 260 uart = ser_get_uart (sim->serport[ser]); 261 262 e8250_set_send_fct (uart, sim->slip, slip_uart_check_out); 263 e8250_set_recv_fct (uart, sim->slip, slip_uart_check_inp); 264 e8250_set_setup_fct (uart, NULL, NULL); 265 266 slip_set_get_uint8_fct (sim->slip, uart, e8250_send); 267 slip_set_set_uint8_fct (sim->slip, uart, e8250_receive); 268 269 if (slip_set_tun (sim->slip, name)) { 270 pce_log (MSG_ERR, "*** creating tun interface failed (%s)\n", name); 271 } 272} 273 274static 275void s405_setup_disks (sim405_t *sim, ini_sct_t *ini) 276{ 277 sim->dsks = ini_get_disks (ini); 278} 279 280static 281void s405_setup_pci (sim405_t *sim, ini_sct_t *ini) 282{ 283 sim->pci = s405_pci_new(); 284 285 mem_add_blk (sim->mem, s405_pci_get_mem_ioa (sim->pci), 0); 286 mem_add_blk (sim->mem, s405_pci_get_mem_iob (sim->pci), 0); 287 mem_add_blk (sim->mem, s405_pci_get_mem_cfg (sim->pci), 0); 288 mem_add_blk (sim->mem, s405_pci_get_mem_special (sim->pci), 0); 289 mem_add_blk (sim->mem, s405_pci_get_mem_csr (sim->pci), 0); 290 291 pce_log_tag (MSG_INF, "PCI:", "initialized\n"); 292} 293 294static 295void s405_setup_ata (sim405_t *sim, ini_sct_t *ini) 296{ 297 unsigned pcidev, pciirq; 298 unsigned long vendor_id, device_id; 299 ini_sct_t *sct; 300 301 pci_ata_init (&sim->pciata); 302 303 sct = ini_next_sct (ini, NULL, "pci_ata"); 304 if (sct == NULL) { 305 return; 306 } 307 308 ini_get_uint16 (sct, "pci_device", &pcidev, 1); 309 ini_get_uint16 (sct, "pci_irq", &pciirq, 31); 310 311 ini_get_uint32 (sct, "vendor_id", &vendor_id, PCIID_VENDOR_VIA); 312 ini_get_uint32 (sct, "device_id", &device_id, PCIID_VIA_82C561); 313 314 pce_log_tag (MSG_INF, "PCI-ATA:", 315 "pcidev=%u irq=%u vendor=0x%04lx id=0x%04lx\n", 316 pcidev, pciirq, vendor_id, device_id 317 ); 318 319 pci_dev_set_device_id (&sim->pciata.pci, vendor_id, device_id); 320 321 pci_set_device (&sim->pci->bus, &sim->pciata.pci, pcidev); 322 pci_dev_set_intr_fct (&sim->pciata.pci, 0, 323 &sim->uic, p405uic_get_irq_fct (&sim->uic, pciirq) 324 ); 325 326 ini_get_pci_ata (&sim->pciata, sim->dsks, sct); 327} 328 329static 330void s405_setup_ds1743 (sim405_t *sim, ini_sct_t *sct) 331{ 332 unsigned long addr, size; 333 const char *fname; 334 dev_ds1743_t *rtc; 335 336 ini_get_uint32 (sct, "address", &addr, 0xf0000000); 337 ini_get_uint32 (sct, "size", &size, 8192); 338 ini_get_string (sct, "file", &fname, NULL); 339 340 pce_log_tag (MSG_INF, "DS1743:", "addr=0x%08lx size=%lu file=%s\n", 341 addr, size, (fname != NULL) ? fname : "<none>" 342 ); 343 344 rtc = dev_ds1743_new (addr, size); 345 if (rtc == NULL) { 346 return; 347 } 348 349 if (fname != NULL) { 350 if (dev_ds1743_set_fname (rtc, fname)) { 351 pce_log (MSG_ERR, "*** opening file failed (%s)\n", 352 fname 353 ); 354 } 355 } 356 357 mem_add_blk (sim->mem, &rtc->blk, 0); 358 359 dev_lst_add (&sim->devlst, &rtc->dev); 360} 361 362static 363void s405_setup_devices (sim405_t *sim, ini_sct_t *ini) 364{ 365 ini_sct_t *sct; 366 const char *type; 367 368 sct = NULL; 369 while ((sct = ini_next_sct (ini, sct, "device")) != NULL) { 370 ini_get_string (sct, "type", &type, NULL); 371 372 if (type != NULL) { 373 if (strcmp (type, "ds1743") == 0) { 374 s405_setup_ds1743 (sim, sct); 375 } 376 else { 377 pce_log (MSG_INF, "*** unknown device '%s'\n", 378 type 379 ); 380 } 381 } 382 } 383} 384 385sim405_t *s405_new (ini_sct_t *ini) 386{ 387 unsigned i; 388 sim405_t *sim; 389 390 sim = malloc (sizeof (sim405_t)); 391 if (sim == NULL) { 392 return (NULL); 393 } 394 395 sim->brk = 0; 396 sim->clk_cnt = 0; 397 sim->real_clk = clock(); 398 399 sim->sync_clock_sim = 0; 400 sim->sync_clock_real = 0; 401 sim->sync_interval = 0; 402 403 sim->serial_clock = 1; 404 sim->serial_clock_count = 0; 405 406 pce_get_interval_us (&sim->sync_interval); 407 408 for (i = 0; i < 4; i++) { 409 sim->clk_div[i] = 0; 410 } 411 412 s405_hook_init (sim); 413 414 bps_init (&sim->bps); 415 416 dev_lst_init (&sim->devlst); 417 418 sim->mem = mem_new(); 419 420 ini_get_ram (sim->mem, ini, &sim->ram); 421 ini_get_rom (sim->mem, ini); 422 423 s405_setup_system (sim, ini); 424 s405_setup_serport (sim, ini); 425 s405_setup_sercons (sim, ini); 426 s405_setup_slip (sim, ini); 427 s405_setup_disks (sim, ini); 428 s405_setup_pci (sim, ini); 429 s405_setup_ata (sim, ini); 430 s405_setup_devices (sim, ini); 431 432 sim->ocm0_iscntl = 0; 433 sim->ocm0_isarc = 0; 434 sim->ocm0_dscntl = 0; 435 sim->ocm0_dsarc = 0; 436 sim->cpc0_cr0 = 0x00000000; 437 sim->cpc0_cr1 = 0x00000000; 438 sim->cpc0_psr = 0x00000400; 439 440 pce_load_mem_ini (sim->mem, ini); 441 442 return (sim); 443} 444 445void s405_del (sim405_t *sim) 446{ 447 if (sim == NULL) { 448 return; 449 } 450 451 dev_lst_free (&sim->devlst); 452 453 pci_ata_free (&sim->pciata); 454 s405_pci_del (sim->pci); 455 456 dsks_del (sim->dsks); 457 458 slip_del (sim->slip); 459 460 ser_del (sim->serport[1]); 461 ser_del (sim->serport[0]); 462 463 p405uic_free (&sim->uic); 464 p405_del (sim->ppc); 465 466 mem_del (sim->mem); 467 468 bps_free (&sim->bps); 469 470 s405_hook_free (sim); 471 472 free (sim); 473} 474 475unsigned long long s405_get_clkcnt (sim405_t *sim) 476{ 477 return (sim->clk_cnt); 478} 479 480static 481unsigned long s405_get_dcr (void *ext, unsigned long dcrn) 482{ 483 sim405_t *sim; 484 485 sim = (sim405_t *) ext; 486 487 switch (dcrn) { 488 case 0: 489 s405_break (sim, PCE_BRK_STOP); 490 break; 491 492 case SIM405_DCRN_OCM0_ISARC: /* 0x18 */ 493 return (sim->ocm0_isarc); 494 495 case SIM405_DCRN_OCM0_ISCNTL: /* 0x19 */ 496 return (sim->ocm0_iscntl); 497 498 case SIM405_DCRN_OCM0_DSARC: /* 0x1a */ 499 return (sim->ocm0_dsarc); 500 501 case SIM405_DCRN_OCM0_DSCNTL: /* 0x1b */ 502 return (sim->ocm0_dscntl); 503 504 case SIM405_DCRN_CPC0_CR0: /* 0xb1 */ 505 return (sim->cpc0_cr0); 506 507 case SIM405_DCRN_CPC0_CR1: /* 0xb2 */ 508 return (sim->cpc0_cr1); 509 510 case SIM405_DCRN_CPC0_PSR: /* 0xb4 */ 511 return (sim->cpc0_psr); 512 513 case SIM405_DCRN_UIC0_SR: 514 return (p405uic_get_sr (&sim->uic)); 515 516 case SIM405_DCRN_UIC0_ER: 517 return (p405uic_get_er (&sim->uic)); 518 519 case SIM405_DCRN_UIC0_CR: 520 return (p405uic_get_cr (&sim->uic)); 521 522 case SIM405_DCRN_UIC0_PR: 523 return (p405uic_get_er (&sim->uic)); 524 525 case SIM405_DCRN_UIC0_TR: 526 return (p405uic_get_er (&sim->uic)); 527 528 case SIM405_DCRN_UIC0_MSR: 529 return (p405uic_get_msr (&sim->uic)); 530 531 case SIM405_DCRN_UIC0_VR: 532 return (p405uic_get_vr (&sim->uic)); 533 534 case SIM405_DCRN_MAL0_CFG: /* 0x180 */ 535 return (0); 536 537 default: 538 pce_log (MSG_DEB, "%08lX: get dcr %03lx\n", 539 (unsigned long) p405_get_pc (sim->ppc), dcrn 540 ); 541 break; 542 } 543 544 return (0); 545} 546 547static 548void s405_set_dcr (void *ext, unsigned long dcrn, unsigned long val) 549{ 550 sim405_t *sim; 551 552 sim = (sim405_t *) ext; 553 554 switch (dcrn) { 555 case SIM405_DCRN_OCM0_ISARC: /* 0x18 */ 556 sim->ocm0_isarc = val; 557 break; 558 559 case SIM405_DCRN_OCM0_ISCNTL: /* 0x19 */ 560 sim->ocm0_iscntl = val; 561 if (val & 0x80000000) { 562 pce_log (MSG_DEB, 563 "%08lX: instruction side ocm0 enabled\n", 564 (unsigned long) p405_get_pc (sim->ppc) 565 ); 566 } 567 break; 568 569 case SIM405_DCRN_OCM0_DSARC: /* 0x1a */ 570 sim->ocm0_dsarc = val; 571 break; 572 573 case SIM405_DCRN_OCM0_DSCNTL: /* 0x1b */ 574 sim->ocm0_dscntl = val; 575 if (val & 0x80000000) { 576 pce_log (MSG_DEB, 577 "%08lX: data side ocm0 enabled\n", 578 (unsigned long) p405_get_pc (sim->ppc) 579 ); 580 } 581 break; 582 583 case SIM405_DCRN_CPC0_CR0: /* 0xb1 */ 584 sim->cpc0_cr0 = val; 585 break; 586 587 case SIM405_DCRN_CPC0_CR1: /* 0xb2 */ 588 sim->cpc0_cr1 = val; 589 break; 590 591 case SIM405_DCRN_CPC0_PSR: /* 0xb4 */ 592 sim->cpc0_psr = val; 593 break; 594 595 case SIM405_DCRN_UIC0_SR: 596 p405uic_set_sr (&sim->uic, val); 597 break; 598 599 case SIM405_DCRN_UIC0_ER: 600 p405uic_set_er (&sim->uic, val); 601 break; 602 603 case SIM405_DCRN_UIC0_CR: 604 p405uic_set_cr (&sim->uic, val); 605 break; 606 607 case SIM405_DCRN_UIC0_PR: 608 p405uic_set_pr (&sim->uic, val); 609 break; 610 611 case SIM405_DCRN_UIC0_TR: 612 p405uic_set_tr (&sim->uic, val); 613 break; 614 615 case SIM405_DCRN_UIC0_VCR: 616 p405uic_set_vcr (&sim->uic, val); 617 break; 618 619 case SIM405_DCRN_MAL0_CFG: /* 0x180 */ 620 break; 621 622 default: 623 pce_log (MSG_DEB, "%08lX: set dcr %03lx <- %08lx\n", 624 (unsigned long) p405_get_pc (sim->ppc), dcrn, val 625 ); 626 break; 627 } 628} 629 630void s405_break (sim405_t *sim, unsigned char val) 631{ 632 if ((val == PCE_BRK_STOP) || (val == PCE_BRK_ABORT)) { 633 sim->brk = val; 634 } 635} 636 637void s405_set_keycode (sim405_t *sim, unsigned char val) 638{ 639 if (sim->serport[sim->sercons] != NULL) { 640 ser_receive (sim->serport[sim->sercons], val); 641 } 642} 643 644void s405_reset (sim405_t *sim) 645{ 646 p405_reset (sim->ppc); 647} 648 649void s405_clock_discontinuity (sim405_t *sim) 650{ 651 sim->sync_clock_sim = 0; 652 pce_get_interval_us (&sim->sync_interval); 653} 654 655static 656void s405_sync (sim405_t *sim) 657{ 658 unsigned long vclk; 659 unsigned long rclk; 660 661 vclk = sim->sync_clock_sim; 662 sim->sync_clock_sim = 0; 663 664 rclk = pce_get_interval_us (&sim->sync_interval); 665 rclk = (S405_CLOCK * (unsigned long long) rclk) / (1 * 1000000); 666 667 if (vclk < rclk) { 668 p405_add_timer_clock (sim->ppc, rclk - vclk); 669 } 670} 671 672void s405_clock (sim405_t *sim, unsigned n) 673{ 674 unsigned long clk, ser; 675 676 if (sim->clk_div[0] >= 256) { 677 clk = sim->clk_div[0] & ~255UL; 678 sim->clk_div[1] += clk; 679 sim->clk_div[0] &= 255; 680 681 if (sim->clk_div[1] >= 4096) { 682 clk = sim->clk_div[1] & ~4095UL; 683 sim->clk_div[2] += clk; 684 sim->clk_div[1] &= 4095UL; 685 686 if (sim->serport[0] != NULL) { 687 ser_clock (sim->serport[0], clk); 688 } 689 690 if (sim->serport[1] != NULL) { 691 ser_clock (sim->serport[1], clk); 692 } 693 694 if (sim->slip != NULL) { 695 slip_clock (sim->slip, clk); 696 } 697 698 if (sim->clk_div[2] >= 65536) { 699 scon_check (sim); 700 701 if (sim->sync_time_base) { 702 s405_sync (sim); 703 } 704 705 sim->clk_div[2] &= 65535; 706 } 707 } 708 } 709 710 ser = sim->serial_clock_count >> 10; 711 712 if (ser > 0) { 713 if (sim->serport[0] != NULL) { 714 e8250_clock (&sim->serport[0]->uart, ser); 715 } 716 717 if (sim->serport[1] != NULL) { 718 e8250_clock (&sim->serport[1]->uart, ser); 719 } 720 721 sim->serial_clock_count -= (ser << 4); 722 } 723 724 p405_clock (sim->ppc, n); 725 726 sim->clk_cnt += n; 727 sim->clk_div[0] += n; 728 729 sim->sync_clock_sim += n; 730 sim->serial_clock_count += n; 731}