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 485