]> Git Repo - binutils.git/blob - sim/mips/sim-main.c
Automatic date update in version.in
[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 /* 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)
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)
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)
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)
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)
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)
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)
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
This page took 0.048179 seconds and 4 git commands to generate.