1/*
2Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3Permission is hereby granted, free of charge, to any person
4obtaining a copy of this software and associated documentation
5files (the "Software"), to deal in the Software without
6restriction, including without limitation the rights to use,
7copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following
10conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23*/
24
25#include "uwx_env.h"
26#include "uwx_scoreboard.h"
27#include "uwx_step.h"
28#include "uwx_trace.h"
29
30int uwx_init_context(
31    struct uwx_env *env,
32    uint64_t ip,
33    uint64_t sp,
34    uint64_t bsp,
35    uint64_t cfm)
36{
37    int i;
38
39    if (env == 0)
40	return UWX_ERR_NOENV;
41
42    env->context.special[UWX_REG_IP] = ip;
43    env->context.special[UWX_REG_SP] = sp;
44    env->context.special[UWX_REG_BSP] = bsp;
45    env->context.special[UWX_REG_CFM] = cfm;
46    for (i = UWX_REG_RP; i < NSPECIALREG; i++)
47	env->context.special[i] = 0;
48    for (i = 0; i < NPRESERVEDGR; i++)
49	env->context.gr[i] = 0;
50    env->context.valid_regs = VALID_BASIC4;
51    env->context.valid_frs = 0;
52    env->rstate = 0;
53    (void)uwx_init_history(env);
54    return UWX_OK;
55}
56
57int uwx_get_reg(struct uwx_env *env, int regid, uint64_t *valp)
58{
59    int status;
60    int sor;
61    int rrb_gr;
62    uint64_t bsp;
63    int n;
64
65    if (env == 0)
66	return UWX_ERR_NOENV;
67
68    status = UWX_OK;
69
70    if (regid == UWX_REG_GR(12))
71	regid = UWX_REG_SP;
72    if (regid < NSPECIALREG && (env->context.valid_regs & (1 << regid)))
73	*valp = env->context.special[regid];
74    else if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
75					regid == UWX_REG_PFS) {
76	status = uwx_restore_markers(env);
77	if (status != UWX_OK)
78	    return status;
79	*valp = env->context.special[regid];
80    }
81    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
82		(env->context.valid_regs &
83		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) )
84	*valp = env->context.gr[regid - UWX_REG_GR(4)];
85    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
86	if (env->copyin == 0)
87	    return UWX_ERR_NOCALLBACKS;
88	bsp = env->context.special[UWX_REG_BSP];
89	TRACE_C_GET_REG(regid, bsp)
90	regid -= UWX_REG_GR(32);
91	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
92	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
93	if (sor != 0 && rrb_gr != 0 && regid < sor) {
94	    TRACE_C_ROTATE_GR(regid, sor, rrb_gr, (regid+rrb_gr)%sor)
95	    regid = (regid + rrb_gr) % sor;
96	}
97	bsp = uwx_add_to_bsp(bsp, regid);
98	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)valp,
99		    bsp, DWORDSZ, env->cb_token);
100	if (n != DWORDSZ)
101	    status = UWX_ERR_COPYIN_RSTK;
102    }
103    else if (regid == UWX_REG_GR(0))
104	*valp = 0;
105    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5) &&
106		(env->context.valid_regs &
107		    (1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT))) )
108	*valp = env->context.br[regid - UWX_REG_BR(1)];
109    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5) &&
110	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(2)))) ) {
111	valp[0] = env->context.fr[regid - UWX_REG_FR(2)].part0;
112	valp[1] = env->context.fr[regid - UWX_REG_FR(2)].part1;
113    }
114    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31) &&
115	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(16) + 4))) ) {
116	valp[0] = env->context.fr[regid - UWX_REG_FR(16) + 4].part0;
117	valp[1] = env->context.fr[regid - UWX_REG_FR(16) + 4].part1;
118    }
119    else if ( (regid < NSPECIALREG) ||
120		(regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
121		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ) {
122	if (env->copyin == 0)
123	    return UWX_ERR_NOCALLBACKS;
124	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
125			    regid, DWORDSZ, env->cb_token);
126	if (n != DWORDSZ)
127	    status = UWX_ERR_COPYIN_REG;
128    }
129    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
130	if (env->copyin == 0)
131	    return UWX_ERR_NOCALLBACKS;
132	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
133			    regid, 2*DWORDSZ, env->cb_token);
134	if (n != 2*DWORDSZ)
135	    status = UWX_ERR_COPYIN_REG;
136    }
137    else if (regid == UWX_REG_FR(0)) {
138	valp[0] = 0;
139	valp[1] = 0;
140    }
141    else if (regid == UWX_REG_FR(1)) {
142	valp[0] = 0x000000000000ffffULL;
143	valp[1] = 0x8000000000000000ULL;
144    }
145    else
146	status = UWX_ERR_BADREGID;
147    return status;
148}
149
150int uwx_get_nat(struct uwx_env *env, int regid, int *natp)
151{
152    int status;
153    int sor;
154    int rrb_gr;
155    uint64_t bsp;
156    uint64_t natcollp;
157    uint64_t natcoll;
158    int n;
159
160    if (env == 0)
161	return UWX_ERR_NOENV;
162
163    status = UWX_OK;
164
165    if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
166		(env->context.valid_regs &
167		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) ) {
168	*natp = (env->context.special[UWX_REG_PRIUNAT] >>
169				(regid - UWX_REG_GR(4)) ) & 0x01;
170    }
171    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
172	if (env->copyin == 0)
173	    return UWX_ERR_NOCALLBACKS;
174	bsp = env->context.special[UWX_REG_BSP];
175	regid -= UWX_REG_GR(32);
176	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
177	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
178	if (sor != 0 && rrb_gr != 0 && regid < sor) {
179	    regid = (regid + rrb_gr) % sor;
180	}
181	bsp = uwx_add_to_bsp(bsp, regid);
182	natcollp = bsp | 0x01f8;
183	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)&natcoll,
184			natcollp, DWORDSZ, env->cb_token);
185	if (n != DWORDSZ)
186	    return UWX_ERR_COPYIN_RSTK;
187	*natp = (int)(natcoll >> (((int)bsp >> 3) & 0x3f)) & 0x01;
188    }
189    else if (regid == UWX_REG_GR(0))
190	*natp = 0;
191    else
192	status = UWX_ERR_BADREGID;
193    return status;
194}
195
196int uwx_get_spill_loc(struct uwx_env *env, int regid, uint64_t *dispp)
197{
198    int status;
199    int sor;
200    int rrb_gr;
201    uint64_t bsp;
202
203    if (env == 0)
204	return UWX_ERR_NOENV;
205
206    status = UWX_OK;
207
208    if (regid == UWX_REG_GR(12))
209	regid = UWX_REG_SP;
210    if (regid < NSPECIALREG) {
211	if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
212						regid == UWX_REG_PFS) {
213	    if (!(env->context.valid_regs & (1 << regid))) {
214		status = uwx_restore_markers(env);
215		if (status != UWX_OK)
216		    return status;
217	    }
218	}
219	*dispp = env->history.special[regid];
220    }
221    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7))
222	*dispp = env->history.gr[regid - UWX_REG_GR(4)];
223    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
224	bsp = env->context.special[UWX_REG_BSP];
225	regid -= UWX_REG_GR(32);
226	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
227	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
228	if (sor != 0 && rrb_gr != 0 && regid < sor)
229	    regid = (regid + rrb_gr) % sor;
230	bsp = uwx_add_to_bsp(bsp, regid);
231	*dispp = UWX_DISP_RSTK(bsp);
232    }
233    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_GR(5))
234	*dispp = env->history.br[regid - UWX_REG_BR(1)];
235    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
236	*dispp = env->history.fr[regid - UWX_REG_FR(2)];
237    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
238	*dispp = env->history.fr[regid - UWX_REG_FR(16) + 4];
239    else if ( (regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
240		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ||
241		(regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) )
242	*dispp = UWX_DISP_REG(regid);
243    else
244	status = UWX_ERR_BADREGID;
245    return status;
246}
247
248int uwx_set_reg(struct uwx_env *env, int regid, uint64_t val)
249{
250    int status;
251
252    if (env == 0)
253	return UWX_ERR_NOENV;
254
255    if (regid == UWX_REG_GR(12))
256	regid = UWX_REG_SP;
257    if (regid < NSPECIALREG) {
258	env->context.special[regid] = val;
259	env->context.valid_regs |= 1 << regid;
260	status = UWX_OK;
261    }
262    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7)) {
263	env->context.gr[regid - UWX_REG_GR(4)] = val;
264	env->context.valid_regs |=
265			1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT);
266	status = UWX_OK;
267    }
268    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
269	status = UWX_ERR_BADREGID;
270    }
271    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5)) {
272	env->context.br[regid - UWX_REG_BR(1)] = val;
273	env->context.valid_regs |=
274			1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT);
275	status = UWX_OK;
276    }
277    else
278	status = UWX_ERR_BADREGID;
279    return status;
280}
281
282int uwx_set_fr(struct uwx_env *env, int regid, uint64_t *val)
283{
284
285    if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
286	regid -= UWX_REG_FR(2);
287    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
288	regid -= UWX_REG_FR(16) - 4;
289    else
290	return UWX_ERR_BADREGID;
291
292    env->context.fr[regid].part0 = val[0];
293    env->context.fr[regid].part1 = val[1];
294    env->context.valid_frs |= 1 << regid;
295    env->nsbreg = NSBREG;
296    return UWX_OK;
297}
298
299uint64_t uwx_add_to_bsp(uint64_t bsp, int nslots)
300{
301    int bias;
302
303    /*
304     *  Here's a picture of the backing store as modeled in
305     *  the computations below. "X" marks NaT collections at
306     *  every 0x1f8 mod 0x200 address.
307     *
308     *  To make the NaT adjustments easier, we bias the current bsp
309     *  by enough slots to place it at the previous NaT collection.
310     *  Then we need to add the bias to the number of slots,
311     *  then add 1 for every 63 slots to account for NaT collections.
312     *  Then we can remove the bias again and add the adjusted
313     *  number of slots to the bsp.
314     *
315     *   0                           1f8                             3f8
316     *  +---------------------------------------------------------------+
317     *  |                              X                               X|
318     *  +---------------------------------------------------------------+
319     *   <-------- bias -------->
320     *                           <--- nslots --->
321     *                           ^
322     *                           |
323     *                          bsp
324     *   <------------ nslots + bias ----------->
325
326     *  When subtracting from bsp, we avoid depending on the sign of
327     *  the quotient by adding 63*8 before division and subtracting 8
328     *  after division. (Assumes that we will never be called upon
329     *  to subtract more than 504 slots from bsp.)
330     *
331     *   0                           1f8                             3f8
332     *  +---------------------------------------------------------------+
333     *  |                              X                               X|
334     *  +---------------------------------------------------------------+
335     *                                  <-- bias -->
336     *                           <--- (-nslots) --->
337     *                                              ^
338     *                                              |
339     *                                             bsp
340     *                           <----------------->
341     *                             -(nslots + bias)
342     */
343
344    bias = ((unsigned int)bsp & 0x1f8) / DWORDSZ;
345    nslots += (nslots + bias + 63*8) / 63 - 8;
346    return bsp + nslots * DWORDSZ;
347}
348
349#if 0
350int uwx_selftest_bsp_arithmetic()
351{
352    int i;
353    int j;
354    int r;
355    uint64_t bstore[161];
356    uint64_t *bsp;
357    uint64_t *p;
358    int failed = 0;
359
360    printf("uwx_selftest_bsp_arithmetic: bsp at %08lx\n", (unsigned int)bstore);
361    r = 0;
362    bsp = bstore;
363    for (i = 0; i < 161; i++) {
364	if (((unsigned int)bsp & 0x1f8) == 0x1f8)
365	    *bsp++ = 1000 + r;
366	else
367	    *bsp++ = r++;
368    }
369
370    printf("uwx_selftest_bsp_arithmetic: plus tests...\n");
371    bsp = bstore;
372    for (i = 0; i < 64; i++) {
373	r = (int)*bsp;
374	if (r >= 1000)
375	    r -= 1000;
376	for (j = 0; j < 96; j++) {
377	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, j);
378	    if (*p != (r + j)) {
379		failed++;
380		printf("%d [%08lx] + %d -> %08lx ",
381				i, (unsigned int)bsp, j, (unsigned int)p);
382		printf("(read %d instead of %d)\n", (int)*p, r + j);
383	    }
384	}
385	bsp++;
386    }
387
388    printf("uwx_selftest_bsp_arithmetic: minus tests...\n");
389    bsp = &bstore[161];
390    for (i = 63; i >= 0; i--) {
391	bsp--;
392	r = (int)*bsp;
393	if (r >= 1000)
394	    r -= 1000;
395	for (j = 0; j < 96; j++) {
396	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, -j);
397	    if (*p != (r - j)) {
398		failed++;
399		printf("%d [%08lx] - %d -> %08lx ",
400				i, (unsigned int)bsp, j, (unsigned int)p);
401		printf("(read %d instead of %d)\n", (int)*p, r - j);
402	    }
403	}
404    }
405
406    return failed;
407}
408#endif
409