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