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

Subversion Repositories or1k

[/] [or1k/] [tags/] [rel-0-3-0-rc2/] [or1ksim/] [mmu/] [immu.c] - Blame information for rev 1717

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
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
3
 
4
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20 1538 nogj
/* IMMU model, perfectly functional. */
21 74 lampret
 
22 1350 nogj
#include "config.h"
23
 
24
#ifdef HAVE_INTTYPES_H
25
#include <inttypes.h>
26
#endif
27
 
28
#include "port.h"
29
#include "arch.h"
30 74 lampret
#include "immu.h"
31
#include "abstract.h"
32 1344 nogj
#include "opcode/or32.h"
33 1432 nogj
#include "spr_defs.h"
34
#include "execute.h"
35 74 lampret
#include "stats.h"
36
#include "sprs.h"
37
#include "except.h"
38 425 markom
#include "sim-config.h"
39 1308 phoenix
#include "debug.h"
40 1555 nogj
#include "misc.h"
41 74 lampret
 
42 1416 nogj
DEFAULT_DEBUG_CHANNEL(immu);
43
 
44 1717 nogj
struct immu *immu_state;
45
 
46 74 lampret
/* Insn MMU */
47
 
48 1717 nogj
static inline uorreg_t *immu_find_tlbmr(oraddr_t virtaddr,
49
                                        uorreg_t **itlbmr_lru,
50
                                        struct immu *immu)
51 1538 nogj
{
52
  int set;
53 430 markom
  int i;
54 1538 nogj
  oraddr_t vpn;
55
  uorreg_t *itlbmr;
56 884 markom
 
57 1538 nogj
  /* Which set to check out? */
58 1717 nogj
  set = IADDR_PAGE(virtaddr) >> immu->pagesize_log2;
59
  set &= immu->set_mask;
60
  vpn = virtaddr & immu->vpn_mask;
61 1538 nogj
 
62
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE(0) + set];
63
  *itlbmr_lru = itlbmr;
64
 
65
  /* Scan all ways and try to find a matching way. */
66
  /* FIXME: Should this be reversed? */
67 1717 nogj
  for(i = immu->nways; i; i--, itlbmr += (128 * 2)) {
68
    if(((*itlbmr & immu->vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
69 1538 nogj
      return itlbmr;
70
  }
71
 
72
  return NULL;
73
}
74
 
75
oraddr_t immu_translate(oraddr_t virtaddr)
76
{
77
  int i;
78
  uorreg_t *itlbmr;
79
  uorreg_t *itlbtr;
80
  uorreg_t *itlbmr_lru;
81 1717 nogj
  struct immu *immu = immu_state;
82 1538 nogj
 
83 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
84
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
85 638 simons
    insn_ci = (virtaddr >= 0x80000000);
86 430 markom
    return virtaddr;
87 638 simons
  }
88 430 markom
 
89 1717 nogj
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru, immu);
90 1416 nogj
 
91 430 markom
  /* Did we find our tlb entry? */
92 1538 nogj
  if(itlbmr) { /* Yes, we did. */
93 430 markom
    immu_stats.fetch_tlbhit++;
94 1416 nogj
    TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
95 430 markom
 
96 1538 nogj
    itlbtr = itlbmr + 128;
97
 
98 430 markom
    /* Set LRUs */
99 1717 nogj
    for(i = 0; i < immu->nways; i++, itlbmr_lru += (128 * 2)) {
100 1538 nogj
      if(*itlbmr_lru & SPR_ITLBMR_LRU)
101
        *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
102
                                        ((*itlbmr_lru & SPR_ITLBMR_LRU) - 0x40);
103 1506 nogj
    }
104
 
105 1538 nogj
    /* This is not necessary `*itlbmr &= ~SPR_ITLBMR_LRU;' since SPR_DTLBMR_LRU
106
     * is always decremented and the number of sets is always a power of two and
107
     * as such lru_reload has all bits set that get touched during decrementing
108
     * SPR_DTLBMR_LRU */
109 1717 nogj
    *itlbmr |= immu->lru_reload;
110 1538 nogj
 
111 638 simons
    /* Check if page is cache inhibited */
112 1538 nogj
    insn_ci = *itlbtr & SPR_ITLBTR_CI;
113 638 simons
 
114 1717 nogj
    runtime.sim.mem_cycles += immu->hitdelay;
115 1418 nogj
 
116
    /* Test for page fault */
117 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
118 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_SXE))
119 1418 nogj
        except_handle(EXCEPT_IPF, virtaddr);
120
    } else {
121 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_UXE))
122 1418 nogj
        except_handle(EXCEPT_IPF, virtaddr);
123
    }
124
 
125 1538 nogj
    TRACE("Returning physical address %"PRIxADDR"\n",
126 1717 nogj
          (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask));
127
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
128 430 markom
  }
129 1538 nogj
 
130
  /* No, we didn't. */
131
  immu_stats.fetch_tlbmiss++;
132 430 markom
#if 0
133 1717 nogj
  for (i = 0; i < immu->nways; i++)
134 1538 nogj
    if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_LRU) >> 6) < minlru)
135
      minway = i;
136
 
137
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] &= ~SPR_ITLBMR_VPN;
138
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= vpn << 12;
139 1717 nogj
  for (i = 0; i < immu->nways; i++) {
140 1538 nogj
    uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE(i) + set];
141
    if (lru & SPR_ITLBMR_LRU) {
142
      lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
143
      cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] = lru;
144 1506 nogj
    }
145 1538 nogj
  }
146
  cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] &= ~SPR_ITLBMR_LRU;
147 1717 nogj
  cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] |= (immu->nsets - 1) << 6;
148 1506 nogj
 
149 1538 nogj
  /* 1 to 1 mapping */
150
  cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] &= ~SPR_ITLBTR_PPN;
151
  cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] |= vpn << 12;
152 1506 nogj
 
153 1538 nogj
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= SPR_ITLBMR_V;
154 430 markom
#endif
155 1418 nogj
 
156 1538 nogj
  /* if tlb refill implemented in HW */
157 1717 nogj
  /* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * immu->pagesize + (virtaddr % immu->pagesize); */
158
  runtime.sim.mem_cycles += immu->missdelay;
159 1418 nogj
 
160 1538 nogj
  except_handle(EXCEPT_ITLBMISS, virtaddr);
161
  return 0;
162 430 markom
}
163
 
164 1174 phoenix
/* DESC: try to find EA -> PA transaltion without changing
165
 *       any of precessor states. if this is not passible gives up
166 1446 nogj
 *       (without triggering exceptions).
167 1174 phoenix
 *
168
 * PRMS: virtaddr  - EA for which to find translation
169
 *
170
 * RTRN: 0         - no IMMU, IMMU disabled or ITLB miss
171
 *       else      - appropriate PA (note it IMMU is not present
172
 *                   PA === EA)
173
 */
174 1350 nogj
oraddr_t peek_into_itlb(oraddr_t virtaddr)
175 1174 phoenix
{
176 1538 nogj
  uorreg_t *itlbmr;
177
  uorreg_t *itlbtr;
178
  uorreg_t *itlbmr_lru;
179 1717 nogj
  struct immu *immu = immu_state;
180 1174 phoenix
 
181 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
182
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
183 1174 phoenix
     return(virtaddr);
184
  }
185
 
186 1717 nogj
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru, immu);
187 1174 phoenix
 
188
  /* Did we find our tlb entry? */
189 1538 nogj
  if(itlbmr) { /* Yes, we did. */
190
    itlbtr = itlbmr + 128;
191
 
192 1174 phoenix
    /* Test for page fault */
193 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
194 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_SXE)) {
195 1174 phoenix
        /* no luck, giving up */
196
        return(0);
197
      }
198
    } else {
199 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_UXE)) {
200 1174 phoenix
        /* no luck, giving up */
201
        return(0);
202
      }
203
    }
204
 
205 1717 nogj
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr & immu->page_offset_mask);
206 1174 phoenix
  }
207 1538 nogj
 
208 1174 phoenix
  return(0);
209
}
210
 
211
 
212 1717 nogj
/* FIXME: Check validity */
213 74 lampret
/* First check if virtual address is covered by ITLB and if it is:
214
    - increment ITLB read hit stats,
215 1717 nogj
    - set 'lru' at this way to immu->ustates - 1 and
216 74 lampret
      decrement 'lru' of other ways unless they have reached 0,
217
    - check page access attributes and invoke IMMU page fault exception
218
      handler if necessary
219
   and if not:
220
    - increment ITLB read miss stats
221
    - find lru way and entry and invoke ITLB miss exception handler
222 1717 nogj
    - set 'lru' with immu->ustates - 1 and decrement 'lru' of other
223 74 lampret
      ways unless they have reached 0
224
*/
225
 
226 1717 nogj
static void itlb_status(void *dat)
227 74 lampret
{
228 1717 nogj
  struct immu *immu = dat;
229 429 markom
  int set;
230
  int way;
231 1717 nogj
  int end_set = immu->nsets;
232 74 lampret
 
233 1506 nogj
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
234 997 markom
    PRINTF("IMMU not implemented. Set UPR[IMP].\n");
235 429 markom
    return;
236
  }
237 102 lampret
 
238 1717 nogj
  if (0 < end_set) PRINTF("\nIMMU: ");
239 429 markom
  /* Scan set(s) and way(s). */
240 1717 nogj
  for (set = 0; set < end_set; set++) {
241
    for (way = 0; way < immu->nways; way++) {
242 1532 nogj
      PRINTF("%s\n", dump_spr(SPR_ITLBMR_BASE(way) + set,
243
                              cpu_state.sprs[SPR_ITLBMR_BASE(way) + set]));
244
      PRINTF("%s\n", dump_spr(SPR_ITLBTR_BASE(way) + set,
245
                              cpu_state.sprs[SPR_ITLBTR_BASE(way) + set]));
246 429 markom
    }
247
  }
248 1717 nogj
  if (0 < end_set) PRINTF("\n");
249 74 lampret
}
250 1358 nogj
 
251
/*---------------------------------------------------[ IMMU configuration ]---*/
252 1649 nogj
static void immu_enabled(union param_val val, void *dat)
253 1358 nogj
{
254 1717 nogj
  struct immu *immu = dat;
255
 
256 1506 nogj
  if(val.int_val)
257
    cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
258
  else
259
    cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
260 1717 nogj
  immu->enabled = val.int_val;
261 1358 nogj
}
262
 
263 1649 nogj
static void immu_nsets(union param_val val, void *dat)
264 1358 nogj
{
265 1717 nogj
  struct immu *immu = dat;
266
 
267 1382 nogj
  if (is_power2(val.int_val) && val.int_val <= 256) {
268 1717 nogj
    immu->nsets = val.int_val;
269 1506 nogj
    cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
270 1555 nogj
    cpu_state.sprs[SPR_IMMUCFGR] |= log2_int(val.int_val) << 3;
271 1382 nogj
  }
272 1358 nogj
  else
273
    CONFIG_ERROR("value of power of two and lower or equal than 256 expected.");
274
}
275
 
276 1649 nogj
static void immu_nways(union param_val val, void *dat)
277 1358 nogj
{
278 1717 nogj
  struct immu *immu = dat;
279
 
280 1382 nogj
  if (val.int_val >= 1 && val.int_val <= 4) {
281 1717 nogj
    immu->nways = val.int_val;
282 1506 nogj
    cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
283
    cpu_state.sprs[SPR_IMMUCFGR] |= val.int_val - 1;
284 1382 nogj
  }
285 1358 nogj
  else
286
    CONFIG_ERROR("value 1, 2, 3 or 4 expected.");
287
}
288
 
289 1649 nogj
static void immu_pagesize(union param_val val, void *dat)
290 1358 nogj
{
291 1717 nogj
  struct immu *immu = dat;
292
 
293 1358 nogj
  if (is_power2(val.int_val))
294 1717 nogj
    immu->pagesize = val.int_val;
295 1358 nogj
  else
296
    CONFIG_ERROR("value of power of two expected.");
297
}
298
 
299 1649 nogj
static void immu_entrysize(union param_val val, void *dat)
300 1358 nogj
{
301 1717 nogj
  struct immu *immu = dat;
302
 
303 1358 nogj
  if (is_power2(val.int_val))
304 1717 nogj
    immu->entrysize = val.int_val;
305 1358 nogj
  else
306
    CONFIG_ERROR("value of power of two expected.");
307
}
308
 
309 1649 nogj
static void immu_ustates(union param_val val, void *dat)
310 1358 nogj
{
311 1717 nogj
  struct immu *immu = dat;
312
 
313 1358 nogj
  if (val.int_val >= 2 && val.int_val <= 4)
314 1717 nogj
    immu->ustates = val.int_val;
315 1358 nogj
  else
316
    CONFIG_ERROR("invalid USTATE.");
317
}
318
 
319 1649 nogj
static void immu_missdelay(union param_val val, void *dat)
320 1358 nogj
{
321 1717 nogj
  struct immu *immu = dat;
322
 
323
  immu->missdelay = val.int_val;
324 1358 nogj
}
325
 
326 1649 nogj
static void immu_hitdelay(union param_val val, void *dat)
327 1358 nogj
{
328 1717 nogj
  struct immu *immu = dat;
329
 
330
  immu->hitdelay = val.int_val;
331 1358 nogj
}
332
 
333 1654 nogj
static void *immu_start_sec(void)
334
{
335 1717 nogj
  struct immu *immu;
336
 
337
  if(!(immu = malloc(sizeof(struct immu)))) {
338
    fprintf(stderr, "OOM\n");
339
    exit(1);
340
  }
341
 
342
  immu->enabled = 0;
343
  immu->hitdelay = 1;
344
  immu->missdelay = 1;
345
  immu->pagesize = 8192;
346
  /* FIXME: Something sane */
347
  immu->entrysize = 0;
348
 
349
  immu_state = immu;
350
 
351
  return immu;
352 1654 nogj
}
353
 
354
static void immu_end_sec(void *dat)
355
{
356 1717 nogj
  struct immu *immu = dat;
357
 
358 1654 nogj
  /* Precalculate some values for use during address translation */
359 1717 nogj
  immu->pagesize_log2 = log2_int(immu->pagesize);
360
  immu->page_offset_mask = immu->pagesize - 1;
361
  immu->page_mask = ~immu->page_offset_mask;
362
  immu->vpn_mask = ~((immu->pagesize * immu->nsets) - 1);
363
  immu->set_mask = immu->nsets - 1;
364
  immu->lru_reload = (immu->set_mask << 6) & SPR_ITLBMR_LRU;
365
 
366
  if(immu->enabled) {
367
    PRINTF("Insn MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
368
           immu->nsets * immu->entrysize * immu->nways / 1024, immu->nways,
369
           immu->nsets, immu->entrysize);
370
    reg_sim_stat(itlb_status, immu);
371
  }
372 1654 nogj
}
373
 
374 1358 nogj
void reg_immu_sec(void)
375
{
376 1654 nogj
  struct config_section *sec = reg_config_sec("immu", immu_start_sec,
377
                                              immu_end_sec);
378 1358 nogj
 
379
  reg_config_param(sec, "enabled", paramt_int, immu_enabled);
380
  reg_config_param(sec, "nsets", paramt_int, immu_nsets);
381
  reg_config_param(sec, "nways", paramt_int, immu_nways);
382
  reg_config_param(sec, "pagesize", paramt_int, immu_pagesize);
383
  reg_config_param(sec, "entrysize", paramt_int, immu_entrysize);
384
  reg_config_param(sec, "ustates", paramt_int, immu_ustates);
385
  reg_config_param(sec, "missdelay", paramt_int, immu_missdelay);
386
  reg_config_param(sec, "hitdelay", paramt_int, immu_hitdelay);
387
}

powered by: WebSVN 2.1.0

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