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

Subversion Repositories openrisc

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

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
 
49
 
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
  return *(uint32_t *) & ic->mem[way | (reload_addr & ic->block_offset_mask)];
179
}
180
 
181
/* First check if data is already in the cache and if it is:
182
    - invalidate block if way isn't locked
183
   otherwise don't do anything.
184
*/
185
 
186
void
187
ic_inv (oraddr_t dataaddr)
188
{
189
  oraddr_t set;
190
  oraddr_t way;
191
  oraddr_t tagaddr;
192
  struct ic *ic = ic_state;
193
 
194
  if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_ICP))
195
    return;
196
 
197
  /* Which set to check out? */
198
  set = (dataaddr & ic->set_mask) >> ic->blocksize_log2;
199
 
200
  if (!(cpu_state.sprs[SPR_SR] & SPR_SR_ICE))
201
    {
202
      for (way = set; way < ic->last_way; way += ic->nsets)
203
        {
204
          ic->tags[way] = -1;
205
          ic->lrus[way] = 0;
206
        }
207
      return;
208
    }
209
 
210
  tagaddr = dataaddr & ic->tagaddr_mask;
211
 
212
  /* Scan all ways and try to find a matching way. */
213
  for (way = set; way < ic->last_way; way += ic->nsets)
214
    {
215
      if (ic->tags[way] == tagaddr)
216
        {
217
          ic->tags[way] = -1;
218
          ic->lrus[way] = 0;
219
        }
220
    }
221
}
222
 
223
/*-----------------------------------------------------[ IC configuration ]---*/
224
 
225
 
226
/*---------------------------------------------------------------------------*/
227
/*!Enable or disable the instruction cache
228
 
229 83 jeremybenn
   Set the corresponding fields in the UPR
230 19 jeremybenn
 
231
   @param[in] val  The value to use
232
   @param[in] dat  The config data structure                                 */
233
/*---------------------------------------------------------------------------*/
234
static void
235
ic_enabled (union param_val  val,
236
            void            *dat)
237
{
238
  struct ic *ic = dat;
239
 
240
  ic->enabled = val.int_val;
241
 
242
  if (val.int_val)
243
    {
244
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_ICP;
245
    }
246
  else
247
    {
248
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_ICP;
249
    }
250
}       /* ic_enabled() */
251
 
252
 
253
/*---------------------------------------------------------------------------*/
254
/*!Set the number of instruction cache sets
255
 
256
   Set the corresponding field in the UPR
257
 
258
   @param[in] val  The value to use
259
   @param[in] dat  The config data structure                                 */
260
/*---------------------------------------------------------------------------*/
261
static void
262
ic_nsets (union param_val  val,
263
          void            *dat)
264
{
265
  struct ic *ic = dat;
266
 
267
  if (is_power2 (val.int_val) && (val.int_val <= MAX_IC_SETS))
268
    {
269
      int  set_bits = log2_int (val.int_val);
270
 
271
      ic->nsets = val.int_val;
272
 
273
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCS;
274
      cpu_state.sprs[SPR_ICCFGR] |= set_bits << SPR_ICCFGR_NCS_OFF;
275
    }
276
  else
277
    {
278
      fprintf (stderr, "Warning: instruction cache nsets not a power of "
279
               "2 <= %d: ignored\n", MAX_IC_SETS);
280
    }
281
}       /* ic_nsets() */
282
 
283
 
284
/*---------------------------------------------------------------------------*/
285
/*!Set the number of instruction cache ways
286
 
287
   Set the corresponding field in the UPR
288
 
289
   @param[in] val  The value to use
290
   @param[in] dat  The config data structure                                 */
291
/*---------------------------------------------------------------------------*/
292
static void
293
ic_nways (union param_val  val,
294
            void            *dat)
295
{
296
  struct ic *ic = dat;
297
 
298
  if (is_power2 (val.int_val) && (val.int_val <= MAX_IC_WAYS))
299
    {
300
      int  way_bits = log2_int (val.int_val);
301
 
302
      ic->nways = val.int_val;
303
 
304
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCW;
305
      cpu_state.sprs[SPR_ICCFGR] |= way_bits << SPR_ICCFGR_NCW_OFF;
306
    }
307
  else
308
    {
309
      fprintf (stderr, "Warning: instruction cache nways not a power of "
310
               "2 <= %d: ignored\n", MAX_IC_WAYS);
311
    }
312
}       /* ic_nways() */
313
 
314
 
315
/*---------------------------------------------------------------------------*/
316
/*!Set the instruction cache block size
317
 
318
   Value must be either MIN_IC_BLOCK_SIZE or MAX_IC_BLOCK_SIZE. If not issue a
319
   warning and ignore. Set the relevant field in the data cache config register
320
 
321
   @param[in] val  The value to use
322
   @param[in] dat  The config data structure                                 */
323
/*---------------------------------------------------------------------------*/
324
static void
325
ic_blocksize (union param_val  val,
326
              void            *dat)
327
{
328
  struct ic *ic = dat;
329
 
330
  switch (val.int_val)
331
    {
332
    case MIN_IC_BLOCK_SIZE:
333
      ic->blocksize               = val.int_val;
334
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_CBS;
335
      break;
336
 
337
    case MAX_IC_BLOCK_SIZE:
338
      ic->blocksize               = val.int_val;
339
      cpu_state.sprs[SPR_ICCFGR] |= SPR_ICCFGR_CBS;
340
      break;
341
 
342
    default:
343
      fprintf (stderr, "Warning: instruction cache block size not %d or %d: "
344
               "ignored\n", MIN_IC_BLOCK_SIZE, MAX_IC_BLOCK_SIZE);
345
      break;
346
    }
347
}       /* ic_blocksize() */
348
 
349
 
350
/*---------------------------------------------------------------------------*/
351
/*!Set the number of instruction cache usage states
352
 
353
   Value must be 2, 3 or 4. If not issue a warning and ignore.
354
 
355
   @param[in] val  The value to use
356
   @param[in] dat  The config data structure                                 */
357
/*---------------------------------------------------------------------------*/
358
static void
359
ic_ustates (union param_val  val,
360
            void            *dat)
361
{
362
  struct ic *ic = dat;
363
 
364
  if ((val.int_val >= 2) && (val.int_val <= 4))
365
    {
366
      ic->ustates = val.int_val;
367
    }
368
  else
369
    {
370
      fprintf (stderr, "Warning number of instruction cache usage states "
371
               "must be 2, 3 or 4: ignored\n");
372
    }
373
}       /* ic_ustates() */
374
 
375
 
376
static void
377
ic_hitdelay (union param_val  val,
378
             void            *dat)
379
{
380
  struct ic *ic = dat;
381
  ic->hitdelay = val.int_val;
382
}
383
 
384
 
385
static void
386
ic_missdelay (union param_val  val,
387
              void            *dat)
388
{
389
  struct ic *ic = dat;
390
  ic->missdelay = val.int_val;
391
}
392
 
393
 
394
/*---------------------------------------------------------------------------*/
395
/*!Initialize a new instruction cache configuration
396
 
397
   ALL parameters are set explicitly to default values. Corresponding SPR
398
   flags are set as appropriate.
399
 
400
   @return  The new memory configuration data structure                      */
401
/*---------------------------------------------------------------------------*/
402
static void *
403
ic_start_sec ()
404
{
405
  struct ic *ic;
406
  int        set_bits;
407
  int        way_bits;
408
 
409
  if (NULL == (ic = malloc (sizeof (struct ic))))
410
    {
411
      fprintf (stderr, "OOM\n");
412
      exit (1);
413
    }
414
 
415
  ic->enabled   = 0;
416
  ic->nsets     = 1;
417
  ic->nways     = 1;
418
  ic->blocksize = MIN_IC_BLOCK_SIZE;
419
  ic->ustates   = 2;
420
  ic->hitdelay  = 1;
421
  ic->missdelay = 1;
422
 
423
  ic->mem       = NULL;         /* Internal configuration */
424
  ic->lrus      = NULL;
425
  ic->tags      = NULL;
426
 
427
  /* Set SPRs as appropriate */
428
 
429
  if (ic->enabled)
430
    {
431
      cpu_state.sprs[SPR_UPR] |= SPR_UPR_ICP;
432
    }
433
  else
434
    {
435
      cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_ICP;
436
    }
437
 
438
  set_bits = log2_int (ic->nsets);
439
  cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCS;
440
  cpu_state.sprs[SPR_ICCFGR] |= set_bits << SPR_ICCFGR_NCS_OFF;
441
 
442
  way_bits = log2_int (ic->nways);
443
  cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_NCW;
444
  cpu_state.sprs[SPR_ICCFGR] |= way_bits << SPR_ICCFGR_NCW_OFF;
445
 
446
  if (MIN_IC_BLOCK_SIZE == ic->blocksize)
447
    {
448
      cpu_state.sprs[SPR_ICCFGR] &= ~SPR_ICCFGR_CBS;
449
    }
450
  else
451
    {
452
      cpu_state.sprs[SPR_ICCFGR] |= SPR_ICCFGR_CBS;
453
    }
454
 
455
  ic_state = ic;
456
  return ic;
457
 
458
}       /* ic_start_sec() */
459
 
460
 
461
static void
462
ic_end_sec (void *dat)
463
{
464
  struct ic *ic = dat;
465
  unsigned int size = ic->nways * ic->nsets * ic->blocksize;
466
 
467
  if (size)
468
    {
469
      if (!(ic->mem = malloc (size)))
470
        {
471
          fprintf (stderr, "OOM\n");
472
          exit (1);
473
        }
474
      if (!
475
          (ic->lrus = malloc (ic->nsets * ic->nways * sizeof (unsigned int))))
476
        {
477
          fprintf (stderr, "OOM\n");
478
          exit (1);
479
        }
480
      if (!(ic->tags = malloc (ic->nsets * ic->nways * sizeof (oraddr_t))))
481
        {
482
          fprintf (stderr, "OOM\n");
483
          exit (1);
484
        }
485
 
486 83 jeremybenn
      /* Clear the cache data. John Alfredo's fix for using 0 (which is a
487
         valid tag), so we now use -1 */
488 19 jeremybenn
      memset (ic->mem,  0, size);
489
      memset (ic->lrus, 0, ic->nsets * ic->nways * sizeof (unsigned int));
490 83 jeremybenn
      memset (ic->tags, -1, ic->nsets * ic->nways * sizeof (oraddr_t));
491 19 jeremybenn
    }
492
  else
493
    {
494
      ic->enabled = 0;
495
    }
496
 
497
  ic->blocksize_log2    = log2_int (ic->blocksize);
498
  ic->set_mask          = (ic->nsets - 1) << ic->blocksize_log2;
499
  ic->tagaddr_mask      = ~((ic->nsets * ic->blocksize) - 1);
500
  ic->last_way          = ic->nsets * ic->nways;
501
  ic->block_offset_mask = ic->blocksize - 1;
502
  ic->block_mask        = ~ic->block_offset_mask;
503
  ic->ustates_reload    = ic->ustates - 1;
504
 
505
  if (ic->enabled)
506
    reg_sim_stat (ic_info, dat);
507
}
508
 
509
void
510
reg_ic_sec (void)
511
{
512
  struct config_section *sec =
513
    reg_config_sec ("ic", ic_start_sec, ic_end_sec);
514
 
515 224 jeremybenn
  reg_config_param (sec, "enabled",   PARAMT_INT, ic_enabled);
516
  reg_config_param (sec, "nsets",     PARAMT_INT, ic_nsets);
517
  reg_config_param (sec, "nways",     PARAMT_INT, ic_nways);
518
  reg_config_param (sec, "blocksize", PARAMT_INT, ic_blocksize);
519
  reg_config_param (sec, "ustates",   PARAMT_INT, ic_ustates);
520
  reg_config_param (sec, "missdelay", PARAMT_INT, ic_missdelay);
521
  reg_config_param (sec, "hitdelay" , PARAMT_INT, ic_hitdelay);
522 19 jeremybenn
}

powered by: WebSVN 2.1.0

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