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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [cache/] [icache-model.c] - Blame information for rev 584

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

Line No. Rev Author Line
1 19 jeremybenn
/* icache-model.c -- instruction cache simulation
2
 
3
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
4
   Copyright (C) 2008 Embecosm Limited
5
 
6
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
7
 
8
   This file is part of OpenRISC 1000 Architectural Simulator.
9
 
10
   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
 
15
   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
 
20
   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
/* Cache functions.
27
   At the moment this functions only simulate functionality of instruction
28
   caches and do not influence on fetche/decode/execute stages and timings.
29
   They are here only to verify performance of various cache configurations.
30
 */
31
 
32
 
33
/* Autoconf and/or portability configuration */
34
#include "config.h"
35
#include "port.h"
36
 
37
/* System includes */
38
#include <stdlib.h>
39
 
40
/* Package includes */
41
#include "icache-model.h"
42
#include "execute.h"
43
#include "spr-defs.h"
44
#include "abstract.h"
45
#include "misc.h"
46
#include "stats.h"
47
#include "sim-cmd.h"
48 556 julius
#include "pcu.h"
49 19 jeremybenn
 
50
#define MAX_IC_SETS        1024
51
#define MAX_IC_WAYS          32
52
#define MIN_IC_BLOCK_SIZE    16
53
#define MAX_IC_BLOCK_SIZE    32
54
 
55
 
56
struct ic *ic_state = NULL;
57
 
58
static void
59
ic_info (void *dat)
60
{
61
  struct ic *ic = dat;
62
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP))
63
    {
64
      PRINTF ("ICache not implemented. Set UPR[ICP].\n");
65
      return;
66
    }
67
 
68
  PRINTF ("Instruction cache %dKB: ",
69
          ic->nsets * ic->blocksize * ic->nways / 1024);
70
  PRINTF ("%d ways, %d sets, block size %d bytes\n", ic->nways, ic->nsets,
71
          ic->blocksize);
72
}
73
 
74
/* First check if instruction is already in the cache and if it is:
75
    - increment IC read hit stats,
76
    - set 'lru' at this way to ic->ustates - 1 and
77
      decrement 'lru' of other ways unless they have reached 0,
78
    - read insn from the cache line
79
   and if not:
80
    - increment IC read miss stats
81
    - find lru way and entry and replace old tag with tag of the 'fetchaddr'
82
    - set 'lru' with ic->ustates - 1 and decrement 'lru' of other
83
      ways unless they have reached 0
84
    - refill cache line
85
*/
86
 
87
uint32_t
88
ic_simulate_fetch (oraddr_t fetchaddr, oraddr_t virt_addr)
89
{
90
  oraddr_t set;
91
  oraddr_t way;
92
  oraddr_t lru_way;
93
  oraddr_t tagaddr;
94
  uint32_t tmp;
95
  oraddr_t reload_addr;
96
  oraddr_t reload_end;
97
  unsigned int minlru;
98
  struct ic *ic = ic_state;
99
 
100
  /* ICache simulation enabled/disabled. */
101
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP) ||
102
      !(cpu_state.sprs[SPR_SR] & SPR_SR_ICE) || insn_ci)
103
    {
104
      tmp = evalsim_mem32 (fetchaddr, virt_addr);
105
      if (cur_area && cur_area->log)
106
        fprintf (cur_area->log, "[%" PRIxADDR "] -> read %08" PRIx32 "\n",
107
                 fetchaddr, tmp);
108
      return tmp;
109
    }
110
 
111
  /* Which set to check out? */
112
  set = (fetchaddr & ic->set_mask) >> ic->blocksize_log2;
113
  tagaddr = fetchaddr & ic->tagaddr_mask;
114
 
115
  /* Scan all ways and try to find a matching way. */
116
  for (way = set; way < ic->last_way; way += ic->nsets)
117
    {
118
      if (ic->tags[way] == tagaddr)
119
        {
120
          ic_stats.readhit++;
121
 
122
          for (lru_way = set; lru_way < ic->last_way; lru_way += ic->nsets)
123
            if (ic->lrus[lru_way] > ic->lrus[way])
124
              ic->lrus[lru_way]--;
125
          ic->lrus[way] = ic->ustates_reload;
126
          runtime.sim.mem_cycles += ic->hitdelay;
127
          way <<= ic->blocksize_log2;
128
          return *(uint32_t *) & ic->
129
            mem[way | (fetchaddr & ic->block_offset_mask)];
130
        }
131
    }
132
 
133
  minlru = ic->ustates_reload;
134
  way = set;
135
 
136
  ic_stats.readmiss++;
137
 
138
  for (lru_way = set; lru_way < ic->last_way; lru_way += ic->nsets)
139
    {
140
      if (ic->lrus[lru_way] < minlru)
141
        {
142
          way = lru_way;
143
          minlru = ic->lrus[lru_way];
144
        }
145
    }
146
 
147
  ic->tags[way] = tagaddr;
148
  for (lru_way = set; lru_way < ic->last_way; lru_way += ic->nsets)
149
    if (ic->lrus[lru_way])
150
      ic->lrus[lru_way]--;
151
  ic->lrus[way] = ic->ustates_reload;
152
 
153
  reload_addr = fetchaddr & ic->block_offset_mask;
154
  reload_end = reload_addr + ic->blocksize;
155
 
156
  fetchaddr &= ic->block_mask;
157
 
158
  way <<= ic->blocksize_log2;
159
  for (; reload_addr < reload_end; reload_addr += 4)
160
    {
161
      tmp =
162
        *(uint32_t *) & ic->mem[way | (reload_addr & ic->block_offset_mask)] =
163
        /* FIXME: What is the virtual address meant to be? (ie. What happens if
164
         * we read out of memory while refilling a cache line?) */
165
        evalsim_mem32 (fetchaddr | (reload_addr & ic->block_offset_mask), 0);
166
      if (!cur_area)
167
        {
168
          ic->tags[way >> ic->blocksize_log2] = -1;
169
          ic->lrus[way >> ic->blocksize_log2] = 0;
170
          return 0;
171
        }
172
      else if (cur_area->log)
173
        fprintf (cur_area->log, "[%" PRIxADDR "] -> read %08" PRIx32 "\n",
174
                 fetchaddr, tmp);
175
    }
176
 
177
  runtime.sim.mem_cycles += ic->missdelay;
178 556 julius
 
179
  if (config.pcu.enabled)
180
    pcu_count_event(SPR_PCMR_ICM);
181
 
182
 
183 19 jeremybenn
  return *(uint32_t *) & ic->mem[way | (reload_addr & ic->block_offset_mask)];
184
}
185
 
186
/* First check if data is already in the cache and if it is:
187
    - invalidate block if way isn't locked
188
   otherwise don't do anything.
189
*/
190
 
191
void
192
ic_inv (oraddr_t dataaddr)
193
{
194
  oraddr_t set;
195
  oraddr_t way;
196
  oraddr_t tagaddr;
197
  struct ic *ic = ic_state;
198
 
199
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP))
200
    return;
201
 
202
  /* Which set to check out? */
203
  set = (dataaddr & ic->set_mask) >> ic->blocksize_log2;
204
 
205
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_ICE))
206
    {
207
      for (way = set; way < ic->last_way; way += ic->nsets)
208
        {
209
          ic->tags[way] = -1;
210
          ic->lrus[way] = 0;
211
        }
212
      return;
213
    }
214
 
215
  tagaddr = dataaddr & ic->tagaddr_mask;
216
 
217
  /* Scan all ways and try to find a matching way. */
218
  for (way = set; way < ic->last_way; way += ic->nsets)
219
    {
220
      if (ic->tags[way] == tagaddr)
221
        {
222
          ic->tags[way] = -1;
223
          ic->lrus[way] = 0;
224
        }
225
    }
226
}
227
 
228
/*-----------------------------------------------------[ IC configuration ]---*/
229
 
230
 
231
/*---------------------------------------------------------------------------*/
232
/*!Enable or disable the instruction cache
233
 
234 83 jeremybenn
   Set the corresponding fields in the UPR
235 19 jeremybenn
 
236
   @param[in] val  The value to use
237
   @param[in] dat  The config data structure                                 */
238
/*---------------------------------------------------------------------------*/
239
static void
240
ic_enabled (union param_val  val,
241
            void            *dat)
242
{
243
  struct ic *ic = dat;
244
 
245
  ic->enabled = val.int_val;
246
 
247
  if (val.int_val)
248
    {
249
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_ICP;
250
    }
251
  else
252
    {
253
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_ICP;
254
    }
255
}       /* ic_enabled() */
256
 
257
 
258
/*---------------------------------------------------------------------------*/
259
/*!Set the number of instruction cache sets
260
 
261
   Set the corresponding field in the UPR
262
 
263
   @param[in] val  The value to use
264
   @param[in] dat  The config data structure                                 */
265
/*---------------------------------------------------------------------------*/
266
static void
267
ic_nsets (union param_val  val,
268
          void            *dat)
269
{
270
  struct ic *ic = dat;
271
 
272
  if (is_power2 (val.int_val) && (val.int_val <= MAX_IC_SETS))
273
    {
274
      int  set_bits = log2_int (val.int_val);
275
 
276
      ic->nsets = val.int_val;
277
 
278
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCS;
279
      cpu_state.sprs[SPR_ICCFGR] |= set_bits << SPR_ICCFGR_NCS_OFF;
280
    }
281
  else
282
    {
283
      fprintf (stderr, "Warning: instruction cache nsets not a power of "
284
               "2 <= %d: ignored\n", MAX_IC_SETS);
285
    }
286
}       /* ic_nsets() */
287
 
288
 
289
/*---------------------------------------------------------------------------*/
290
/*!Set the number of instruction cache ways
291
 
292
   Set the corresponding field in the UPR
293
 
294
   @param[in] val  The value to use
295
   @param[in] dat  The config data structure                                 */
296
/*---------------------------------------------------------------------------*/
297
static void
298
ic_nways (union param_val  val,
299
            void            *dat)
300
{
301
  struct ic *ic = dat;
302
 
303
  if (is_power2 (val.int_val) && (val.int_val <= MAX_IC_WAYS))
304
    {
305
      int  way_bits = log2_int (val.int_val);
306
 
307
      ic->nways = val.int_val;
308
 
309
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCW;
310
      cpu_state.sprs[SPR_ICCFGR] |= way_bits << SPR_ICCFGR_NCW_OFF;
311
    }
312
  else
313
    {
314
      fprintf (stderr, "Warning: instruction cache nways not a power of "
315
               "2 <= %d: ignored\n", MAX_IC_WAYS);
316
    }
317
}       /* ic_nways() */
318
 
319
 
320
/*---------------------------------------------------------------------------*/
321
/*!Set the instruction cache block size
322
 
323
   Value must be either MIN_IC_BLOCK_SIZE or MAX_IC_BLOCK_SIZE. If not issue a
324
   warning and ignore. Set the relevant field in the data cache config register
325
 
326
   @param[in] val  The value to use
327
   @param[in] dat  The config data structure                                 */
328
/*---------------------------------------------------------------------------*/
329
static void
330
ic_blocksize (union param_val  val,
331
              void            *dat)
332
{
333
  struct ic *ic = dat;
334
 
335
  switch (val.int_val)
336
    {
337
    case MIN_IC_BLOCK_SIZE:
338
      ic->blocksize               = val.int_val;
339
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_CBS;
340
      break;
341
 
342
    case MAX_IC_BLOCK_SIZE:
343
      ic->blocksize               = val.int_val;
344
      cpu_state.sprs[SPR_ICCFGR] |= SPR_ICCFGR_CBS;
345
      break;
346
 
347
    default:
348
      fprintf (stderr, "Warning: instruction cache block size not %d or %d: "
349
               "ignored\n", MIN_IC_BLOCK_SIZE, MAX_IC_BLOCK_SIZE);
350
      break;
351
    }
352
}       /* ic_blocksize() */
353
 
354
 
355
/*---------------------------------------------------------------------------*/
356
/*!Set the number of instruction cache usage states
357
 
358
   Value must be 2, 3 or 4. If not issue a warning and ignore.
359
 
360
   @param[in] val  The value to use
361
   @param[in] dat  The config data structure                                 */
362
/*---------------------------------------------------------------------------*/
363
static void
364
ic_ustates (union param_val  val,
365
            void            *dat)
366
{
367
  struct ic *ic = dat;
368
 
369
  if ((val.int_val >= 2) && (val.int_val <= 4))
370
    {
371
      ic->ustates = val.int_val;
372
    }
373
  else
374
    {
375
      fprintf (stderr, "Warning number of instruction cache usage states "
376
               "must be 2, 3 or 4: ignored\n");
377
    }
378
}       /* ic_ustates() */
379
 
380
 
381
static void
382
ic_hitdelay (union param_val  val,
383
             void            *dat)
384
{
385
  struct ic *ic = dat;
386
  ic->hitdelay = val.int_val;
387
}
388
 
389
 
390
static void
391
ic_missdelay (union param_val  val,
392
              void            *dat)
393
{
394
  struct ic *ic = dat;
395
  ic->missdelay = val.int_val;
396
}
397
 
398
 
399
/*---------------------------------------------------------------------------*/
400
/*!Initialize a new instruction cache configuration
401
 
402
   ALL parameters are set explicitly to default values. Corresponding SPR
403
   flags are set as appropriate.
404
 
405
   @return  The new memory configuration data structure                      */
406
/*---------------------------------------------------------------------------*/
407
static void *
408
ic_start_sec ()
409
{
410
  struct ic *ic;
411
  int        set_bits;
412
  int        way_bits;
413
 
414
  if (NULL == (ic = malloc (sizeof (struct ic))))
415
    {
416
      fprintf (stderr, "OOM\n");
417
      exit (1);
418
    }
419
 
420
  ic->enabled   = 0;
421
  ic->nsets     = 1;
422
  ic->nways     = 1;
423
  ic->blocksize = MIN_IC_BLOCK_SIZE;
424
  ic->ustates   = 2;
425
  ic->hitdelay  = 1;
426
  ic->missdelay = 1;
427
 
428
  ic->mem       = NULL;         /* Internal configuration */
429
  ic->lrus      = NULL;
430
  ic->tags      = NULL;
431
 
432
  /* Set SPRs as appropriate */
433
 
434
  if (ic->enabled)
435
    {
436
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_ICP;
437
    }
438
  else
439
    {
440
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_ICP;
441
    }
442
 
443
  set_bits = log2_int (ic->nsets);
444
  cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCS;
445
  cpu_state.sprs[SPR_ICCFGR] |= set_bits << SPR_ICCFGR_NCS_OFF;
446
 
447
  way_bits = log2_int (ic->nways);
448
  cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCW;
449
  cpu_state.sprs[SPR_ICCFGR] |= way_bits << SPR_ICCFGR_NCW_OFF;
450
 
451
  if (MIN_IC_BLOCK_SIZE == ic->blocksize)
452
    {
453
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_CBS;
454
    }
455
  else
456
    {
457
      cpu_state.sprs[SPR_ICCFGR] |= SPR_ICCFGR_CBS;
458
    }
459
 
460
  ic_state = ic;
461
  return ic;
462
 
463
}       /* ic_start_sec() */
464
 
465
 
466
static void
467
ic_end_sec (void *dat)
468
{
469
  struct ic *ic = dat;
470
  unsigned int size = ic->nways * ic->nsets * ic->blocksize;
471
 
472
  if (size)
473
    {
474
      if (!(ic->mem = malloc (size)))
475
        {
476
          fprintf (stderr, "OOM\n");
477
          exit (1);
478
        }
479
      if (!
480
          (ic->lrus = malloc (ic->nsets * ic->nways * sizeof (unsigned int))))
481
        {
482
          fprintf (stderr, "OOM\n");
483
          exit (1);
484
        }
485
      if (!(ic->tags = malloc (ic->nsets * ic->nways * sizeof (oraddr_t))))
486
        {
487
          fprintf (stderr, "OOM\n");
488
          exit (1);
489
        }
490
 
491 83 jeremybenn
      /* Clear the cache data. John Alfredo's fix for using 0 (which is a
492
         valid tag), so we now use -1 */
493 19 jeremybenn
      memset (ic->mem,  0, size);
494
      memset (ic->lrus, 0, ic->nsets * ic->nways * sizeof (unsigned int));
495 83 jeremybenn
      memset (ic->tags, -1, ic->nsets * ic->nways * sizeof (oraddr_t));
496 19 jeremybenn
    }
497
  else
498
    {
499
      ic->enabled = 0;
500
    }
501
 
502
  ic->blocksize_log2    = log2_int (ic->blocksize);
503
  ic->set_mask          = (ic->nsets - 1) << ic->blocksize_log2;
504
  ic->tagaddr_mask      = ~((ic->nsets * ic->blocksize) - 1);
505
  ic->last_way          = ic->nsets * ic->nways;
506
  ic->block_offset_mask = ic->blocksize - 1;
507
  ic->block_mask        = ~ic->block_offset_mask;
508
  ic->ustates_reload    = ic->ustates - 1;
509
 
510
  if (ic->enabled)
511
    reg_sim_stat (ic_info, dat);
512
}
513
 
514
void
515
reg_ic_sec (void)
516
{
517
  struct config_section *sec =
518
    reg_config_sec ("ic", ic_start_sec, ic_end_sec);
519
 
520 224 jeremybenn
  reg_config_param (sec, "enabled",   PARAMT_INT, ic_enabled);
521
  reg_config_param (sec, "nsets",     PARAMT_INT, ic_nsets);
522
  reg_config_param (sec, "nways",     PARAMT_INT, ic_nways);
523
  reg_config_param (sec, "blocksize", PARAMT_INT, ic_blocksize);
524
  reg_config_param (sec, "ustates",   PARAMT_INT, ic_ustates);
525
  reg_config_param (sec, "missdelay", PARAMT_INT, ic_missdelay);
526
  reg_config_param (sec, "hitdelay" , PARAMT_INT, ic_hitdelay);
527 19 jeremybenn
}

powered by: WebSVN 2.1.0

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