1 /* armvirt.c -- ARMulator virtual memory interace: ARM6 Instruction Emulator. 2 Copyright (C) 1994 Advanced RISC Machines Ltd. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, see <http://www.gnu.org/licenses/>. */ 16 17 /* This file contains a complete ARMulator memory model, modelling a 18 "virtual memory" system. A much simpler model can be found in armfast.c, 19 and that model goes faster too, but has a fixed amount of memory. This 20 model's memory has 64K pages, allocated on demand from a 64K entry page 21 table. The routines PutWord and GetWord implement this. Pages are never 22 freed as they might be needed again. A single area of memory may be 23 defined to generate aborts. */ 24 25 #include "armopts.h" 26 #include "armos.h" 27 #include "armdefs.h" 28 #include "ansidecl.h" 29 30 #ifdef VALIDATE /* for running the validate suite */ 31 #define TUBE 48 * 1024 * 1024 /* write a char on the screen */ 32 #define ABORTS 1 33 #endif 34 35 /* #define ABORTS */ 36 37 #ifdef ABORTS /* the memory system will abort */ 38 /* For the old test suite Abort between 32 Kbytes and 32 Mbytes 39 For the new test suite Abort between 8 Mbytes and 26 Mbytes */ 40 /* #define LOWABORT 32 * 1024 41 #define HIGHABORT 32 * 1024 * 1024 */ 42 #define LOWABORT 8 * 1024 * 1024 43 #define HIGHABORT 26 * 1024 * 1024 44 45 #endif 46 47 #define NUMPAGES 64 * 1024 48 #define PAGESIZE 64 * 1024 49 #define PAGEBITS 16 50 #define OFFSETBITS 0xffff 51 52 int SWI_vector_installed = FALSE; 53 54 /***************************************************************************\ 55 * Get a Word from Virtual Memory, maybe allocating the page * 56 \***************************************************************************/ 57 58 static ARMword 59 GetWord (ARMul_State * state, ARMword address, int check) 60 { 61 ARMword page; 62 ARMword offset; 63 ARMword **pagetable; 64 ARMword *pageptr; 65 66 if (check && state->is_XScale) 67 XScale_check_memacc (state, &address, 0); 68 69 page = address >> PAGEBITS; 70 offset = (address & OFFSETBITS) >> 2; 71 pagetable = (ARMword **) state->MemDataPtr; 72 pageptr = *(pagetable + page); 73 74 if (pageptr == NULL) 75 { 76 pageptr = (ARMword *) malloc (PAGESIZE); 77 78 if (pageptr == NULL) 79 { 80 perror ("ARMulator can't allocate VM page"); 81 exit (12); 82 } 83 84 *(pagetable + page) = pageptr; 85 } 86 87 return *(pageptr + offset); 88 } 89 90 /***************************************************************************\ 91 * Put a Word into Virtual Memory, maybe allocating the page * 92 \***************************************************************************/ 93 94 static void 95 PutWord (ARMul_State * state, ARMword address, ARMword data, int check) 96 { 97 ARMword page; 98 ARMword offset; 99 ARMword **pagetable; 100 ARMword *pageptr; 101 102 if (check && state->is_XScale) 103 XScale_check_memacc (state, &address, 1); 104 105 page = address >> PAGEBITS; 106 offset = (address & OFFSETBITS) >> 2; 107 pagetable = (ARMword **) state->MemDataPtr; 108 pageptr = *(pagetable + page); 109 110 if (pageptr == NULL) 111 { 112 pageptr = (ARMword *) malloc (PAGESIZE); 113 if (pageptr == NULL) 114 { 115 perror ("ARMulator can't allocate VM page"); 116 exit (13); 117 } 118 119 *(pagetable + page) = pageptr; 120 } 121 122 if (address == 0x8) 123 SWI_vector_installed = TRUE; 124 125 *(pageptr + offset) = data; 126 } 127 128 /***************************************************************************\ 129 * Initialise the memory interface * 130 \***************************************************************************/ 131 132 unsigned 133 ARMul_MemoryInit (ARMul_State * state, unsigned long initmemsize) 134 { 135 ARMword **pagetable; 136 unsigned page; 137 138 if (initmemsize) 139 state->MemSize = initmemsize; 140 141 pagetable = (ARMword **) malloc (sizeof (ARMword *) * NUMPAGES); 142 143 if (pagetable == NULL) 144 return FALSE; 145 146 for (page = 0; page < NUMPAGES; page++) 147 *(pagetable + page) = NULL; 148 149 state->MemDataPtr = (unsigned char *) pagetable; 150 151 ARMul_ConsolePrint (state, ", 4 Gb memory"); 152 153 return TRUE; 154 } 155 156 /***************************************************************************\ 157 * Remove the memory interface * 158 \***************************************************************************/ 159 160 void 161 ARMul_MemoryExit (ARMul_State * state) 162 { 163 ARMword page; 164 ARMword **pagetable; 165 ARMword *pageptr; 166 167 pagetable = (ARMword **) state->MemDataPtr; 168 for (page = 0; page < NUMPAGES; page++) 169 { 170 pageptr = *(pagetable + page); 171 if (pageptr != NULL) 172 free ((char *) pageptr); 173 } 174 free ((char *) pagetable); 175 return; 176 } 177 178 /***************************************************************************\ 179 * ReLoad Instruction * 180 \***************************************************************************/ 181 182 ARMword 183 ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) 184 { 185 #ifdef ABORTS 186 if (address >= LOWABORT && address < HIGHABORT) 187 { 188 ARMul_PREFETCHABORT (address); 189 return ARMul_ABORTWORD; 190 } 191 else 192 { 193 ARMul_CLEARABORT; 194 } 195 #endif 196 197 if ((isize == 2) && (address & 0x2)) 198 { 199 /* We return the next two halfwords: */ 200 ARMword lo = GetWord (state, address, FALSE); 201 ARMword hi = GetWord (state, address + 4, FALSE); 202 203 if (state->bigendSig == HIGH) 204 return (lo << 16) | (hi >> 16); 205 else 206 return ((hi & 0xFFFF) << 16) | (lo >> 16); 207 } 208 209 return GetWord (state, address, TRUE); 210 } 211 212 /***************************************************************************\ 213 * Load Instruction, Sequential Cycle * 214 \***************************************************************************/ 215 216 ARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) 217 { 218 state->NumScycles++; 219 220 #ifdef HOURGLASS 221 if ((state->NumScycles & HOURGLASS_RATE) == 0) 222 { 223 HOURGLASS; 224 } 225 #endif 226 227 return ARMul_ReLoadInstr (state, address, isize); 228 } 229 230 /***************************************************************************\ 231 * Load Instruction, Non Sequential Cycle * 232 \***************************************************************************/ 233 234 ARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) 235 { 236 state->NumNcycles++; 237 238 return ARMul_ReLoadInstr (state, address, isize); 239 } 240 241 /***************************************************************************\ 242 * Read Word (but don't tell anyone!) * 243 \***************************************************************************/ 244 245 ARMword ARMul_ReadWord (ARMul_State * state, ARMword address) 246 { 247 #ifdef ABORTS 248 if (address >= LOWABORT && address < HIGHABORT) 249 { 250 ARMul_DATAABORT (address); 251 return ARMul_ABORTWORD; 252 } 253 else 254 { 255 ARMul_CLEARABORT; 256 } 257 #endif 258 259 return GetWord (state, address, TRUE); 260 } 261 262 /***************************************************************************\ 263 * Load Word, Sequential Cycle * 264 \***************************************************************************/ 265 266 ARMword ARMul_LoadWordS (ARMul_State * state, ARMword address) 267 { 268 state->NumScycles++; 269 270 return ARMul_ReadWord (state, address); 271 } 272 273 /***************************************************************************\ 274 * Load Word, Non Sequential Cycle * 275 \***************************************************************************/ 276 277 ARMword ARMul_LoadWordN (ARMul_State * state, ARMword address) 278 { 279 state->NumNcycles++; 280 281 return ARMul_ReadWord (state, address); 282 } 283 284 /***************************************************************************\ 285 * Load Halfword, (Non Sequential Cycle) * 286 \***************************************************************************/ 287 288 ARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address) 289 { 290 ARMword temp, offset; 291 292 state->NumNcycles++; 293 294 temp = ARMul_ReadWord (state, address); 295 offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ 296 297 return (temp >> offset) & 0xffff; 298 } 299 300 /***************************************************************************\ 301 * Read Byte (but don't tell anyone!) * 302 \***************************************************************************/ 303 304 ARMword ARMul_ReadByte (ARMul_State * state, ARMword address) 305 { 306 ARMword temp, offset; 307 308 temp = ARMul_ReadWord (state, address); 309 offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ 310 311 return (temp >> offset & 0xffL); 312 } 313 314 /***************************************************************************\ 315 * Load Byte, (Non Sequential Cycle) * 316 \***************************************************************************/ 317 318 ARMword ARMul_LoadByte (ARMul_State * state, ARMword address) 319 { 320 state->NumNcycles++; 321 322 return ARMul_ReadByte (state, address); 323 } 324 325 /***************************************************************************\ 326 * Write Word (but don't tell anyone!) * 327 \***************************************************************************/ 328 329 void 330 ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) 331 { 332 #ifdef ABORTS 333 if (address >= LOWABORT && address < HIGHABORT) 334 { 335 ARMul_DATAABORT (address); 336 return; 337 } 338 else 339 { 340 ARMul_CLEARABORT; 341 } 342 #endif 343 344 PutWord (state, address, data, TRUE); 345 } 346 347 /***************************************************************************\ 348 * Store Word, Sequential Cycle * 349 \***************************************************************************/ 350 351 void 352 ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) 353 { 354 state->NumScycles++; 355 356 ARMul_WriteWord (state, address, data); 357 } 358 359 /***************************************************************************\ 360 * Store Word, Non Sequential Cycle * 361 \***************************************************************************/ 362 363 void 364 ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) 365 { 366 state->NumNcycles++; 367 368 ARMul_WriteWord (state, address, data); 369 } 370 371 /***************************************************************************\ 372 * Store HalfWord, (Non Sequential Cycle) * 373 \***************************************************************************/ 374 375 void 376 ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) 377 { 378 ARMword temp, offset; 379 380 state->NumNcycles++; 381 382 #ifdef VALIDATE 383 if (address == TUBE) 384 { 385 if (data == 4) 386 state->Emulate = FALSE; 387 else 388 (void) putc ((char) data, stderr); /* Write Char */ 389 return; 390 } 391 #endif 392 393 temp = ARMul_ReadWord (state, address); 394 offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ 395 396 PutWord (state, address, 397 (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset), 398 TRUE); 399 } 400 401 /***************************************************************************\ 402 * Write Byte (but don't tell anyone!) * 403 \***************************************************************************/ 404 405 void 406 ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) 407 { 408 ARMword temp, offset; 409 410 temp = ARMul_ReadWord (state, address); 411 offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ 412 413 PutWord (state, address, 414 (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset), 415 TRUE); 416 } 417 418 /***************************************************************************\ 419 * Store Byte, (Non Sequential Cycle) * 420 \***************************************************************************/ 421 422 void 423 ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) 424 { 425 state->NumNcycles++; 426 427 #ifdef VALIDATE 428 if (address == TUBE) 429 { 430 if (data == 4) 431 state->Emulate = FALSE; 432 else 433 (void) putc ((char) data, stderr); /* Write Char */ 434 return; 435 } 436 #endif 437 438 ARMul_WriteByte (state, address, data); 439 } 440 441 /***************************************************************************\ 442 * Swap Word, (Two Non Sequential Cycles) * 443 \***************************************************************************/ 444 445 ARMword ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) 446 { 447 ARMword temp; 448 449 state->NumNcycles++; 450 451 temp = ARMul_ReadWord (state, address); 452 453 state->NumNcycles++; 454 455 PutWord (state, address, data, TRUE); 456 457 return temp; 458 } 459 460 /***************************************************************************\ 461 * Swap Byte, (Two Non Sequential Cycles) * 462 \***************************************************************************/ 463 464 ARMword ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) 465 { 466 ARMword temp; 467 468 temp = ARMul_LoadByte (state, address); 469 ARMul_StoreByte (state, address, data); 470 471 return temp; 472 } 473 474 /***************************************************************************\ 475 * Count I Cycles * 476 \***************************************************************************/ 477 478 void 479 ARMul_Icycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) 480 { 481 state->NumIcycles += number; 482 ARMul_CLEARABORT; 483 } 484 485 /***************************************************************************\ 486 * Count C Cycles * 487 \***************************************************************************/ 488 489 void 490 ARMul_Ccycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) 491 { 492 state->NumCcycles += number; 493 ARMul_CLEARABORT; 494 } 495 496 497 /* Read a byte. Do not check for alignment or access errors. */ 498 499 ARMword 500 ARMul_SafeReadByte (ARMul_State * state, ARMword address) 501 { 502 ARMword temp, offset; 503 504 temp = GetWord (state, address, FALSE); 505 offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; 506 507 return (temp >> offset & 0xffL); 508 } 509 510 void 511 ARMul_SafeWriteByte (ARMul_State * state, ARMword address, ARMword data) 512 { 513 ARMword temp, offset; 514 515 temp = GetWord (state, address, FALSE); 516 offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; 517 518 PutWord (state, address, 519 (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset), 520 FALSE); 521 } 522