pcache.h
7.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Copyright (C) 1996-1998 by the Board of Trustees
* of Leland Stanford Junior University.
*
* This file is part of the SimOS distribution.
* See LICENSE file for terms of the license.
*
*/
/*****************************************************************
* pcache.h
*
* This is the interface into the 2level cache-based memory
* subsystem. We currently support two first level caches: Split I and D
* All caches have controllable associativity from 1->4.
*
* $Author: blythe $
* $Date: 2002/05/29 01:09:09 $
*******************************************************************/
#ifndef _PCACHE_H
#define _PCACHE_H
#ifdef SIM_ALPHA /* hack */
extern int iAddrDivisor;
extern int dAddrDivisor;
#endif /* SIM_ALPHA */
#include "machine_params.h"
#include "eventcallback.h"
#ifndef NDEBUG
#define error CPUError /* Make ASSERT()s happy */
#endif
/* Currently hardcoded. Supported values are 1,2,4 */
#define ICACHE_ASSOC (2)
#define DCACHE_ASSOC (2)
/* Quickly checking if an instruction is in the same line as the last
* instruction can be an enormous performance gain. Each cache that is
* implemented should supply these calls. Eventually the actual
* handling of a quick hit should be handled here, too.
*/
#if defined(SIM_MIPS32) || defined(SIM_MIPS64)
#include "../../cpus/mipsy/mipsy.h"
# define QUICK_ICACHE_CLEAR(_num) (pePtr[_num]->cachedILine = BAD_CACHED_LINE)
# define QUICK_ICACHE_SET(_num, _addr, _set, _setindex) \
{ pePtr[_num]->cachedILine = ICACHE_ONE_LINE(_addr); \
pePtr[_num]->cachedILineData = (_set)->data[_setindex]; \
}
#else
# define QUICK_ICACHE_CLEAR(_num)
# define QUICK_ICACHE_SET(_num, _addr, _set, _setindex)
#endif
/*
* Data handling flags:
* BLOCKING_WRITES- Writes block until the line is returned in exclusive mode.
* BUFFER_WRITES- When writes on non-blocking, buffer them in the MHT until
* ownership of the line is returned. Otherwise the changes are
* given immediately to the memory system.
*/
#define BLOCKING_WRITES
#ifndef BLOCKING_WRITES
#define BUFFER_WRITES 1
#endif
#ifdef MIPSY_MXS
/*
* MXS does it own write buffer and handling of blocking writes.
*/
#undef BUFFER_WRITES
#ifndef BLOCKING_WRITES
#define BLOCKING_WRITES
#endif
#endif
#if (defined PA_IS_LL)
# define INVALID_TAG (0x8000000000000000LL) /* Line is not valid */
# define EXCLUSIVE_TAG (0x4000000000000000LL) /* Line is exclusive */
# define BAD_CACHED_LINE (0x8fffffffffffffffLL) /* Line is invalid */
#elif (defined PA_IS_UINT)
# define INVALID_TAG 0x80000000 /* Line is not valid */
# define EXCLUSIVE_TAG 0x40000000 /* Line is in exclusive mode */
# define BAD_CACHED_LINE 0x8fffffff /* Line is invalid */
#else
# error You must define either PA_IS_LL or PA_IS_UINT
#endif /* PA_IS_LL */
/* Cache configuation.
* For now, the assoc is hardcoded.
* Everything else is a run-time option
*/
#define WORD_SIZE 4
/*
* Number of miss-handling-table entries below primary caches. This
* value is shared by the primary and secondary cache structures.
*/
#define MHT_SIZE 4
/*
* First level miss handling table.
*/
typedef struct MHT {
EventCallbackHdr evthdr; /* So we can make this an event callback */
int status; /* Used for bus event */
bool inuse; /* TRUE if entry active */
SimTime startTime; /* When request was started */
/* First level data */
PA cmd; /* SCache command causing miss */
VA vAddr; /* Virtual address of miss */
PA pAddr; /* Phsyical address of miss */
VA PC; /* PC causing miss */
#ifdef MIPSY_MXS
int cpu_action; /* Action to take when transaction completes */
void *cpu_action_param; /* An argument to pass */
#endif
int ind; /* Index into the smallest cache */
short lru; /* First level cache LRU bit */
struct {
char data[128];
char mask[128];
int active;
} *writeBuffer;
/* Second level cache - usage */
short smhtEntry; /* SMHT entry for request. */
int mode; /* Return mode. */
#define SECOND_LEVEL_HIT_ENTRY -1
#define SECOND_LEVEL_INVALID_ENTRY -2
} MHT;
#define ICACHE_TAG(a) ((a) >> (iTagShift))
#define ICACHE_ONE_LINE(a) ((a) >> (log2ICACHE_LINE_SIZE))
#define ITAG_TO_PA(t,i) ((((t)*iAddrDivisor) + ((i)*ICACHE_LINE_SIZE)))
#define ICACHE_INDEXOF(a) ((a>>log2ICACHE_LINE_SIZE) & (iIndexMask))
#define DCACHE_TAG(a) ((a) >> (dTagShift))
#define DCACHE_TAG_EX(a) (DCACHE_TAG(a)|EXCLUSIVE_TAG)
#define DCACHE_ONE_LINE(a) ((a) >> (log2DCACHE_LINE_SIZE))
#define DTAG_TO_PA(t,i) ((((~EXCLUSIVE_TAG)&(t))*(dAddrDivisor)) \
+ ((i)*DCACHE_LINE_SIZE))
#define DCACHE_INDEXOF(a) ((a>>log2DCACHE_LINE_SIZE) & (dIndexMask))
/* Figure out which word in an ICache line a VA refers to */
#define I_LINE_WORD(_va) ((_va & iWordMask) >> 2)
typedef struct Cache {
struct ICache {
struct ICacheSet {
PA tags[ICACHE_ASSOC];
uint LRU;
byte *data[ICACHE_ASSOC];
} *set; /* [ICACHE_INDEX]; */
} ICache;
struct DCache {
struct DCacheSet {
PA tags[DCACHE_ASSOC];
uint LRU;
byte *data[DCACHE_ASSOC];
struct FalseSharingEntry *fSharing[DCACHE_ASSOC];
} *set; /* [DCACHE_INDEX]; */
int memSample;
} DCache;
MHT MHT[MHT_SIZE];
int MHTnumInuse; /* Number of active MHT entries */
int activeWriteBuffers;
struct {
SimCounter mhtOccupancyHist[MHT_SIZE+1];
struct {
SimCounter Reads;
SimCounter ReadMisses;
SimCounter Inval;
SimCounter LinesInval;
SimCounter RetriedIGets;
SimTime BusOccupiedTime;
} ICache;
struct {
SimCounter Reads;
SimCounter Writes;
SimCounter ReadMisses;
SimCounter WriteMisses;
SimCounter UpgradeMisses;
SimCounter MergeMisses;
SimCounter Writebacks;
SimCounter Inval;
SimCounter Downgrade;
SimCounter LinesInval;
SimCounter LinesWriteback;
SimCounter WriteWriteStall;
SimCounter WriteWriteHoldoff;
SimCounter WriteHoldoffRetry;
SimCounter RetriedDGets;
SimCounter RetriedDGetXs;
SimTime BusOccupiedTime;
} DCache;
} stats;
} Cache;
extern Cache *CACHE;
extern bool skipCaches;
extern unsigned long verboseDebugEnabled;
#ifdef DEBUG_DATA_VERBOSE
#define VERBOSE_DEBUG verboseDebugEnabled
#else
#define VERBOSE_DEBUG FALSE
#endif
#ifdef MIPSY_MXS
extern Result DCacheFetchShared(int cpuNum, VA vAddr, PA pAddr, int flags,
char **dataPtr);
extern Result DCacheFetchExclusive(int cpuNum, VA vAddr, PA pAddr, int size,
char **dataPtr);
extern int MxsClassifyMiss(int cpuNum, VA vAddr, PA pAddr, bool isICache);
#endif
/* Interface from SCache */
extern void PrimaryFlush(int cpuNum, int writebackonly, int retain,
PA paddr, int size);
extern void MHTReqDone(int cpuNum, MHT *mht, int mode, int status);
extern void MHTReqDoneCallback(int cpuNum, EventCallbackHdr *hdr, void *arg);
extern void MHTRemoveReq(int cpuNum, PA pAddr, int size);
/* Some shared functions for cache manipulation */
extern int SameCacheLine(PA addr1, PA addr2, unsigned cacheLineSize);
extern PA QuadWordAlign(PA offset);
/* This macro is here so we can experiment with shared caches */
#define GET_CACHE_NUM(_cpunum) (_cpunum)
#endif /* _PCACHE_H */