fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/cpu/arm/arm.c *
7 * Created: 2004-11-03 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2009 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 <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include "arm.h"
34#include "internal.h"
35
36
37static unsigned arm_spsr_map[32] = {
38 0, /* 00 */
39 0, /* 01 */
40 0, /* 02 */
41 0, /* 03 */
42 0, /* 04 */
43 0, /* 05 */
44 0, /* 06 */
45 0, /* 07 */
46 0, /* 08 */
47 0, /* 09 */
48 0, /* 0a */
49 0, /* 0b */
50 0, /* 0c */
51 0, /* 0d */
52 0, /* 0e */
53 0, /* 0f */
54 0, /* 10 usr */
55 1, /* 11 fiq */
56 2, /* 12 irq */
57 3, /* 13 svc */
58 0, /* 14 */
59 0, /* 15 */
60 0, /* 16 */
61 4, /* 17 abt */
62 0, /* 18 */
63 0, /* 19 */
64 5, /* 1a und */
65 0, /* 1b */
66 0, /* 1c */
67 0, /* 1d */
68 0, /* 1e */
69 0, /* 1f sys */
70};
71
72static unsigned arm_reg_map[32][8] = {
73 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 00 */
74 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 01 */
75 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 02 */
76 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 03 */
77 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 04 */
78 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 05 */
79 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 06 */
80 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 07 */
81 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 08 */
82 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 09 */
83 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0a */
84 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0b */
85 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0c */
86 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0d */
87 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0e */
88 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0f */
89 { 1, 2, 3, 4, 5, 6, 7, 8 }, /* 10 usr */
90 { 9, 10, 11, 12, 13, 14, 15, 8 }, /* 11 fiq */
91 { 1, 2, 3, 4, 5, 16, 17, 8 }, /* 12 irq */
92 { 1, 2, 3, 4, 5, 18, 19, 8 }, /* 13 svc */
93 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 14 */
94 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 15 */
95 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 16 */
96 { 1, 2, 3, 4, 5, 20, 21, 8 }, /* 17 abt */
97 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 18 */
98 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 19 */
99 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1a */
100 { 1, 2, 3, 4, 5, 22, 23, 8 }, /* 1b und */
101 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1c */
102 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1d */
103 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1e */
104 { 1, 2, 3, 4, 5, 6, 7, 8 } /* 1f sys */
105};
106
107void arm_init (arm_t *c)
108{
109 unsigned i;
110
111 c->flags = 0;
112
113 c->mem_ext = NULL;
114
115 c->get_uint8 = NULL;
116 c->get_uint16 = NULL;
117 c->get_uint32 = NULL;
118
119 c->set_uint8 = NULL;
120 c->set_uint16 = NULL;
121 c->set_uint32 = NULL;
122
123 c->ram = NULL;
124 c->ram_cnt = 0;
125
126 c->log_ext = NULL;
127 c->log_opcode = NULL;
128 c->log_undef = NULL;
129 c->log_exception = NULL;
130
131 arm_set_opcodes (c);
132
133 c->cpsr = 0;
134
135 c->reg_map = 0;
136
137 c->exception_base = 0;
138
139 c->bigendian = 0;
140 c->privileged = 1;
141
142 c->irq = 0;
143 c->fiq = 0;
144 c->irq_or_fiq = 0;
145
146 c->delay = 0;
147 c->oprcnt = 0;
148 c->clkcnt = 0;
149
150 for (i = 0; i < 16; i++) {
151 c->copr[i] = NULL;
152 }
153
154 cp14_init (&c->copr14);
155 c->copr[14] = &c->copr14.copr;
156
157 cp15_init (&c->copr15);
158 c->copr[15] = &c->copr15.copr;
159}
160
161arm_t *arm_new (void)
162{
163 arm_t *c;
164
165 c = malloc (sizeof (arm_t));
166 if (c == NULL) {
167 return (NULL);
168 }
169
170 arm_init (c);
171
172 return (c);
173}
174
175void arm_free (arm_t *c)
176{
177 cp14_free (&c->copr14);
178 cp15_free (&c->copr15);
179}
180
181void arm_del (arm_t *c)
182{
183 if (c != NULL) {
184 arm_free (c);
185 free (c);
186 }
187}
188
189
190void arm_set_mem_fct (arm_t *c, void *ext,
191 void *get8, void *get16, void *get32,
192 void *set8, void *set16, void *set32)
193{
194 c->mem_ext = ext;
195
196 c->get_uint8 = get8;
197 c->get_uint16 = get16;
198 c->get_uint32 = get32;
199
200 c->set_uint8 = set8;
201 c->set_uint16 = set16;
202 c->set_uint32 = set32;
203}
204
205void arm_set_ram (arm_t *c, unsigned char *ram, unsigned long cnt)
206{
207 c->ram = ram;
208 c->ram_cnt = cnt;
209}
210
211unsigned arm_get_flags (const arm_t *c, unsigned flags)
212{
213 return (c->flags & flags);
214}
215
216void arm_set_flags (arm_t *c, unsigned flags, int val)
217{
218 if (val) {
219 c->flags |= flags;
220 }
221 else {
222 c->flags &= ~flags;
223 }
224}
225
226unsigned long arm_get_id (arm_t *c)
227{
228 return (c->copr15.reg[0]);
229}
230
231void arm_set_id (arm_t *c, unsigned long id)
232{
233 c->copr15.reg[0] = id;
234}
235
236static
237int arm_get_reg_idx (const char *reg, unsigned *idx, unsigned max)
238{
239 unsigned n;
240
241 n = 0;
242
243 if ((reg[0] < '0') || (reg[0] > '9')) {
244 return (1);
245 }
246
247 while ((reg[0] >= '0') && (reg[0] <= '9')) {
248 n = 10 * n + (unsigned) (reg[0] - '0');
249 reg += 1;
250 }
251
252 if (reg[0] != 0) {
253 return (1);
254 }
255
256 if (n > max) {
257 return (1);
258 }
259
260 *idx = n;
261
262 return (0);
263}
264
265int arm_get_reg (arm_t *c, const char *reg, unsigned long *val)
266{
267 unsigned idx;
268
269 if (reg[0] == '%') {
270 reg += 1;
271 }
272
273 if (strcmp (reg, "pc") == 0) {
274 *val = arm_get_pc (c);
275 return (0);
276 }
277 else if (strcmp (reg, "lr") == 0) {
278 *val = arm_get_lr (c);
279 return (0);
280 }
281 else if (strcmp (reg, "cpsr") == 0) {
282 *val = arm_get_cpsr (c);
283 return (0);
284 }
285 else if (strcmp (reg, "spsr") == 0) {
286 *val = arm_get_spsr (c);
287 return (0);
288 }
289
290 if (reg[0] == 'r') {
291 if (arm_get_reg_idx (reg + 1, &idx, 15)) {
292 return (1);
293 }
294
295 *val = arm_get_gpr (c, idx);
296
297 return (0);
298 }
299
300 return (1);
301}
302
303int arm_set_reg (arm_t *c, const char *reg, unsigned long val)
304{
305 unsigned idx;
306
307 if (reg[0] == '%') {
308 reg += 1;
309 }
310
311 if (strcmp (reg, "pc") == 0) {
312 arm_set_pc (c, val);
313 return (0);
314 }
315 else if (strcmp (reg, "lr") == 0) {
316 arm_set_lr (c, val);
317 return (0);
318 }
319 else if (strcmp (reg, "cpsr") == 0) {
320 arm_set_cpsr (c, val);
321 return (0);
322 }
323 else if (strcmp (reg, "spsr") == 0) {
324 arm_set_spsr (c, val);
325 return (0);
326 }
327
328 if (reg[0] == 'r') {
329 if (arm_get_reg_idx (reg + 1, &idx, 15)) {
330 return (1);
331 }
332
333 arm_set_gpr (c, idx, val);
334
335 return (0);
336 }
337
338 return (1);
339}
340
341unsigned long long arm_get_opcnt (arm_t *c)
342{
343 return (c->oprcnt);
344}
345
346unsigned long long arm_get_clkcnt (arm_t *c)
347{
348 return (c->clkcnt);
349}
350
351unsigned long arm_get_delay (arm_t *c)
352{
353 return (c->delay);
354}
355
356
357void arm_copr_init (arm_copr_t *p)
358{
359 p->copr_idx = 0;
360 p->exec = NULL;
361 p->reset = NULL;
362 p->ext = NULL;
363}
364
365void arm_copr_free (arm_copr_t *p)
366{
367}
368
369int arm_copr_check (arm_t *c, unsigned i)
370{
371 if (i >= 16) {
372 return (1);
373 }
374
375 if (c->copr[i] == NULL) {
376 return (1);
377 }
378
379 if (c->flags & ARM_FLAG_CPAR) {
380 uint32_t cpar;
381
382 cpar = c->copr15.reg[15];
383
384 if ((i <= 13) && (cpar & (1UL << i))) {
385 return (1);
386 }
387 }
388
389 return (0);
390}
391
392void arm_set_copr (arm_t *c, unsigned i, arm_copr_t *p)
393{
394 if (i < 16) {
395 c->copr[i] = p;
396 }
397}
398
399
400void arm_set_reg_map (arm_t *c, unsigned mode)
401{
402 unsigned i;
403 unsigned m1, m2;
404 unsigned *map1, *map2;
405
406 m1 = c->reg_map;
407 m2 = mode & 0x1f;
408
409 if (m1 == m2) {
410 return;
411 }
412
413 c->spsr_alt[arm_spsr_map[m1]] = c->spsr;
414 c->spsr = c->spsr_alt[arm_spsr_map[m2]];
415
416 map1 = arm_reg_map[m1];
417 map2 = arm_reg_map[m2];
418
419 for (i = 0; i < 8; i++) {
420 c->reg_alt[map1[i]] = c->reg[i + 8];
421 c->reg[i + 8] = c->reg_alt[map2[i]];
422 }
423
424 c->reg_map = m2;
425}
426
427void arm_reset (arm_t *c)
428{
429 unsigned i;
430
431 c->cpsr = ARM_MODE_SVC;
432
433 arm_set_reg_map (c, ARM_MODE_SVC);
434
435 for (i = 0; i < 16; i++) {
436 c->reg[i] = 0;
437 }
438
439 for (i = 0; i < ARM_REG_ALT_CNT; i++) {
440 c->reg_alt[i] = 0;
441 }
442
443 for (i = 0; i < ARM_SPSR_CNT; i++) {
444 c->spsr_alt[i] = 0;
445 }
446
447 c->lastpc[0] = 0;
448 c->lastpc[1] = 0;
449
450 c->ir = 0;
451
452 c->exception_base = 0;
453
454 /* Actually, endianness should be reset to little endian and then
455 * initialized by the CPU itself. We don't do that because we
456 * have a byte based memory system and therefore (contrary to
457 * the specification) this setting *does* affect word loads and
458 * stores. */
459 c->bigendian = ((c->flags & ARM_FLAG_BIGENDIAN) != 0);
460
461 c->privileged = 1;
462
463 c->irq = 0;
464 c->fiq = 0;
465 c->irq_or_fiq = 0;
466
467 c->delay = 1;
468
469 c->oprcnt = 0;
470 c->clkcnt = 0;
471
472 arm_tbuf_flush (c);
473
474 for (i = 0; i < 16; i++) {
475 if (c->copr[i] != NULL) {
476 if (c->copr[i]->reset != NULL) {
477 c->copr[i]->reset (c, c->copr[i]);
478 }
479 }
480 }
481}
482
483void arm_exception (arm_t *c, uint32_t addr, uint32_t ret, unsigned mode)
484{
485 uint32_t cpsr, spsr;
486
487 if (c->log_exception != NULL) {
488 c->log_exception (c->log_ext, addr);
489 }
490
491 c->delay += 1;
492
493 cpsr = arm_get_cpsr (c);
494 spsr = cpsr;
495
496 cpsr &= ~(ARM_PSR_T | ARM_PSR_M);
497 cpsr |= ARM_PSR_I | (mode & 0x1f);
498
499 arm_write_cpsr (c, cpsr, 0);
500 arm_set_spsr (c, spsr);
501 arm_set_lr (c, ret);
502 arm_set_pc (c, (c->exception_base + addr) & 0xffffffffUL);
503}
504
505void arm_exception_reset (arm_t *c)
506{
507 arm_exception (c, 0x00000000UL, 0, ARM_MODE_SVC);
508 arm_set_cpsr_f (c, 1);
509}
510
511void arm_exception_undefined (arm_t *c)
512{
513 arm_exception (c, 0x00000004UL, arm_get_pc (c) + 4, ARM_MODE_UND);
514}
515
516void arm_exception_swi (arm_t *c)
517{
518 arm_exception (c, 0x00000008UL, arm_get_pc (c) + 4, ARM_MODE_SVC);
519}
520
521void arm_exception_prefetch_abort (arm_t *c)
522{
523 arm_exception (c, 0x0000000cUL, arm_get_pc (c) + 4, ARM_MODE_ABT);
524}
525
526void arm_exception_data_abort (arm_t *c)
527{
528 arm_exception (c, 0x00000010UL, arm_get_pc (c) + 8, ARM_MODE_ABT);
529}
530
531void arm_exception_irq (arm_t *c)
532{
533 arm_exception (c, 0x00000018UL, arm_get_pc (c) + 4, ARM_MODE_IRQ);
534}
535
536void arm_exception_fiq (arm_t *c)
537{
538 arm_exception (c, 0x0000001cUL, arm_get_pc (c) + 4, ARM_MODE_FIQ);
539 arm_set_cpsr_f (c, 1);
540}
541
542void arm_set_irq (arm_t *c, unsigned char val)
543{
544 c->irq = (val != 0);
545 c->irq_or_fiq = c->irq || c->fiq;
546}
547
548void arm_set_fiq (arm_t *c, unsigned char val)
549{
550 c->fiq = (val != 0);
551 c->irq_or_fiq = c->irq || c->fiq;
552}
553
554void arm_execute (arm_t *c)
555{
556 c->oprcnt += 1;
557
558 c->lastpc[1] = c->lastpc[0];
559 c->lastpc[0] = arm_get_pc (c);
560
561 if (arm_ifetch (c, c->lastpc[0], &c->ir)) {
562 return;
563 }
564
565#if 0
566 if (c->log_opcode != NULL) {
567 if (c->log_opcode (c->log_ext, c->ir)) {
568 /* nop */
569 c->ir = 0xe1a00000UL;
570 }
571 }
572#endif
573
574 if (arm_check_cond_al (c->ir) || arm_check_cond (c, arm_ir_cond (c->ir))) {
575 c->opcodes[(c->ir >> 20) & 0xff] (c);
576 }
577 else {
578 arm_set_clk (c, 4, 1);
579 }
580
581 if (c->irq_or_fiq) {
582 if (c->fiq && (arm_get_cpsr_f (c) == 0)) {
583 arm_exception_fiq (c);
584 }
585 else if (c->irq && (arm_get_cpsr_i (c) == 0)) {
586 arm_exception_irq (c);
587 }
588 }
589}
590
591void arm_clock (arm_t *c, unsigned long n)
592{
593 while (n >= c->delay) {
594 n -= c->delay;
595
596 c->clkcnt += c->delay;
597 c->delay = 0;
598
599 arm_execute (c);
600
601#if 0
602 if (c->delay == 0) {
603 fprintf (stderr, "%08lX ARM: delay == 0\n",
604 (unsigned long) arm_get_pc (c)
605 );
606 fflush (stderr);
607 c->delay = 1;
608 }
609#endif
610 }
611
612 c->clkcnt += n;
613 c->delay -= n;
614}