916769e7c1f94bc19e73bbdd9492e0327b6acce1
[binutils-gdb.git] / sim / mips / sim-main.c
1 /* Copyright (C) 1998, Cygnus Solutions
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, see <http://www.gnu.org/licenses/>.
15
16 */
17
18
19 #ifndef SIM_MAIN_C
20 #define SIM_MAIN_C
21
22 #include "sim-main.h"
23 #include "sim-assert.h"
24
25
26 /*---------------------------------------------------------------------------*/
27 /*-- simulator engine -------------------------------------------------------*/
28 /*---------------------------------------------------------------------------*/
29
30
31 /* Description from page A-22 of the "MIPS IV Instruction Set" manual
32 (revision 3.1) */
33 /* Translate a virtual address to a physical address and cache
34 coherence algorithm describing the mechanism used to resolve the
35 memory reference. Given the virtual address vAddr, and whether the
36 reference is to Instructions ot Data (IorD), find the corresponding
37 physical address (pAddr) and the cache coherence algorithm (CCA)
38 used to resolve the reference. If the virtual address is in one of
39 the unmapped address spaces the physical address and the CCA are
40 determined directly by the virtual address. If the virtual address
41 is in one of the mapped address spaces then the TLB is used to
42 determine the physical address and access type; if the required
43 translation is not present in the TLB or the desired access is not
44 permitted the function fails and an exception is taken.
45
46 NOTE: Normally (RAW == 0), when address translation fails, this
47 function raises an exception and does not return. */
48
49 INLINE_SIM_MAIN
50 (int)
51 address_translation (SIM_DESC sd,
52 sim_cpu * cpu,
53 address_word cia,
54 address_word vAddr,
55 int IorD,
56 int LorS,
57 address_word * pAddr,
58 int *CCA,
59 int raw)
60 {
61 int res = -1; /* TRUE : Assume good return */
62
63 #ifdef DEBUG
64 sim_io_printf (sd, "AddressTranslation(0x%s,%s,%s,...);\n", pr_addr (vAddr), (IorD ? "isDATA" : "isINSTRUCTION"), (LorS ? "iSTORE" : "isLOAD"));
65 #endif
66
67 /* Check that the address is valid for this memory model */
68
69 /* For a simple (flat) memory model, we simply pass virtual
70 addressess through (mostly) unchanged. */
71 vAddr &= 0xFFFFFFFF;
72
73 *pAddr = vAddr; /* default for isTARGET */
74 *CCA = Uncached; /* not used for isHOST */
75
76 return (res);
77 }
78
79
80
81 /* Description from page A-23 of the "MIPS IV Instruction Set" manual
82 (revision 3.1) */
83 /* Prefetch data from memory. Prefetch is an advisory instruction for
84 which an implementation specific action is taken. The action taken
85 may increase performance, but must not change the meaning of the
86 program, or alter architecturally-visible state. */
87
88 INLINE_SIM_MAIN (void)
89 prefetch (SIM_DESC sd,
90 sim_cpu *cpu,
91 address_word cia,
92 int CCA,
93 address_word pAddr,
94 address_word vAddr,
95 int DATA,
96 int hint)
97 {
98 #ifdef DEBUG
99 sim_io_printf(sd,"Prefetch(%d,0x%s,0x%s,%d,%d);\n",CCA,pr_addr(pAddr),pr_addr(vAddr),DATA,hint);
100 #endif /* DEBUG */
101
102 /* For our simple memory model we do nothing */
103 return;
104 }
105
106 /* Description from page A-22 of the "MIPS IV Instruction Set" manual
107 (revision 3.1) */
108 /* Load a value from memory. Use the cache and main memory as
109 specified in the Cache Coherence Algorithm (CCA) and the sort of
110 access (IorD) to find the contents of AccessLength memory bytes
111 starting at physical location pAddr. The data is returned in the
112 fixed width naturally-aligned memory element (MemElem). The
113 low-order two (or three) bits of the address and the AccessLength
114 indicate which of the bytes within MemElem needs to be given to the
115 processor. If the memory access type of the reference is uncached
116 then only the referenced bytes are read from memory and valid
117 within the memory element. If the access type is cached, and the
118 data is not present in cache, an implementation specific size and
119 alignment block of memory is read and loaded into the cache to
120 satisfy a load reference. At a minimum, the block is the entire
121 memory element. */
122 INLINE_SIM_MAIN (void)
123 load_memory (SIM_DESC SD,
124 sim_cpu *CPU,
125 address_word cia,
126 uword64* memvalp,
127 uword64* memval1p,
128 int CCA,
129 unsigned int AccessLength,
130 address_word pAddr,
131 address_word vAddr,
132 int IorD)
133 {
134 uword64 value = 0;
135 uword64 value1 = 0;
136
137 #ifdef DEBUG
138 sim_io_printf(sd,"DBG: LoadMemory(%p,%p,%d,%d,0x%s,0x%s,%s)\n",memvalp,memval1p,CCA,AccessLength,pr_addr(pAddr),pr_addr(vAddr),(IorD ? "isDATA" : "isINSTRUCTION"));
139 #endif /* DEBUG */
140
141 #if defined(WARN_MEM)
142 if (CCA != uncached)
143 sim_io_eprintf(sd,"LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
144 #endif /* WARN_MEM */
145
146 if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
147 {
148 /* In reality this should be a Bus Error */
149 sim_io_error (SD, "LOAD AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
150 AccessLength,
151 (LOADDRMASK + 1) << 3,
152 pr_addr (pAddr));
153 }
154
155 dotrace (SD, CPU, tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
156
157 /* Read the specified number of bytes from memory. Adjust for
158 host/target byte ordering/ Align the least significant byte
159 read. */
160
161 switch (AccessLength)
162 {
163 case AccessLength_QUADWORD:
164 {
165 unsigned_16 val = sim_core_read_aligned_16 (CPU, cia, read_map, pAddr);
166 value1 = VH8_16 (val);
167 value = VL8_16 (val);
168 break;
169 }
170 case AccessLength_DOUBLEWORD:
171 value = sim_core_read_aligned_8 (CPU, cia, read_map, pAddr);
172 break;
173 case AccessLength_SEPTIBYTE:
174 value = sim_core_read_misaligned_7 (CPU, cia, read_map, pAddr);
175 break;
176 case AccessLength_SEXTIBYTE:
177 value = sim_core_read_misaligned_6 (CPU, cia, read_map, pAddr);
178 break;
179 case AccessLength_QUINTIBYTE:
180 value = sim_core_read_misaligned_5 (CPU, cia, read_map, pAddr);
181 break;
182 case AccessLength_WORD:
183 value = sim_core_read_aligned_4 (CPU, cia, read_map, pAddr);
184 break;
185 case AccessLength_TRIPLEBYTE:
186 value = sim_core_read_misaligned_3 (CPU, cia, read_map, pAddr);
187 break;
188 case AccessLength_HALFWORD:
189 value = sim_core_read_aligned_2 (CPU, cia, read_map, pAddr);
190 break;
191 case AccessLength_BYTE:
192 value = sim_core_read_aligned_1 (CPU, cia, read_map, pAddr);
193 break;
194 default:
195 abort ();
196 }
197
198 #ifdef DEBUG
199 printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
200 (int)(pAddr & LOADDRMASK),pr_uword64(value1),pr_uword64(value));
201 #endif /* DEBUG */
202
203 /* See also store_memory. Position data in correct byte lanes. */
204 if (AccessLength <= LOADDRMASK)
205 {
206 if (BigEndianMem)
207 /* for big endian target, byte (pAddr&LOADDRMASK == 0) is
208 shifted to the most significant byte position. */
209 value <<= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
210 else
211 /* For little endian target, byte (pAddr&LOADDRMASK == 0)
212 is already in the correct postition. */
213 value <<= ((pAddr & LOADDRMASK) * 8);
214 }
215
216 #ifdef DEBUG
217 printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
218 pr_uword64(value1),pr_uword64(value));
219 #endif /* DEBUG */
220
221 *memvalp = value;
222 if (memval1p) *memval1p = value1;
223 }
224
225
226 /* Description from page A-23 of the "MIPS IV Instruction Set" manual
227 (revision 3.1) */
228 /* Store a value to memory. The specified data is stored into the
229 physical location pAddr using the memory hierarchy (data caches and
230 main memory) as specified by the Cache Coherence Algorithm
231 (CCA). The MemElem contains the data for an aligned, fixed-width
232 memory element (word for 32-bit processors, doubleword for 64-bit
233 processors), though only the bytes that will actually be stored to
234 memory need to be valid. The low-order two (or three) bits of pAddr
235 and the AccessLength field indicates which of the bytes within the
236 MemElem data should actually be stored; only these bytes in memory
237 will be changed. */
238
239 INLINE_SIM_MAIN (void)
240 store_memory (SIM_DESC SD,
241 sim_cpu *CPU,
242 address_word cia,
243 int CCA,
244 unsigned int AccessLength,
245 uword64 MemElem,
246 uword64 MemElem1, /* High order 64 bits */
247 address_word pAddr,
248 address_word vAddr)
249 {
250 #ifdef DEBUG
251 sim_io_printf(sd,"DBG: StoreMemory(%d,%d,0x%s,0x%s,0x%s,0x%s)\n",CCA,AccessLength,pr_uword64(MemElem),pr_uword64(MemElem1),pr_addr(pAddr),pr_addr(vAddr));
252 #endif /* DEBUG */
253
254 #if defined(WARN_MEM)
255 if (CCA != uncached)
256 sim_io_eprintf(sd,"StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
257 #endif /* WARN_MEM */
258
259 if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
260 sim_io_error (SD, "STORE AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
261 AccessLength,
262 (LOADDRMASK + 1) << 3,
263 pr_addr(pAddr));
264
265 dotrace (SD, CPU, tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
266
267 #ifdef DEBUG
268 printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr & LOADDRMASK),pr_uword64(MemElem1),pr_uword64(MemElem));
269 #endif /* DEBUG */
270
271 /* See also load_memory. Position data in correct byte lanes. */
272 if (AccessLength <= LOADDRMASK)
273 {
274 if (BigEndianMem)
275 /* for big endian target, byte (pAddr&LOADDRMASK == 0) is
276 shifted to the most significant byte position. */
277 MemElem >>= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
278 else
279 /* For little endian target, byte (pAddr&LOADDRMASK == 0)
280 is already in the correct postition. */
281 MemElem >>= ((pAddr & LOADDRMASK) * 8);
282 }
283
284 #ifdef DEBUG
285 printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift,pr_uword64(MemElem1),pr_uword64(MemElem));
286 #endif /* DEBUG */
287
288 switch (AccessLength)
289 {
290 case AccessLength_QUADWORD:
291 {
292 unsigned_16 val = U16_8 (MemElem1, MemElem);
293 sim_core_write_aligned_16 (CPU, cia, write_map, pAddr, val);
294 break;
295 }
296 case AccessLength_DOUBLEWORD:
297 sim_core_write_aligned_8 (CPU, cia, write_map, pAddr, MemElem);
298 break;
299 case AccessLength_SEPTIBYTE:
300 sim_core_write_misaligned_7 (CPU, cia, write_map, pAddr, MemElem);
301 break;
302 case AccessLength_SEXTIBYTE:
303 sim_core_write_misaligned_6 (CPU, cia, write_map, pAddr, MemElem);
304 break;
305 case AccessLength_QUINTIBYTE:
306 sim_core_write_misaligned_5 (CPU, cia, write_map, pAddr, MemElem);
307 break;
308 case AccessLength_WORD:
309 sim_core_write_aligned_4 (CPU, cia, write_map, pAddr, MemElem);
310 break;
311 case AccessLength_TRIPLEBYTE:
312 sim_core_write_misaligned_3 (CPU, cia, write_map, pAddr, MemElem);
313 break;
314 case AccessLength_HALFWORD:
315 sim_core_write_aligned_2 (CPU, cia, write_map, pAddr, MemElem);
316 break;
317 case AccessLength_BYTE:
318 sim_core_write_aligned_1 (CPU, cia, write_map, pAddr, MemElem);
319 break;
320 default:
321 abort ();
322 }
323
324 return;
325 }
326
327
328 INLINE_SIM_MAIN (unsigned32)
329 ifetch32 (SIM_DESC SD,
330 sim_cpu *CPU,
331 address_word cia,
332 address_word vaddr)
333 {
334 /* Copy the action of the LW instruction */
335 address_word mask = LOADDRMASK;
336 address_word access = AccessLength_WORD;
337 address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
338 address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
339 unsigned int byte;
340 address_word paddr;
341 int uncached;
342 unsigned64 memval;
343
344 if ((vaddr & access) != 0)
345 SignalExceptionInstructionFetch ();
346 AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
347 paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
348 LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
349 byte = ((vaddr & mask) ^ bigendiancpu);
350 return (memval >> (8 * byte));
351 }
352
353
354 INLINE_SIM_MAIN (unsigned16)
355 ifetch16 (SIM_DESC SD,
356 sim_cpu *CPU,
357 address_word cia,
358 address_word vaddr)
359 {
360 /* Copy the action of the LH instruction */
361 address_word mask = LOADDRMASK;
362 address_word access = AccessLength_HALFWORD;
363 address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
364 address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
365 unsigned int byte;
366 address_word paddr;
367 int uncached;
368 unsigned64 memval;
369
370 if ((vaddr & access) != 0)
371 SignalExceptionInstructionFetch ();
372 AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
373 paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
374 LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
375 byte = ((vaddr & mask) ^ bigendiancpu);
376 return (memval >> (8 * byte));
377 }
378
379
380
381 /* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
382 /* Order loads and stores to synchronise shared memory. Perform the
383 action necessary to make the effects of groups of synchronizable
384 loads and stores indicated by stype occur in the same order for all
385 processors. */
386 INLINE_SIM_MAIN (void)
387 sync_operation (SIM_DESC sd,
388 sim_cpu *cpu,
389 address_word cia,
390 int stype)
391 {
392 #ifdef DEBUG
393 sim_io_printf(sd,"SyncOperation(%d) : TODO\n",stype);
394 #endif /* DEBUG */
395 return;
396 }
397
398 INLINE_SIM_MAIN (void)
399 cache_op (SIM_DESC SD,
400 sim_cpu *CPU,
401 address_word cia,
402 int op,
403 address_word pAddr,
404 address_word vAddr,
405 unsigned int instruction)
406 {
407 #if 1 /* stop warning message being displayed (we should really just remove the code) */
408 static int icache_warning = 1;
409 static int dcache_warning = 1;
410 #else
411 static int icache_warning = 0;
412 static int dcache_warning = 0;
413 #endif
414
415 /* If CP0 is not useable (User or Supervisor mode) and the CP0
416 enable bit in the Status Register is clear - a coprocessor
417 unusable exception is taken. */
418 #if 0
419 sim_io_printf(SD,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(cia));
420 #endif
421
422 switch (op & 0x3) {
423 case 0: /* instruction cache */
424 switch (op >> 2) {
425 case 0: /* Index Invalidate */
426 case 1: /* Index Load Tag */
427 case 2: /* Index Store Tag */
428 case 4: /* Hit Invalidate */
429 case 5: /* Fill */
430 case 6: /* Hit Writeback */
431 if (!icache_warning)
432 {
433 sim_io_eprintf(SD,"Instruction CACHE operation %d to be coded\n",(op >> 2));
434 icache_warning = 1;
435 }
436 break;
437
438 default:
439 SignalException(ReservedInstruction,instruction);
440 break;
441 }
442 break;
443
444 case 1: /* data cache */
445 case 3: /* secondary data cache */
446 switch (op >> 2) {
447 case 0: /* Index Writeback Invalidate */
448 case 1: /* Index Load Tag */
449 case 2: /* Index Store Tag */
450 case 3: /* Create Dirty */
451 case 4: /* Hit Invalidate */
452 case 5: /* Hit Writeback Invalidate */
453 case 6: /* Hit Writeback */
454 if (!dcache_warning)
455 {
456 sim_io_eprintf(SD,"Data CACHE operation %d to be coded\n",(op >> 2));
457 dcache_warning = 1;
458 }
459 break;
460
461 default:
462 SignalException(ReservedInstruction,instruction);
463 break;
464 }
465 break;
466
467 default: /* unrecognised cache ID */
468 SignalException(ReservedInstruction,instruction);
469 break;
470 }
471
472 return;
473 }
474
475
476 INLINE_SIM_MAIN (void)
477 pending_tick (SIM_DESC SD,
478 sim_cpu *CPU,
479 address_word cia)
480 {
481 if (PENDING_TRACE)
482 sim_io_eprintf (SD, "PENDING_DRAIN - 0x%lx - pending_in = %d, pending_out = %d, pending_total = %d\n", (unsigned long) cia, PENDING_IN, PENDING_OUT, PENDING_TOTAL);
483 if (PENDING_OUT != PENDING_IN)
484 {
485 int loop;
486 int index = PENDING_OUT;
487 int total = PENDING_TOTAL;
488 if (PENDING_TOTAL == 0)
489 sim_engine_abort (SD, CPU, cia, "PENDING_DRAIN - Mis-match on pending update pointers\n");
490 for (loop = 0, index = PENDING_OUT;
491 (loop < total);
492 loop++, index = (index + 1) % PSLOTS)
493 {
494 if (PENDING_SLOT_DEST[index] != NULL)
495 {
496 PENDING_SLOT_DELAY[index] -= 1;
497 if (PENDING_SLOT_DELAY[index] == 0)
498 {
499 if (PENDING_TRACE)
500 sim_io_eprintf (SD, "PENDING_DRAIN - drained - index %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
501 index,
502 (unsigned long) PENDING_SLOT_DEST[index],
503 PENDING_SLOT_BIT[index],
504 (unsigned long) PENDING_SLOT_VALUE[index],
505 PENDING_SLOT_SIZE[index]);
506 if (PENDING_SLOT_BIT[index] >= 0)
507 switch (PENDING_SLOT_SIZE[index])
508 {
509 case 4:
510 if (PENDING_SLOT_VALUE[index])
511 *(unsigned32*)PENDING_SLOT_DEST[index] |=
512 BIT32 (PENDING_SLOT_BIT[index]);
513 else
514 *(unsigned32*)PENDING_SLOT_DEST[index] &=
515 BIT32 (PENDING_SLOT_BIT[index]);
516 break;
517 case 8:
518 if (PENDING_SLOT_VALUE[index])
519 *(unsigned64*)PENDING_SLOT_DEST[index] |=
520 BIT64 (PENDING_SLOT_BIT[index]);
521 else
522 *(unsigned64*)PENDING_SLOT_DEST[index] &=
523 BIT64 (PENDING_SLOT_BIT[index]);
524 break;
525 }
526 else
527 switch (PENDING_SLOT_SIZE[index])
528 {
529 case 4:
530 *(unsigned32*)PENDING_SLOT_DEST[index] =
531 PENDING_SLOT_VALUE[index];
532 break;
533 case 8:
534 *(unsigned64*)PENDING_SLOT_DEST[index] =
535 PENDING_SLOT_VALUE[index];
536 break;
537 }
538 if (PENDING_OUT == index)
539 {
540 PENDING_SLOT_DEST[index] = NULL;
541 PENDING_OUT = (PENDING_OUT + 1) % PSLOTS;
542 PENDING_TOTAL--;
543 }
544 }
545 else if (PENDING_TRACE && PENDING_SLOT_DELAY[index] > 0)
546 sim_io_eprintf (SD, "PENDING_DRAIN - queued - index %d, delay %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
547 index, PENDING_SLOT_DELAY[index],
548 (unsigned long) PENDING_SLOT_DEST[index],
549 PENDING_SLOT_BIT[index],
550 (unsigned long) PENDING_SLOT_VALUE[index],
551 PENDING_SLOT_SIZE[index]);
552
553 }
554 }
555 }
556 }
557
558
559 #endif