Home | History | Annotate | Line # | Download | only in mips
sim-main.c revision 1.7
      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