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