-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathclock.h
310 lines (262 loc) · 9.22 KB
/
clock.h
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
/* CLOCK.H (c) Copyright Jan Jaeger, 2000-2012 */
/* TOD Clock functions */
#if !defined(_CLOCK_C_)
#define _CLOCK_EXTERN extern
#else
#undef _CLOCK_EXTERN
#define _CLOCK_EXTERN
#endif
#if !defined(_CLOCK_H)
#define _CLOCK_H
/* TOD Clock Definitions */
#define TOD_USEC (4096LL)
#define TOD_SEC (1000000 * TOD_USEC)
#define TOD_MIN (60 * TOD_SEC)
#define TOD_HOUR (60 * TOD_MIN)
#define TOD_DAY (24 * TOD_HOUR)
#define TOD_YEAR (365 * TOD_DAY)
#define TOD_LYEAR (TOD_YEAR + TOD_DAY)
#define TOD_4YEARS (1461 * TOD_DAY)
#define TOD_1970 0x7D91048BCA000000ULL // TOD base for host epoch of 1970
typedef U64 TOD; // one microsecond = Bit 51
/* Hercules and Extended TOD Clock Definitions for high-order 64-bits */
#define ETOD_USEC 16LL
#define ETOD_SEC (1000000 * ETOD_USEC)
#define ETOD_MIN (60 * ETOD_SEC)
#define ETOD_HOUR (60 * ETOD_MIN)
#define ETOD_DAY (24 * ETOD_HOUR)
#define ETOD_YEAR (365 * ETOD_DAY)
#define ETOD_LYEAR (ETOD_YEAR + ETOD_DAY)
#define ETOD_4YEARS (1461 * ETOD_DAY)
#define ETOD_1970 0x007D91048BCA0000ULL // Extended TOD base for host epoch of 1970
#if __BIG_ENDIAN__
typedef struct ETOD { U64 high, low; } ETOD;
#define ETOD_init(_high,_low) \
{_high,_low}
#else
typedef struct ETOD { U64 low, high; } ETOD;
#define ETOD_init(_high,_low) \
{_low,_high}
#endif
static INLINE void
ETOD_add (ETOD* result, const ETOD a, const ETOD b)
{
register uint64_t high = a.high + b.high;
register uint64_t low = a.low + b.low;
if (low < a.low)
++high;
result->high = high;
result->low = low;
}
static INLINE void
ETOD_sub (ETOD* result, const ETOD a, const ETOD b)
{
register uint64_t high = a.high - b.high;
register uint64_t low = a.low - b.low;
if (a.low < b.low)
--high;
result->high = high;
result->low = low;
}
static INLINE void
ETOD_shift (ETOD* result, const ETOD a, int shift)
{
register uint64_t high;
register uint64_t low;
if (shift == 0)
{
high = a.high;
low = a.low;
}
else if (shift < 0)
{
shift = -shift;
if (shift >= 64)
{
shift -= 64;
if (shift == 0)
high = a.low;
else if (shift > 64)
high = 0;
else
high = a.low << shift;
low = 0;
}
else
{
high = a.high << shift |
a.low >> (64 - shift);
low = a.low << shift;
}
}
else if (shift >= 64)
{
shift -= 64;
high = 0;
if (shift == 0)
low = a.high;
else if (shift < 64)
low = a.high >> shift;
else
low = 0;
}
else
{
high = a.high >> shift;
low = a.high << (64 - shift) |
a.low >> shift;
}
result->low = low;
result->high = high;
}
/* Clock Steering Registers */
#if !defined(_CSR_)
#define _CSR_
typedef struct _CSR {
U64 start_time;
S64 base_offset;
S32 fine_s_rate;
S32 gross_s_rate;
} CSR;
#endif
void csr_reset(void); /* Reset cs registers */
void set_tod_steering(double); /* Set steering rate */
double get_tod_steering(void); /* Get steering rate */
U64 update_tod_clock(void); /* Update the TOD clock */
void update_cpu_timer(void); /* Update the CPU timer */
void set_tod_epoch(S64); /* Set TOD epoch */
void adjust_tod_epoch(S64); /* Adjust TOD epoch */
S64 get_tod_epoch(void); /* Get TOD epoch */
U64 hw_clock(void); /* Get hardware clock */
S64 cpu_timer(REGS *); /* Retrieve CPU timer */
void set_cpu_timer(REGS *, S64); /* Set CPU timer */
void set_int_timer(REGS *, S32); /* Set interval timer */
TOD tod_clock(REGS *); /* Get TOD clock non-unique */
typedef enum
{
ETOD_raw,
ETOD_fast,
ETOD_standard,
ETOD_extended
} ETOD_format;
TOD etod_clock(REGS*, ETOD*, /* Get extended TOD clock */
ETOD_format);
void set_tod_clock(U64); /* Set TOD clock */
int chk_int_timer(REGS *); /* Check int_timer pending */
int clock_hsuspend(void *file); /* Hercules suspend */
int clock_hresume(void *file); /* Hercules resume */
int query_tzoffset(void); /* Report current TzOFFSET */
ETOD* host_ETOD (ETOD*); /* Retrieve extended TOD */
/*----------------------------------------------------------------------------*/
/* host_TOD - Clock fetch and conversion for routines that DO NOT use the */
/* synchronized clock services or emulation services (including */
/* clock steering), and can tolerate duplicate time stamp */
/* generation. */
/*----------------------------------------------------------------------------*/
static INLINE TOD
host_tod (void)
{
register TOD result;
register U64 temp;
/* Use the same clock source as host_ETOD; refer to host_ETOD in clock.c for
* additional comments.
*/
#if !defined(_MSVC_) && !defined(CLOCK_REALTIME)
{
struct timeval time;
gettimeofday(&time, NULL); /* Get current host time */
result = time.tv_usec << 4; /* Adjust microseconds to bit-59 */
temp = time.tv_sec; /* Load seconds */
}
#else
{
struct timespec time;
clock_gettime(CLOCK_REALTIME, &time);
result = time.tv_nsec; /* Adjust nanoseconds to bit-59 and */
result <<= 1; /* divide by 1000 (bit-shift compressed) */
result /= 125; /* ... */
temp = time.tv_sec; /* Load seconds */
}
#endif
temp *= ETOD_SEC; /* Convert seconds to ETOD format */
result += temp; /* Add seconds */
result += ETOD_1970; /* Adjust to open source epoch of 1970 */
return ( result );
}
static INLINE TOD
ETOD2TOD (const ETOD ETOD)
{
return ( (ETOD.high << 8) | (ETOD.low >> 56) );
}
#endif
DLL_EXPORT void ARCH_DEP(store_int_timer) (REGS *);
void ARCH_DEP(store_int_timer_nolock) (REGS *);
DLL_EXPORT void ARCH_DEP(fetch_int_timer) (REGS *);
void ARCH_DEP(set_gross_s_rate) (REGS *);
void ARCH_DEP(set_fine_s_rate) (REGS *);
void ARCH_DEP(set_tod_offset) (REGS *);
void ARCH_DEP(adjust_tod_offset) (REGS *);
void ARCH_DEP(query_physical_clock) (REGS *);
void ARCH_DEP(query_steering_information) (REGS *);
void ARCH_DEP(query_tod_offset) (REGS *);
void ARCH_DEP(query_available_functions) (REGS *);
_CLOCK_EXTERN ETOD tod_value; /* Bits 0-7 TOD clock epoch */
/* Bits 8-63 TOD bits 0-55 */
/* Bits 64-111 TOD bits 56-103 */
_CLOCK_EXTERN S64 tod_epoch; /* Bits 0-7 TOD clock epoch */
/* Bits 8-63 offset bits 0-55 */
_CLOCK_EXTERN ETOD hw_tod; /* Hardware clock */
#define TOD_CLOCK(_regs) \
((tod_value.high & 0x00FFFFFFFFFFFFFFULL) + (_regs)->tod_epoch)
#define CPU_TIMER(_regs) \
((S64)((_regs)->cpu_timer - hw_tod.high))
//----------------------------------------------------------------------
//
// Interval Timer Conversions to/from Extended TOD Clock Values
//
// S/360 - Decrementing at 50 or 60 cycles per second, depending on line
// frequency, effectively decrementing at 1/300 second in bit
// position 23.
//
// S/370 - Decrementing at 1/300 second in bit position 23.
//
// ITIMER -> ETOD = (units * ETOD_SEC) / (300 << 8)
// = (units * 16000000) / 76800
// = (units * 625) / 3
//
// ETOD -> ITIMER = (units * (300 << 8)) / ETOD_SEC
// = (units * 768) / 16000000
// = (units * 3) / 625
//
// References:
//
// A22-6821-7 IBM System/360 Principles of Operation, Timer Feature,
// p. 17.1
// GA22-6942-1 IBM System/370 Model 155 Functional Characteristics,
// Interval Timer, p. 7
//
#define ITIMER_TO_TOD(_units) \
(((S64)(_units) * 625) / 3)
#define TOD_TO_ITIMER(_units) \
((S32)(((S64)(_units) * 3) / 625))
#define INT_TIMER(_regs) \
((S32)TOD_TO_ITIMER((S64)((_regs)->int_timer - hw_tod.high)))
#define ITIMER_ACCESS(_addr, _len) \
(unlikely(unlikely((_addr) < 84) && (((_addr) + (_len)) >= 80)))
#undef ITIMER_UPDATE
#undef ITIMER_SYNC
#if defined(FEATURE_INTERVAL_TIMER)
#define ITIMER_UPDATE(_addr, _len, _regs) \
do { \
if( ITIMER_ACCESS((_addr), (_len)) ) \
ARCH_DEP(fetch_int_timer) ((_regs)); \
} while(0)
#define ITIMER_SYNC(_addr, _len, _regs) \
do { \
if( ITIMER_ACCESS((_addr), (_len)) ) \
ARCH_DEP(store_int_timer) ((_regs)); \
} while (0)
#else
#define ITIMER_UPDATE(_addr, _len, _regs)
#define ITIMER_SYNC(_addr, _len, _regs)
#endif