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 | |
6 | the Free Software Foundation; either version 2 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, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | /* This file contains a complete ARMulator memory model, modelling a | |
19 | "virtual memory" system. A much simpler model can be found in armfast.c, | |
20 | and that model goes faster too, but has a fixed amount of memory. This | |
21 | model's memory has 64K pages, allocated on demand from a 64K entry page | |
22 | table. The routines PutWord and GetWord implement this. Pages are never | |
23 | freed as they might be needed again. A single area of memory may be | |
24 | defined to generate aborts. */ | |
25 | ||
26 | #include "armopts.h" | |
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 | |
59 | GetWord (ARMul_State * state, ARMword address) | |
60 | { | |
dfcd3bfb JM |
61 | ARMword page; |
62 | ARMword offset; | |
63 | ARMword **pagetable; | |
64 | ARMword *pageptr; | |
c906108c | 65 | |
dfcd3bfb JM |
66 | page = address >> PAGEBITS; |
67 | offset = (address & OFFSETBITS) >> 2; | |
c906108c | 68 | pagetable = (ARMword **) state->MemDataPtr; |
dfcd3bfb JM |
69 | pageptr = *(pagetable + page); |
70 | ||
c906108c SS |
71 | if (pageptr == NULL) |
72 | { | |
73 | pageptr = (ARMword *) malloc (PAGESIZE); | |
dfcd3bfb | 74 | |
c906108c SS |
75 | if (pageptr == NULL) |
76 | { | |
77 | perror ("ARMulator can't allocate VM page"); | |
78 | exit (12); | |
79 | } | |
dfcd3bfb | 80 | |
c906108c SS |
81 | *(pagetable + page) = pageptr; |
82 | } | |
dfcd3bfb | 83 | |
c906108c SS |
84 | return *(pageptr + offset); |
85 | } | |
86 | ||
87 | /***************************************************************************\ | |
88 | * Put a Word into Virtual Memory, maybe allocating the page * | |
89 | \***************************************************************************/ | |
90 | ||
91 | static void | |
92 | PutWord (ARMul_State * state, ARMword address, ARMword data) | |
93 | { | |
dfcd3bfb JM |
94 | ARMword page; |
95 | ARMword offset; | |
96 | ARMword **pagetable; | |
97 | ARMword *pageptr; | |
98 | ||
99 | page = address >> PAGEBITS; | |
100 | offset = (address & OFFSETBITS) >> 2; | |
101 | pagetable = (ARMword **) state->MemDataPtr; | |
102 | pageptr = *(pagetable + page); | |
103 | ||
c906108c SS |
104 | if (pageptr == NULL) |
105 | { | |
106 | pageptr = (ARMword *) malloc (PAGESIZE); | |
107 | if (pageptr == NULL) | |
108 | { | |
109 | perror ("ARMulator can't allocate VM page"); | |
dfcd3bfb | 110 | exit (13); |
c906108c | 111 | } |
dfcd3bfb | 112 | |
c906108c SS |
113 | *(pagetable + page) = pageptr; |
114 | } | |
dfcd3bfb | 115 | |
88694af3 NC |
116 | if (address == 0x8) |
117 | SWI_vector_installed = TRUE; | |
118 | ||
c906108c SS |
119 | *(pageptr + offset) = data; |
120 | } | |
121 | ||
122 | /***************************************************************************\ | |
123 | * Initialise the memory interface * | |
124 | \***************************************************************************/ | |
125 | ||
126 | unsigned | |
127 | ARMul_MemoryInit (ARMul_State * state, unsigned long initmemsize) | |
128 | { | |
dfcd3bfb JM |
129 | ARMword **pagetable; |
130 | unsigned page; | |
c906108c SS |
131 | |
132 | if (initmemsize) | |
133 | state->MemSize = initmemsize; | |
dfcd3bfb | 134 | |
c906108c | 135 | pagetable = (ARMword **) malloc (sizeof (ARMword) * NUMPAGES); |
dfcd3bfb | 136 | |
c906108c SS |
137 | if (pagetable == NULL) |
138 | return FALSE; | |
dfcd3bfb JM |
139 | |
140 | for (page = 0; page < NUMPAGES; page++) | |
c906108c | 141 | *(pagetable + page) = NULL; |
dfcd3bfb JM |
142 | |
143 | state->MemDataPtr = (unsigned char *) pagetable; | |
c906108c SS |
144 | |
145 | ARMul_ConsolePrint (state, ", 4 Gb memory"); | |
dfcd3bfb JM |
146 | |
147 | return TRUE; | |
c906108c SS |
148 | } |
149 | ||
150 | /***************************************************************************\ | |
151 | * Remove the memory interface * | |
152 | \***************************************************************************/ | |
153 | ||
154 | void | |
155 | ARMul_MemoryExit (ARMul_State * state) | |
156 | { | |
dfcd3bfb JM |
157 | ARMword page; |
158 | ARMword **pagetable; | |
159 | ARMword *pageptr; | |
c906108c | 160 | |
dfcd3bfb JM |
161 | pagetable = (ARMword **) state->MemDataPtr; |
162 | for (page = 0; page < NUMPAGES; page++) | |
c906108c SS |
163 | { |
164 | pageptr = *(pagetable + page); | |
165 | if (pageptr != NULL) | |
dfcd3bfb | 166 | free ((char *) pageptr); |
c906108c | 167 | } |
dfcd3bfb | 168 | free ((char *) pagetable); |
c906108c SS |
169 | return; |
170 | } | |
171 | ||
172 | /***************************************************************************\ | |
173 | * ReLoad Instruction * | |
174 | \***************************************************************************/ | |
175 | ||
176 | ARMword | |
177 | ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) | |
178 | { | |
179 | #ifdef ABORTS | |
dfcd3bfb | 180 | if (address >= LOWABORT && address < HIGHABORT) |
c906108c SS |
181 | { |
182 | ARMul_PREFETCHABORT (address); | |
183 | return ARMul_ABORTWORD; | |
184 | } | |
dfcd3bfb JM |
185 | else |
186 | { | |
187 | ARMul_CLEARABORT; | |
188 | } | |
c906108c SS |
189 | #endif |
190 | ||
dfcd3bfb JM |
191 | if ((isize == 2) && (address & 0x2)) |
192 | { | |
193 | /* We return the next two halfwords: */ | |
194 | ARMword lo = GetWord (state, address); | |
195 | ARMword hi = GetWord (state, address + 4); | |
c906108c | 196 | |
dfcd3bfb JM |
197 | if (state->bigendSig == HIGH) |
198 | return (lo << 16) | (hi >> 16); | |
199 | else | |
200 | return ((hi & 0xFFFF) << 16) | (lo >> 16); | |
201 | } | |
c906108c SS |
202 | |
203 | return GetWord (state, address); | |
204 | } | |
205 | ||
206 | /***************************************************************************\ | |
207 | * Load Instruction, Sequential Cycle * | |
208 | \***************************************************************************/ | |
209 | ||
dfcd3bfb | 210 | ARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) |
c906108c | 211 | { |
dfcd3bfb | 212 | state->NumScycles++; |
c906108c SS |
213 | |
214 | #ifdef HOURGLASS | |
dfcd3bfb | 215 | if ((state->NumScycles & HOURGLASS_RATE) == 0) |
c906108c SS |
216 | { |
217 | HOURGLASS; | |
218 | } | |
219 | #endif | |
220 | ||
221 | return ARMul_ReLoadInstr (state, address, isize); | |
222 | } | |
223 | ||
224 | /***************************************************************************\ | |
225 | * Load Instruction, Non Sequential Cycle * | |
226 | \***************************************************************************/ | |
227 | ||
dfcd3bfb | 228 | ARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) |
c906108c | 229 | { |
dfcd3bfb | 230 | state->NumNcycles++; |
c906108c SS |
231 | |
232 | return ARMul_ReLoadInstr (state, address, isize); | |
233 | } | |
234 | ||
235 | /***************************************************************************\ | |
236 | * Read Word (but don't tell anyone!) * | |
237 | \***************************************************************************/ | |
238 | ||
dfcd3bfb | 239 | ARMword ARMul_ReadWord (ARMul_State * state, ARMword address) |
c906108c SS |
240 | { |
241 | #ifdef ABORTS | |
242 | if (address >= LOWABORT && address < HIGHABORT) | |
243 | { | |
244 | ARMul_DATAABORT (address); | |
245 | return ARMul_ABORTWORD; | |
246 | } | |
247 | else | |
248 | { | |
249 | ARMul_CLEARABORT; | |
250 | } | |
251 | #endif | |
252 | ||
253 | return GetWord (state, address); | |
254 | } | |
255 | ||
256 | /***************************************************************************\ | |
257 | * Load Word, Sequential Cycle * | |
258 | \***************************************************************************/ | |
259 | ||
dfcd3bfb | 260 | ARMword ARMul_LoadWordS (ARMul_State * state, ARMword address) |
c906108c | 261 | { |
dfcd3bfb | 262 | state->NumScycles++; |
c906108c SS |
263 | |
264 | return ARMul_ReadWord (state, address); | |
265 | } | |
266 | ||
267 | /***************************************************************************\ | |
268 | * Load Word, Non Sequential Cycle * | |
269 | \***************************************************************************/ | |
270 | ||
dfcd3bfb | 271 | ARMword ARMul_LoadWordN (ARMul_State * state, ARMword address) |
c906108c | 272 | { |
dfcd3bfb JM |
273 | state->NumNcycles++; |
274 | ||
c906108c SS |
275 | return ARMul_ReadWord (state, address); |
276 | } | |
277 | ||
278 | /***************************************************************************\ | |
279 | * Load Halfword, (Non Sequential Cycle) * | |
280 | \***************************************************************************/ | |
281 | ||
dfcd3bfb | 282 | ARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address) |
c906108c SS |
283 | { |
284 | ARMword temp, offset; | |
285 | ||
dfcd3bfb | 286 | state->NumNcycles++; |
c906108c | 287 | |
dfcd3bfb JM |
288 | temp = ARMul_ReadWord (state, address); |
289 | offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ | |
c906108c SS |
290 | |
291 | return (temp >> offset) & 0xffff; | |
292 | } | |
293 | ||
294 | /***************************************************************************\ | |
295 | * Read Byte (but don't tell anyone!) * | |
296 | \***************************************************************************/ | |
297 | ||
dfcd3bfb | 298 | ARMword ARMul_ReadByte (ARMul_State * state, ARMword address) |
c906108c SS |
299 | { |
300 | ARMword temp, offset; | |
301 | ||
dfcd3bfb JM |
302 | temp = ARMul_ReadWord (state, address); |
303 | offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ | |
c906108c | 304 | |
dfcd3bfb | 305 | return (temp >> offset & 0xffL); |
c906108c SS |
306 | } |
307 | ||
308 | /***************************************************************************\ | |
309 | * Load Byte, (Non Sequential Cycle) * | |
310 | \***************************************************************************/ | |
311 | ||
dfcd3bfb | 312 | ARMword ARMul_LoadByte (ARMul_State * state, ARMword address) |
c906108c | 313 | { |
dfcd3bfb | 314 | state->NumNcycles++; |
c906108c SS |
315 | |
316 | return ARMul_ReadByte (state, address); | |
317 | } | |
318 | ||
319 | /***************************************************************************\ | |
320 | * Write Word (but don't tell anyone!) * | |
321 | \***************************************************************************/ | |
322 | ||
323 | void | |
324 | ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) | |
325 | { | |
326 | #ifdef ABORTS | |
327 | if (address >= LOWABORT && address < HIGHABORT) | |
328 | { | |
329 | ARMul_DATAABORT (address); | |
330 | return; | |
331 | } | |
332 | else | |
333 | { | |
334 | ARMul_CLEARABORT; | |
335 | } | |
336 | #endif | |
337 | ||
338 | PutWord (state, address, data); | |
339 | } | |
340 | ||
341 | /***************************************************************************\ | |
342 | * Store Word, Sequential Cycle * | |
343 | \***************************************************************************/ | |
344 | ||
345 | void | |
346 | ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) | |
347 | { | |
dfcd3bfb | 348 | state->NumScycles++; |
c906108c SS |
349 | |
350 | ARMul_WriteWord (state, address, data); | |
351 | } | |
352 | ||
353 | /***************************************************************************\ | |
354 | * Store Word, Non Sequential Cycle * | |
355 | \***************************************************************************/ | |
356 | ||
357 | void | |
358 | ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) | |
359 | { | |
dfcd3bfb | 360 | state->NumNcycles++; |
c906108c SS |
361 | |
362 | ARMul_WriteWord (state, address, data); | |
363 | } | |
364 | ||
365 | /***************************************************************************\ | |
366 | * Store HalfWord, (Non Sequential Cycle) * | |
367 | \***************************************************************************/ | |
368 | ||
369 | void | |
370 | ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) | |
371 | { | |
372 | ARMword temp, offset; | |
373 | ||
dfcd3bfb JM |
374 | state->NumNcycles++; |
375 | ||
c906108c SS |
376 | #ifdef VALIDATE |
377 | if (address == TUBE) | |
378 | { | |
379 | if (data == 4) | |
380 | state->Emulate = FALSE; | |
381 | else | |
dfcd3bfb | 382 | (void) putc ((char) data, stderr); /* Write Char */ |
c906108c SS |
383 | return; |
384 | } | |
385 | #endif | |
386 | ||
dfcd3bfb JM |
387 | temp = ARMul_ReadWord (state, address); |
388 | offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */ | |
389 | ||
390 | PutWord (state, address, | |
391 | (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset)); | |
c906108c SS |
392 | } |
393 | ||
394 | /***************************************************************************\ | |
395 | * Write Byte (but don't tell anyone!) * | |
396 | \***************************************************************************/ | |
397 | ||
398 | void | |
399 | ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) | |
400 | { | |
401 | ARMword temp, offset; | |
402 | ||
dfcd3bfb JM |
403 | temp = ARMul_ReadWord (state, address); |
404 | offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */ | |
405 | ||
406 | PutWord (state, address, | |
407 | (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset)); | |
c906108c SS |
408 | } |
409 | ||
410 | /***************************************************************************\ | |
411 | * Store Byte, (Non Sequential Cycle) * | |
412 | \***************************************************************************/ | |
413 | ||
414 | void | |
415 | ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) | |
416 | { | |
dfcd3bfb | 417 | state->NumNcycles++; |
c906108c SS |
418 | |
419 | #ifdef VALIDATE | |
420 | if (address == TUBE) | |
421 | { | |
422 | if (data == 4) | |
423 | state->Emulate = FALSE; | |
424 | else | |
dfcd3bfb | 425 | (void) putc ((char) data, stderr); /* Write Char */ |
c906108c SS |
426 | return; |
427 | } | |
428 | #endif | |
429 | ||
430 | ARMul_WriteByte (state, address, data); | |
431 | } | |
432 | ||
433 | /***************************************************************************\ | |
434 | * Swap Word, (Two Non Sequential Cycles) * | |
435 | \***************************************************************************/ | |
436 | ||
dfcd3bfb | 437 | ARMword ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) |
c906108c SS |
438 | { |
439 | ARMword temp; | |
440 | ||
dfcd3bfb | 441 | state->NumNcycles++; |
c906108c SS |
442 | |
443 | temp = ARMul_ReadWord (state, address); | |
dfcd3bfb JM |
444 | |
445 | state->NumNcycles++; | |
446 | ||
c906108c | 447 | PutWord (state, address, data); |
dfcd3bfb | 448 | |
c906108c SS |
449 | return temp; |
450 | } | |
451 | ||
452 | /***************************************************************************\ | |
453 | * Swap Byte, (Two Non Sequential Cycles) * | |
454 | \***************************************************************************/ | |
455 | ||
dfcd3bfb | 456 | ARMword ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) |
c906108c SS |
457 | { |
458 | ARMword temp; | |
459 | ||
460 | temp = ARMul_LoadByte (state, address); | |
461 | ARMul_StoreByte (state, address, data); | |
dfcd3bfb | 462 | |
c906108c SS |
463 | return temp; |
464 | } | |
465 | ||
466 | /***************************************************************************\ | |
467 | * Count I Cycles * | |
468 | \***************************************************************************/ | |
469 | ||
470 | void | |
6d358e86 | 471 | ARMul_Icycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) |
c906108c SS |
472 | { |
473 | state->NumIcycles += number; | |
474 | ARMul_CLEARABORT; | |
475 | } | |
476 | ||
477 | /***************************************************************************\ | |
478 | * Count C Cycles * | |
479 | \***************************************************************************/ | |
480 | ||
481 | void | |
6d358e86 | 482 | ARMul_Ccycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED) |
c906108c SS |
483 | { |
484 | state->NumCcycles += number; | |
485 | ARMul_CLEARABORT; | |
486 | } |