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