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 55int SWI_vector_installed = FALSE; 56 57/***************************************************************************\ 58* Get a Word from Virtual Memory, maybe allocating the page * 59\***************************************************************************/ 60 61static ARMword 62GetWord (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 97static void 98PutWord (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 135unsigned 136ARMul_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 163void 164ARMul_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 185ARMword 186ARMul_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 219ARMword 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 230ARMword 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 241ARMword 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 262ARMword 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 273ARMword 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 284ARMword 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 300ARMword 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 314ARMword 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 325void 326ARMul_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 347void 348ARMul_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 359void 360ARMul_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 371void 372ARMul_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 401void 402ARMul_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 418void 419ARMul_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 441ARMword 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 460ARMword 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 474void 475ARMul_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 485void 486ARMul_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 495ARMword 496ARMul_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 506void 507ARMul_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