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