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
GetWord(ARMul_State * state,ARMword address,int check)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
PutWord(ARMul_State * state,ARMword address,ARMword data,int check)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
ARMul_MemoryInit(ARMul_State * state,unsigned long initmemsize)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
ARMul_MemoryExit(ARMul_State * state)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
ARMul_ReLoadInstr(ARMul_State * state,ARMword address,ARMword isize)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 
ARMul_LoadInstrS(ARMul_State * state,ARMword address,ARMword isize)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 
ARMul_LoadInstrN(ARMul_State * state,ARMword address,ARMword isize)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 
ARMul_ReadWord(ARMul_State * state,ARMword address)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 
ARMul_LoadWordS(ARMul_State * state,ARMword address)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 
ARMul_LoadWordN(ARMul_State * state,ARMword address)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 
ARMul_LoadHalfWord(ARMul_State * state,ARMword address)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 
ARMul_ReadByte(ARMul_State * state,ARMword address)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 
ARMul_LoadByte(ARMul_State * state,ARMword address)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
ARMul_WriteWord(ARMul_State * state,ARMword address,ARMword data)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
ARMul_StoreWordS(ARMul_State * state,ARMword address,ARMword data)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
ARMul_StoreWordN(ARMul_State * state,ARMword address,ARMword data)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
ARMul_StoreHalfWord(ARMul_State * state,ARMword address,ARMword data)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
ARMul_WriteByte(ARMul_State * state,ARMword address,ARMword data)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
ARMul_StoreByte(ARMul_State * state,ARMword address,ARMword data)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 
ARMul_SwapWord(ARMul_State * state,ARMword address,ARMword data)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 
ARMul_SwapByte(ARMul_State * state,ARMword address,ARMword data)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
ARMul_Icycles(ARMul_State * state,unsigned number,ARMword address ATTRIBUTE_UNUSED)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
ARMul_Ccycles(ARMul_State * state,unsigned number,ARMword address ATTRIBUTE_UNUSED)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
ARMul_SafeReadByte(ARMul_State * state,ARMword address)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
ARMul_SafeWriteByte(ARMul_State * state,ARMword address,ARMword data)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 }
522