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