sim/testsuite/or1k: Add test for 64-bit fpu operations
[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 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