xref: /netbsd-src/external/gpl3/gdb/dist/sim/mips/sim-main.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
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 /* This must come before any other includes.  */
23 #include "defs.h"
24 
25 #include "sim-main.h"
26 #include "sim-assert.h"
27 
28 #include <stdlib.h>
29 
30 /*---------------------------------------------------------------------------*/
31 /*-- simulator engine -------------------------------------------------------*/
32 /*---------------------------------------------------------------------------*/
33 
34 
35 /* Description from page A-22 of the "MIPS IV Instruction Set" manual
36    (revision 3.1) */
37 /* Load a value from memory. Use the cache and main memory as
38    specified in the Cache Coherence Algorithm (CCA) and the sort of
39    access (IorD) to find the contents of AccessLength memory bytes
40    starting at physical location pAddr. The data is returned in the
41    fixed width naturally-aligned memory element (MemElem). The
42    low-order two (or three) bits of the address and the AccessLength
43    indicate which of the bytes within MemElem needs to be given to the
44    processor. If the memory access type of the reference is uncached
45    then only the referenced bytes are read from memory and valid
46    within the memory element. If the access type is cached, and the
47    data is not present in cache, an implementation specific size and
48    alignment block of memory is read and loaded into the cache to
49    satisfy a load reference. At a minimum, the block is the entire
50    memory element. */
51 INLINE_SIM_MAIN (void)
load_memory(SIM_DESC SD,sim_cpu * CPU,address_word cia,uword64 * memvalp,uword64 * memval1p,int CCA,unsigned int AccessLength,address_word pAddr,address_word vAddr,int IorD)52 load_memory (SIM_DESC SD,
53 	     sim_cpu *CPU,
54 	     address_word cia,
55 	     uword64* memvalp,
56 	     uword64* memval1p,
57 	     int CCA,
58 	     unsigned int AccessLength,
59 	     address_word pAddr,
60 	     address_word vAddr,
61 	     int IorD)
62 {
63   uword64 value = 0;
64   uword64 value1 = 0;
65 
66 #ifdef DEBUG
67   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"));
68 #endif /* DEBUG */
69 
70 #if defined(WARN_MEM)
71   if (CCA != uncached)
72     sim_io_eprintf(sd,"LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
73 #endif /* WARN_MEM */
74 
75   if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
76     {
77       /* In reality this should be a Bus Error */
78       sim_io_error (SD, "LOAD AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
79 		    AccessLength,
80 		    (LOADDRMASK + 1) << 3,
81 		    pr_addr (pAddr));
82     }
83 
84   dotrace (SD, CPU, tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
85 
86   /* Read the specified number of bytes from memory.  Adjust for
87      host/target byte ordering/ Align the least significant byte
88      read. */
89 
90   switch (AccessLength)
91     {
92     case AccessLength_QUADWORD:
93       {
94 	unsigned_16 val = sim_core_read_aligned_16 (CPU, cia, read_map, pAddr);
95 	value1 = VH8_16 (val);
96 	value = VL8_16 (val);
97 	break;
98       }
99     case AccessLength_DOUBLEWORD:
100       value = sim_core_read_aligned_8 (CPU, cia, read_map, pAddr);
101       break;
102     case AccessLength_SEPTIBYTE:
103       value = sim_core_read_misaligned_7 (CPU, cia, read_map, pAddr);
104       break;
105     case AccessLength_SEXTIBYTE:
106       value = sim_core_read_misaligned_6 (CPU, cia, read_map, pAddr);
107       break;
108     case AccessLength_QUINTIBYTE:
109       value = sim_core_read_misaligned_5 (CPU, cia, read_map, pAddr);
110       break;
111     case AccessLength_WORD:
112       value = sim_core_read_aligned_4 (CPU, cia, read_map, pAddr);
113       break;
114     case AccessLength_TRIPLEBYTE:
115       value = sim_core_read_misaligned_3 (CPU, cia, read_map, pAddr);
116       break;
117     case AccessLength_HALFWORD:
118       value = sim_core_read_aligned_2 (CPU, cia, read_map, pAddr);
119       break;
120     case AccessLength_BYTE:
121       value = sim_core_read_aligned_1 (CPU, cia, read_map, pAddr);
122       break;
123     default:
124       abort ();
125     }
126 
127 #ifdef DEBUG
128   printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
129 	 (int)(pAddr & LOADDRMASK),pr_uword64(value1),pr_uword64(value));
130 #endif /* DEBUG */
131 
132   /* See also store_memory. Position data in correct byte lanes. */
133   if (AccessLength <= LOADDRMASK)
134     {
135       if (BigEndianMem)
136 	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
137 	   shifted to the most significant byte position.  */
138 	value <<= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
139       else
140 	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
141 	   is already in the correct postition. */
142 	value <<= ((pAddr & LOADDRMASK) * 8);
143     }
144 
145 #ifdef DEBUG
146   printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
147 	 pr_uword64(value1),pr_uword64(value));
148 #endif /* DEBUG */
149 
150   *memvalp = value;
151   if (memval1p) *memval1p = value1;
152 }
153 
154 
155 /* Description from page A-23 of the "MIPS IV Instruction Set" manual
156    (revision 3.1) */
157 /* Store a value to memory. The specified data is stored into the
158    physical location pAddr using the memory hierarchy (data caches and
159    main memory) as specified by the Cache Coherence Algorithm
160    (CCA). The MemElem contains the data for an aligned, fixed-width
161    memory element (word for 32-bit processors, doubleword for 64-bit
162    processors), though only the bytes that will actually be stored to
163    memory need to be valid. The low-order two (or three) bits of pAddr
164    and the AccessLength field indicates which of the bytes within the
165    MemElem data should actually be stored; only these bytes in memory
166    will be changed. */
167 
168 INLINE_SIM_MAIN (void)
store_memory(SIM_DESC SD,sim_cpu * CPU,address_word cia,int CCA,unsigned int AccessLength,uword64 MemElem,uword64 MemElem1,address_word pAddr,address_word vAddr)169 store_memory (SIM_DESC SD,
170 	      sim_cpu *CPU,
171 	      address_word cia,
172 	      int CCA,
173 	      unsigned int AccessLength,
174 	      uword64 MemElem,
175 	      uword64 MemElem1,   /* High order 64 bits */
176 	      address_word pAddr,
177 	      address_word vAddr)
178 {
179 #ifdef DEBUG
180   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));
181 #endif /* DEBUG */
182 
183 #if defined(WARN_MEM)
184   if (CCA != uncached)
185     sim_io_eprintf(sd,"StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
186 #endif /* WARN_MEM */
187 
188   if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
189     sim_io_error (SD, "STORE AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
190 		  AccessLength,
191 		  (LOADDRMASK + 1) << 3,
192 		  pr_addr(pAddr));
193 
194   dotrace (SD, CPU, tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
195 
196 #ifdef DEBUG
197   printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr & LOADDRMASK),pr_uword64(MemElem1),pr_uword64(MemElem));
198 #endif /* DEBUG */
199 
200   /* See also load_memory. Position data in correct byte lanes. */
201   if (AccessLength <= LOADDRMASK)
202     {
203       if (BigEndianMem)
204 	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
205 	   shifted to the most significant byte position.  */
206 	MemElem >>= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
207       else
208 	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
209 	   is already in the correct postition. */
210 	MemElem >>= ((pAddr & LOADDRMASK) * 8);
211     }
212 
213 #ifdef DEBUG
214   printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift,pr_uword64(MemElem1),pr_uword64(MemElem));
215 #endif /* DEBUG */
216 
217   switch (AccessLength)
218     {
219     case AccessLength_QUADWORD:
220       {
221 	unsigned_16 val = U16_8 (MemElem1, MemElem);
222 	sim_core_write_aligned_16 (CPU, cia, write_map, pAddr, val);
223 	break;
224       }
225     case AccessLength_DOUBLEWORD:
226       sim_core_write_aligned_8 (CPU, cia, write_map, pAddr, MemElem);
227       break;
228     case AccessLength_SEPTIBYTE:
229       sim_core_write_misaligned_7 (CPU, cia, write_map, pAddr, MemElem);
230       break;
231     case AccessLength_SEXTIBYTE:
232       sim_core_write_misaligned_6 (CPU, cia, write_map, pAddr, MemElem);
233       break;
234     case AccessLength_QUINTIBYTE:
235       sim_core_write_misaligned_5 (CPU, cia, write_map, pAddr, MemElem);
236       break;
237     case AccessLength_WORD:
238       sim_core_write_aligned_4 (CPU, cia, write_map, pAddr, MemElem);
239       break;
240     case AccessLength_TRIPLEBYTE:
241       sim_core_write_misaligned_3 (CPU, cia, write_map, pAddr, MemElem);
242       break;
243     case AccessLength_HALFWORD:
244       sim_core_write_aligned_2 (CPU, cia, write_map, pAddr, MemElem);
245       break;
246     case AccessLength_BYTE:
247       sim_core_write_aligned_1 (CPU, cia, write_map, pAddr, MemElem);
248       break;
249     default:
250       abort ();
251     }
252 
253   return;
254 }
255 
256 
257 INLINE_SIM_MAIN (uint32_t)
ifetch32(SIM_DESC SD,sim_cpu * CPU,address_word cia,address_word vaddr)258 ifetch32 (SIM_DESC SD,
259 	  sim_cpu *CPU,
260 	  address_word cia,
261 	  address_word vaddr)
262 {
263   /* Copy the action of the LW instruction */
264   address_word mask = LOADDRMASK;
265   address_word access = AccessLength_WORD;
266   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
267   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
268   unsigned int byte;
269   address_word paddr = vaddr;
270   uint64_t memval;
271 
272   if ((vaddr & access) != 0)
273     SignalExceptionInstructionFetch ();
274   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
275   LoadMemory (&memval, NULL, access, paddr, vaddr, isINSTRUCTION, isREAL);
276   byte = ((vaddr & mask) ^ bigendiancpu);
277   return (memval >> (8 * byte));
278 }
279 
280 
281 INLINE_SIM_MAIN (uint16_t)
ifetch16(SIM_DESC SD,sim_cpu * CPU,address_word cia,address_word vaddr)282 ifetch16 (SIM_DESC SD,
283 	  sim_cpu *CPU,
284 	  address_word cia,
285 	  address_word vaddr)
286 {
287   /* Copy the action of the LH instruction */
288   address_word mask = LOADDRMASK;
289   address_word access = AccessLength_HALFWORD;
290   address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
291   address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
292   unsigned int byte;
293   address_word paddr = vaddr;
294   uint64_t memval;
295 
296   if ((vaddr & access) != 0)
297     SignalExceptionInstructionFetch ();
298   paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
299   LoadMemory (&memval, NULL, access, paddr, vaddr, isINSTRUCTION, isREAL);
300   byte = ((vaddr & mask) ^ bigendiancpu);
301   return (memval >> (8 * byte));
302 }
303 
304 
305 
306 /* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
307 /* Order loads and stores to synchronise shared memory. Perform the
308    action necessary to make the effects of groups of synchronizable
309    loads and stores indicated by stype occur in the same order for all
310    processors. */
311 INLINE_SIM_MAIN (void)
sync_operation(SIM_DESC sd,sim_cpu * cpu,address_word cia,int stype)312 sync_operation (SIM_DESC sd,
313 		sim_cpu *cpu,
314 		address_word cia,
315 		int stype)
316 {
317 #ifdef DEBUG
318   sim_io_printf(sd,"SyncOperation(%d) : TODO\n",stype);
319 #endif /* DEBUG */
320   return;
321 }
322 
323 INLINE_SIM_MAIN (void)
cache_op(SIM_DESC SD,sim_cpu * CPU,address_word cia,int op,address_word pAddr,address_word vAddr,unsigned int instruction)324 cache_op (SIM_DESC SD,
325 	  sim_cpu *CPU,
326 	  address_word cia,
327 	  int op,
328 	  address_word pAddr,
329 	  address_word vAddr,
330 	  unsigned int instruction)
331 {
332 #if 1 /* stop warning message being displayed (we should really just remove the code) */
333   static int icache_warning = 1;
334   static int dcache_warning = 1;
335 #else
336   static int icache_warning = 0;
337   static int dcache_warning = 0;
338 #endif
339 
340   /* If CP0 is not useable (User or Supervisor mode) and the CP0
341      enable bit in the Status Register is clear - a coprocessor
342      unusable exception is taken. */
343 #if 0
344   sim_io_printf(SD,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(cia));
345 #endif
346 
347   switch (op & 0x3) {
348     case 0: /* instruction cache */
349       switch (op >> 2) {
350         case 0: /* Index Invalidate */
351         case 1: /* Index Load Tag */
352         case 2: /* Index Store Tag */
353         case 4: /* Hit Invalidate */
354         case 5: /* Fill */
355         case 6: /* Hit Writeback */
356           if (!icache_warning)
357             {
358               sim_io_eprintf(SD,"Instruction CACHE operation %d to be coded\n",(op >> 2));
359               icache_warning = 1;
360             }
361           break;
362 
363         default:
364           SignalException(ReservedInstruction,instruction);
365           break;
366       }
367       break;
368 
369     case 1: /* data cache */
370     case 3: /* secondary data cache */
371       switch (op >> 2) {
372         case 0: /* Index Writeback Invalidate */
373         case 1: /* Index Load Tag */
374         case 2: /* Index Store Tag */
375         case 3: /* Create Dirty */
376         case 4: /* Hit Invalidate */
377         case 5: /* Hit Writeback Invalidate */
378         case 6: /* Hit Writeback */
379           if (!dcache_warning)
380             {
381               sim_io_eprintf(SD,"Data CACHE operation %d to be coded\n",(op >> 2));
382               dcache_warning = 1;
383             }
384           break;
385 
386         default:
387           SignalException(ReservedInstruction,instruction);
388           break;
389       }
390       break;
391 
392     default: /* unrecognised cache ID */
393       SignalException(ReservedInstruction,instruction);
394       break;
395   }
396 
397   return;
398 }
399 
400 
401 INLINE_SIM_MAIN (void)
pending_tick(SIM_DESC SD,sim_cpu * CPU,address_word cia)402 pending_tick (SIM_DESC SD,
403 	      sim_cpu *CPU,
404 	      address_word cia)
405 {
406   if (PENDING_TRACE)
407     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);
408   if (PENDING_OUT != PENDING_IN)
409     {
410       int loop;
411       int index = PENDING_OUT;
412       int total = PENDING_TOTAL;
413       if (PENDING_TOTAL == 0)
414 	sim_engine_abort (SD, CPU, cia, "PENDING_DRAIN - Mis-match on pending update pointers\n");
415       for (loop = 0, index = PENDING_OUT;
416 	   (loop < total);
417 	   loop++, index = (index + 1) % PSLOTS)
418 	{
419 	  if (PENDING_SLOT_DEST[index] != NULL)
420 	    {
421 	      PENDING_SLOT_DELAY[index] -= 1;
422 	      if (PENDING_SLOT_DELAY[index] == 0)
423 		{
424 		  if (PENDING_TRACE)
425 		    sim_io_eprintf (SD, "PENDING_DRAIN - drained - index %d, dest %p, bit %d, val %" PRIx64 ", size %d\n",
426 				    index,
427 				    PENDING_SLOT_DEST[index],
428 				    PENDING_SLOT_BIT[index],
429 				    PENDING_SLOT_VALUE[index],
430 				    PENDING_SLOT_SIZE[index]);
431 		  if (PENDING_SLOT_BIT[index] >= 0)
432 		    switch (PENDING_SLOT_SIZE[index])
433 		      {
434 		      case 4:
435 			if (PENDING_SLOT_VALUE[index])
436 			  *(uint32_t*)PENDING_SLOT_DEST[index] |=
437 			    BIT32 (PENDING_SLOT_BIT[index]);
438 			else
439 			  *(uint32_t*)PENDING_SLOT_DEST[index] &=
440 			    BIT32 (PENDING_SLOT_BIT[index]);
441 			break;
442 		      case 8:
443 			if (PENDING_SLOT_VALUE[index])
444 			  *(uint64_t*)PENDING_SLOT_DEST[index] |=
445 			    BIT64 (PENDING_SLOT_BIT[index]);
446 			else
447 			  *(uint64_t*)PENDING_SLOT_DEST[index] &=
448 			    BIT64 (PENDING_SLOT_BIT[index]);
449 			break;
450 		      }
451 		  else
452 		    switch (PENDING_SLOT_SIZE[index])
453 		      {
454 		      case 4:
455 			*(uint32_t*)PENDING_SLOT_DEST[index] =
456 			  PENDING_SLOT_VALUE[index];
457 			break;
458 		      case 8:
459 			*(uint64_t*)PENDING_SLOT_DEST[index] =
460 			  PENDING_SLOT_VALUE[index];
461 			break;
462 		      }
463 		  if (PENDING_OUT == index)
464 		    {
465 		      PENDING_SLOT_DEST[index] = NULL;
466 		      PENDING_OUT = (PENDING_OUT + 1) % PSLOTS;
467 		      PENDING_TOTAL--;
468 		    }
469 		}
470 	      else if (PENDING_TRACE && PENDING_SLOT_DELAY[index] > 0)
471 		sim_io_eprintf (SD, "PENDING_DRAIN - queued - index %d, delay %d, dest %p, bit %d, val %" PRIx64 ", size %d\n",
472 				index, PENDING_SLOT_DELAY[index],
473 				PENDING_SLOT_DEST[index],
474 				PENDING_SLOT_BIT[index],
475 				PENDING_SLOT_VALUE[index],
476 				PENDING_SLOT_SIZE[index]);
477 
478 	    }
479 	}
480     }
481 }
482 
483 
484 #endif
485