fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 477 lines 8.7 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/cpu/arm/copr15.c * 7 * Created: 2004-11-09 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 "arm.h" 30#include "internal.h" 31 32 33static int cp15_reset (arm_t *c, arm_copr_t *p); 34static int cp15_exec (arm_t *c, arm_copr_t *p); 35 36 37void cp15_init (arm_copr15_t *p) 38{ 39 unsigned i; 40 41 arm_copr_init (&p->copr); 42 43 p->copr.ext = p; 44 p->copr.reset = cp15_reset; 45 p->copr.exec = cp15_exec; 46 47 p->reg[0] = ARM_C15_ID; 48 p->reg[1] = ARM_C15_CR_P | ARM_C15_CR_D | ARM_C15_CR_L; 49 50 for (i = 2; i < 16; i++) { 51 p->reg[i] = 0; 52 } 53 54 p->cache_type = 0; 55 p->auxiliary_control = 0; 56} 57 58arm_copr_t *cp15_new (void) 59{ 60 arm_copr15_t *c; 61 62 c = malloc (sizeof (arm_copr15_t)); 63 if (c == NULL) { 64 return (NULL); 65 } 66 67 cp15_init (c); 68 69 return (&c->copr); 70} 71 72void cp15_free (arm_copr15_t *p) 73{ 74} 75 76void cp15_del (arm_copr15_t *p) 77{ 78 if (p != NULL) { 79 cp15_free (p); 80 } 81 82 free (p); 83} 84 85 86/* 87 * Get CP15/0 (ID) 88 */ 89static 90int cp15_get_reg0 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t *val) 91{ 92 switch (op2) { 93 case 0: 94 /* ID */ 95 *val = p->reg[0]; 96 return (0); 97 98 case 1: 99 /* XScale Cache Type */ 100 *val = p->cache_type; 101 return (0); 102 } 103 104 return (1); 105} 106 107/* 108 * Get CP15/1 (Control) 109 */ 110static 111int cp15_get_reg1 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t *val) 112{ 113 switch (op2) { 114 case 0: 115 /* Control */ 116 *val = p->reg[1]; 117 return (0); 118 119 case 1: 120 /* XScale Auxiliary Control */ 121 *val = p->auxiliary_control; 122 return (0); 123 } 124 125 return (1); 126} 127 128/* 129 * Set CP15/1 (Control) 130 */ 131static 132int cp15_set_reg1 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t val) 133{ 134 switch (op2) { 135 case 0: 136 /* Control */ 137 val &= ~ARM_C15_CR_C; 138 val &= ~ARM_C15_CR_W; 139 val |= ARM_C15_CR_P; 140 val |= ARM_C15_CR_D; 141 val |= ARM_C15_CR_L; 142 arm_set_bits (val, ARM_C15_CR_B, c->bigendian); 143 p->reg[1] = val & 0xffffffff; 144 145 c->exception_base = (val & ARM_C15_CR_V) ? 0xffff0000 : 0x00000000; 146 147 return (0); 148 149 case 1: 150 /* XScale Auxiliary Control */ 151 p->auxiliary_control = val; 152 153 return (0); 154 } 155 156 return (1); 157} 158 159/* cache functions */ 160static 161int cp15_set_reg7 (arm_t *c, arm_copr15_t *p) 162{ 163 unsigned rm, op2; 164 165 rm = arm_ir_rm (c->ir); 166 op2 = arm_get_bits (c->ir, 5, 3); 167 168 if ((rm == 7) && (op2 == 0)) { 169 /* invalidate all caches */ 170 return (0); 171 } 172 else if ((rm == 2) && (op2 == 5)) { 173 /* ??? */ 174 return (0); 175 } 176 else if (rm == 5) { 177 switch (op2) { 178 case 0x00: 179 /* invalidate entire instruction cache */ 180 return (0); 181 182 case 0x01: 183 /* invalidate instruction cache line */ 184 return (0); 185 186 case 0x02: 187 /* invalidate instruction cache line */ 188 return (0); 189 190 case 0x04: 191 /* flush prefetch buffer */ 192 return (0); 193 194 case 0x06: 195 /* flush entire branch target cache */ 196 return (0); 197 198 case 0x07: 199 /* flush branch target cache entry */ 200 return (0); 201 } 202 203 return (1); 204 } 205 else if (rm == 6) { 206 switch (op2) { 207 case 0x00: 208 /* invalidate entire data cache */ 209 return (0); 210 211 case 0x01: 212 /* invalidate data cache line */ 213 return (0); 214 215 case 0x02: 216 /* invalidate data cache line */ 217 return (0); 218 } 219 } 220 else if (rm == 10) { 221 switch (op2) { 222 case 0x01: 223 /* clean data cache line */ 224 return (0); 225 226 case 0x02: 227 /* clean data cache line */ 228 return (0); 229 230 case 0x04: 231 /* drain write buffer */ 232 return (0); 233 } 234 235 return (1); 236 } 237 238 return (1); 239} 240 241/* TLB functions */ 242static 243int cp15_set_reg8 (arm_t *c, arm_copr15_t *p) 244{ 245 unsigned rm, op2; 246 247 rm = arm_ir_rm (c->ir); 248 op2 = arm_get_bits (c->ir, 5, 3); 249 250 if (rm == 5) { 251 switch (op2) { 252 case 0x00: 253 /* invalidate entire instruction tlb */ 254 return (0); 255 256 case 0x01: 257 /* invalidate instruction tlb single entry */ 258 return (0); 259 } 260 } 261 else if (rm == 6) { 262 switch (op2) { 263 case 0x00: 264 /* invalidate entire data tlb */ 265 return (0); 266 267 case 0x01: 268 /* invalidate data tlb single entry */ 269 return (0); 270 } 271 } 272 else if (rm == 7) { 273 switch (op2) { 274 case 0x00: 275 /* invalidate entire unified tlb */ 276 return (0); 277 278 case 0x01: 279 /* invalidate unified tlb single entry */ 280 return (0); 281 } 282 } 283 284 return (1); 285} 286 287static 288int cp15_set_reg15 (arm_t *c, arm_copr15_t *p, uint32_t val) 289{ 290 unsigned rm; 291 292 rm = arm_ir_rm (c->ir); 293 /* op2 = arm_get_bits (c->ir, 5, 3); */ 294 295 if (rm == 1) { 296 /* xscale: coprocessor access register */ 297 p->reg[15] = val & 0x00003fff; 298 return (0); 299 } 300 301 return (1); 302} 303 304static 305int cp15_op_mrc (arm_t *c, arm_copr_t *p) 306{ 307 arm_copr15_t *p15; 308 unsigned op2; 309 uint32_t val; 310 311 p15 = p->ext; 312 313 op2 = arm_get_bits (c->ir, 5, 3); 314 315 switch (arm_ir_rn (c->ir)) { 316 case 0x00: /* ID register */ 317 if (cp15_get_reg0 (c, p15, op2, &val)) { 318 return (1); 319 } 320 break; 321 322 case 0x01: /* control register */ 323 if (cp15_get_reg1 (c, p15, op2, &val)) { 324 return (1); 325 } 326 break; 327 328 case 0x02: /* translation table base */ 329 val = p15->reg[2]; 330 break; 331 332 case 0x03: /* domain access control */ 333 val = p15->reg[2]; 334 break; 335 336 case 0x05: /* fault status */ 337 val = p15->reg[5]; 338 break; 339 340 case 0x06: /* fault address */ 341 val = p15->reg[6]; 342 break; 343 344 case 0x0f: /* implementation defined */ 345 val = p15->reg[15]; 346 break; 347 348 default: 349 return (1); 350 } 351 352 if (arm_rd_is_pc (c->ir)) { 353 arm_set_cpsr (c, (arm_get_cpsr (c) & ~ARM_PSR_CC) | (val & ARM_PSR_CC)); 354 } 355 else { 356 arm_set_rd (c, c->ir, val & 0xffffffff); 357 } 358 359 return (0); 360} 361 362static 363int cp15_op_mcr (arm_t *c, arm_copr_t *p) 364{ 365 arm_copr15_t *p15; 366 unsigned op2; 367 uint32_t val; 368 369 p15 = p->ext; 370 371 op2 = arm_get_bits (c->ir, 5, 3); 372 373 val = arm_get_rd (c, c->ir); 374 375 /* conservative flushing of translation buffer */ 376 arm_tbuf_flush (c); 377 378 switch (arm_ir_rn (c->ir)) { 379 case 0x00: /* id register */ 380 return (1); 381 382 case 0x01: /* control register */ 383 return (cp15_set_reg1 (c, p15, op2, val)); 384 385 case 0x02: /* translation table base */ 386 p15->reg[2] = val & 0xffffc000; 387 break; 388 389 case 0x03: /* domain access control */ 390 p15->reg[3] = val & 0xffffffff; 391 break; 392 393 case 0x07: 394 return (cp15_set_reg7 (c, p15)); 395 396 case 0x08: 397 return (cp15_set_reg8 (c, p15)); 398 399 case 0x0f: /* implementation defined */ 400 return (cp15_set_reg15 (c, p15, val)); 401 402 default: 403 return (1); 404 } 405 406 return (0); 407} 408 409static 410int cp15_reset (arm_t *c, arm_copr_t *p) 411{ 412 unsigned i; 413 arm_copr15_t *p15; 414 415 p15 = p->ext; 416 417 if (c->bigendian) { 418 p15->reg[1] |= ARM_C15_CR_B; 419 } 420 else { 421 p15->reg[1] &= ~ARM_C15_CR_B; 422 } 423 424 for (i = 2; i < 16; i++) { 425 p15->reg[i] = 0; 426 } 427 428 return (0); 429} 430 431static 432int cp15_exec (arm_t *c, arm_copr_t *p) 433{ 434 int r; 435 unsigned long pc; 436 char *op; 437 438 pc = arm_get_pc (c); 439 440 if (arm_is_privileged (c) == 0) { 441 return (1); 442 } 443 444 op = "?"; 445 446 switch (c->ir & 0x00f00010) { 447 case 0x00000010: /* mcr */ 448 op = "W"; 449 r = cp15_op_mcr (c, p); 450 break; 451 452 case 0x00100010: /* mrc */ 453 op = "R"; 454 r = cp15_op_mrc (c, p); 455 break; 456 457 default: 458 r = 1; 459 break; 460 } 461 462 if (r == 0) { 463 arm_set_clk (c, 4, 1); 464 } 465 466 if (r) { 467 fprintf (stderr, "%08lX C15: %s Rd=%u Rn=%u Rm=%u op2=%u\n", 468 pc, op, 469 (unsigned) arm_ir_rd (c->ir), 470 (unsigned) arm_ir_rn (c->ir), 471 (unsigned) arm_ir_rm (c->ir), 472 (unsigned) arm_get_bits (c->ir, 5, 3) 473 ); fflush (stderr); 474 } 475 476 return (r); 477}