1 /* Copyright (C) 1998, Cygnus Solutions
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.
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.
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/>.
23 #include "sim-assert.h"
27 /*---------------------------------------------------------------------------*/
28 /*-- simulator engine -------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*/
32 /* Description from page A-22 of the "MIPS IV Instruction Set" manual
34 /* Load a value from memory. Use the cache and main memory as
35 specified in the Cache Coherence Algorithm (CCA) and the sort of
36 access (IorD) to find the contents of AccessLength memory bytes
37 starting at physical location pAddr. The data is returned in the
38 fixed width naturally-aligned memory element (MemElem). The
39 low-order two (or three) bits of the address and the AccessLength
40 indicate which of the bytes within MemElem needs to be given to the
41 processor. If the memory access type of the reference is uncached
42 then only the referenced bytes are read from memory and valid
43 within the memory element. If the access type is cached, and the
44 data is not present in cache, an implementation specific size and
45 alignment block of memory is read and loaded into the cache to
46 satisfy a load reference. At a minimum, the block is the entire
48 INLINE_SIM_MAIN (void)
49 load_memory (SIM_DESC SD
,
55 unsigned int AccessLength
,
64 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"));
69 sim_io_eprintf(sd
,"LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA
);
72 if (((pAddr
& LOADDRMASK
) + AccessLength
) > LOADDRMASK
)
74 /* In reality this should be a Bus Error */
75 sim_io_error (SD
, "LOAD AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
77 (LOADDRMASK
+ 1) << 3,
81 dotrace (SD
, CPU
, tracefh
,((IorD
== isDATA
) ? 0 : 2),(unsigned int)(pAddr
&0xFFFFFFFF),(AccessLength
+ 1),"load%s",((IorD
== isDATA
) ? "" : " instruction"));
83 /* Read the specified number of bytes from memory. Adjust for
84 host/target byte ordering/ Align the least significant byte
89 case AccessLength_QUADWORD
:
91 unsigned_16 val
= sim_core_read_aligned_16 (CPU
, cia
, read_map
, pAddr
);
92 value1
= VH8_16 (val
);
96 case AccessLength_DOUBLEWORD
:
97 value
= sim_core_read_aligned_8 (CPU
, cia
, read_map
, pAddr
);
99 case AccessLength_SEPTIBYTE
:
100 value
= sim_core_read_misaligned_7 (CPU
, cia
, read_map
, pAddr
);
102 case AccessLength_SEXTIBYTE
:
103 value
= sim_core_read_misaligned_6 (CPU
, cia
, read_map
, pAddr
);
105 case AccessLength_QUINTIBYTE
:
106 value
= sim_core_read_misaligned_5 (CPU
, cia
, read_map
, pAddr
);
108 case AccessLength_WORD
:
109 value
= sim_core_read_aligned_4 (CPU
, cia
, read_map
, pAddr
);
111 case AccessLength_TRIPLEBYTE
:
112 value
= sim_core_read_misaligned_3 (CPU
, cia
, read_map
, pAddr
);
114 case AccessLength_HALFWORD
:
115 value
= sim_core_read_aligned_2 (CPU
, cia
, read_map
, pAddr
);
117 case AccessLength_BYTE
:
118 value
= sim_core_read_aligned_1 (CPU
, cia
, read_map
, pAddr
);
125 printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
126 (int)(pAddr
& LOADDRMASK
),pr_uword64(value1
),pr_uword64(value
));
129 /* See also store_memory. Position data in correct byte lanes. */
130 if (AccessLength
<= LOADDRMASK
)
133 /* for big endian target, byte (pAddr&LOADDRMASK == 0) is
134 shifted to the most significant byte position. */
135 value
<<= (((LOADDRMASK
- (pAddr
& LOADDRMASK
)) - AccessLength
) * 8);
137 /* For little endian target, byte (pAddr&LOADDRMASK == 0)
138 is already in the correct postition. */
139 value
<<= ((pAddr
& LOADDRMASK
) * 8);
143 printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
144 pr_uword64(value1
),pr_uword64(value
));
148 if (memval1p
) *memval1p
= value1
;
152 /* Description from page A-23 of the "MIPS IV Instruction Set" manual
154 /* Store a value to memory. The specified data is stored into the
155 physical location pAddr using the memory hierarchy (data caches and
156 main memory) as specified by the Cache Coherence Algorithm
157 (CCA). The MemElem contains the data for an aligned, fixed-width
158 memory element (word for 32-bit processors, doubleword for 64-bit
159 processors), though only the bytes that will actually be stored to
160 memory need to be valid. The low-order two (or three) bits of pAddr
161 and the AccessLength field indicates which of the bytes within the
162 MemElem data should actually be stored; only these bytes in memory
165 INLINE_SIM_MAIN (void)
166 store_memory (SIM_DESC SD
,
170 unsigned int AccessLength
,
172 uword64 MemElem1
, /* High order 64 bits */
177 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
));
180 #if defined(WARN_MEM)
182 sim_io_eprintf(sd
,"StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA
);
183 #endif /* WARN_MEM */
185 if (((pAddr
& LOADDRMASK
) + AccessLength
) > LOADDRMASK
)
186 sim_io_error (SD
, "STORE AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
188 (LOADDRMASK
+ 1) << 3,
191 dotrace (SD
, CPU
, tracefh
,1,(unsigned int)(pAddr
&0xFFFFFFFF),(AccessLength
+ 1),"store");
194 printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr
& LOADDRMASK
),pr_uword64(MemElem1
),pr_uword64(MemElem
));
197 /* See also load_memory. Position data in correct byte lanes. */
198 if (AccessLength
<= LOADDRMASK
)
201 /* for big endian target, byte (pAddr&LOADDRMASK == 0) is
202 shifted to the most significant byte position. */
203 MemElem
>>= (((LOADDRMASK
- (pAddr
& LOADDRMASK
)) - AccessLength
) * 8);
205 /* For little endian target, byte (pAddr&LOADDRMASK == 0)
206 is already in the correct postition. */
207 MemElem
>>= ((pAddr
& LOADDRMASK
) * 8);
211 printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift
,pr_uword64(MemElem1
),pr_uword64(MemElem
));
214 switch (AccessLength
)
216 case AccessLength_QUADWORD
:
218 unsigned_16 val
= U16_8 (MemElem1
, MemElem
);
219 sim_core_write_aligned_16 (CPU
, cia
, write_map
, pAddr
, val
);
222 case AccessLength_DOUBLEWORD
:
223 sim_core_write_aligned_8 (CPU
, cia
, write_map
, pAddr
, MemElem
);
225 case AccessLength_SEPTIBYTE
:
226 sim_core_write_misaligned_7 (CPU
, cia
, write_map
, pAddr
, MemElem
);
228 case AccessLength_SEXTIBYTE
:
229 sim_core_write_misaligned_6 (CPU
, cia
, write_map
, pAddr
, MemElem
);
231 case AccessLength_QUINTIBYTE
:
232 sim_core_write_misaligned_5 (CPU
, cia
, write_map
, pAddr
, MemElem
);
234 case AccessLength_WORD
:
235 sim_core_write_aligned_4 (CPU
, cia
, write_map
, pAddr
, MemElem
);
237 case AccessLength_TRIPLEBYTE
:
238 sim_core_write_misaligned_3 (CPU
, cia
, write_map
, pAddr
, MemElem
);
240 case AccessLength_HALFWORD
:
241 sim_core_write_aligned_2 (CPU
, cia
, write_map
, pAddr
, MemElem
);
243 case AccessLength_BYTE
:
244 sim_core_write_aligned_1 (CPU
, cia
, write_map
, pAddr
, MemElem
);
254 INLINE_SIM_MAIN (unsigned32
)
255 ifetch32 (SIM_DESC SD
,
260 /* Copy the action of the LW instruction */
261 address_word mask
= LOADDRMASK
;
262 address_word access
= AccessLength_WORD
;
263 address_word reverseendian
= (ReverseEndian
? (mask
^ access
) : 0);
264 address_word bigendiancpu
= (BigEndianCPU
? (mask
^ access
) : 0);
266 address_word paddr
= vaddr
;
269 if ((vaddr
& access
) != 0)
270 SignalExceptionInstructionFetch ();
271 paddr
= ((paddr
& ~mask
) | ((paddr
& mask
) ^ reverseendian
));
272 LoadMemory (&memval
, NULL
, access
, paddr
, vaddr
, isINSTRUCTION
, isREAL
);
273 byte
= ((vaddr
& mask
) ^ bigendiancpu
);
274 return (memval
>> (8 * byte
));
278 INLINE_SIM_MAIN (unsigned16
)
279 ifetch16 (SIM_DESC SD
,
284 /* Copy the action of the LH instruction */
285 address_word mask
= LOADDRMASK
;
286 address_word access
= AccessLength_HALFWORD
;
287 address_word reverseendian
= (ReverseEndian
? (mask
^ access
) : 0);
288 address_word bigendiancpu
= (BigEndianCPU
? (mask
^ access
) : 0);
290 address_word paddr
= vaddr
;
293 if ((vaddr
& access
) != 0)
294 SignalExceptionInstructionFetch ();
295 paddr
= ((paddr
& ~mask
) | ((paddr
& mask
) ^ reverseendian
));
296 LoadMemory (&memval
, NULL
, access
, paddr
, vaddr
, isINSTRUCTION
, isREAL
);
297 byte
= ((vaddr
& mask
) ^ bigendiancpu
);
298 return (memval
>> (8 * byte
));
303 /* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
304 /* Order loads and stores to synchronise shared memory. Perform the
305 action necessary to make the effects of groups of synchronizable
306 loads and stores indicated by stype occur in the same order for all
308 INLINE_SIM_MAIN (void)
309 sync_operation (SIM_DESC sd
,
315 sim_io_printf(sd
,"SyncOperation(%d) : TODO\n",stype
);
320 INLINE_SIM_MAIN (void)
321 cache_op (SIM_DESC SD
,
327 unsigned int instruction
)
329 #if 1 /* stop warning message being displayed (we should really just remove the code) */
330 static int icache_warning
= 1;
331 static int dcache_warning
= 1;
333 static int icache_warning
= 0;
334 static int dcache_warning
= 0;
337 /* If CP0 is not useable (User or Supervisor mode) and the CP0
338 enable bit in the Status Register is clear - a coprocessor
339 unusable exception is taken. */
341 sim_io_printf(SD
,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(cia
));
345 case 0: /* instruction cache */
347 case 0: /* Index Invalidate */
348 case 1: /* Index Load Tag */
349 case 2: /* Index Store Tag */
350 case 4: /* Hit Invalidate */
352 case 6: /* Hit Writeback */
355 sim_io_eprintf(SD
,"Instruction CACHE operation %d to be coded\n",(op
>> 2));
361 SignalException(ReservedInstruction
,instruction
);
366 case 1: /* data cache */
367 case 3: /* secondary data cache */
369 case 0: /* Index Writeback Invalidate */
370 case 1: /* Index Load Tag */
371 case 2: /* Index Store Tag */
372 case 3: /* Create Dirty */
373 case 4: /* Hit Invalidate */
374 case 5: /* Hit Writeback Invalidate */
375 case 6: /* Hit Writeback */
378 sim_io_eprintf(SD
,"Data CACHE operation %d to be coded\n",(op
>> 2));
384 SignalException(ReservedInstruction
,instruction
);
389 default: /* unrecognised cache ID */
390 SignalException(ReservedInstruction
,instruction
);
398 INLINE_SIM_MAIN (void)
399 pending_tick (SIM_DESC SD
,
404 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
);
405 if (PENDING_OUT
!= PENDING_IN
)
408 int index
= PENDING_OUT
;
409 int total
= PENDING_TOTAL
;
410 if (PENDING_TOTAL
== 0)
411 sim_engine_abort (SD
, CPU
, cia
, "PENDING_DRAIN - Mis-match on pending update pointers\n");
412 for (loop
= 0, index
= PENDING_OUT
;
414 loop
++, index
= (index
+ 1) % PSLOTS
)
416 if (PENDING_SLOT_DEST
[index
] != NULL
)
418 PENDING_SLOT_DELAY
[index
] -= 1;
419 if (PENDING_SLOT_DELAY
[index
] == 0)
422 sim_io_eprintf (SD
, "PENDING_DRAIN - drained - index %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
424 (unsigned long) PENDING_SLOT_DEST
[index
],
425 PENDING_SLOT_BIT
[index
],
426 (unsigned long) PENDING_SLOT_VALUE
[index
],
427 PENDING_SLOT_SIZE
[index
]);
428 if (PENDING_SLOT_BIT
[index
] >= 0)
429 switch (PENDING_SLOT_SIZE
[index
])
432 if (PENDING_SLOT_VALUE
[index
])
433 *(unsigned32
*)PENDING_SLOT_DEST
[index
] |=
434 BIT32 (PENDING_SLOT_BIT
[index
]);
436 *(unsigned32
*)PENDING_SLOT_DEST
[index
] &=
437 BIT32 (PENDING_SLOT_BIT
[index
]);
440 if (PENDING_SLOT_VALUE
[index
])
441 *(unsigned64
*)PENDING_SLOT_DEST
[index
] |=
442 BIT64 (PENDING_SLOT_BIT
[index
]);
444 *(unsigned64
*)PENDING_SLOT_DEST
[index
] &=
445 BIT64 (PENDING_SLOT_BIT
[index
]);
449 switch (PENDING_SLOT_SIZE
[index
])
452 *(unsigned32
*)PENDING_SLOT_DEST
[index
] =
453 PENDING_SLOT_VALUE
[index
];
456 *(unsigned64
*)PENDING_SLOT_DEST
[index
] =
457 PENDING_SLOT_VALUE
[index
];
460 if (PENDING_OUT
== index
)
462 PENDING_SLOT_DEST
[index
] = NULL
;
463 PENDING_OUT
= (PENDING_OUT
+ 1) % PSLOTS
;
467 else if (PENDING_TRACE
&& PENDING_SLOT_DELAY
[index
] > 0)
468 sim_io_eprintf (SD
, "PENDING_DRAIN - queued - index %d, delay %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
469 index
, PENDING_SLOT_DELAY
[index
],
470 (unsigned long) PENDING_SLOT_DEST
[index
],
471 PENDING_SLOT_BIT
[index
],
472 (unsigned long) PENDING_SLOT_VALUE
[index
],
473 PENDING_SLOT_SIZE
[index
]);