unit at a time
[platform/upstream/binutils.git] / sim / arm / armvirt.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }