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

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc3/] [or1ksim/] [mmu/] [immu.c] - Blame information for rev 1778

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 74 lampret
/* Insn MMU */
45
 
46 1538 nogj
/* Precalculates some values for use during address translation */
47
void init_immu(void)
48 430 markom
{
49 1555 nogj
  config.immu.pagesize_log2 = log2_int(config.immu.pagesize);
50 1538 nogj
  config.immu.page_offset_mask = config.immu.pagesize - 1;
51
  config.immu.page_mask = ~config.immu.page_offset_mask;
52
  config.immu.vpn_mask = ~((config.immu.pagesize * config.immu.nsets) - 1);
53
  config.immu.set_mask = config.immu.nsets - 1;
54
  config.immu.lru_reload = (config.immu.set_mask << 6) & SPR_ITLBMR_LRU;
55
}
56
 
57
inline uorreg_t *immu_find_tlbmr(oraddr_t virtaddr, uorreg_t **itlbmr_lru)
58
{
59
  int set;
60 430 markom
  int i;
61 1538 nogj
  oraddr_t vpn;
62
  uorreg_t *itlbmr;
63 884 markom
 
64 1538 nogj
  /* Which set to check out? */
65
  set = IADDR_PAGE(virtaddr) >> config.immu.pagesize_log2;
66
  set &= config.immu.set_mask;
67
  vpn = virtaddr & config.immu.vpn_mask;
68
 
69
  itlbmr = &cpu_state.sprs[SPR_ITLBMR_BASE(0) + set];
70
  *itlbmr_lru = itlbmr;
71
 
72
  /* Scan all ways and try to find a matching way. */
73
  /* FIXME: Should this be reversed? */
74
  for(i = config.immu.nways; i; i--, itlbmr += (128 * 2)) {
75
    if(((*itlbmr & config.immu.vpn_mask) == vpn) && (*itlbmr & SPR_ITLBMR_V))
76
      return itlbmr;
77
  }
78
 
79
  return NULL;
80
}
81
 
82
oraddr_t immu_translate(oraddr_t virtaddr)
83
{
84
  int i;
85
  uorreg_t *itlbmr;
86
  uorreg_t *itlbtr;
87
  uorreg_t *itlbmr_lru;
88
 
89 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
90
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
91 638 simons
    insn_ci = (virtaddr >= 0x80000000);
92 430 markom
    return virtaddr;
93 638 simons
  }
94 430 markom
 
95 1538 nogj
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru);
96 1416 nogj
 
97 430 markom
  /* Did we find our tlb entry? */
98 1538 nogj
  if(itlbmr) { /* Yes, we did. */
99 430 markom
    immu_stats.fetch_tlbhit++;
100 1416 nogj
    TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
101 430 markom
 
102 1538 nogj
    itlbtr = itlbmr + 128;
103
 
104 430 markom
    /* Set LRUs */
105 1538 nogj
    for(i = 0; i < config.immu.nways; i++, itlbmr_lru += (128 * 2)) {
106
      if(*itlbmr_lru & SPR_ITLBMR_LRU)
107
        *itlbmr_lru = (*itlbmr_lru & ~SPR_ITLBMR_LRU) |
108
                                        ((*itlbmr_lru & SPR_ITLBMR_LRU) - 0x40);
109 1506 nogj
    }
110
 
111 1538 nogj
    /* This is not necessary `*itlbmr &= ~SPR_ITLBMR_LRU;' since SPR_DTLBMR_LRU
112
     * is always decremented and the number of sets is always a power of two and
113
     * as such lru_reload has all bits set that get touched during decrementing
114
     * SPR_DTLBMR_LRU */
115
    *itlbmr |= config.immu.lru_reload;
116
 
117 638 simons
    /* Check if page is cache inhibited */
118 1538 nogj
    insn_ci = *itlbtr & SPR_ITLBTR_CI;
119 638 simons
 
120 884 markom
    runtime.sim.mem_cycles += config.immu.hitdelay;
121 1418 nogj
 
122
    /* Test for page fault */
123 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
124 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_SXE))
125 1418 nogj
        except_handle(EXCEPT_IPF, virtaddr);
126
    } else {
127 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_UXE))
128 1418 nogj
        except_handle(EXCEPT_IPF, virtaddr);
129
    }
130
 
131 1538 nogj
    TRACE("Returning physical address %"PRIxADDR"\n",
132
          (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
133
                                               (config.immu.page_offset_mask)));
134
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
135
                                                (config.immu.page_offset_mask));
136 430 markom
  }
137 1538 nogj
 
138
  /* No, we didn't. */
139
  immu_stats.fetch_tlbmiss++;
140 430 markom
#if 0
141 1538 nogj
  for (i = 0; i < config.immu.nways; i++)
142
    if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_LRU) >> 6) < minlru)
143
      minway = i;
144
 
145
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] &= ~SPR_ITLBMR_VPN;
146
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= vpn << 12;
147
  for (i = 0; i < config.immu.nways; i++) {
148
    uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE(i) + set];
149
    if (lru & SPR_ITLBMR_LRU) {
150
      lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
151
      cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] = lru;
152 1506 nogj
    }
153 1538 nogj
  }
154
  cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] &= ~SPR_ITLBMR_LRU;
155
  cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] |= (config.immu.nsets - 1) << 6;
156 1506 nogj
 
157 1538 nogj
  /* 1 to 1 mapping */
158
  cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] &= ~SPR_ITLBTR_PPN;
159
  cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] |= vpn << 12;
160 1506 nogj
 
161 1538 nogj
  cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= SPR_ITLBMR_V;
162 430 markom
#endif
163 1418 nogj
 
164 1538 nogj
  /* if tlb refill implemented in HW */
165
  /* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * config.immu.pagesize + (virtaddr % config.immu.pagesize); */
166
  runtime.sim.mem_cycles += config.immu.missdelay;
167 1418 nogj
 
168 1538 nogj
  except_handle(EXCEPT_ITLBMISS, virtaddr);
169
  return 0;
170 430 markom
}
171
 
172 1174 phoenix
/* DESC: try to find EA -> PA transaltion without changing
173
 *       any of precessor states. if this is not passible gives up
174 1446 nogj
 *       (without triggering exceptions).
175 1174 phoenix
 *
176
 * PRMS: virtaddr  - EA for which to find translation
177
 *
178
 * RTRN: 0         - no IMMU, IMMU disabled or ITLB miss
179
 *       else      - appropriate PA (note it IMMU is not present
180
 *                   PA === EA)
181
 */
182 1350 nogj
oraddr_t peek_into_itlb(oraddr_t virtaddr)
183 1174 phoenix
{
184 1538 nogj
  uorreg_t *itlbmr;
185
  uorreg_t *itlbtr;
186
  uorreg_t *itlbmr_lru;
187 1174 phoenix
 
188 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
189
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
190 1174 phoenix
     return(virtaddr);
191
  }
192
 
193 1538 nogj
  itlbmr = immu_find_tlbmr(virtaddr, &itlbmr_lru);
194 1174 phoenix
 
195
  /* Did we find our tlb entry? */
196 1538 nogj
  if(itlbmr) { /* Yes, we did. */
197
    itlbtr = itlbmr + 128;
198
 
199 1174 phoenix
    /* Test for page fault */
200 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
201 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_SXE)) {
202 1174 phoenix
        /* no luck, giving up */
203
        return(0);
204
      }
205
    } else {
206 1538 nogj
      if (!(*itlbtr & SPR_ITLBTR_UXE)) {
207 1174 phoenix
        /* no luck, giving up */
208
        return(0);
209
      }
210
    }
211
 
212 1538 nogj
    return (*itlbtr & SPR_ITLBTR_PPN) | (virtaddr &
213
                                                (config.immu.page_offset_mask));
214 1174 phoenix
  }
215 1538 nogj
 
216 1174 phoenix
  return(0);
217
}
218
 
219
 
220 1506 nogj
void itlb_info(void)
221 74 lampret
{
222 1506 nogj
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
223 997 markom
    PRINTF("IMMU not implemented. Set UPR[IMP].\n");
224 429 markom
    return;
225
  }
226 102 lampret
 
227 997 markom
  PRINTF("Insn MMU %dKB: ", config.immu.nsets * config.immu.entrysize * config.immu.nways / 1024);
228
  PRINTF("%d ways, %d sets, entry size %d bytes\n", config.immu.nways, config.immu.nsets, config.immu.entrysize);
229 74 lampret
}
230
 
231
/* First check if virtual address is covered by ITLB and if it is:
232
    - increment ITLB read hit stats,
233 425 markom
    - set 'lru' at this way to config.immu.ustates - 1 and
234 74 lampret
      decrement 'lru' of other ways unless they have reached 0,
235
    - check page access attributes and invoke IMMU page fault exception
236
      handler if necessary
237
   and if not:
238
    - increment ITLB read miss stats
239
    - find lru way and entry and invoke ITLB miss exception handler
240 425 markom
    - set 'lru' with config.immu.ustates - 1 and decrement 'lru' of other
241 74 lampret
      ways unless they have reached 0
242
*/
243
 
244 102 lampret
void itlb_status(int start_set)
245 74 lampret
{
246 429 markom
  int set;
247
  int way;
248
  int end_set = config.immu.nsets;
249 74 lampret
 
250 1506 nogj
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
251 997 markom
    PRINTF("IMMU not implemented. Set UPR[IMP].\n");
252 429 markom
    return;
253
  }
254 102 lampret
 
255 429 markom
  if ((start_set >= 0) && (start_set < end_set))
256
    end_set = start_set + 1;
257
  else
258
    start_set = 0;
259 74 lampret
 
260 997 markom
  if (start_set < end_set) PRINTF("\nIMMU: ");
261 429 markom
  /* Scan set(s) and way(s). */
262
  for (set = start_set; set < end_set; set++) {
263 997 markom
    PRINTF("\nSet %x: ", set);
264 429 markom
    for (way = 0; way < config.immu.nways; way++) {
265 997 markom
      PRINTF("  way %d: ", way);
266 1532 nogj
      PRINTF("%s\n", dump_spr(SPR_ITLBMR_BASE(way) + set,
267
                              cpu_state.sprs[SPR_ITLBMR_BASE(way) + set]));
268
      PRINTF("%s\n", dump_spr(SPR_ITLBTR_BASE(way) + set,
269
                              cpu_state.sprs[SPR_ITLBTR_BASE(way) + set]));
270 429 markom
    }
271
  }
272 997 markom
  if (start_set < end_set) PRINTF("\n");
273 74 lampret
}
274 1358 nogj
 
275
/*---------------------------------------------------[ IMMU configuration ]---*/
276
void immu_enabled(union param_val val, void *dat)
277
{
278 1506 nogj
  if(val.int_val)
279
    cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
280
  else
281
    cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
282 1358 nogj
  config.immu.enabled = val.int_val;
283
}
284
 
285
void immu_nsets(union param_val val, void *dat)
286
{
287 1382 nogj
  if (is_power2(val.int_val) && val.int_val <= 256) {
288 1358 nogj
    config.immu.nsets = val.int_val;
289 1506 nogj
    cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
290 1555 nogj
    cpu_state.sprs[SPR_IMMUCFGR] |= log2_int(val.int_val) << 3;
291 1382 nogj
  }
292 1358 nogj
  else
293
    CONFIG_ERROR("value of power of two and lower or equal than 256 expected.");
294
}
295
 
296
void immu_nways(union param_val val, void *dat)
297
{
298 1382 nogj
  if (val.int_val >= 1 && val.int_val <= 4) {
299 1358 nogj
    config.immu.nways = val.int_val;
300 1506 nogj
    cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
301
    cpu_state.sprs[SPR_IMMUCFGR] |= val.int_val - 1;
302 1382 nogj
  }
303 1358 nogj
  else
304
    CONFIG_ERROR("value 1, 2, 3 or 4 expected.");
305
}
306
 
307
void immu_pagesize(union param_val val, void *dat)
308
{
309
  if (is_power2(val.int_val))
310
    config.immu.pagesize = val.int_val;
311
  else
312
    CONFIG_ERROR("value of power of two expected.");
313
}
314
 
315
void immu_entrysize(union param_val val, void *dat)
316
{
317
  if (is_power2(val.int_val))
318
    config.immu.entrysize = val.int_val;
319
  else
320
    CONFIG_ERROR("value of power of two expected.");
321
}
322
 
323
void immu_ustates(union param_val val, void *dat)
324
{
325
  if (val.int_val >= 2 && val.int_val <= 4)
326
    config.immu.ustates = val.int_val;
327
  else
328
    CONFIG_ERROR("invalid USTATE.");
329
}
330
 
331
void immu_missdelay(union param_val val, void *dat)
332
{
333
  config.immu.missdelay = val.int_val;
334
}
335
 
336
void immu_hitdelay(union param_val val, void *dat)
337
{
338
  config.immu.hitdelay = val.int_val;
339
}
340
 
341
void reg_immu_sec(void)
342
{
343
  struct config_section *sec = reg_config_sec("immu", NULL, NULL);
344
 
345
  reg_config_param(sec, "enabled", paramt_int, immu_enabled);
346
  reg_config_param(sec, "nsets", paramt_int, immu_nsets);
347
  reg_config_param(sec, "nways", paramt_int, immu_nways);
348
  reg_config_param(sec, "pagesize", paramt_int, immu_pagesize);
349
  reg_config_param(sec, "entrysize", paramt_int, immu_entrysize);
350
  reg_config_param(sec, "ustates", paramt_int, immu_ustates);
351
  reg_config_param(sec, "missdelay", paramt_int, immu_missdelay);
352
  reg_config_param(sec, "hitdelay", paramt_int, immu_hitdelay);
353
}

powered by: WebSVN 2.1.0

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