xref: /netbsd-src/external/gpl3/gdb/dist/sim/mips/sim-main.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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 #if defined(TRACE)
156   dotrace (SD, CPU, tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
157 #endif /* TRACE */
158 
159   /* Read the specified number of bytes from memory.  Adjust for
160      host/target byte ordering/ Align the least significant byte
161      read. */
162 
163   switch (AccessLength)
164     {
165     case AccessLength_QUADWORD:
166       {
167 	unsigned_16 val = sim_core_read_aligned_16 (CPU, cia, read_map, pAddr);
168 	value1 = VH8_16 (val);
169 	value = VL8_16 (val);
170 	break;
171       }
172     case AccessLength_DOUBLEWORD:
173       value = sim_core_read_aligned_8 (CPU, cia, read_map, pAddr);
174       break;
175     case AccessLength_SEPTIBYTE:
176       value = sim_core_read_misaligned_7 (CPU, cia, read_map, pAddr);
177       break;
178     case AccessLength_SEXTIBYTE:
179       value = sim_core_read_misaligned_6 (CPU, cia, read_map, pAddr);
180       break;
181     case AccessLength_QUINTIBYTE:
182       value = sim_core_read_misaligned_5 (CPU, cia, read_map, pAddr);
183       break;
184     case AccessLength_WORD:
185       value = sim_core_read_aligned_4 (CPU, cia, read_map, pAddr);
186       break;
187     case AccessLength_TRIPLEBYTE:
188       value = sim_core_read_misaligned_3 (CPU, cia, read_map, pAddr);
189       break;
190     case AccessLength_HALFWORD:
191       value = sim_core_read_aligned_2 (CPU, cia, read_map, pAddr);
192       break;
193     case AccessLength_BYTE:
194       value = sim_core_read_aligned_1 (CPU, cia, read_map, pAddr);
195       break;
196     default:
197       abort ();
198     }
199 
200 #ifdef DEBUG
201   printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
202 	 (int)(pAddr & LOADDRMASK),pr_uword64(value1),pr_uword64(value));
203 #endif /* DEBUG */
204 
205   /* See also store_memory. Position data in correct byte lanes. */
206   if (AccessLength <= LOADDRMASK)
207     {
208       if (BigEndianMem)
209 	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
210 	   shifted to the most significant byte position.  */
211 	value <<= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
212       else
213 	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
214 	   is already in the correct postition. */
215 	value <<= ((pAddr & LOADDRMASK) * 8);
216     }
217 
218 #ifdef DEBUG
219   printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
220 	 pr_uword64(value1),pr_uword64(value));
221 #endif /* DEBUG */
222 
223   *memvalp = value;
224   if (memval1p) *memval1p = value1;
225 }
226 
227 
228 /* Description from page A-23 of the "MIPS IV Instruction Set" manual
229    (revision 3.1) */
230 /* Store a value to memory. The specified data is stored into the
231    physical location pAddr using the memory hierarchy (data caches and
232    main memory) as specified by the Cache Coherence Algorithm
233    (CCA). The MemElem contains the data for an aligned, fixed-width
234    memory element (word for 32-bit processors, doubleword for 64-bit
235    processors), though only the bytes that will actually be stored to
236    memory need to be valid. The low-order two (or three) bits of pAddr
237    and the AccessLength field indicates which of the bytes within the
238    MemElem data should actually be stored; only these bytes in memory
239    will be changed. */
240 
241 INLINE_SIM_MAIN (void)
242 store_memory (SIM_DESC SD,
243 	      sim_cpu *CPU,
244 	      address_word cia,
245 	      int CCA,
246 	      unsigned int AccessLength,
247 	      uword64 MemElem,
248 	      uword64 MemElem1,   /* High order 64 bits */
249 	      address_word pAddr,
250 	      address_word vAddr)
251 {
252 #ifdef DEBUG
253   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));
254 #endif /* DEBUG */
255 
256 #if defined(WARN_MEM)
257   if (CCA != uncached)
258     sim_io_eprintf(sd,"StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
259 #endif /* WARN_MEM */
260 
261   if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
262     sim_io_error (SD, "STORE AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
263 		  AccessLength,
264 		  (LOADDRMASK + 1) << 3,
265 		  pr_addr(pAddr));
266 
267 #if defined(TRACE)
268   dotrace (SD, CPU, tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
269 #endif /* TRACE */
270 
271 #ifdef DEBUG
272   printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr & LOADDRMASK),pr_uword64(MemElem1),pr_uword64(MemElem));
273 #endif /* DEBUG */
274 
275   /* See also load_memory. Position data in correct byte lanes. */
276   if (AccessLength <= LOADDRMASK)
277     {
278       if (BigEndianMem)
279 	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
280 	   shifted to the most significant byte position.  */
281 	MemElem >>= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
282       else
283 	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
284 	   is already in the correct postition. */
285 	MemElem >>= ((pAddr & LOADDRMASK) * 8);
286     }
287 
288 #ifdef DEBUG
289   printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift,pr_uword64(MemElem1),pr_uword64(MemElem));
290 #endif /* DEBUG */
291 
292   switch (AccessLength)
293     {
294     case AccessLength_QUADWORD:
295       {
296 	unsigned_16 val = U16_8 (MemElem1, MemElem);
297 	sim_core_write_aligned_16 (CPU, cia, write_map, pAddr, val);
298 	break;
299       }
300     case AccessLength_DOUBLEWORD:
301       sim_core_write_aligned_8 (CPU, cia, write_map, pAddr, MemElem);
302       break;
303     case AccessLength_SEPTIBYTE:
304       sim_core_write_misaligned_7 (CPU, cia, write_map, pAddr, MemElem);
305       break;
306     case AccessLength_SEXTIBYTE:
307       sim_core_write_misaligned_6 (CPU, cia, write_map, pAddr, MemElem);
308       break;
309     case AccessLength_QUINTIBYTE:
310       sim_core_write_misaligned_5 (CPU, cia, write_map, pAddr, MemElem);
311       break;
312     case AccessLength_WORD:
313       sim_core_write_aligned_4 (CPU, cia, write_map, pAddr, MemElem);
314       break;
315     case AccessLength_TRIPLEBYTE:
316       sim_core_write_misaligned_3 (CPU, cia, write_map, pAddr, MemElem);
317       break;
318     case AccessLength_HALFWORD:
319       sim_core_write_aligned_2 (CPU, cia, write_map, pAddr, MemElem);
320       break;
321     case AccessLength_BYTE:
322       sim_core_write_aligned_1 (CPU, cia, write_map, pAddr, MemElem);
323       break;
324     default:
325       abort ();
326     }
327 
328   return;
329 }
330 
331 
332 INLINE_SIM_MAIN (unsigned32)
333 ifetch32 (SIM_DESC SD,
334 	  sim_cpu *CPU,
335 	  address_word cia,
336 	  address_word vaddr)
337 {
338   /* Copy the action of the LW instruction */
339   address_word mask = LOADDRMASK;
340   address_word access = AccessLength_WORD;
341   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
342   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
343   unsigned int byte;
344   address_word paddr;
345   int uncached;
346   unsigned64 memval;
347 
348   if ((vaddr & access) != 0)
349     SignalExceptionInstructionFetch ();
350   AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
351   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
352   LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
353   byte = ((vaddr & mask) ^ bigendiancpu);
354   return (memval >> (8 * byte));
355 }
356 
357 
358 INLINE_SIM_MAIN (unsigned16)
359 ifetch16 (SIM_DESC SD,
360 	  sim_cpu *CPU,
361 	  address_word cia,
362 	  address_word vaddr)
363 {
364   /* Copy the action of the LH instruction */
365   address_word mask = LOADDRMASK;
366   address_word access = AccessLength_HALFWORD;
367   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
368   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
369   unsigned int byte;
370   address_word paddr;
371   int uncached;
372   unsigned64 memval;
373 
374   if ((vaddr & access) != 0)
375     SignalExceptionInstructionFetch ();
376   AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
377   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
378   LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
379   byte = ((vaddr & mask) ^ bigendiancpu);
380   return (memval >> (8 * byte));
381 }
382 
383 
384 
385 /* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
386 /* Order loads and stores to synchronise shared memory. Perform the
387    action necessary to make the effects of groups of synchronizable
388    loads and stores indicated by stype occur in the same order for all
389    processors. */
390 INLINE_SIM_MAIN (void)
391 sync_operation (SIM_DESC sd,
392 		sim_cpu *cpu,
393 		address_word cia,
394 		int stype)
395 {
396 #ifdef DEBUG
397   sim_io_printf(sd,"SyncOperation(%d) : TODO\n",stype);
398 #endif /* DEBUG */
399   return;
400 }
401 
402 INLINE_SIM_MAIN (void)
403 cache_op (SIM_DESC SD,
404 	  sim_cpu *CPU,
405 	  address_word cia,
406 	  int op,
407 	  address_word pAddr,
408 	  address_word vAddr,
409 	  unsigned int instruction)
410 {
411 #if 1 /* stop warning message being displayed (we should really just remove the code) */
412   static int icache_warning = 1;
413   static int dcache_warning = 1;
414 #else
415   static int icache_warning = 0;
416   static int dcache_warning = 0;
417 #endif
418 
419   /* If CP0 is not useable (User or Supervisor mode) and the CP0
420      enable bit in the Status Register is clear - a coprocessor
421      unusable exception is taken. */
422 #if 0
423   sim_io_printf(SD,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(cia));
424 #endif
425 
426   switch (op & 0x3) {
427     case 0: /* instruction cache */
428       switch (op >> 2) {
429         case 0: /* Index Invalidate */
430         case 1: /* Index Load Tag */
431         case 2: /* Index Store Tag */
432         case 4: /* Hit Invalidate */
433         case 5: /* Fill */
434         case 6: /* Hit Writeback */
435           if (!icache_warning)
436             {
437               sim_io_eprintf(SD,"Instruction CACHE operation %d to be coded\n",(op >> 2));
438               icache_warning = 1;
439             }
440           break;
441 
442         default:
443           SignalException(ReservedInstruction,instruction);
444           break;
445       }
446       break;
447 
448     case 1: /* data cache */
449     case 3: /* secondary data cache */
450       switch (op >> 2) {
451         case 0: /* Index Writeback Invalidate */
452         case 1: /* Index Load Tag */
453         case 2: /* Index Store Tag */
454         case 3: /* Create Dirty */
455         case 4: /* Hit Invalidate */
456         case 5: /* Hit Writeback Invalidate */
457         case 6: /* Hit Writeback */
458           if (!dcache_warning)
459             {
460               sim_io_eprintf(SD,"Data CACHE operation %d to be coded\n",(op >> 2));
461               dcache_warning = 1;
462             }
463           break;
464 
465         default:
466           SignalException(ReservedInstruction,instruction);
467           break;
468       }
469       break;
470 
471     default: /* unrecognised cache ID */
472       SignalException(ReservedInstruction,instruction);
473       break;
474   }
475 
476   return;
477 }
478 
479 
480 INLINE_SIM_MAIN (void)
481 pending_tick (SIM_DESC SD,
482 	      sim_cpu *CPU,
483 	      address_word cia)
484 {
485   if (PENDING_TRACE)
486     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);
487   if (PENDING_OUT != PENDING_IN)
488     {
489       int loop;
490       int index = PENDING_OUT;
491       int total = PENDING_TOTAL;
492       if (PENDING_TOTAL == 0)
493 	sim_engine_abort (SD, CPU, cia, "PENDING_DRAIN - Mis-match on pending update pointers\n");
494       for (loop = 0, index = PENDING_OUT;
495 	   (loop < total);
496 	   loop++, index = (index + 1) % PSLOTS)
497 	{
498 	  if (PENDING_SLOT_DEST[index] != NULL)
499 	    {
500 	      PENDING_SLOT_DELAY[index] -= 1;
501 	      if (PENDING_SLOT_DELAY[index] == 0)
502 		{
503 		  if (PENDING_TRACE)
504 		    sim_io_eprintf (SD, "PENDING_DRAIN - drained - index %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
505 				    index,
506 				    (unsigned long) PENDING_SLOT_DEST[index],
507 				    PENDING_SLOT_BIT[index],
508 				    (unsigned long) PENDING_SLOT_VALUE[index],
509 				    PENDING_SLOT_SIZE[index]);
510 		  if (PENDING_SLOT_BIT[index] >= 0)
511 		    switch (PENDING_SLOT_SIZE[index])
512 		      {
513 		      case 4:
514 			if (PENDING_SLOT_VALUE[index])
515 			  *(unsigned32*)PENDING_SLOT_DEST[index] |=
516 			    BIT32 (PENDING_SLOT_BIT[index]);
517 			else
518 			  *(unsigned32*)PENDING_SLOT_DEST[index] &=
519 			    BIT32 (PENDING_SLOT_BIT[index]);
520 			break;
521 		      case 8:
522 			if (PENDING_SLOT_VALUE[index])
523 			  *(unsigned64*)PENDING_SLOT_DEST[index] |=
524 			    BIT64 (PENDING_SLOT_BIT[index]);
525 			else
526 			  *(unsigned64*)PENDING_SLOT_DEST[index] &=
527 			    BIT64 (PENDING_SLOT_BIT[index]);
528 			break;
529 		      }
530 		  else
531 		    switch (PENDING_SLOT_SIZE[index])
532 		      {
533 		      case 4:
534 			*(unsigned32*)PENDING_SLOT_DEST[index] =
535 			  PENDING_SLOT_VALUE[index];
536 			break;
537 		      case 8:
538 			*(unsigned64*)PENDING_SLOT_DEST[index] =
539 			  PENDING_SLOT_VALUE[index];
540 			break;
541 		      }
542 		  if (PENDING_OUT == index)
543 		    {
544 		      PENDING_SLOT_DEST[index] = NULL;
545 		      PENDING_OUT = (PENDING_OUT + 1) % PSLOTS;
546 		      PENDING_TOTAL--;
547 		    }
548 		}
549 	      else if (PENDING_TRACE && PENDING_SLOT_DELAY[index] > 0)
550 		sim_io_eprintf (SD, "PENDING_DRAIN - queued - index %d, delay %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
551 				index, PENDING_SLOT_DELAY[index],
552 				(unsigned long) PENDING_SLOT_DEST[index],
553 				PENDING_SLOT_BIT[index],
554 				(unsigned long) PENDING_SLOT_VALUE[index],
555 				PENDING_SLOT_SIZE[index]);
556 
557 	    }
558 	}
559     }
560 }
561 
562 
563 #endif
564