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