armvirt.c revision 1.5
1207536Smav/* armvirt.c -- ARMulator virtual memory interace: ARM6 Instruction Emulator. 2207536Smav Copyright (C) 1994 Advanced RISC Machines Ltd. 3207536Smav 4207536Smav This program is free software; you can redistribute it and/or modify 5207536Smav it under the terms of the GNU General Public License as published by 6207536Smav the Free Software Foundation; either version 3 of the License, or 7207536Smav (at your option) any later version. 8207536Smav 9207536Smav This program is distributed in the hope that it will be useful, 10207536Smav but WITHOUT ANY WARRANTY; without even the implied warranty of 11207536Smav MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12207536Smav GNU General Public License for more details. 13207536Smav 14207536Smav You should have received a copy of the GNU General Public License 15207536Smav along with this program; if not, see <http://www.gnu.org/licenses/>. */ 16207536Smav 17207536Smav/* This file contains a complete ARMulator memory model, modelling a 18207536Smav"virtual memory" system. A much simpler model can be found in armfast.c, 19207536Smavand that model goes faster too, but has a fixed amount of memory. This 20207536Smavmodel's memory has 64K pages, allocated on demand from a 64K entry page 21207536Smavtable. The routines PutWord and GetWord implement this. Pages are never 22207536Smavfreed as they might be needed again. A single area of memory may be 23207536Smavdefined to generate aborts. */ 24207536Smav 25207536Smav#include "armopts.h" 26207536Smav#include "armos.h" 27207536Smav#include "armdefs.h" 28207536Smav#include "ansidecl.h" 29207536Smav 30207536Smav#ifdef VALIDATE /* for running the validate suite */ 31207536Smav#define TUBE 48 * 1024 * 1024 /* write a char on the screen */ 32207536Smav#define ABORTS 1 33207536Smav#endif 34207536Smav 35207536Smav/* #define ABORTS */ 36207536Smav 37207536Smav#ifdef ABORTS /* the memory system will abort */ 38207536Smav/* For the old test suite Abort between 32 Kbytes and 32 Mbytes 39207536Smav For the new test suite Abort between 8 Mbytes and 26 Mbytes */ 40207536Smav/* #define LOWABORT 32 * 1024 41207536Smav#define HIGHABORT 32 * 1024 * 1024 */ 42207536Smav#define LOWABORT 8 * 1024 * 1024 43207536Smav#define HIGHABORT 26 * 1024 * 1024 44207536Smav 45207536Smav#endif 46207536Smav 47207536Smav#define NUMPAGES 64 * 1024 48207536Smav#define PAGESIZE 64 * 1024 49207536Smav#define PAGEBITS 16 50207536Smav#define OFFSETBITS 0xffff 51207536Smav 52207536Smavint SWI_vector_installed = FALSE; 53207536Smav 54207536Smav/***************************************************************************\ 55207536Smav* Get a Word from Virtual Memory, maybe allocating the page * 56207536Smav\***************************************************************************/ 57207536Smav 58207536Smavstatic ARMword 59207536SmavGetWord (ARMul_State * state, ARMword address, int check) 60207536Smav{ 61207536Smav ARMword page; 62207536Smav ARMword offset; 63207536Smav ARMword **pagetable; 64207536Smav ARMword *pageptr; 65207536Smav 66207536Smav if (check && state->is_XScale) 67207536Smav XScale_check_memacc (state, &address, 0); 68207536Smav 69207536Smav page = address >> PAGEBITS; 70207536Smav offset = (address & OFFSETBITS) >> 2; 71207536Smav pagetable = (ARMword **) state->MemDataPtr; 72207536Smav pageptr = *(pagetable + page); 73207536Smav 74207536Smav if (pageptr == NULL) 75207536Smav { 76207536Smav pageptr = (ARMword *) malloc (PAGESIZE); 77207536Smav 78207536Smav if (pageptr == NULL) 79207536Smav { 80207536Smav perror ("ARMulator can't allocate VM page"); 81207536Smav exit (12); 82207536Smav } 83207536Smav 84207536Smav *(pagetable + page) = pageptr; 85207536Smav } 86207536Smav 87207536Smav return *(pageptr + offset); 88207536Smav} 89207536Smav 90207536Smav/***************************************************************************\ 91207536Smav* Put a Word into Virtual Memory, maybe allocating the page * 92207536Smav\***************************************************************************/ 93207536Smav 94207536Smavstatic void 95207536SmavPutWord (ARMul_State * state, ARMword address, ARMword data, int check) 96207536Smav{ 97207536Smav ARMword page; 98207536Smav ARMword offset; 99207536Smav ARMword **pagetable; 100207536Smav ARMword *pageptr; 101207536Smav 102207536Smav if (check && state->is_XScale) 103207536Smav XScale_check_memacc (state, &address, 1); 104207536Smav 105207536Smav page = address >> PAGEBITS; 106207536Smav offset = (address & OFFSETBITS) >> 2; 107207536Smav pagetable = (ARMword **) state->MemDataPtr; 108207536Smav pageptr = *(pagetable + page); 109207536Smav 110207536Smav if (pageptr == NULL) 111207536Smav { 112207536Smav pageptr = (ARMword *) malloc (PAGESIZE); 113207536Smav if (pageptr == NULL) 114207536Smav { 115207536Smav perror ("ARMulator can't allocate VM page"); 116207536Smav exit (13); 117207536Smav } 118207536Smav 119207536Smav *(pagetable + page) = pageptr; 120207536Smav } 121207536Smav 122207536Smav if (address == 0x8) 123207536Smav SWI_vector_installed = TRUE; 124207536Smav 125207536Smav *(pageptr + offset) = data; 126207536Smav} 127207536Smav 128207536Smav/***************************************************************************\ 129207536Smav* Initialise the memory interface * 130207536Smav\***************************************************************************/ 131207536Smav 132207536Smavunsigned 133207536SmavARMul_MemoryInit (ARMul_State * state, unsigned long initmemsize) 134207536Smav{ 135207536Smav ARMword **pagetable; 136207536Smav unsigned page; 137207536Smav 138207536Smav if (initmemsize) 139207536Smav state->MemSize = initmemsize; 140207536Smav 141207536Smav pagetable = (ARMword **) malloc (sizeof (ARMword *) * NUMPAGES); 142207536Smav 143207536Smav if (pagetable == NULL) 144207536Smav return FALSE; 145207536Smav 146207536Smav for (page = 0; page < NUMPAGES; page++) 147207536Smav *(pagetable + page) = NULL; 148207536Smav 149207536Smav state->MemDataPtr = (unsigned char *) pagetable; 150207536Smav 151207536Smav ARMul_ConsolePrint (state, ", 4 Gb memory"); 152207536Smav 153207536Smav return TRUE; 154207536Smav} 155207536Smav 156207536Smav/***************************************************************************\ 157207536Smav* Remove the memory interface * 158207536Smav\***************************************************************************/ 159207536Smav 160207536Smavvoid 161207536SmavARMul_MemoryExit (ARMul_State * state) 162207536Smav{ 163207536Smav ARMword page; 164207536Smav ARMword **pagetable; 165207536Smav ARMword *pageptr; 166207536Smav 167207536Smav pagetable = (ARMword **) state->MemDataPtr; 168207536Smav for (page = 0; page < NUMPAGES; page++) 169207536Smav { 170207536Smav pageptr = *(pagetable + page); 171207536Smav if (pageptr != NULL) 172207536Smav free ((char *) pageptr); 173207536Smav } 174207536Smav free ((char *) pagetable); 175207536Smav return; 176207536Smav} 177207536Smav 178207536Smav/***************************************************************************\ 179207536Smav* ReLoad Instruction * 180207536Smav\***************************************************************************/ 181207536Smav 182207536SmavARMword 183207536SmavARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) 184207536Smav{ 185207536Smav#ifdef ABORTS 186207536Smav if (address >= LOWABORT && address < HIGHABORT) 187207536Smav { 188207536Smav ARMul_PREFETCHABORT (address); 189207536Smav return ARMul_ABORTWORD; 190207536Smav } 191207536Smav else 192207536Smav { 193207536Smav ARMul_CLEARABORT; 194207536Smav } 195207536Smav#endif 196207536Smav 197207536Smav if ((isize == 2) && (address & 0x2)) 198207536Smav { 199207536Smav /* We return the next two halfwords: */ 200207536Smav ARMword lo = GetWord (state, address, FALSE); 201207536Smav ARMword hi = GetWord (state, address + 4, FALSE); 202207536Smav 203207536Smav if (state->bigendSig == HIGH) 204207536Smav return (lo << 16) | (hi >> 16); 205207536Smav else 206207536Smav return ((hi & 0xFFFF) << 16) | (lo >> 16); 207207536Smav } 208207536Smav 209207536Smav return GetWord (state, address, TRUE); 210207536Smav} 211207536Smav 212207536Smav/***************************************************************************\ 213207536Smav* Load Instruction, Sequential Cycle * 214207536Smav\***************************************************************************/ 215207536Smav 216207536SmavARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) 217207536Smav{ 218207536Smav state->NumScycles++; 219207536Smav 220207536Smav#ifdef HOURGLASS 221207536Smav if ((state->NumScycles & HOURGLASS_RATE) == 0) 222207536Smav { 223207536Smav HOURGLASS; 224207536Smav } 225207536Smav#endif 226207536Smav 227207536Smav return ARMul_ReLoadInstr (state, address, isize); 228207536Smav} 229207536Smav 230207536Smav/***************************************************************************\ 231207536Smav* Load Instruction, Non Sequential Cycle * 232207536Smav\***************************************************************************/ 233207536Smav 234207536SmavARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) 235207536Smav{ 236207536Smav state->NumNcycles++; 237207536Smav 238207536Smav return ARMul_ReLoadInstr (state, address, isize); 239207536Smav} 240207536Smav 241207536Smav/***************************************************************************\ 242207536Smav* Read Word (but don't tell anyone!) * 243207536Smav\***************************************************************************/ 244207536Smav 245207536SmavARMword ARMul_ReadWord (ARMul_State * state, ARMword address) 246207536Smav{ 247207536Smav#ifdef ABORTS 248207536Smav if (address >= LOWABORT && address < HIGHABORT) 249207536Smav { 250207536Smav ARMul_DATAABORT (address); 251207536Smav return ARMul_ABORTWORD; 252207536Smav } 253207536Smav else 254207536Smav { 255207536Smav ARMul_CLEARABORT; 256207536Smav } 257207536Smav#endif 258207536Smav 259207536Smav return GetWord (state, address, TRUE); 260207536Smav} 261207536Smav 262207536Smav/***************************************************************************\ 263207536Smav* Load Word, Sequential Cycle * 264207536Smav\***************************************************************************/ 265207536Smav 266207536SmavARMword ARMul_LoadWordS (ARMul_State * state, ARMword address) 267207536Smav{ 268207536Smav state->NumScycles++; 269207536Smav 270207536Smav return ARMul_ReadWord (state, address); 271207536Smav} 272207536Smav 273207536Smav/***************************************************************************\ 274207536Smav* Load Word, Non Sequential Cycle * 275207536Smav\***************************************************************************/ 276207536Smav 277207536SmavARMword ARMul_LoadWordN (ARMul_State * state, ARMword address) 278207536Smav{ 279207536Smav state->NumNcycles++; 280207536Smav 281207536Smav return ARMul_ReadWord (state, address); 282207536Smav} 283207536Smav 284207536Smav/***************************************************************************\ 285207536Smav* Load Halfword, (Non Sequential Cycle) * 286207536Smav\***************************************************************************/ 287207536Smav 288207536SmavARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address) 289207536Smav{ 290207536Smav ARMword temp, offset; 291207536Smav 292207536Smav state->NumNcycles++; 293207536Smav 294207536Smav temp = ARMul_ReadWord (state, address); 295207536Smav offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ 296207536Smav 297207536Smav return (temp >> offset) & 0xffff; 298207536Smav} 299207536Smav 300207536Smav/***************************************************************************\ 301207536Smav* Read Byte (but don't tell anyone!) * 302207536Smav\***************************************************************************/ 303207536Smav 304207536SmavARMword ARMul_ReadByte (ARMul_State * state, ARMword address) 305207536Smav{ 306207536Smav ARMword temp, offset; 307207536Smav 308207536Smav temp = ARMul_ReadWord (state, address); 309207536Smav offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ 310207536Smav 311207536Smav return (temp >> offset & 0xffL); 312207536Smav} 313207536Smav 314207536Smav/***************************************************************************\ 315207536Smav* Load Byte, (Non Sequential Cycle) * 316207536Smav\***************************************************************************/ 317207536Smav 318207536SmavARMword ARMul_LoadByte (ARMul_State * state, ARMword address) 319207536Smav{ 320207536Smav state->NumNcycles++; 321207536Smav 322207536Smav return ARMul_ReadByte (state, address); 323207536Smav} 324207536Smav 325207536Smav/***************************************************************************\ 326207536Smav* Write Word (but don't tell anyone!) * 327207536Smav\***************************************************************************/ 328207536Smav 329207536Smavvoid 330207536SmavARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) 331207536Smav{ 332207536Smav#ifdef ABORTS 333207536Smav if (address >= LOWABORT && address < HIGHABORT) 334207536Smav { 335207536Smav ARMul_DATAABORT (address); 336207536Smav return; 337207536Smav } 338207536Smav else 339207536Smav { 340207536Smav ARMul_CLEARABORT; 341207536Smav } 342207536Smav#endif 343207536Smav 344207536Smav PutWord (state, address, data, TRUE); 345207536Smav} 346207536Smav 347207536Smav/***************************************************************************\ 348207536Smav* Store Word, Sequential Cycle * 349207536Smav\***************************************************************************/ 350207536Smav 351207536Smavvoid 352207536SmavARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) 353207536Smav{ 354207536Smav state->NumScycles++; 355207536Smav 356207536Smav ARMul_WriteWord (state, address, data); 357207536Smav} 358207536Smav 359207536Smav/***************************************************************************\ 360207536Smav* Store Word, Non Sequential Cycle * 361207536Smav\***************************************************************************/ 362207536Smav 363207536Smavvoid 364207536SmavARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) 365207536Smav{ 366207536Smav state->NumNcycles++; 367207536Smav 368207536Smav ARMul_WriteWord (state, address, data); 369207536Smav} 370207536Smav 371207536Smav/***************************************************************************\ 372207536Smav* Store HalfWord, (Non Sequential Cycle) * 373207536Smav\***************************************************************************/ 374207536Smav 375207536Smavvoid 376207536SmavARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) 377207536Smav{ 378207536Smav ARMword temp, offset; 379207536Smav 380207536Smav state->NumNcycles++; 381207536Smav 382207536Smav#ifdef VALIDATE 383207536Smav if (address == TUBE) 384207536Smav { 385207536Smav if (data == 4) 386207536Smav state->Emulate = FALSE; 387207536Smav else 388207536Smav (void) putc ((char) data, stderr); /* Write Char */ 389207536Smav return; 390207536Smav } 391207536Smav#endif 392207536Smav 393207536Smav temp = ARMul_ReadWord (state, address); 394207536Smav offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ 395207536Smav 396207536Smav PutWord (state, address, 397207536Smav (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset), 398207536Smav TRUE); 399207536Smav} 400207536Smav 401207536Smav/***************************************************************************\ 402207536Smav* Write Byte (but don't tell anyone!) * 403207536Smav\***************************************************************************/ 404207536Smav 405207536Smavvoid 406207536SmavARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) 407207536Smav{ 408207536Smav ARMword temp, offset; 409207536Smav 410207536Smav temp = ARMul_ReadWord (state, address); 411207536Smav offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ 412207536Smav 413207536Smav PutWord (state, address, 414207536Smav (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset), 415207536Smav TRUE); 416207536Smav} 417207536Smav 418207536Smav/***************************************************************************\ 419207536Smav* Store Byte, (Non Sequential Cycle) * 420207536Smav\***************************************************************************/ 421207536Smav 422207536Smavvoid 423207536SmavARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) 424207536Smav{ 425207536Smav state->NumNcycles++; 426207536Smav 427207536Smav#ifdef VALIDATE 428207536Smav if (address == TUBE) 429207536Smav { 430207536Smav if (data == 4) 431207536Smav state->Emulate = FALSE; 432207536Smav else 433207536Smav (void) putc ((char) data, stderr); /* Write Char */ 434207536Smav return; 435207536Smav } 436207536Smav#endif 437207536Smav 438207536Smav ARMul_WriteByte (state, address, data); 439207536Smav} 440207536Smav 441207536Smav/***************************************************************************\ 442207536Smav* Swap Word, (Two Non Sequential Cycles) * 443207536Smav\***************************************************************************/ 444207536Smav 445207536SmavARMword ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) 446207536Smav{ 447207536Smav ARMword temp; 448207536Smav 449207536Smav state->NumNcycles++; 450207536Smav 451207536Smav temp = ARMul_ReadWord (state, address); 452207536Smav 453207536Smav state->NumNcycles++; 454207536Smav 455207536Smav PutWord (state, address, data, TRUE); 456207536Smav 457207536Smav return temp; 458207536Smav} 459207536Smav 460207536Smav/***************************************************************************\ 461207536Smav* Swap Byte, (Two Non Sequential Cycles) * 462207536Smav\***************************************************************************/ 463207536Smav 464207536SmavARMword ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) 465207536Smav{ 466207536Smav ARMword temp; 467207536Smav 468207536Smav temp = ARMul_LoadByte (state, address); 469207536Smav ARMul_StoreByte (state, address, data); 470207536Smav 471207536Smav return temp; 472207536Smav} 473207536Smav 474207536Smav/***************************************************************************\ 475207536Smav* Count I Cycles * 476207536Smav\***************************************************************************/ 477207536Smav 478207536Smavvoid 479207536SmavARMul_Icycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) 480207536Smav{ 481207536Smav state->NumIcycles += number; 482207536Smav ARMul_CLEARABORT; 483207536Smav} 484207536Smav 485208410Smav/***************************************************************************\ 486208410Smav* Count C Cycles * 487208410Smav\***************************************************************************/ 488208410Smav 489208410Smavvoid 490208410SmavARMul_Ccycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) 491208410Smav{ 492208410Smav state->NumCcycles += number; 493208410Smav ARMul_CLEARABORT; 494208410Smav} 495207536Smav 496207536Smav 497207536Smav/* Read a byte. Do not check for alignment or access errors. */ 498207536Smav 499207536SmavARMword 500207536SmavARMul_SafeReadByte (ARMul_State * state, ARMword address) 501207536Smav{ 502207536Smav ARMword temp, offset; 503207536Smav 504207536Smav temp = GetWord (state, address, FALSE); 505207536Smav offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; 506208410Smav 507207536Smav return (temp >> offset & 0xffL); 508207536Smav} 509207536Smav 510207536Smavvoid 511207536SmavARMul_SafeWriteByte (ARMul_State * state, ARMword address, ARMword data) 512207536Smav{ 513207536Smav ARMword temp, offset; 514207536Smav 515207536Smav temp = GetWord (state, address, FALSE); 516207536Smav offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; 517207536Smav 518207536Smav PutWord (state, address, 519 (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset), 520 FALSE); 521} 522