fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
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}