fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 614 lines 12 kB view raw
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}