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