embra.h
9.06 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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
* 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.
*
*/
#ifndef EMBRA_H
#define EMBRA_H
#include <sys/cdefs.h>
/* From embra - should this be shared? */
#include "c_port.h"
/* From the shared directory */
#include "mips_arch.h"
#include "addr_layout.h"
#include "cpu_state.h"
#include "cpu_interface.h"
#include "sim_error.h"
/* From simos */
#include "syslimits.h"
#ifndef _LANGUAGE_ASSEMBLY
#include "simmisc.h"
#include "machine_params.h"
/* *****************************************************************
* A form of PC that allows us to pass information as to whether we
* are in the delay slot
* ****************************************************************/
typedef VA PC_BD;
#define IN_BD(_pc) ((_pc) & 0x1)
#define CLEAR_BD(_pc) ((_pc) & (~(0x1)))
/* Directory Entry. Limits to 30 cpus, but ll/sc is word limited */
/* Could expand to 62 cpus with lld MIPS III opcode */
typedef uint Dir_Entry;
/* ****************************************************************
* Virtual quick check status byte
* *****************************************************************/
typedef enum {MEM_D_EXCLUSIVE = 0x80,
MEM_I_EXCLUSIVE = 0xc0,
MEM_D_SHARED = 0x01,
MEM_I_SHARED = 0x41,
MEM_INVALID = 0x00} EmVQCMemState;
#define VQC_SHARED(_x)((int)(_x) & 0x00000001)
#define VQC_EXCL(_x) ((int)(_x) & 0x00000080 )
#define VQC_INST(_x) ((int)(_x) & 0x00000040 )
#define VQC_DATA(_x) ((int)(_x) == MEM_D_EXCLUSIVE || (int)(_x) == MEM_D_SHARED)
#endif /* _LANGUAGE_ASSEMBLY */
/* ***********************************************************************
* Still this BACKDOOR vs KSEG1 confusion.
* ***********************************************************************/
#define IS_BACKDOOR(_addr) (IS_KSEG1(_addr))
#if defined(SIM_MIPS32)
#define IS_USER(_pc) (!IS_KSEG0(_pc))
#else
#define IS_USER(_pc) (IS_XKUSEG(_pc))
#endif
/* Zero offset bits, and add a line */
#define ALIGN_IT( _val, _mod ) ( ((unsigned)(_val) & (~((unsigned)_mod-1))) +\
(unsigned)_mod )
#define HOST_SCACHE_LINE_SIZE (128)
/* *******************************************************************
* Memory Address macros. Should in fact be somewhere else (not
* embra specific)
* ******************************************************************/
#define MA_TO_UINT(x) ((uint)(x))
#define EMBRA_IS_MEMADDR(_m, x) (IS_VALID_MA((_m), (x)))
#define EMBRA_IS_PADDR(_m, x) (IS_VALID_PA((_m), (x)))
#ifndef _LANGUAGE_ASSEMBLY
/* We may need extra state eventually, but right now, CPUState is sufficient*/
typedef CPUState EmbraState;
extern EmbraState* EMP; /* allocated in driver.c */
typedef struct EmbraParams {
int sequential; /* not really a param - for now 1 */
int parallel; /* not really a param - for now 0 */
CPUType emode; /* not really a param - EMBRA_CACHE | EMBRA_PAGE */
int MPinUP; /* never set for cpuNum==1 - yes */
int useETLB; /* boolean - yes */
int useVQC; /* boolean - yes */
int stats; /* boolean - yes */
int inlineQC; /* boolean - yes */
int timeQuantum; /* 1024 */
int periodicAnnInterval; /* 32*1024*1024 */
int statInterval; /* 32*1024*1024 */
int miscCheckInterval; /* 50000 */
int separateMMUs;
} EmbraParams;
extern EmbraParams embra;
/* **********************************************************
* Current EMP and cpu is determined by curEmp, updated
* on context switches
* *********************************************************
*/
extern int EmbraCurrentCpuNum(void);
#define CURR_CPU (curEmp->myNum)
extern EmbraState* curEmp;
/* Allocated in driver.c This is NOT shared*/
extern int quick_ASID[SIM_MAXCPUS];
/* Allocated in simos_interface.c - the number of CPUs in the simulation */
/* Here are a whole bunch of defines. All of the registers, and how */
/* Embra uses them are here. */
#endif /* _LANGUAGE_ASSEMBLY */
/* DEFINE what registers simulator will use */
#ifndef _LANGUAGE_ASSEMBLY
typedef struct RegNoDummy {
char nothing[1];
} RegNo;
#define REGNUM(_x) ((int)(_x))
#endif
#ifdef _LANGUAGE_ASSEMBLY
/*
* this is a work-around around the expansion rules of cpp.
*/
#if defined(_ABIN32)
#define REGISTER_NUMBER(_x) $/**/_x
#else
#define REGISTER_NUMBER2(_dollar,_x) _dollar##_x
#define REGISTER_NUMBER(_x) REGISTER_NUMBER2($,_x)
#endif
#else
#define REGISTER_NUMBER(_x) (_x)
#endif
/* *********************************************************************
* new register map:
* *********************************************************************
* 0 zero :
* 1 at : shadow
* 2 v0 : used to return stuff (tc internal)
* 3 v1 : shadow
* 4 a0-a3 : parameter passing (tc internal + callout)
* 8 t0-t2 : shadow
* 11 t3-t6 : tc internal
* 15 t7 : shadow
* 24 t8-t9 : shadow
* s0-s8 : common variables
* ********************************************************************/
/* *********************************************************************
* Simulator working registers
* SIM_T1 & SIM_T2 are used by ALU_OPS and L/S generally as
* rs == SIM_T2, rt == SIM_T1, rd = SIM_T2
*
* BRANCHREG holds either the branch condition or the target address if
* its a register indirect jump. Therefore it must be saved on
* callouts because if we callout in a delay slot, we don't want to
* lose our branch information
*
* XXX bugnion(fix this. should be a callee saved register)
*
* SIM_T4 Used for Quick Check and link address in branch and link
* instructions
*
************************************************************************/
#define SIM_T1 REGISTER_NUMBER(REG_T3)
#define SIM_T2 REGISTER_NUMBER(REG_T4)
#define SIM_T3 unused-register
#define SIM_T4 REGISTER_NUMBER(REG_T6)
/* *******************************************************************
* Simulator permanent registers.
* These registers are used to cache the most frequently accessed
* variables from within the translation cache.
* All registers are callee saved, therefore do not need to
* explicitely saved on callouts.
*
* VSS_BASE == curEmp == &EMP[CURR_CPU]
* QC_REG == curEmp->qc_v, (cache mode only)
* MMU_REG == curEmp->mmu: base of relocation array
* PC_REG == curEmp->PC (must spill on callouts!)
* CLOCK_REG== curEmp->XXX
* MMUMASK_REG == 0x7fffffff (page mode only)
*
* IHIT == number of instructions executed
* DHIT == number of references
*
* *******************************************************************/
/* common variables: reconstruct after callout
* Either have these variables callee saved or recompute them
* after returning from the callout
*/
#define VSS_BASE REGISTER_NUMBER(REG_S8)
#define QC_REG REGISTER_NUMBER(REG_T1)
#define PA_REG QC_REG
#define MMU_REG REGISTER_NUMBER(REG_T0)
#define MMUMASK_REG REGISTER_NUMBER(REG_V1)
/* volatile registers: save to EMP before callout. Restore from EMP
* Note that the clock and ihit must be adjusted.
* Ideally, these registers are caller saved.
*/
#define CLOCK_REG REGISTER_NUMBER(REG_T7)
#define IHIT_REG REGISTER_NUMBER(REG_T8)
#define DHIT_REG REGISTER_NUMBER(REG_T9)
/* internal registers: save to stack if caller saved
*
* As non-intuitive as this might seem, PC_REG and curEmp->PC
* MUST BE KEPT incoherent, the first walue corresponds
* to the start ot the BB while the second one is updated on
* callouts !!!!
* Note that there is an incentive of having them callee saved.
* If we support mid-translation context switches, we must
* save the BRANCHREG and the PC_REG in the saveArea.
*/
#define BRANCHREG REGISTER_NUMBER(REG_T5)
#define PC_REG REGISTER_NUMBER(REG_S5)
#define UNUSED REGISTER_NUMBER(REG_T2)
/* shadow registers: save to stack if caller saved
* Again, there is an incentive of having them callee
* saved.
*/
#define SHADOW0 REGISTER_NUMBER(REG_S0)
#define SHADOW1 REGISTER_NUMBER(REG_S1)
#define SHADOW2 REGISTER_NUMBER(REG_S2)
#define SHADOW3 REGISTER_NUMBER(REG_S3)
#define SHADOW4 REGISTER_NUMBER(REG_S4)
#define SHADOW5 REGISTER_NUMBER(REG_S6)
#define SHADOW6 REGISTER_NUMBER(REG_S7)
/* DON'T USE $AT!!! VCODE CAN USE $AT and this
* CAN HOSE US BIG TIME. Should fix vcode, but for now
* play it safe. XXX -BL */
/* #define SHADOW7 REGISTER_NUMBER(REG_AT) */
#define REGALLOC_LIST {SHADOW0,SHADOW1,SHADOW2, \
SHADOW3,SHADOW4,SHADOW5, \
SHADOW6,0}
#ifdef OBSOLETE
/* This is used to hold the old PC, so we can see if we are */
/* transfering to code on the same page */
#define OLD_PC REGISTER_NUMBER(REG_S3)
/* In MP_IN_UP, we store the old PC directly in the state structure, */
/* so we use it to provide guarantees on interleaving between */
/* processors It holds the threshold which, with CLOCK_REG falls under */
/* this value, we context switch*/
#define TQUANTUM_REG REGISTER_NUMBER(REG_S3)
#endif
#endif /* EMBRA_H */