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