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