xref: /netbsd-src/external/gpl3/gdb/dist/sim/mips/sim-main.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
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
560