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