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