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