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 2 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, write to the Free Software
15    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
17    */
18
19
20#ifndef SIM_MAIN_C
21#define SIM_MAIN_C
22
23#include "sim-main.h"
24#include "sim-assert.h"
25
26
27/*---------------------------------------------------------------------------*/
28/*-- simulator engine -------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31
32/* Description from page A-22 of the "MIPS IV Instruction Set" manual
33   (revision 3.1) */
34/* Translate a virtual address to a physical address and cache
35   coherence algorithm describing the mechanism used to resolve the
36   memory reference. Given the virtual address vAddr, and whether the
37   reference is to Instructions ot Data (IorD), find the corresponding
38   physical address (pAddr) and the cache coherence algorithm (CCA)
39   used to resolve the reference. If the virtual address is in one of
40   the unmapped address spaces the physical address and the CCA are
41   determined directly by the virtual address. If the virtual address
42   is in one of the mapped address spaces then the TLB is used to
43   determine the physical address and access type; if the required
44   translation is not present in the TLB or the desired access is not
45   permitted the function fails and an exception is taken.
46
47   NOTE: Normally (RAW == 0), when address translation fails, this
48   function raises an exception and does not return. */
49
50INLINE_SIM_MAIN
51(int)
52address_translation (SIM_DESC sd,
53		     sim_cpu * cpu,
54		     address_word cia,
55		     address_word vAddr,
56		     int IorD,
57		     int LorS,
58		     address_word * pAddr,
59		     int *CCA,
60		     int raw)
61{
62  int res = -1;			/* TRUE : Assume good return */
63
64#ifdef DEBUG
65  sim_io_printf (sd, "AddressTranslation(0x%s,%s,%s,...);\n", pr_addr (vAddr), (IorD ? "isDATA" : "isINSTRUCTION"), (LorS ? "iSTORE" : "isLOAD"));
66#endif
67
68  /* Check that the address is valid for this memory model */
69
70  /* For a simple (flat) memory model, we simply pass virtual
71     addressess through (mostly) unchanged. */
72  vAddr &= 0xFFFFFFFF;
73
74  *pAddr = vAddr;		/* default for isTARGET */
75  *CCA = Uncached;		/* not used for isHOST */
76
77  return (res);
78}
79
80
81
82/* Description from page A-23 of the "MIPS IV Instruction Set" manual
83   (revision 3.1) */
84/* Prefetch data from memory. Prefetch is an advisory instruction for
85   which an implementation specific action is taken. The action taken
86   may increase performance, but must not change the meaning of the
87   program, or alter architecturally-visible state. */
88
89INLINE_SIM_MAIN (void)
90prefetch (SIM_DESC sd,
91	  sim_cpu *cpu,
92	  address_word cia,
93	  int CCA,
94	  address_word pAddr,
95	  address_word vAddr,
96	  int DATA,
97	  int hint)
98{
99#ifdef DEBUG
100  sim_io_printf(sd,"Prefetch(%d,0x%s,0x%s,%d,%d);\n",CCA,pr_addr(pAddr),pr_addr(vAddr),DATA,hint);
101#endif /* DEBUG */
102
103  /* For our simple memory model we do nothing */
104  return;
105}
106
107/* Description from page A-22 of the "MIPS IV Instruction Set" manual
108   (revision 3.1) */
109/* Load a value from memory. Use the cache and main memory as
110   specified in the Cache Coherence Algorithm (CCA) and the sort of
111   access (IorD) to find the contents of AccessLength memory bytes
112   starting at physical location pAddr. The data is returned in the
113   fixed width naturally-aligned memory element (MemElem). The
114   low-order two (or three) bits of the address and the AccessLength
115   indicate which of the bytes within MemElem needs to be given to the
116   processor. If the memory access type of the reference is uncached
117   then only the referenced bytes are read from memory and valid
118   within the memory element. If the access type is cached, and the
119   data is not present in cache, an implementation specific size and
120   alignment block of memory is read and loaded into the cache to
121   satisfy a load reference. At a minimum, the block is the entire
122   memory element. */
123INLINE_SIM_MAIN (void)
124load_memory (SIM_DESC SD,
125	     sim_cpu *CPU,
126	     address_word cia,
127	     uword64* memvalp,
128	     uword64* memval1p,
129	     int CCA,
130	     unsigned int AccessLength,
131	     address_word pAddr,
132	     address_word vAddr,
133	     int IorD)
134{
135  uword64 value = 0;
136  uword64 value1 = 0;
137
138#ifdef DEBUG
139  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"));
140#endif /* DEBUG */
141
142#if defined(WARN_MEM)
143  if (CCA != uncached)
144    sim_io_eprintf(sd,"LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
145#endif /* WARN_MEM */
146
147  if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
148    {
149      /* In reality this should be a Bus Error */
150      sim_io_error (SD, "LOAD AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
151		    AccessLength,
152		    (LOADDRMASK + 1) << 3,
153		    pr_addr (pAddr));
154    }
155
156#if defined(TRACE)
157  dotrace (SD, CPU, tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
158#endif /* TRACE */
159
160  /* Read the specified number of bytes from memory.  Adjust for
161     host/target byte ordering/ Align the least significant byte
162     read. */
163
164  switch (AccessLength)
165    {
166    case AccessLength_QUADWORD:
167      {
168	unsigned_16 val = sim_core_read_aligned_16 (CPU, cia, read_map, pAddr);
169	value1 = VH8_16 (val);
170	value = VL8_16 (val);
171	break;
172      }
173    case AccessLength_DOUBLEWORD:
174      value = sim_core_read_aligned_8 (CPU, cia, read_map, pAddr);
175      break;
176    case AccessLength_SEPTIBYTE:
177      value = sim_core_read_misaligned_7 (CPU, cia, read_map, pAddr);
178      break;
179    case AccessLength_SEXTIBYTE:
180      value = sim_core_read_misaligned_6 (CPU, cia, read_map, pAddr);
181      break;
182    case AccessLength_QUINTIBYTE:
183      value = sim_core_read_misaligned_5 (CPU, cia, read_map, pAddr);
184      break;
185    case AccessLength_WORD:
186      value = sim_core_read_aligned_4 (CPU, cia, read_map, pAddr);
187      break;
188    case AccessLength_TRIPLEBYTE:
189      value = sim_core_read_misaligned_3 (CPU, cia, read_map, pAddr);
190      break;
191    case AccessLength_HALFWORD:
192      value = sim_core_read_aligned_2 (CPU, cia, read_map, pAddr);
193      break;
194    case AccessLength_BYTE:
195      value = sim_core_read_aligned_1 (CPU, cia, read_map, pAddr);
196      break;
197    default:
198      abort ();
199    }
200
201#ifdef DEBUG
202  printf("DBG: LoadMemory() : (offset %d) : value = 0x%s%s\n",
203	 (int)(pAddr & LOADDRMASK),pr_uword64(value1),pr_uword64(value));
204#endif /* DEBUG */
205
206  /* See also store_memory. Position data in correct byte lanes. */
207  if (AccessLength <= LOADDRMASK)
208    {
209      if (BigEndianMem)
210	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
211	   shifted to the most significant byte position.  */
212	value <<= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
213      else
214	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
215	   is already in the correct postition. */
216	value <<= ((pAddr & LOADDRMASK) * 8);
217    }
218
219#ifdef DEBUG
220  printf("DBG: LoadMemory() : shifted value = 0x%s%s\n",
221	 pr_uword64(value1),pr_uword64(value));
222#endif /* DEBUG */
223
224  *memvalp = value;
225  if (memval1p) *memval1p = value1;
226}
227
228
229/* Description from page A-23 of the "MIPS IV Instruction Set" manual
230   (revision 3.1) */
231/* Store a value to memory. The specified data is stored into the
232   physical location pAddr using the memory hierarchy (data caches and
233   main memory) as specified by the Cache Coherence Algorithm
234   (CCA). The MemElem contains the data for an aligned, fixed-width
235   memory element (word for 32-bit processors, doubleword for 64-bit
236   processors), though only the bytes that will actually be stored to
237   memory need to be valid. The low-order two (or three) bits of pAddr
238   and the AccessLength field indicates which of the bytes within the
239   MemElem data should actually be stored; only these bytes in memory
240   will be changed. */
241
242INLINE_SIM_MAIN (void)
243store_memory (SIM_DESC SD,
244	      sim_cpu *CPU,
245	      address_word cia,
246	      int CCA,
247	      unsigned int AccessLength,
248	      uword64 MemElem,
249	      uword64 MemElem1,   /* High order 64 bits */
250	      address_word pAddr,
251	      address_word vAddr)
252{
253#ifdef DEBUG
254  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));
255#endif /* DEBUG */
256
257#if defined(WARN_MEM)
258  if (CCA != uncached)
259    sim_io_eprintf(sd,"StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
260#endif /* WARN_MEM */
261
262  if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
263    sim_io_error (SD, "STORE AccessLength of %d would extend over %d bit aligned boundary for physical address 0x%s\n",
264		  AccessLength,
265		  (LOADDRMASK + 1) << 3,
266		  pr_addr(pAddr));
267
268#if defined(TRACE)
269  dotrace (SD, CPU, tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
270#endif /* TRACE */
271
272#ifdef DEBUG
273  printf("DBG: StoreMemory: offset = %d MemElem = 0x%s%s\n",(unsigned int)(pAddr & LOADDRMASK),pr_uword64(MemElem1),pr_uword64(MemElem));
274#endif /* DEBUG */
275
276  /* See also load_memory. Position data in correct byte lanes. */
277  if (AccessLength <= LOADDRMASK)
278    {
279      if (BigEndianMem)
280	/* for big endian target, byte (pAddr&LOADDRMASK == 0) is
281	   shifted to the most significant byte position.  */
282	MemElem >>= (((LOADDRMASK - (pAddr & LOADDRMASK)) - AccessLength) * 8);
283      else
284	/* For little endian target, byte (pAddr&LOADDRMASK == 0)
285	   is already in the correct postition. */
286	MemElem >>= ((pAddr & LOADDRMASK) * 8);
287    }
288
289#ifdef DEBUG
290  printf("DBG: StoreMemory: shift = %d MemElem = 0x%s%s\n",shift,pr_uword64(MemElem1),pr_uword64(MemElem));
291#endif /* DEBUG */
292
293  switch (AccessLength)
294    {
295    case AccessLength_QUADWORD:
296      {
297	unsigned_16 val = U16_8 (MemElem1, MemElem);
298	sim_core_write_aligned_16 (CPU, cia, write_map, pAddr, val);
299	break;
300      }
301    case AccessLength_DOUBLEWORD:
302      sim_core_write_aligned_8 (CPU, cia, write_map, pAddr, MemElem);
303      break;
304    case AccessLength_SEPTIBYTE:
305      sim_core_write_misaligned_7 (CPU, cia, write_map, pAddr, MemElem);
306      break;
307    case AccessLength_SEXTIBYTE:
308      sim_core_write_misaligned_6 (CPU, cia, write_map, pAddr, MemElem);
309      break;
310    case AccessLength_QUINTIBYTE:
311      sim_core_write_misaligned_5 (CPU, cia, write_map, pAddr, MemElem);
312      break;
313    case AccessLength_WORD:
314      sim_core_write_aligned_4 (CPU, cia, write_map, pAddr, MemElem);
315      break;
316    case AccessLength_TRIPLEBYTE:
317      sim_core_write_misaligned_3 (CPU, cia, write_map, pAddr, MemElem);
318      break;
319    case AccessLength_HALFWORD:
320      sim_core_write_aligned_2 (CPU, cia, write_map, pAddr, MemElem);
321      break;
322    case AccessLength_BYTE:
323      sim_core_write_aligned_1 (CPU, cia, write_map, pAddr, MemElem);
324      break;
325    default:
326      abort ();
327    }
328
329  return;
330}
331
332
333INLINE_SIM_MAIN (unsigned32)
334ifetch32 (SIM_DESC SD,
335	  sim_cpu *CPU,
336	  address_word cia,
337	  address_word vaddr)
338{
339  /* Copy the action of the LW instruction */
340  address_word mask = LOADDRMASK;
341  address_word access = AccessLength_WORD;
342  address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
343  address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
344  unsigned int byte;
345  address_word paddr;
346  int uncached;
347  unsigned64 memval;
348
349  if ((vaddr & access) != 0)
350    SignalExceptionInstructionFetch ();
351  AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
352  paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
353  LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
354  byte = ((vaddr & mask) ^ bigendiancpu);
355  return (memval >> (8 * byte));
356}
357
358
359INLINE_SIM_MAIN (unsigned16)
360ifetch16 (SIM_DESC SD,
361	  sim_cpu *CPU,
362	  address_word cia,
363	  address_word vaddr)
364{
365  /* Copy the action of the LH instruction */
366  address_word mask = LOADDRMASK;
367  address_word access = AccessLength_HALFWORD;
368  address_word reverseendian = (ReverseEndian ? (mask ^ access) : 0);
369  address_word bigendiancpu = (BigEndianCPU ? (mask ^ access) : 0);
370  unsigned int byte;
371  address_word paddr;
372  int uncached;
373  unsigned64 memval;
374
375  if ((vaddr & access) != 0)
376    SignalExceptionInstructionFetch ();
377  AddressTranslation (vaddr, isINSTRUCTION, isLOAD, &paddr, &uncached, isTARGET, isREAL);
378  paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverseendian));
379  LoadMemory (&memval, NULL, uncached, access, paddr, vaddr, isINSTRUCTION, isREAL);
380  byte = ((vaddr & mask) ^ bigendiancpu);
381  return (memval >> (8 * byte));
382}
383
384
385
386/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
387/* Order loads and stores to synchronise shared memory. Perform the
388   action necessary to make the effects of groups of synchronizable
389   loads and stores indicated by stype occur in the same order for all
390   processors. */
391INLINE_SIM_MAIN (void)
392sync_operation (SIM_DESC sd,
393		sim_cpu *cpu,
394		address_word cia,
395		int stype)
396{
397#ifdef DEBUG
398  sim_io_printf(sd,"SyncOperation(%d) : TODO\n",stype);
399#endif /* DEBUG */
400  return;
401}
402
403INLINE_SIM_MAIN (void)
404cache_op (SIM_DESC SD,
405	  sim_cpu *CPU,
406	  address_word cia,
407	  int op,
408	  address_word pAddr,
409	  address_word vAddr,
410	  unsigned int instruction)
411{
412#if 1 /* stop warning message being displayed (we should really just remove the code) */
413  static int icache_warning = 1;
414  static int dcache_warning = 1;
415#else
416  static int icache_warning = 0;
417  static int dcache_warning = 0;
418#endif
419
420  /* If CP0 is not useable (User or Supervisor mode) and the CP0
421     enable bit in the Status Register is clear - a coprocessor
422     unusable exception is taken. */
423#if 0
424  sim_io_printf(SD,"TODO: Cache availability checking (PC = 0x%s)\n",pr_addr(cia));
425#endif
426
427  switch (op & 0x3) {
428    case 0: /* instruction cache */
429      switch (op >> 2) {
430        case 0: /* Index Invalidate */
431        case 1: /* Index Load Tag */
432        case 2: /* Index Store Tag */
433        case 4: /* Hit Invalidate */
434        case 5: /* Fill */
435        case 6: /* Hit Writeback */
436          if (!icache_warning)
437            {
438              sim_io_eprintf(SD,"Instruction CACHE operation %d to be coded\n",(op >> 2));
439              icache_warning = 1;
440            }
441          break;
442
443        default:
444          SignalException(ReservedInstruction,instruction);
445          break;
446      }
447      break;
448
449    case 1: /* data cache */
450    case 3: /* secondary data cache */
451      switch (op >> 2) {
452        case 0: /* Index Writeback Invalidate */
453        case 1: /* Index Load Tag */
454        case 2: /* Index Store Tag */
455        case 3: /* Create Dirty */
456        case 4: /* Hit Invalidate */
457        case 5: /* Hit Writeback Invalidate */
458        case 6: /* Hit Writeback */
459          if (!dcache_warning)
460            {
461              sim_io_eprintf(SD,"Data CACHE operation %d to be coded\n",(op >> 2));
462              dcache_warning = 1;
463            }
464          break;
465
466        default:
467          SignalException(ReservedInstruction,instruction);
468          break;
469      }
470      break;
471
472    default: /* unrecognised cache ID */
473      SignalException(ReservedInstruction,instruction);
474      break;
475  }
476
477  return;
478}
479
480
481INLINE_SIM_MAIN (void)
482pending_tick (SIM_DESC SD,
483	      sim_cpu *CPU,
484	      address_word cia)
485{
486  if (PENDING_TRACE)
487    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);
488  if (PENDING_OUT != PENDING_IN)
489    {
490      int loop;
491      int index = PENDING_OUT;
492      int total = PENDING_TOTAL;
493      if (PENDING_TOTAL == 0)
494	sim_engine_abort (SD, CPU, cia, "PENDING_DRAIN - Mis-match on pending update pointers\n");
495      for (loop = 0, index = PENDING_OUT;
496	   (loop < total);
497	   loop++, index = (index + 1) % PSLOTS)
498	{
499	  if (PENDING_SLOT_DEST[index] != NULL)
500	    {
501	      PENDING_SLOT_DELAY[index] -= 1;
502	      if (PENDING_SLOT_DELAY[index] == 0)
503		{
504		  if (PENDING_TRACE)
505		    sim_io_eprintf (SD, "PENDING_DRAIN - drained - index %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
506				    index,
507				    (unsigned long) PENDING_SLOT_DEST[index],
508				    PENDING_SLOT_BIT[index],
509				    (unsigned long) PENDING_SLOT_VALUE[index],
510				    PENDING_SLOT_SIZE[index]);
511		  if (PENDING_SLOT_BIT[index] >= 0)
512		    switch (PENDING_SLOT_SIZE[index])
513		      {
514		      case 4:
515			if (PENDING_SLOT_VALUE[index])
516			  *(unsigned32*)PENDING_SLOT_DEST[index] |=
517			    BIT32 (PENDING_SLOT_BIT[index]);
518			else
519			  *(unsigned32*)PENDING_SLOT_DEST[index] &=
520			    BIT32 (PENDING_SLOT_BIT[index]);
521			break;
522		      case 8:
523			if (PENDING_SLOT_VALUE[index])
524			  *(unsigned64*)PENDING_SLOT_DEST[index] |=
525			    BIT64 (PENDING_SLOT_BIT[index]);
526			else
527			  *(unsigned64*)PENDING_SLOT_DEST[index] &=
528			    BIT64 (PENDING_SLOT_BIT[index]);
529			break;
530		      }
531		  else
532		    switch (PENDING_SLOT_SIZE[index])
533		      {
534		      case 4:
535			*(unsigned32*)PENDING_SLOT_DEST[index] =
536			  PENDING_SLOT_VALUE[index];
537			break;
538		      case 8:
539			*(unsigned64*)PENDING_SLOT_DEST[index] =
540			  PENDING_SLOT_VALUE[index];
541			break;
542		      }
543		  if (PENDING_OUT == index)
544		    {
545		      PENDING_SLOT_DEST[index] = NULL;
546		      PENDING_OUT = (PENDING_OUT + 1) % PSLOTS;
547		      PENDING_TOTAL--;
548		    }
549		}
550	      else if (PENDING_TRACE && PENDING_SLOT_DELAY[index] > 0)
551		sim_io_eprintf (SD, "PENDING_DRAIN - queued - index %d, delay %d, dest 0x%lx, bit %d, val 0x%lx, size %d\n",
552				index, PENDING_SLOT_DELAY[index],
553				(unsigned long) PENDING_SLOT_DEST[index],
554				PENDING_SLOT_BIT[index],
555				(unsigned long) PENDING_SLOT_VALUE[index],
556				PENDING_SLOT_SIZE[index]);
557
558	    }
559	}
560    }
561}
562
563
564#endif
565