OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [or1ksim/] [mmu/] [immu.c] - Blame information for rev 1751

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 74 lampret
/* immu.c -- Instruction MMU simulation
2 1748 jeremybenn
 
3 74 lampret
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
4 1748 jeremybenn
   Copyright (C) 2008 Embecosm Limited
5 74 lampret
 
6 1748 jeremybenn
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
7 74 lampret
 
8 1748 jeremybenn
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
9 74 lampret
 
10 1748 jeremybenn
   This program is free software; you can redistribute it and/or modify it
11
   under the terms of the GNU General Public License as published by the Free
12
   Software Foundation; either version 3 of the License, or (at your option)
13
   any later version.
14 74 lampret
 
15 1748 jeremybenn
   This program is distributed in the hope that it will be useful, but WITHOUT
16
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18
   more details.
19 74 lampret
 
20 1748 jeremybenn
   You should have received a copy of the GNU General Public License along
21
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
 
23
/* This program is commented throughout in a fashion suitable for processing
24
   with Doxygen. */
25
 
26
 
27
/* Autoconf and/or portability configuration */
28 1350 nogj
#include "config.h"
29
 
30 1748 jeremybenn
/* System includes */
31
#include <stdlib.h>
32 1350 nogj
 
33 1748 jeremybenn
/* Package includes */
34 74 lampret
#include "immu.h"
35 1748 jeremybenn
#include "sim-config.h"
36 1432 nogj
#include "execute.h"
37 74 lampret
#include "stats.h"
38
#include "except.h"
39 1748 jeremybenn
#include "spr-dump.h"
40 1555 nogj
#include "misc.h"
41 1748 jeremybenn
#include "sim-cmd.h"
42 74 lampret
 
43 1416 nogj
 
44 1717 nogj
struct immu *immu_state;
45
 
46 74 lampret
/* Insn MMU */
47
 
48 1748 jeremybenn
static uorreg_t *
49
immu_find_tlbmr (oraddr_t virtaddr, uorreg_t ** itlbmr_lru, struct immu *immu)
50 1538 nogj
{
51
  int set;
52 430 markom
  int i;
53 1538 nogj
  oraddr_t vpn;
54
  uorreg_t *itlbmr;
55 884 markom
 
56 1538 nogj
  /* Which set to check out? */
57 1748 jeremybenn
  set = IADDR_PAGE (virtaddr) >> immu->pagesize_log2;
58 1717 nogj
  set &= immu->set_mask;
59
  vpn = virtaddr & immu->vpn_mask;
60 1538 nogj
 
61 1748 jeremybenn
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE (0) + set];
62 1538 nogj
  *itlbmr_lru = itlbmr;
63
 
64
  /* Scan all ways and try to find a matching way. */
65
  /* FIXME: Should this be reversed? */
66 1748 jeremybenn
  for (i = immu->nways; i; i--, itlbmr += (128 * 2))
67
    {
68
      if (((*itlbmr & immu->vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
69
        return itlbmr;
70
    }
71 1538 nogj
 
72
  return NULL;
73
}
74
 
75 1748 jeremybenn
oraddr_t
76
immu_translate (oraddr_t virtaddr)
77 1538 nogj
{
78
  int i;
79
  uorreg_t *itlbmr;
80
  uorreg_t *itlbtr;
81
  uorreg_t *itlbmr_lru;
82 1717 nogj
  struct immu *immu = immu_state;
83 1538 nogj
 
84 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
85 1748 jeremybenn
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
86
    {
87
      insn_ci = (virtaddr >= 0x80000000);
88
      return virtaddr;
89
    }
90 430 markom
 
91 1748 jeremybenn
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
92 1416 nogj
 
93 430 markom
  /* Did we find our tlb entry? */
94 1748 jeremybenn
  if (itlbmr)
95
    {                           /* Yes, we did. */
96
      immu_stats.fetch_tlbhit++;
97
      itlbtr = itlbmr + 128;
98 1538 nogj
 
99 1748 jeremybenn
      /* Set LRUs */
100
      for (i = 0; i < immu->nways; i++, itlbmr_lru += (128 * 2))
101
        {
102
          if (*itlbmr_lru & SPR_ITLBMR_LRU)
103
            *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
104
              ((*itlbmr_lru & SPR_ITLBMR_LRU) - 0x40);
105
        }
106 638 simons
 
107 1748 jeremybenn
      /* This is not necessary `*itlbmr &= ~SPR_ITLBMR_LRU;' since SPR_DTLBMR_LRU
108
       * is always decremented and the number of sets is always a power of two and
109
       * as such lru_reload has all bits set that get touched during decrementing
110
       * SPR_DTLBMR_LRU */
111
      *itlbmr |= immu->lru_reload;
112 1418 nogj
 
113 1748 jeremybenn
      /* Check if page is cache inhibited */
114
      insn_ci = *itlbtr & SPR_ITLBTR_CI;
115
 
116
      runtime.sim.mem_cycles += immu->hitdelay;
117
 
118
      /* Test for page fault */
119
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
120
        {
121
          if (!(*itlbtr & SPR_ITLBTR_SXE))
122
            except_handle (EXCEPT_IPF, virtaddr);
123
        }
124
      else
125
        {
126
          if (!(*itlbtr & SPR_ITLBTR_UXE))
127
            except_handle (EXCEPT_IPF, virtaddr);
128
        }
129
 
130
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
131 1418 nogj
    }
132
 
133 1538 nogj
  /* No, we didn't. */
134
  immu_stats.fetch_tlbmiss++;
135 430 markom
#if 0
136 1717 nogj
  for (i = 0; i < immu->nways; i++)
137 1748 jeremybenn
    if (((cpu_state.sprs[SPR_ITLBMR_BASE (i) + set] & SPR_ITLBMR_LRU) >> 6) <
138
        minlru)
139 1538 nogj
      minway = i;
140 1748 jeremybenn
 
141
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] &= ~SPR_ITLBMR_VPN;
142
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] |= vpn << 12;
143
  for (i = 0; i < immu->nways; i++)
144
    {
145
      uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE (i) + set];
146
      if (lru & SPR_ITLBMR_LRU)
147
        {
148
          lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
149
          cpu_state.sprs[SPR_ITLBMR_BASE (i) + set] = lru;
150
        }
151 1506 nogj
    }
152 1748 jeremybenn
  cpu_state.sprs[SPR_ITLBMR_BASE (way) + set] &= ~SPR_ITLBMR_LRU;
153
  cpu_state.sprs[SPR_ITLBMR_BASE (way) + set] |= (immu->nsets - 1) << 6;
154 1506 nogj
 
155 1538 nogj
  /* 1 to 1 mapping */
156 1748 jeremybenn
  cpu_state.sprs[SPR_ITLBTR_BASE (minway) + set] &= ~SPR_ITLBTR_PPN;
157
  cpu_state.sprs[SPR_ITLBTR_BASE (minway) + set] |= vpn << 12;
158 1506 nogj
 
159 1748 jeremybenn
  cpu_state.sprs[SPR_ITLBMR_BASE (minway) + set] |= SPR_ITLBMR_V;
160 430 markom
#endif
161 1418 nogj
 
162 1538 nogj
  /* if tlb refill implemented in HW */
163 1717 nogj
  /* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * immu->pagesize + (virtaddr % immu->pagesize); */
164
  runtime.sim.mem_cycles += immu->missdelay;
165 1418 nogj
 
166 1748 jeremybenn
  except_handle (EXCEPT_ITLBMISS, virtaddr);
167 1538 nogj
  return 0;
168 430 markom
}
169
 
170 1174 phoenix
/* DESC: try to find EA -> PA transaltion without changing
171
 *       any of precessor states. if this is not passible gives up
172 1446 nogj
 *       (without triggering exceptions).
173 1174 phoenix
 *
174
 * PRMS: virtaddr  - EA for which to find translation
175
 *
176
 * RTRN: 0         - no IMMU, IMMU disabled or ITLB miss
177
 *       else      - appropriate PA (note it IMMU is not present
178
 *                   PA === EA)
179
 */
180 1748 jeremybenn
oraddr_t
181
peek_into_itlb (oraddr_t virtaddr)
182 1174 phoenix
{
183 1538 nogj
  uorreg_t *itlbmr;
184
  uorreg_t *itlbtr;
185
  uorreg_t *itlbmr_lru;
186 1717 nogj
  struct immu *immu = immu_state;
187 1174 phoenix
 
188 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
189 1748 jeremybenn
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
190
    {
191
      return (virtaddr);
192
    }
193 1174 phoenix
 
194 1748 jeremybenn
  itlbmr = immu_find_tlbmr (virtaddr, &itlbmr_lru, immu);
195 1174 phoenix
 
196
  /* Did we find our tlb entry? */
197 1748 jeremybenn
  if (itlbmr)
198
    {                           /* Yes, we did. */
199
      itlbtr = itlbmr + 128;
200 1538 nogj
 
201 1748 jeremybenn
      /* Test for page fault */
202
      if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
203
        {
204
          if (!(*itlbtr & SPR_ITLBTR_SXE))
205
            {
206
              /* no luck, giving up */
207
              return (0);
208
            }
209
        }
210
      else
211
        {
212
          if (!(*itlbtr & SPR_ITLBTR_UXE))
213
            {
214
              /* no luck, giving up */
215
              return (0);
216
            }
217
        }
218
 
219
      return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
220 1174 phoenix
    }
221
 
222 1748 jeremybenn
  return (0);
223 1174 phoenix
}
224
 
225
 
226 1717 nogj
/* FIXME: Check validity */
227 74 lampret
/* First check if virtual address is covered by ITLB and if it is:
228
    - increment ITLB read hit stats,
229 1717 nogj
    - set 'lru' at this way to immu->ustates - 1 and
230 74 lampret
      decrement 'lru' of other ways unless they have reached 0,
231
    - check page access attributes and invoke IMMU page fault exception
232
      handler if necessary
233
   and if not:
234
    - increment ITLB read miss stats
235
    - find lru way and entry and invoke ITLB miss exception handler
236 1717 nogj
    - set 'lru' with immu->ustates - 1 and decrement 'lru' of other
237 74 lampret
      ways unless they have reached 0
238
*/
239
 
240 1748 jeremybenn
static void
241
itlb_status (void *dat)
242 74 lampret
{
243 1717 nogj
  struct immu *immu = dat;
244 429 markom
  int set;
245
  int way;
246 1717 nogj
  int end_set = immu->nsets;
247 74 lampret
 
248 1748 jeremybenn
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP))
249
    {
250
      PRINTF ("IMMU not implemented. Set UPR[IMP].\n");
251
      return;
252
    }
253 102 lampret
 
254 1748 jeremybenn
  if (0 < end_set)
255
    PRINTF ("\nIMMU: ");
256 429 markom
  /* Scan set(s) and way(s). */
257 1748 jeremybenn
  for (set = 0; set < end_set; set++)
258
    {
259
      for (way = 0; way < immu->nways; way++)
260
        {
261
          PRINTF ("%s\n", dump_spr (SPR_ITLBMR_BASE (way) + set,
262
                                    cpu_state.sprs[SPR_ITLBMR_BASE (way) +
263
                                                   set]));
264
          PRINTF ("%s\n",
265
                  dump_spr (SPR_ITLBTR_BASE (way) + set,
266
                            cpu_state.sprs[SPR_ITLBTR_BASE (way) + set]));
267
        }
268 429 markom
    }
269 1748 jeremybenn
  if (0 < end_set)
270
    PRINTF ("\n");
271 74 lampret
}
272 1358 nogj
 
273
/*---------------------------------------------------[ IMMU configuration ]---*/
274 1748 jeremybenn
 
275
/*---------------------------------------------------------------------------*/
276
/*!Enable or disable the IMMU
277
 
278
   Set the corresponding field in the UPR
279
 
280
   @param[in] val  The value to use
281
   @param[in] dat  The config data structure                                 */
282
/*---------------------------------------------------------------------------*/
283
static void
284
immu_enabled (union param_val val, void *dat)
285 1358 nogj
{
286 1717 nogj
  struct immu *immu = dat;
287
 
288 1748 jeremybenn
  if (val.int_val)
289
    {
290
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
291
    }
292 1506 nogj
  else
293 1748 jeremybenn
    {
294
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
295
    }
296
 
297 1717 nogj
  immu->enabled = val.int_val;
298 1358 nogj
}
299
 
300 1748 jeremybenn
 
301
/*---------------------------------------------------------------------------*/
302
/*!Set the number of DMMU sets
303
 
304
   Value must be a power of 2 <= 256. Ignore any other values with a
305
   warning. Set the corresponding IMMU configuration flags.
306
 
307
   @param[in] val  The value to use
308
   @param[in] dat  The config data structure                                 */
309
/*---------------------------------------------------------------------------*/
310
static void
311
immu_nsets (union param_val  val,
312
            void            *dat)
313 1358 nogj
{
314 1717 nogj
  struct immu *immu = dat;
315
 
316 1748 jeremybenn
  if (is_power2 (val.int_val) && (val.int_val <= 128))
317
    {
318
      int  set_bits = log2_int (val.int_val);
319
 
320
      immu->nsets = val.int_val;
321
 
322
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
323
      cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
324
    }
325 1358 nogj
  else
326 1748 jeremybenn
    {
327
      fprintf (stderr, "Warning IMMU nsets not a power of 2 <= 128: ignored\n");
328
    }
329
}       /* immu_nsets() */
330 1358 nogj
 
331 1748 jeremybenn
 
332
/*---------------------------------------------------------------------------*/
333
/*!Set the number of IMMU ways
334
 
335
   Value must be in the range 1-4. Ignore other values with a warning.  Set
336
   the corresponding IMMU configuration flags.
337
 
338
   @param[in] val  The value to use
339
   @param[in] dat  The config data structure                                 */
340
/*---------------------------------------------------------------------------*/
341
static void
342
immu_nways (union param_val  val,
343
            void            *dat)
344 1358 nogj
{
345 1717 nogj
  struct immu *immu = dat;
346
 
347 1748 jeremybenn
  if (val.int_val >= 1 && val.int_val <= 4)
348
    {
349
      int  way_bits = val.int_val - 1;
350
 
351
      immu->nways = val.int_val;
352
 
353
      cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
354
      cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
355
    }
356 1358 nogj
  else
357 1748 jeremybenn
    {
358
      fprintf (stderr, "Warning IMMU nways not in range 1-4: ignored\n");
359
    }
360
}       /* immu_nways() */
361 1358 nogj
 
362 1748 jeremybenn
 
363
/*---------------------------------------------------------------------------*/
364
/*!Set the IMMU page size
365
 
366
   Value must be a power of 2. Ignore other values with a warning
367
 
368
   @param[in] val  The value to use
369
   @param[in] dat  The config data structure                                 */
370
/*---------------------------------------------------------------------------*/
371
static void
372
immu_pagesize (union param_val  val,
373
               void            *dat)
374 1358 nogj
{
375 1717 nogj
  struct immu *immu = dat;
376
 
377 1748 jeremybenn
  if (is_power2 (val.int_val))
378
    {
379
      immu->pagesize = val.int_val;
380
    }
381 1358 nogj
  else
382 1748 jeremybenn
    {
383
      fprintf (stderr, "Warning IMMU page size must be power of 2: ignored\n");
384
    }
385
}       /* immu_pagesize() */
386 1358 nogj
 
387 1748 jeremybenn
 
388
/*---------------------------------------------------------------------------*/
389
/*!Set the IMMU entry size
390
 
391
   Value must be a power of 2. Ignore other values with a warning
392
 
393
   @param[in] val  The value to use
394
   @param[in] dat  The config data structure                                 */
395
/*---------------------------------------------------------------------------*/
396
static void
397
immu_entrysize (union param_val  val,
398
                void            *dat)
399 1358 nogj
{
400 1717 nogj
  struct immu *immu = dat;
401
 
402 1748 jeremybenn
  if (is_power2 (val.int_val))
403
    {
404
      immu->entrysize = val.int_val;
405
    }
406 1358 nogj
  else
407 1748 jeremybenn
    {
408
      fprintf (stderr, "Warning IMMU entry size must be power of 2: ignored\n");
409
    }
410
}       /* immu_entrysize() */
411 1358 nogj
 
412 1748 jeremybenn
 
413
/*---------------------------------------------------------------------------*/
414
/*!Set the number of IMMU usage states
415
 
416
   Value must be 2, 3 or 4. Ignore other values with a warning
417
 
418
   @param[in] val  The value to use
419
   @param[in] dat  The config data structure                                 */
420
/*---------------------------------------------------------------------------*/
421
static void
422
immu_ustates (union param_val  val,
423
              void            *dat)
424 1358 nogj
{
425 1717 nogj
  struct immu *immu = dat;
426
 
427 1748 jeremybenn
  if ((val.int_val >= 2) && (val.int_val <= 4))
428
    {
429
      immu->ustates = val.int_val;
430
    }
431 1358 nogj
  else
432 1748 jeremybenn
    {
433
      fprintf (stderr, "Warning number of IMMU usage states must be 2, 3 or 4:"
434
               "ignored\n");
435
    }
436
}       /* immu_ustates() */
437 1358 nogj
 
438 1748 jeremybenn
 
439
static void
440
immu_missdelay (union param_val val, void *dat)
441 1358 nogj
{
442 1717 nogj
  struct immu *immu = dat;
443
 
444
  immu->missdelay = val.int_val;
445 1358 nogj
}
446
 
447 1748 jeremybenn
static void
448
immu_hitdelay (union param_val val, void *dat)
449 1358 nogj
{
450 1717 nogj
  struct immu *immu = dat;
451
 
452
  immu->hitdelay = val.int_val;
453 1358 nogj
}
454
 
455 1748 jeremybenn
/*---------------------------------------------------------------------------*/
456
/*!Initialize a new DMMU configuration
457
 
458
   ALL parameters are set explicitly to default values.                      */
459
/*---------------------------------------------------------------------------*/
460
static void *
461
immu_start_sec ()
462 1654 nogj
{
463 1717 nogj
  struct immu *immu;
464 1748 jeremybenn
  int          set_bits;
465
  int          way_bits;
466 1717 nogj
 
467 1748 jeremybenn
  if (NULL == (immu = malloc (sizeof (struct immu))))
468
    {
469
      fprintf (stderr, "OOM\n");
470
      exit (1);
471
    }
472 1717 nogj
 
473 1748 jeremybenn
  immu->enabled   = 0;
474
  immu->nsets     = 1;
475
  immu->nways     = 1;
476
  immu->pagesize  = 8192;
477
  immu->entrysize = 1;          /* Not currently used */
478
  immu->ustates   = 2;
479
  immu->hitdelay  = 1;
480 1717 nogj
  immu->missdelay = 1;
481
 
482 1748 jeremybenn
  if (immu->enabled)
483
    {
484
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
485
    }
486
  else
487
    {
488
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
489
    }
490
 
491
  set_bits = log2_int (immu->nsets);
492
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
493
  cpu_state.sprs[SPR_IMMUCFGR] |= set_bits << SPR_IMMUCFGR_NTS_OFF;
494
 
495
  way_bits = immu->nways - 1;
496
  cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
497
  cpu_state.sprs[SPR_IMMUCFGR] |= way_bits << SPR_IMMUCFGR_NTW_OFF;
498
 
499 1717 nogj
  immu_state = immu;
500
  return immu;
501 1654 nogj
 
502 1748 jeremybenn
}       /* immu_start_sec() */
503
 
504
 
505
static void
506
immu_end_sec (void *dat)
507 1654 nogj
{
508 1717 nogj
  struct immu *immu = dat;
509
 
510 1654 nogj
  /* Precalculate some values for use during address translation */
511 1748 jeremybenn
  immu->pagesize_log2 = log2_int (immu->pagesize);
512 1717 nogj
  immu->page_offset_mask = immu->pagesize - 1;
513
  immu->page_mask = ~immu->page_offset_mask;
514
  immu->vpn_mask = ~((immu->pagesize * immu->nsets) - 1);
515
  immu->set_mask = immu->nsets - 1;
516
  immu->lru_reload = (immu->set_mask << 6) & SPR_ITLBMR_LRU;
517
 
518 1748 jeremybenn
  if (immu->enabled)
519
    {
520
      PRINTF ("Insn MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
521
              immu->nsets * immu->entrysize * immu->nways / 1024, immu->nways,
522
              immu->nsets, immu->entrysize);
523
      reg_sim_stat (itlb_status, immu);
524
    }
525 1654 nogj
}
526
 
527 1748 jeremybenn
void
528
reg_immu_sec (void)
529 1358 nogj
{
530 1748 jeremybenn
  struct config_section *sec = reg_config_sec ("immu", immu_start_sec,
531
                                               immu_end_sec);
532 1358 nogj
 
533 1748 jeremybenn
  reg_config_param (sec, "enabled", paramt_int, immu_enabled);
534
  reg_config_param (sec, "nsets", paramt_int, immu_nsets);
535
  reg_config_param (sec, "nways", paramt_int, immu_nways);
536
  reg_config_param (sec, "pagesize", paramt_int, immu_pagesize);
537
  reg_config_param (sec, "entrysize", paramt_int, immu_entrysize);
538
  reg_config_param (sec, "ustates", paramt_int, immu_ustates);
539
  reg_config_param (sec, "missdelay", paramt_int, immu_missdelay);
540
  reg_config_param (sec, "hitdelay", paramt_int, immu_hitdelay);
541 1358 nogj
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.