1115013Smarcel/*
2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3121642SmarcelPermission is hereby granted, free of charge, to any person
4121642Smarcelobtaining a copy of this software and associated documentation
5121642Smarcelfiles (the "Software"), to deal in the Software without
6121642Smarcelrestriction, including without limitation the rights to use,
7121642Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell
8121642Smarcelcopies of the Software, and to permit persons to whom the
9121642SmarcelSoftware is furnished to do so, subject to the following
10121642Smarcelconditions:
11115013Smarcel
12121642SmarcelThe above copyright notice and this permission notice shall be
13121642Smarcelincluded in all copies or substantial portions of the Software.
14121642Smarcel
15121642SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16121642SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17121642SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18121642SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19121642SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20121642SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21121642SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22121642SmarcelOTHER DEALINGS IN THE SOFTWARE.
23121642Smarcel*/
24121642Smarcel
25115013Smarcel#include "uwx_env.h"
26115013Smarcel#include "uwx_scoreboard.h"
27120925Smarcel#include "uwx_step.h"
28115013Smarcel#include "uwx_trace.h"
29115013Smarcel
30115013Smarcelint uwx_init_context(
31115013Smarcel    struct uwx_env *env,
32115013Smarcel    uint64_t ip,
33115013Smarcel    uint64_t sp,
34115013Smarcel    uint64_t bsp,
35115013Smarcel    uint64_t cfm)
36115013Smarcel{
37115013Smarcel    int i;
38115013Smarcel
39115013Smarcel    if (env == 0)
40115013Smarcel	return UWX_ERR_NOENV;
41115013Smarcel
42115013Smarcel    env->context.special[UWX_REG_IP] = ip;
43115013Smarcel    env->context.special[UWX_REG_SP] = sp;
44115013Smarcel    env->context.special[UWX_REG_BSP] = bsp;
45115013Smarcel    env->context.special[UWX_REG_CFM] = cfm;
46115013Smarcel    for (i = UWX_REG_RP; i < NSPECIALREG; i++)
47115013Smarcel	env->context.special[i] = 0;
48115013Smarcel    for (i = 0; i < NPRESERVEDGR; i++)
49115013Smarcel	env->context.gr[i] = 0;
50115013Smarcel    env->context.valid_regs = VALID_BASIC4;
51120925Smarcel    env->context.valid_frs = 0;
52115013Smarcel    env->rstate = 0;
53115013Smarcel    (void)uwx_init_history(env);
54115013Smarcel    return UWX_OK;
55115013Smarcel}
56115013Smarcel
57115013Smarcelint uwx_get_reg(struct uwx_env *env, int regid, uint64_t *valp)
58115013Smarcel{
59115013Smarcel    int status;
60115013Smarcel    int sor;
61115013Smarcel    int rrb_gr;
62115013Smarcel    uint64_t bsp;
63115013Smarcel    int n;
64115013Smarcel
65115013Smarcel    if (env == 0)
66115013Smarcel	return UWX_ERR_NOENV;
67115013Smarcel
68115013Smarcel    status = UWX_OK;
69115013Smarcel
70120925Smarcel    if (regid == UWX_REG_GR(12))
71120925Smarcel	regid = UWX_REG_SP;
72115013Smarcel    if (regid < NSPECIALREG && (env->context.valid_regs & (1 << regid)))
73115013Smarcel	*valp = env->context.special[regid];
74120925Smarcel    else if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
75120925Smarcel					regid == UWX_REG_PFS) {
76120925Smarcel	status = uwx_restore_markers(env);
77120925Smarcel	if (status != UWX_OK)
78120925Smarcel	    return status;
79120925Smarcel	*valp = env->context.special[regid];
80120925Smarcel    }
81115013Smarcel    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
82115013Smarcel		(env->context.valid_regs &
83115013Smarcel		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) )
84115013Smarcel	*valp = env->context.gr[regid - UWX_REG_GR(4)];
85115013Smarcel    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
86115013Smarcel	if (env->copyin == 0)
87115013Smarcel	    return UWX_ERR_NOCALLBACKS;
88115013Smarcel	bsp = env->context.special[UWX_REG_BSP];
89115013Smarcel	TRACE_C_GET_REG(regid, bsp)
90115013Smarcel	regid -= UWX_REG_GR(32);
91115013Smarcel	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
92115013Smarcel	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
93115013Smarcel	if (sor != 0 && rrb_gr != 0 && regid < sor) {
94115013Smarcel	    TRACE_C_ROTATE_GR(regid, sor, rrb_gr, (regid+rrb_gr)%sor)
95115013Smarcel	    regid = (regid + rrb_gr) % sor;
96115013Smarcel	}
97115013Smarcel	bsp = uwx_add_to_bsp(bsp, regid);
98115013Smarcel	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)valp,
99115013Smarcel		    bsp, DWORDSZ, env->cb_token);
100115013Smarcel	if (n != DWORDSZ)
101115013Smarcel	    status = UWX_ERR_COPYIN_RSTK;
102115013Smarcel    }
103115013Smarcel    else if (regid == UWX_REG_GR(0))
104115013Smarcel	*valp = 0;
105115013Smarcel    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5) &&
106115013Smarcel		(env->context.valid_regs &
107115013Smarcel		    (1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT))) )
108115013Smarcel	*valp = env->context.br[regid - UWX_REG_BR(1)];
109120925Smarcel    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5) &&
110120925Smarcel	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(2)))) ) {
111115013Smarcel	valp[0] = env->context.fr[regid - UWX_REG_FR(2)].part0;
112115013Smarcel	valp[1] = env->context.fr[regid - UWX_REG_FR(2)].part1;
113115013Smarcel    }
114120925Smarcel    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31) &&
115120925Smarcel	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(16) + 4))) ) {
116115013Smarcel	valp[0] = env->context.fr[regid - UWX_REG_FR(16) + 4].part0;
117115013Smarcel	valp[1] = env->context.fr[regid - UWX_REG_FR(16) + 4].part1;
118115013Smarcel    }
119115013Smarcel    else if ( (regid < NSPECIALREG) ||
120115013Smarcel		(regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
121115013Smarcel		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ) {
122115013Smarcel	if (env->copyin == 0)
123115013Smarcel	    return UWX_ERR_NOCALLBACKS;
124115013Smarcel	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
125115013Smarcel			    regid, DWORDSZ, env->cb_token);
126115013Smarcel	if (n != DWORDSZ)
127115013Smarcel	    status = UWX_ERR_COPYIN_REG;
128115013Smarcel    }
129120925Smarcel    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
130115013Smarcel	if (env->copyin == 0)
131115013Smarcel	    return UWX_ERR_NOCALLBACKS;
132115013Smarcel	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
133115013Smarcel			    regid, 2*DWORDSZ, env->cb_token);
134115013Smarcel	if (n != 2*DWORDSZ)
135115013Smarcel	    status = UWX_ERR_COPYIN_REG;
136115013Smarcel    }
137115013Smarcel    else if (regid == UWX_REG_FR(0)) {
138115013Smarcel	valp[0] = 0;
139115013Smarcel	valp[1] = 0;
140115013Smarcel    }
141115013Smarcel    else if (regid == UWX_REG_FR(1)) {
142115013Smarcel	valp[0] = 0x000000000000ffffULL;
143115013Smarcel	valp[1] = 0x8000000000000000ULL;
144115013Smarcel    }
145115013Smarcel    else
146115013Smarcel	status = UWX_ERR_BADREGID;
147115013Smarcel    return status;
148115013Smarcel}
149115013Smarcel
150115013Smarcelint uwx_get_nat(struct uwx_env *env, int regid, int *natp)
151115013Smarcel{
152115013Smarcel    int status;
153115013Smarcel    int sor;
154115013Smarcel    int rrb_gr;
155115013Smarcel    uint64_t bsp;
156115013Smarcel    uint64_t natcollp;
157115013Smarcel    uint64_t natcoll;
158115013Smarcel    int n;
159115013Smarcel
160115013Smarcel    if (env == 0)
161115013Smarcel	return UWX_ERR_NOENV;
162115013Smarcel
163115013Smarcel    status = UWX_OK;
164115013Smarcel
165115013Smarcel    if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
166115013Smarcel		(env->context.valid_regs &
167115013Smarcel		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) ) {
168115013Smarcel	*natp = (env->context.special[UWX_REG_PRIUNAT] >>
169115013Smarcel				(regid - UWX_REG_GR(4)) ) & 0x01;
170115013Smarcel    }
171115013Smarcel    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
172115013Smarcel	if (env->copyin == 0)
173115013Smarcel	    return UWX_ERR_NOCALLBACKS;
174115013Smarcel	bsp = env->context.special[UWX_REG_BSP];
175115013Smarcel	regid -= UWX_REG_GR(32);
176115013Smarcel	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
177115013Smarcel	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
178115013Smarcel	if (sor != 0 && rrb_gr != 0 && regid < sor) {
179115013Smarcel	    regid = (regid + rrb_gr) % sor;
180115013Smarcel	}
181115013Smarcel	bsp = uwx_add_to_bsp(bsp, regid);
182115013Smarcel	natcollp = bsp | 0x01f8;
183129059Smarcel	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)&natcoll,
184160157Smarcel			natcollp, DWORDSZ, env->cb_token);
185115013Smarcel	if (n != DWORDSZ)
186115013Smarcel	    return UWX_ERR_COPYIN_RSTK;
187115013Smarcel	*natp = (int)(natcoll >> (((int)bsp >> 3) & 0x3f)) & 0x01;
188115013Smarcel    }
189115013Smarcel    else if (regid == UWX_REG_GR(0))
190115013Smarcel	*natp = 0;
191115013Smarcel    else
192115013Smarcel	status = UWX_ERR_BADREGID;
193115013Smarcel    return status;
194115013Smarcel}
195115013Smarcel
196115013Smarcelint uwx_get_spill_loc(struct uwx_env *env, int regid, uint64_t *dispp)
197115013Smarcel{
198115013Smarcel    int status;
199115013Smarcel    int sor;
200115013Smarcel    int rrb_gr;
201115013Smarcel    uint64_t bsp;
202115013Smarcel
203115013Smarcel    if (env == 0)
204115013Smarcel	return UWX_ERR_NOENV;
205115013Smarcel
206115013Smarcel    status = UWX_OK;
207115013Smarcel
208120925Smarcel    if (regid == UWX_REG_GR(12))
209120925Smarcel	regid = UWX_REG_SP;
210160157Smarcel    if (regid < NSPECIALREG) {
211160157Smarcel	if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
212160157Smarcel						regid == UWX_REG_PFS) {
213160157Smarcel	    if (!(env->context.valid_regs & (1 << regid))) {
214160157Smarcel		status = uwx_restore_markers(env);
215160157Smarcel		if (status != UWX_OK)
216160157Smarcel		    return status;
217160157Smarcel	    }
218160157Smarcel	}
219115013Smarcel	*dispp = env->history.special[regid];
220160157Smarcel    }
221115013Smarcel    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7))
222115013Smarcel	*dispp = env->history.gr[regid - UWX_REG_GR(4)];
223115013Smarcel    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
224115013Smarcel	bsp = env->context.special[UWX_REG_BSP];
225115013Smarcel	regid -= UWX_REG_GR(32);
226115013Smarcel	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
227115013Smarcel	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
228115013Smarcel	if (sor != 0 && rrb_gr != 0 && regid < sor)
229115013Smarcel	    regid = (regid + rrb_gr) % sor;
230115013Smarcel	bsp = uwx_add_to_bsp(bsp, regid);
231115013Smarcel	*dispp = UWX_DISP_RSTK(bsp);
232115013Smarcel    }
233115013Smarcel    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_GR(5))
234115013Smarcel	*dispp = env->history.br[regid - UWX_REG_BR(1)];
235115013Smarcel    else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
236115013Smarcel	*dispp = env->history.fr[regid - UWX_REG_FR(2)];
237115013Smarcel    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
238115013Smarcel	*dispp = env->history.fr[regid - UWX_REG_FR(16) + 4];
239115013Smarcel    else if ( (regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
240115013Smarcel		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ||
241115013Smarcel		(regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) )
242115013Smarcel	*dispp = UWX_DISP_REG(regid);
243115013Smarcel    else
244115013Smarcel	status = UWX_ERR_BADREGID;
245115013Smarcel    return status;
246115013Smarcel}
247115013Smarcel
248115013Smarcelint uwx_set_reg(struct uwx_env *env, int regid, uint64_t val)
249115013Smarcel{
250115013Smarcel    int status;
251115013Smarcel
252115013Smarcel    if (env == 0)
253115013Smarcel	return UWX_ERR_NOENV;
254115013Smarcel
255120925Smarcel    if (regid == UWX_REG_GR(12))
256120925Smarcel	regid = UWX_REG_SP;
257115013Smarcel    if (regid < NSPECIALREG) {
258115013Smarcel	env->context.special[regid] = val;
259115013Smarcel	env->context.valid_regs |= 1 << regid;
260115013Smarcel	status = UWX_OK;
261115013Smarcel    }
262115013Smarcel    else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7)) {
263115013Smarcel	env->context.gr[regid - UWX_REG_GR(4)] = val;
264115013Smarcel	env->context.valid_regs |=
265115013Smarcel			1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT);
266115013Smarcel	status = UWX_OK;
267115013Smarcel    }
268115013Smarcel    else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
269115013Smarcel	status = UWX_ERR_BADREGID;
270115013Smarcel    }
271115013Smarcel    else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5)) {
272115013Smarcel	env->context.br[regid - UWX_REG_BR(1)] = val;
273115013Smarcel	env->context.valid_regs |=
274115013Smarcel			1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT);
275115013Smarcel	status = UWX_OK;
276115013Smarcel    }
277115013Smarcel    else
278115013Smarcel	status = UWX_ERR_BADREGID;
279115013Smarcel    return status;
280115013Smarcel}
281115013Smarcel
282115013Smarcelint uwx_set_fr(struct uwx_env *env, int regid, uint64_t *val)
283115013Smarcel{
284115013Smarcel
285115013Smarcel    if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
286115013Smarcel	regid -= UWX_REG_FR(2);
287115013Smarcel    else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
288115013Smarcel	regid -= UWX_REG_FR(16) - 4;
289115013Smarcel    else
290115013Smarcel	return UWX_ERR_BADREGID;
291115013Smarcel
292115013Smarcel    env->context.fr[regid].part0 = val[0];
293115013Smarcel    env->context.fr[regid].part1 = val[1];
294115013Smarcel    env->context.valid_frs |= 1 << regid;
295115013Smarcel    env->nsbreg = NSBREG;
296115013Smarcel    return UWX_OK;
297115013Smarcel}
298115013Smarcel
299115013Smarceluint64_t uwx_add_to_bsp(uint64_t bsp, int nslots)
300115013Smarcel{
301115013Smarcel    int bias;
302115013Smarcel
303115013Smarcel    /*
304115013Smarcel     *  Here's a picture of the backing store as modeled in
305115013Smarcel     *  the computations below. "X" marks NaT collections at
306115013Smarcel     *  every 0x1f8 mod 0x200 address.
307115013Smarcel     *
308115013Smarcel     *  To make the NaT adjustments easier, we bias the current bsp
309115013Smarcel     *  by enough slots to place it at the previous NaT collection.
310115013Smarcel     *  Then we need to add the bias to the number of slots,
311115013Smarcel     *  then add 1 for every 63 slots to account for NaT collections.
312115013Smarcel     *  Then we can remove the bias again and add the adjusted
313115013Smarcel     *  number of slots to the bsp.
314115013Smarcel     *
315115013Smarcel     *   0                           1f8                             3f8
316115013Smarcel     *  +---------------------------------------------------------------+
317115013Smarcel     *  |                              X                               X|
318115013Smarcel     *  +---------------------------------------------------------------+
319115013Smarcel     *   <-------- bias -------->
320115013Smarcel     *                           <--- nslots --->
321115013Smarcel     *                           ^
322115013Smarcel     *                           |
323115013Smarcel     *                          bsp
324160157Smarcel     *   <------------ nslots + bias ----------->
325115013Smarcel
326129059Smarcel     *  When subtracting from bsp, we avoid depending on the sign of
327129059Smarcel     *  the quotient by adding 63*8 before division and subtracting 8
328129059Smarcel     *  after division. (Assumes that we will never be called upon
329129059Smarcel     *  to subtract more than 504 slots from bsp.)
330115013Smarcel     *
331115013Smarcel     *   0                           1f8                             3f8
332115013Smarcel     *  +---------------------------------------------------------------+
333115013Smarcel     *  |                              X                               X|
334115013Smarcel     *  +---------------------------------------------------------------+
335129059Smarcel     *                                  <-- bias -->
336160157Smarcel     *                           <--- (-nslots) --->
337129059Smarcel     *                                              ^
338129059Smarcel     *                                              |
339129059Smarcel     *                                             bsp
340129059Smarcel     *                           <----------------->
341160157Smarcel     *                             -(nslots + bias)
342115013Smarcel     */
343115013Smarcel
344129059Smarcel    bias = ((unsigned int)bsp & 0x1f8) / DWORDSZ;
345129059Smarcel    nslots += (nslots + bias + 63*8) / 63 - 8;
346129059Smarcel    return bsp + nslots * DWORDSZ;
347129059Smarcel}
348129059Smarcel
349160163Smarcel#if 0
350129059Smarcelint uwx_selftest_bsp_arithmetic()
351129059Smarcel{
352129059Smarcel    int i;
353129059Smarcel    int j;
354129059Smarcel    int r;
355129059Smarcel    uint64_t bstore[161];
356129059Smarcel    uint64_t *bsp;
357129059Smarcel    uint64_t *p;
358129059Smarcel    int failed = 0;
359129059Smarcel
360129059Smarcel    printf("uwx_selftest_bsp_arithmetic: bsp at %08lx\n", (unsigned int)bstore);
361129059Smarcel    r = 0;
362129059Smarcel    bsp = bstore;
363129059Smarcel    for (i = 0; i < 161; i++) {
364129059Smarcel	if (((unsigned int)bsp & 0x1f8) == 0x1f8)
365129059Smarcel	    *bsp++ = 1000 + r;
366129059Smarcel	else
367129059Smarcel	    *bsp++ = r++;
368115013Smarcel    }
369129059Smarcel
370129059Smarcel    printf("uwx_selftest_bsp_arithmetic: plus tests...\n");
371129059Smarcel    bsp = bstore;
372129059Smarcel    for (i = 0; i < 64; i++) {
373129059Smarcel	r = (int)*bsp;
374129059Smarcel	if (r >= 1000)
375129059Smarcel	    r -= 1000;
376129059Smarcel	for (j = 0; j < 96; j++) {
377160157Smarcel	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, j);
378129059Smarcel	    if (*p != (r + j)) {
379129059Smarcel		failed++;
380129059Smarcel		printf("%d [%08lx] + %d -> %08lx ",
381129059Smarcel				i, (unsigned int)bsp, j, (unsigned int)p);
382129059Smarcel		printf("(read %d instead of %d)\n", (int)*p, r + j);
383129059Smarcel	    }
384129059Smarcel	}
385129059Smarcel	bsp++;
386115013Smarcel    }
387129059Smarcel
388129059Smarcel    printf("uwx_selftest_bsp_arithmetic: minus tests...\n");
389129059Smarcel    bsp = &bstore[161];
390129059Smarcel    for (i = 63; i >= 0; i--) {
391129059Smarcel	bsp--;
392129059Smarcel	r = (int)*bsp;
393129059Smarcel	if (r >= 1000)
394129059Smarcel	    r -= 1000;
395129059Smarcel	for (j = 0; j < 96; j++) {
396160157Smarcel	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, -j);
397129059Smarcel	    if (*p != (r - j)) {
398129059Smarcel		failed++;
399129059Smarcel		printf("%d [%08lx] - %d -> %08lx ",
400129059Smarcel				i, (unsigned int)bsp, j, (unsigned int)p);
401129059Smarcel		printf("(read %d instead of %d)\n", (int)*p, r - j);
402129059Smarcel	    }
403129059Smarcel	}
404129059Smarcel    }
405129059Smarcel
406129059Smarcel    return failed;
407115013Smarcel}
408160163Smarcel#endif
409