armvirt.c revision 1.5
1207536Smav/*  armvirt.c -- ARMulator virtual memory interace:  ARM6 Instruction Emulator.
2207536Smav    Copyright (C) 1994 Advanced RISC Machines Ltd.
3207536Smav
4207536Smav    This program is free software; you can redistribute it and/or modify
5207536Smav    it under the terms of the GNU General Public License as published by
6207536Smav    the Free Software Foundation; either version 3 of the License, or
7207536Smav    (at your option) any later version.
8207536Smav
9207536Smav    This program is distributed in the hope that it will be useful,
10207536Smav    but WITHOUT ANY WARRANTY; without even the implied warranty of
11207536Smav    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12207536Smav    GNU General Public License for more details.
13207536Smav
14207536Smav    You should have received a copy of the GNU General Public License
15207536Smav    along with this program; if not, see <http://www.gnu.org/licenses/>. */
16207536Smav
17207536Smav/* This file contains a complete ARMulator memory model, modelling a
18207536Smav"virtual memory" system. A much simpler model can be found in armfast.c,
19207536Smavand that model goes faster too, but has a fixed amount of memory. This
20207536Smavmodel's memory has 64K pages, allocated on demand from a 64K entry page
21207536Smavtable. The routines PutWord and GetWord implement this. Pages are never
22207536Smavfreed as they might be needed again. A single area of memory may be
23207536Smavdefined to generate aborts. */
24207536Smav
25207536Smav#include "armopts.h"
26207536Smav#include "armos.h"
27207536Smav#include "armdefs.h"
28207536Smav#include "ansidecl.h"
29207536Smav
30207536Smav#ifdef VALIDATE			/* for running the validate suite */
31207536Smav#define TUBE 48 * 1024 * 1024	/* write a char on the screen */
32207536Smav#define ABORTS 1
33207536Smav#endif
34207536Smav
35207536Smav/* #define ABORTS */
36207536Smav
37207536Smav#ifdef ABORTS			/* the memory system will abort */
38207536Smav/* For the old test suite Abort between 32 Kbytes and 32 Mbytes
39207536Smav   For the new test suite Abort between 8 Mbytes and 26 Mbytes */
40207536Smav/* #define LOWABORT 32 * 1024
41207536Smav#define HIGHABORT 32 * 1024 * 1024 */
42207536Smav#define LOWABORT 8 * 1024 * 1024
43207536Smav#define HIGHABORT 26 * 1024 * 1024
44207536Smav
45207536Smav#endif
46207536Smav
47207536Smav#define NUMPAGES 64 * 1024
48207536Smav#define PAGESIZE 64 * 1024
49207536Smav#define PAGEBITS 16
50207536Smav#define OFFSETBITS 0xffff
51207536Smav
52207536Smavint SWI_vector_installed = FALSE;
53207536Smav
54207536Smav/***************************************************************************\
55207536Smav*        Get a Word from Virtual Memory, maybe allocating the page          *
56207536Smav\***************************************************************************/
57207536Smav
58207536Smavstatic ARMword
59207536SmavGetWord (ARMul_State * state, ARMword address, int check)
60207536Smav{
61207536Smav  ARMword page;
62207536Smav  ARMword offset;
63207536Smav  ARMword **pagetable;
64207536Smav  ARMword *pageptr;
65207536Smav
66207536Smav  if (check && state->is_XScale)
67207536Smav    XScale_check_memacc (state, &address, 0);
68207536Smav
69207536Smav  page = address >> PAGEBITS;
70207536Smav  offset = (address & OFFSETBITS) >> 2;
71207536Smav  pagetable = (ARMword **) state->MemDataPtr;
72207536Smav  pageptr = *(pagetable + page);
73207536Smav
74207536Smav  if (pageptr == NULL)
75207536Smav    {
76207536Smav      pageptr = (ARMword *) malloc (PAGESIZE);
77207536Smav
78207536Smav      if (pageptr == NULL)
79207536Smav	{
80207536Smav	  perror ("ARMulator can't allocate VM page");
81207536Smav	  exit (12);
82207536Smav	}
83207536Smav
84207536Smav      *(pagetable + page) = pageptr;
85207536Smav    }
86207536Smav
87207536Smav  return *(pageptr + offset);
88207536Smav}
89207536Smav
90207536Smav/***************************************************************************\
91207536Smav*        Put a Word into Virtual Memory, maybe allocating the page          *
92207536Smav\***************************************************************************/
93207536Smav
94207536Smavstatic void
95207536SmavPutWord (ARMul_State * state, ARMword address, ARMword data, int check)
96207536Smav{
97207536Smav  ARMword page;
98207536Smav  ARMword offset;
99207536Smav  ARMword **pagetable;
100207536Smav  ARMword *pageptr;
101207536Smav
102207536Smav  if (check && state->is_XScale)
103207536Smav    XScale_check_memacc (state, &address, 1);
104207536Smav
105207536Smav  page = address >> PAGEBITS;
106207536Smav  offset = (address & OFFSETBITS) >> 2;
107207536Smav  pagetable = (ARMword **) state->MemDataPtr;
108207536Smav  pageptr = *(pagetable + page);
109207536Smav
110207536Smav  if (pageptr == NULL)
111207536Smav    {
112207536Smav      pageptr = (ARMword *) malloc (PAGESIZE);
113207536Smav      if (pageptr == NULL)
114207536Smav	{
115207536Smav	  perror ("ARMulator can't allocate VM page");
116207536Smav	  exit (13);
117207536Smav	}
118207536Smav
119207536Smav      *(pagetable + page) = pageptr;
120207536Smav    }
121207536Smav
122207536Smav  if (address == 0x8)
123207536Smav    SWI_vector_installed = TRUE;
124207536Smav
125207536Smav  *(pageptr + offset) = data;
126207536Smav}
127207536Smav
128207536Smav/***************************************************************************\
129207536Smav*                      Initialise the memory interface                      *
130207536Smav\***************************************************************************/
131207536Smav
132207536Smavunsigned
133207536SmavARMul_MemoryInit (ARMul_State * state, unsigned long initmemsize)
134207536Smav{
135207536Smav  ARMword **pagetable;
136207536Smav  unsigned page;
137207536Smav
138207536Smav  if (initmemsize)
139207536Smav    state->MemSize = initmemsize;
140207536Smav
141207536Smav  pagetable = (ARMword **) malloc (sizeof (ARMword *) * NUMPAGES);
142207536Smav
143207536Smav  if (pagetable == NULL)
144207536Smav    return FALSE;
145207536Smav
146207536Smav  for (page = 0; page < NUMPAGES; page++)
147207536Smav    *(pagetable + page) = NULL;
148207536Smav
149207536Smav  state->MemDataPtr = (unsigned char *) pagetable;
150207536Smav
151207536Smav  ARMul_ConsolePrint (state, ", 4 Gb memory");
152207536Smav
153207536Smav  return TRUE;
154207536Smav}
155207536Smav
156207536Smav/***************************************************************************\
157207536Smav*                         Remove the memory interface                       *
158207536Smav\***************************************************************************/
159207536Smav
160207536Smavvoid
161207536SmavARMul_MemoryExit (ARMul_State * state)
162207536Smav{
163207536Smav  ARMword page;
164207536Smav  ARMword **pagetable;
165207536Smav  ARMword *pageptr;
166207536Smav
167207536Smav  pagetable = (ARMword **) state->MemDataPtr;
168207536Smav  for (page = 0; page < NUMPAGES; page++)
169207536Smav    {
170207536Smav      pageptr = *(pagetable + page);
171207536Smav      if (pageptr != NULL)
172207536Smav	free ((char *) pageptr);
173207536Smav    }
174207536Smav  free ((char *) pagetable);
175207536Smav  return;
176207536Smav}
177207536Smav
178207536Smav/***************************************************************************\
179207536Smav*                   ReLoad Instruction                                     *
180207536Smav\***************************************************************************/
181207536Smav
182207536SmavARMword
183207536SmavARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize)
184207536Smav{
185207536Smav#ifdef ABORTS
186207536Smav  if (address >= LOWABORT && address < HIGHABORT)
187207536Smav    {
188207536Smav      ARMul_PREFETCHABORT (address);
189207536Smav      return ARMul_ABORTWORD;
190207536Smav    }
191207536Smav  else
192207536Smav    {
193207536Smav      ARMul_CLEARABORT;
194207536Smav    }
195207536Smav#endif
196207536Smav
197207536Smav  if ((isize == 2) && (address & 0x2))
198207536Smav    {
199207536Smav      /* We return the next two halfwords: */
200207536Smav      ARMword lo = GetWord (state, address, FALSE);
201207536Smav      ARMword hi = GetWord (state, address + 4, FALSE);
202207536Smav
203207536Smav      if (state->bigendSig == HIGH)
204207536Smav	return (lo << 16) | (hi >> 16);
205207536Smav      else
206207536Smav	return ((hi & 0xFFFF) << 16) | (lo >> 16);
207207536Smav    }
208207536Smav
209207536Smav  return GetWord (state, address, TRUE);
210207536Smav}
211207536Smav
212207536Smav/***************************************************************************\
213207536Smav*                   Load Instruction, Sequential Cycle                      *
214207536Smav\***************************************************************************/
215207536Smav
216207536SmavARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize)
217207536Smav{
218207536Smav  state->NumScycles++;
219207536Smav
220207536Smav#ifdef HOURGLASS
221207536Smav  if ((state->NumScycles & HOURGLASS_RATE) == 0)
222207536Smav    {
223207536Smav      HOURGLASS;
224207536Smav    }
225207536Smav#endif
226207536Smav
227207536Smav  return ARMul_ReLoadInstr (state, address, isize);
228207536Smav}
229207536Smav
230207536Smav/***************************************************************************\
231207536Smav*                 Load Instruction, Non Sequential Cycle                    *
232207536Smav\***************************************************************************/
233207536Smav
234207536SmavARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize)
235207536Smav{
236207536Smav  state->NumNcycles++;
237207536Smav
238207536Smav  return ARMul_ReLoadInstr (state, address, isize);
239207536Smav}
240207536Smav
241207536Smav/***************************************************************************\
242207536Smav*                      Read Word (but don't tell anyone!)                   *
243207536Smav\***************************************************************************/
244207536Smav
245207536SmavARMword ARMul_ReadWord (ARMul_State * state, ARMword address)
246207536Smav{
247207536Smav#ifdef ABORTS
248207536Smav  if (address >= LOWABORT && address < HIGHABORT)
249207536Smav    {
250207536Smav      ARMul_DATAABORT (address);
251207536Smav      return ARMul_ABORTWORD;
252207536Smav    }
253207536Smav  else
254207536Smav    {
255207536Smav      ARMul_CLEARABORT;
256207536Smav    }
257207536Smav#endif
258207536Smav
259207536Smav  return GetWord (state, address, TRUE);
260207536Smav}
261207536Smav
262207536Smav/***************************************************************************\
263207536Smav*                        Load Word, Sequential Cycle                        *
264207536Smav\***************************************************************************/
265207536Smav
266207536SmavARMword ARMul_LoadWordS (ARMul_State * state, ARMword address)
267207536Smav{
268207536Smav  state->NumScycles++;
269207536Smav
270207536Smav  return ARMul_ReadWord (state, address);
271207536Smav}
272207536Smav
273207536Smav/***************************************************************************\
274207536Smav*                      Load Word, Non Sequential Cycle                      *
275207536Smav\***************************************************************************/
276207536Smav
277207536SmavARMword ARMul_LoadWordN (ARMul_State * state, ARMword address)
278207536Smav{
279207536Smav  state->NumNcycles++;
280207536Smav
281207536Smav  return ARMul_ReadWord (state, address);
282207536Smav}
283207536Smav
284207536Smav/***************************************************************************\
285207536Smav*                     Load Halfword, (Non Sequential Cycle)                 *
286207536Smav\***************************************************************************/
287207536Smav
288207536SmavARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address)
289207536Smav{
290207536Smav  ARMword temp, offset;
291207536Smav
292207536Smav  state->NumNcycles++;
293207536Smav
294207536Smav  temp = ARMul_ReadWord (state, address);
295207536Smav  offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3;	/* bit offset into the word */
296207536Smav
297207536Smav  return (temp >> offset) & 0xffff;
298207536Smav}
299207536Smav
300207536Smav/***************************************************************************\
301207536Smav*                      Read Byte (but don't tell anyone!)                   *
302207536Smav\***************************************************************************/
303207536Smav
304207536SmavARMword ARMul_ReadByte (ARMul_State * state, ARMword address)
305207536Smav{
306207536Smav  ARMword temp, offset;
307207536Smav
308207536Smav  temp = ARMul_ReadWord (state, address);
309207536Smav  offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3;	/* bit offset into the word */
310207536Smav
311207536Smav  return (temp >> offset & 0xffL);
312207536Smav}
313207536Smav
314207536Smav/***************************************************************************\
315207536Smav*                     Load Byte, (Non Sequential Cycle)                     *
316207536Smav\***************************************************************************/
317207536Smav
318207536SmavARMword ARMul_LoadByte (ARMul_State * state, ARMword address)
319207536Smav{
320207536Smav  state->NumNcycles++;
321207536Smav
322207536Smav  return ARMul_ReadByte (state, address);
323207536Smav}
324207536Smav
325207536Smav/***************************************************************************\
326207536Smav*                     Write Word (but don't tell anyone!)                   *
327207536Smav\***************************************************************************/
328207536Smav
329207536Smavvoid
330207536SmavARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data)
331207536Smav{
332207536Smav#ifdef ABORTS
333207536Smav  if (address >= LOWABORT && address < HIGHABORT)
334207536Smav    {
335207536Smav      ARMul_DATAABORT (address);
336207536Smav      return;
337207536Smav    }
338207536Smav  else
339207536Smav    {
340207536Smav      ARMul_CLEARABORT;
341207536Smav    }
342207536Smav#endif
343207536Smav
344207536Smav  PutWord (state, address, data, TRUE);
345207536Smav}
346207536Smav
347207536Smav/***************************************************************************\
348207536Smav*                       Store Word, Sequential Cycle                        *
349207536Smav\***************************************************************************/
350207536Smav
351207536Smavvoid
352207536SmavARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data)
353207536Smav{
354207536Smav  state->NumScycles++;
355207536Smav
356207536Smav  ARMul_WriteWord (state, address, data);
357207536Smav}
358207536Smav
359207536Smav/***************************************************************************\
360207536Smav*                       Store Word, Non Sequential Cycle                        *
361207536Smav\***************************************************************************/
362207536Smav
363207536Smavvoid
364207536SmavARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data)
365207536Smav{
366207536Smav  state->NumNcycles++;
367207536Smav
368207536Smav  ARMul_WriteWord (state, address, data);
369207536Smav}
370207536Smav
371207536Smav/***************************************************************************\
372207536Smav*                    Store HalfWord, (Non Sequential Cycle)                 *
373207536Smav\***************************************************************************/
374207536Smav
375207536Smavvoid
376207536SmavARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data)
377207536Smav{
378207536Smav  ARMword temp, offset;
379207536Smav
380207536Smav  state->NumNcycles++;
381207536Smav
382207536Smav#ifdef VALIDATE
383207536Smav  if (address == TUBE)
384207536Smav    {
385207536Smav      if (data == 4)
386207536Smav	state->Emulate = FALSE;
387207536Smav      else
388207536Smav	(void) putc ((char) data, stderr);	/* Write Char */
389207536Smav      return;
390207536Smav    }
391207536Smav#endif
392207536Smav
393207536Smav  temp = ARMul_ReadWord (state, address);
394207536Smav  offset = (((ARMword) state->bigendSig * 2) ^ (address & 2)) << 3;	/* bit offset into the word */
395207536Smav
396207536Smav  PutWord (state, address,
397207536Smav	   (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset),
398207536Smav	   TRUE);
399207536Smav}
400207536Smav
401207536Smav/***************************************************************************\
402207536Smav*                     Write Byte (but don't tell anyone!)                   *
403207536Smav\***************************************************************************/
404207536Smav
405207536Smavvoid
406207536SmavARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data)
407207536Smav{
408207536Smav  ARMword temp, offset;
409207536Smav
410207536Smav  temp = ARMul_ReadWord (state, address);
411207536Smav  offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3;	/* bit offset into the word */
412207536Smav
413207536Smav  PutWord (state, address,
414207536Smav	   (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset),
415207536Smav	   TRUE);
416207536Smav}
417207536Smav
418207536Smav/***************************************************************************\
419207536Smav*                    Store Byte, (Non Sequential Cycle)                     *
420207536Smav\***************************************************************************/
421207536Smav
422207536Smavvoid
423207536SmavARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data)
424207536Smav{
425207536Smav  state->NumNcycles++;
426207536Smav
427207536Smav#ifdef VALIDATE
428207536Smav  if (address == TUBE)
429207536Smav    {
430207536Smav      if (data == 4)
431207536Smav	state->Emulate = FALSE;
432207536Smav      else
433207536Smav	(void) putc ((char) data, stderr);	/* Write Char */
434207536Smav      return;
435207536Smav    }
436207536Smav#endif
437207536Smav
438207536Smav  ARMul_WriteByte (state, address, data);
439207536Smav}
440207536Smav
441207536Smav/***************************************************************************\
442207536Smav*                   Swap Word, (Two Non Sequential Cycles)                  *
443207536Smav\***************************************************************************/
444207536Smav
445207536SmavARMword ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data)
446207536Smav{
447207536Smav  ARMword temp;
448207536Smav
449207536Smav  state->NumNcycles++;
450207536Smav
451207536Smav  temp = ARMul_ReadWord (state, address);
452207536Smav
453207536Smav  state->NumNcycles++;
454207536Smav
455207536Smav  PutWord (state, address, data, TRUE);
456207536Smav
457207536Smav  return temp;
458207536Smav}
459207536Smav
460207536Smav/***************************************************************************\
461207536Smav*                   Swap Byte, (Two Non Sequential Cycles)                  *
462207536Smav\***************************************************************************/
463207536Smav
464207536SmavARMword ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data)
465207536Smav{
466207536Smav  ARMword temp;
467207536Smav
468207536Smav  temp = ARMul_LoadByte (state, address);
469207536Smav  ARMul_StoreByte (state, address, data);
470207536Smav
471207536Smav  return temp;
472207536Smav}
473207536Smav
474207536Smav/***************************************************************************\
475207536Smav*                             Count I Cycles                                *
476207536Smav\***************************************************************************/
477207536Smav
478207536Smavvoid
479207536SmavARMul_Icycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED)
480207536Smav{
481207536Smav  state->NumIcycles += number;
482207536Smav  ARMul_CLEARABORT;
483207536Smav}
484207536Smav
485208410Smav/***************************************************************************\
486208410Smav*                             Count C Cycles                                *
487208410Smav\***************************************************************************/
488208410Smav
489208410Smavvoid
490208410SmavARMul_Ccycles (ARMul_State * state, unsigned number, ARMword address ATTRIBUTE_UNUSED)
491208410Smav{
492208410Smav  state->NumCcycles += number;
493208410Smav  ARMul_CLEARABORT;
494208410Smav}
495207536Smav
496207536Smav
497207536Smav/* Read a byte.  Do not check for alignment or access errors.  */
498207536Smav
499207536SmavARMword
500207536SmavARMul_SafeReadByte (ARMul_State * state, ARMword address)
501207536Smav{
502207536Smav  ARMword temp, offset;
503207536Smav
504207536Smav  temp = GetWord (state, address, FALSE);
505207536Smav  offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3;
506208410Smav
507207536Smav  return (temp >> offset & 0xffL);
508207536Smav}
509207536Smav
510207536Smavvoid
511207536SmavARMul_SafeWriteByte (ARMul_State * state, ARMword address, ARMword data)
512207536Smav{
513207536Smav  ARMword temp, offset;
514207536Smav
515207536Smav  temp = GetWord (state, address, FALSE);
516207536Smav  offset = (((ARMword) state->bigendSig * 3) ^ (address & 3)) << 3;
517207536Smav
518207536Smav  PutWord (state, address,
519	   (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset),
520	   FALSE);
521}
522