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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [mmu/] [dmmu.c] - Blame information for rev 1718

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

Line No. Rev Author Line
1 62 lampret
/* dmmu.c -- Data MMU simulation
2 6 lampret
   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 1539 nogj
/* DMMU model, perfectly functional. */
21 6 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 6 lampret
#include "dmmu.h"
31
#include "abstract.h"
32 1344 nogj
#include "opcode/or32.h"
33 1432 nogj
#include "spr_defs.h"
34
#include "execute.h"
35 6 lampret
#include "stats.h"
36 62 lampret
#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 6 lampret
 
42 1412 nogj
DEFAULT_DEBUG_CHANNEL(dmmu);
43
 
44 1718 nogj
struct dmmu *dmmu_state;
45
 
46 6 lampret
/* Data MMU */
47
 
48 1718 nogj
static inline uorreg_t *dmmu_find_tlbmr(oraddr_t virtaddr,
49
                                        uorreg_t **dtlbmr_lru,
50
                                        struct dmmu *dmmu)
51 1539 nogj
{
52
  int set;
53 430 markom
  int i;
54 1539 nogj
  oraddr_t vpn;
55
  uorreg_t *dtlbmr;
56 572 simons
 
57 1539 nogj
  /* Which set to check out? */
58 1718 nogj
  set = DADDR_PAGE(virtaddr) >> dmmu->pagesize_log2;
59
  set &= dmmu->set_mask;
60
  vpn = virtaddr & dmmu->vpn_mask;
61 1539 nogj
 
62
  dtlbmr = &cpu_state.sprs[SPR_DTLBMR_BASE(0) + set];
63
  *dtlbmr_lru = dtlbmr;
64
 
65
  /* FIXME: Should this be reversed? */
66 1718 nogj
  for(i = dmmu->nways; i; i--, dtlbmr += (128 * 2)) {
67
    if(((*dtlbmr & dmmu->vpn_mask) == vpn) && (*dtlbmr & SPR_DTLBMR_V))
68 1539 nogj
      return dtlbmr;
69
  }
70
 
71
  return NULL;
72
}
73
 
74
oraddr_t dmmu_translate(oraddr_t virtaddr, int write_access)
75
{
76
  int i;
77
  uorreg_t *dtlbmr;
78
  uorreg_t *dtlbtr;
79
  uorreg_t *dtlbmr_lru;
80 1718 nogj
  struct dmmu *dmmu = dmmu_state;
81 1539 nogj
 
82 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
83
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP)) {
84 638 simons
    data_ci = (virtaddr >= 0x80000000);
85 430 markom
    return virtaddr;
86 638 simons
  }
87 430 markom
 
88 1718 nogj
  dtlbmr = dmmu_find_tlbmr(virtaddr, &dtlbmr_lru, dmmu);
89 456 simons
 
90 1539 nogj
  /* Did we find our tlb entry? */
91
  if(dtlbmr) { /* Yes, we did. */
92 430 markom
    dmmu_stats.loads_tlbhit++;
93 1539 nogj
 
94
    dtlbtr = dtlbmr + 128;
95
 
96 1412 nogj
    TRACE("DTLB hit (virtaddr=%"PRIxADDR") at %lli.\n", virtaddr,
97
          runtime.sim.cycles);
98 430 markom
 
99 1414 nogj
    /* Set LRUs */
100 1718 nogj
    for(i = 0; i < dmmu->nways; i++, dtlbmr_lru += (128 * 2)) {
101 1539 nogj
      if(*dtlbmr_lru & SPR_DTLBMR_LRU)
102
        *dtlbmr_lru = (*dtlbmr_lru & ~SPR_DTLBMR_LRU) |
103
                                        ((*dtlbmr_lru & SPR_DTLBMR_LRU) - 0x40);
104 1506 nogj
    }
105 1414 nogj
 
106 1539 nogj
    /* This is not necessary `*dtlbmr &= ~SPR_DTLBMR_LRU;' since SPR_DTLBMR_LRU
107
     * is always decremented and the number of sets is always a power of two and
108
     * as such lru_reload has all bits set that get touched during decrementing
109
     * SPR_DTLBMR_LRU */
110 1718 nogj
    *dtlbmr |= dmmu->lru_reload;
111 1539 nogj
 
112 1414 nogj
    /* Check if page is cache inhibited */
113 1539 nogj
    data_ci = *dtlbtr & SPR_DTLBTR_CI;
114 1414 nogj
 
115 1718 nogj
    runtime.sim.mem_cycles += dmmu->hitdelay;
116 1414 nogj
 
117 430 markom
    /* Test for page fault */
118 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
119 1539 nogj
      if ( (write_access && !(*dtlbtr & SPR_DTLBTR_SWE))
120
       || (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
121 430 markom
        except_handle(EXCEPT_DPF, virtaddr);
122
    } else {
123 1539 nogj
      if ( (write_access && !(*dtlbtr & SPR_DTLBTR_UWE))
124
       || (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
125 430 markom
        except_handle(EXCEPT_DPF, virtaddr);
126
    }
127
 
128 1539 nogj
    TRACE("Returning physical address %"PRIxADDR"\n",
129 1718 nogj
          (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr & (dmmu->page_offset_mask)));
130
    return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr & (dmmu->page_offset_mask));
131 430 markom
  }
132 1539 nogj
 
133
  /* No, we didn't. */
134
  dmmu_stats.loads_tlbmiss++;
135 430 markom
#if 0
136 1718 nogj
  for (i = 0; i < dmmu->nways; i++)
137 1539 nogj
    if (((cpu_state.sprs[SPR_DTLBMR_BASE(i) + set] & SPR_DTLBMR_LRU) >> 6) < minlru)
138
      minway = i;
139
 
140
  cpu_state.sprs[SPR_DTLBMR_BASE(minway) + set] &= ~SPR_DTLBMR_VPN;
141
  cpu_state.sprs[SPR_DTLBMR_BASE(minway) + set] |= vpn << 12;
142 1718 nogj
  for (i = 0; i < dmmu->nways; i++) {
143 1539 nogj
    uorreg_t lru = cpu_state.sprs[SPR_DTLBMR_BASE(i) + set];
144
    if (lru & SPR_DTLBMR_LRU) {
145
      lru = (lru & ~SPR_DTLBMR_LRU) | ((lru & SPR_DTLBMR_LRU) - 0x40);
146
      cpu_state.sprs[SPR_DTLBMR_BASE(i) + set] = lru;
147 1506 nogj
    }
148 1539 nogj
  }
149
  cpu_state.sprs[SPR_DTLBMR_BASE(way) + set] &= ~SPR_DTLBMR_LRU;
150 1718 nogj
  cpu_state.sprs[SPR_DTLBMR_BASE(way) + set] |= (dmmu->nsets - 1) << 6;
151 1506 nogj
 
152 1539 nogj
  /* 1 to 1 mapping */
153
  cpu_state.sprs[SPR_DTLBTR_BASE(minway) + set] &= ~SPR_DTLBTR_PPN;
154
  cpu_state.sprs[SPR_DTLBTR_BASE(minway) + set] |= vpn << 12;
155 1506 nogj
 
156 1539 nogj
  cpu_state.sprs[SPR_DTLBMR_BASE(minway) + set] |= SPR_DTLBMR_V;
157 430 markom
#endif
158 1539 nogj
  TRACE("DTLB miss (virtaddr=%"PRIxADDR") at %lli.\n", virtaddr,
159
        runtime.sim.cycles);
160 1718 nogj
  runtime.sim.mem_cycles += dmmu->missdelay;
161 1539 nogj
  /* if tlb refill implemented in HW */
162 1718 nogj
  /* return ((cpu_state.sprs[SPR_DTLBTR_BASE(minway) + set] & SPR_DTLBTR_PPN) >> 12) * dmmu->pagesize + (virtaddr % dmmu->pagesize); */
163 1539 nogj
 
164
  except_handle(EXCEPT_DTLBMISS, virtaddr);
165
  return 0;
166 430 markom
}
167
 
168 1240 phoenix
/* DESC: try to find EA -> PA transaltion without changing
169
 *       any of precessor states. if this is not passible gives up
170
 *       (without triggering exceptions)
171
 *
172
 * PRMS: virtaddr     - EA for which to find translation
173
 *
174
 *       write_access - 0 ignore testing for write access
175
 *                      1 test for write access, if fails
176
 *                        do not return translation
177
 *
178
 *       through_dc   - 1 go through data cache
179
 *                      0 ignore data cache
180
 *
181
 * RTRN: 0            - no DMMU, DMMU disabled or ITLB miss
182
 *       else         - appropriate PA (note it DMMU is not present
183
 *                      PA === EA)
184
 */
185 1350 nogj
oraddr_t peek_into_dtlb(oraddr_t virtaddr, int write_access, int through_dc)
186 1240 phoenix
{
187 1539 nogj
  uorreg_t *dtlbmr;
188
  uorreg_t *dtlbtr;
189
  uorreg_t *dtlbmr_lru;
190 1718 nogj
  struct dmmu *dmmu = dmmu_state;
191 1240 phoenix
 
192 1506 nogj
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_DME) ||
193
      !(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP)) {
194 1240 phoenix
    if (through_dc)
195
      data_ci = (virtaddr >= 0x80000000);
196
    return virtaddr;
197
  }
198
 
199 1718 nogj
  dtlbmr = dmmu_find_tlbmr(virtaddr, &dtlbmr_lru, dmmu);
200 1240 phoenix
 
201 1539 nogj
  /* Did we find our tlb entry? */
202
  if (dtlbmr) { /* Yes, we did. */
203 1240 phoenix
    dmmu_stats.loads_tlbhit++;
204 1539 nogj
 
205
    dtlbtr = dtlbmr + 128;
206
 
207 1412 nogj
    TRACE("DTLB hit (virtaddr=%"PRIxADDR") at %lli.\n", virtaddr,
208
          runtime.sim.cycles);
209 1240 phoenix
 
210
    /* Test for page fault */
211 1508 nogj
    if (cpu_state.sprs[SPR_SR] & SPR_SR_SM) {
212 1539 nogj
      if((write_access && !(*dtlbtr & SPR_DTLBTR_SWE)) ||
213
         (!write_access && !(*dtlbtr & SPR_DTLBTR_SRE)))
214 1240 phoenix
 
215
        /* otherwise exception DPF would be raised */
216
        return(0);
217
    } else {
218 1539 nogj
      if((write_access && !(*dtlbtr & SPR_DTLBTR_UWE)) ||
219
         (!write_access && !(*dtlbtr & SPR_DTLBTR_URE)))
220 1240 phoenix
 
221
        /* otherwise exception DPF would be raised */
222
        return(0);
223
    }
224
 
225
    if (through_dc) {
226
      /* Check if page is cache inhibited */
227 1539 nogj
      data_ci = *dtlbtr & SPR_DTLBTR_CI;
228 1240 phoenix
    }
229
 
230 1718 nogj
    return (*dtlbtr & SPR_DTLBTR_PPN) | (virtaddr & (dmmu->page_offset_mask));
231 1240 phoenix
  }
232 1539 nogj
 
233 1240 phoenix
  return(0);
234
}
235
 
236 1718 nogj
/* FIXME: Is this comment valid? */
237 62 lampret
/* First check if virtual address is covered by DTLB and if it is:
238
    - increment DTLB read hit stats,
239 1718 nogj
    - set 'lru' at this way to dmmu->ustates - 1 and
240 6 lampret
      decrement 'lru' of other ways unless they have reached 0,
241 62 lampret
    - check page access attributes and invoke DMMU page fault exception
242
      handler if necessary
243 6 lampret
   and if not:
244 62 lampret
    - increment DTLB read miss stats
245
    - find lru way and entry and invoke DTLB miss exception handler
246 1718 nogj
    - set 'lru' with dmmu->ustates - 1 and decrement 'lru' of other
247 6 lampret
      ways unless they have reached 0
248
*/
249
 
250 1718 nogj
static void dtlb_status(void *dat)
251 6 lampret
{
252 1718 nogj
  struct dmmu *dmmu = dat;
253 429 markom
  int set;
254
  int way;
255 1718 nogj
  int end_set = dmmu->nsets;
256 62 lampret
 
257 1506 nogj
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP)) {
258 997 markom
    PRINTF("DMMU not implemented. Set UPR[DMP].\n");
259 429 markom
    return;
260
  }
261 102 lampret
 
262 1718 nogj
  if (0 < end_set) PRINTF("\nDMMU: ");
263 429 markom
  /* Scan set(s) and way(s). */
264 1718 nogj
  for (set = 0; set < end_set; set++) {
265
    for (way = 0; way < dmmu->nways; way++) {
266 1532 nogj
      PRINTF("%s\n", dump_spr(SPR_DTLBMR_BASE(way) + set,
267
                              cpu_state.sprs[SPR_DTLBMR_BASE(way) + set]));
268
      PRINTF("%s\n", dump_spr(SPR_DTLBTR_BASE(way) + set,
269
                              cpu_state.sprs[SPR_DTLBTR_BASE(way) + set]));
270 429 markom
    }
271
  }
272 1718 nogj
  if (0 < end_set) PRINTF("\n");
273 6 lampret
}
274 1358 nogj
 
275
/*---------------------------------------------------[ DMMU configuration ]---*/
276 1649 nogj
static void dmmu_enabled(union param_val val, void *dat)
277 1358 nogj
{
278 1718 nogj
  struct dmmu *dmmu = dat;
279
 
280 1506 nogj
  if(val.int_val)
281
    cpu_state.sprs[SPR_UPR] |= SPR_UPR_DMP;
282
  else
283
    cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_DMP;
284 1718 nogj
  dmmu->enabled = val.int_val;
285 1358 nogj
}
286
 
287 1649 nogj
static void dmmu_nsets(union param_val val, void *dat)
288 1358 nogj
{
289 1718 nogj
  struct dmmu *dmmu = dat;
290
 
291 1382 nogj
  if (is_power2(val.int_val) && val.int_val <= 256) {
292 1718 nogj
    dmmu->nsets = val.int_val;
293 1506 nogj
    cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTS;
294 1555 nogj
    cpu_state.sprs[SPR_DMMUCFGR] |= log2_int(val.int_val) << 3;
295 1506 nogj
  } else
296 1358 nogj
    CONFIG_ERROR("value of power of two and lower or equal than 256 expected.");
297
}
298
 
299 1649 nogj
static void dmmu_nways(union param_val val, void *dat)
300 1358 nogj
{
301 1718 nogj
  struct dmmu *dmmu = dat;
302
 
303 1382 nogj
  if (val.int_val >= 1 && val.int_val <= 4) {
304 1718 nogj
    dmmu->nways = val.int_val;
305 1506 nogj
    cpu_state.sprs[SPR_DMMUCFGR] &= ~SPR_DMMUCFGR_NTW;
306
    cpu_state.sprs[SPR_DMMUCFGR] |= val.int_val - 1;
307 1382 nogj
  }
308 1358 nogj
  else
309
    CONFIG_ERROR("value 1, 2, 3 or 4 expected.");
310
}
311
 
312 1649 nogj
static void dmmu_pagesize(union param_val val, void *dat)
313 1358 nogj
{
314 1718 nogj
  struct dmmu *dmmu = dat;
315
 
316 1358 nogj
  if (is_power2(val.int_val))
317 1718 nogj
    dmmu->pagesize = val.int_val;
318 1358 nogj
  else
319
    CONFIG_ERROR("value of power of two expected.");
320
}
321
 
322 1649 nogj
static void dmmu_entrysize(union param_val val, void *dat)
323 1358 nogj
{
324 1718 nogj
  struct dmmu *dmmu = dat;
325
 
326 1358 nogj
  if (is_power2(val.int_val))
327 1718 nogj
    dmmu->entrysize = val.int_val;
328 1358 nogj
  else
329
    CONFIG_ERROR("value of power of two expected.");
330
}
331
 
332 1649 nogj
static void dmmu_ustates(union param_val val, void *dat)
333 1358 nogj
{
334 1718 nogj
  struct dmmu *dmmu = dat;
335
 
336 1358 nogj
  if (val.int_val >= 2 && val.int_val <= 4)
337 1718 nogj
    dmmu->ustates = val.int_val;
338 1358 nogj
  else
339
    CONFIG_ERROR("invalid USTATE.");
340
}
341
 
342 1649 nogj
static void dmmu_missdelay(union param_val val, void *dat)
343 1358 nogj
{
344 1718 nogj
  struct dmmu *dmmu = dat;
345
 
346
  dmmu->missdelay = val.int_val;
347 1358 nogj
}
348
 
349 1649 nogj
static void dmmu_hitdelay(union param_val val, void *dat)
350 1358 nogj
{
351 1718 nogj
  struct dmmu *dmmu = dat;
352
 
353
  dmmu->hitdelay = val.int_val;
354 1358 nogj
}
355
 
356 1655 nogj
static void *dmmu_start_sec(void)
357
{
358 1718 nogj
  struct dmmu *dmmu;
359
 
360
  if(!(dmmu = malloc(sizeof(struct dmmu)))) {
361
    fprintf(stderr, "OOM\n");
362
    exit(1);
363
  }
364
 
365
  dmmu->enabled = 0;
366
  dmmu->hitdelay = 1;
367
  dmmu->missdelay = 1;
368
  dmmu->pagesize = 8192;
369
  /* FIXME: Something sane */
370
  dmmu->entrysize = 0;
371
 
372
  dmmu_state = dmmu;
373
 
374
  return dmmu;
375 1655 nogj
}
376
 
377
static void dmmu_end_sec(void *dat)
378
{
379
  struct dmmu *dmmu = dat;
380
 
381
  /* Precalculate some values for use during address translation */
382 1718 nogj
  dmmu->pagesize_log2 = log2_int(dmmu->pagesize);
383
  dmmu->page_offset_mask = dmmu->pagesize - 1;
384
  dmmu->page_mask = ~dmmu->page_offset_mask;
385
  dmmu->vpn_mask = ~((dmmu->pagesize * dmmu->nsets) - 1);
386
  dmmu->set_mask = dmmu->nsets - 1;
387
  dmmu->lru_reload = (dmmu->set_mask << 6) & SPR_DTLBMR_LRU;
388
 
389
  if(dmmu->enabled) {
390
    PRINTF("Data MMU %dKB: %d ways, %d sets, entry size %d bytes\n",
391
           dmmu->nsets * dmmu->entrysize * dmmu->nways / 1024, dmmu->nways,
392
           dmmu->nsets, dmmu->entrysize);
393
    reg_sim_stat(dtlb_status, dmmu);
394
  }
395 1655 nogj
}
396
 
397 1358 nogj
void reg_dmmu_sec(void)
398
{
399 1655 nogj
  struct config_section *sec = reg_config_sec("dmmu", dmmu_start_sec,
400
                                              dmmu_end_sec);
401 1358 nogj
 
402
  reg_config_param(sec, "enabled", paramt_int, dmmu_enabled);
403
  reg_config_param(sec, "nsets", paramt_int, dmmu_nsets);
404
  reg_config_param(sec, "nways", paramt_int, dmmu_nways);
405
  reg_config_param(sec, "pagesize", paramt_int, dmmu_pagesize);
406
  reg_config_param(sec, "entrysize", paramt_int, dmmu_entrysize);
407
  reg_config_param(sec, "ustates", paramt_int, dmmu_ustates);
408
  reg_config_param(sec, "missdelay", paramt_int, dmmu_missdelay);
409
  reg_config_param(sec, "hitdelay", paramt_int, dmmu_hitdelay);
410
}

powered by: WebSVN 2.1.0

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