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
25160163Smarcel#ifndef _KERNEL
26115013Smarcel#include <stdlib.h>
27160163Smarcel#endif
28115013Smarcel
29115013Smarcel#include "uwx_env.h"
30115013Smarcel#include "uwx_scoreboard.h"
31115013Smarcel#include "uwx_trace.h"
32115013Smarcel
33160163Smarcel#ifdef _KERNEL
34160163Smarcelstatic unsigned short uwx_allocated;
35160163Smarcelstatic struct uwx_scoreboard uwx_scoreboard[sizeof(uwx_allocated) << 3];
36115013Smarcel
37160163Smarcelstatic void
38160163Smarcelfree(struct uwx_scoreboard *p)
39160163Smarcel{
40160163Smarcel	int idx = p - uwx_scoreboard;
41160163Smarcel	uwx_allocated &= ~(1 << idx);
42160163Smarcel}
43160163Smarcel
44160163Smarcelstatic struct uwx_scoreboard *
45160163Smarcelmalloc(size_t sz)
46160163Smarcel{
47160163Smarcel	int idx;
48160163Smarcel	if (sz != sizeof(struct uwx_scoreboard))
49160163Smarcel		return (NULL);
50160163Smarcel	for (idx = 0; idx < (sizeof(uwx_allocated) << 3); idx++) {
51160163Smarcel		if ((uwx_allocated & (1 << idx)) == 0) {
52160163Smarcel			uwx_allocated |= 1 << idx;
53160163Smarcel			return (uwx_scoreboard + idx);
54160163Smarcel		}
55160163Smarcel	}
56160163Smarcel	return (NULL);
57160163Smarcel}
58160163Smarcel#endif
59160163Smarcel
60160163Smarcel
61160157Smarcelvoid uwx_prealloc_scoreboard(struct uwx_env *env, struct uwx_scoreboard *sb)
62129059Smarcel{
63160157Smarcel    sb->id = env->nscoreboards++;
64160157Smarcel    sb->nextused = env->used_scoreboards;
65160157Smarcel    sb->prealloc = 1;
66160157Smarcel    env->used_scoreboards = sb;
67160157Smarcel    TRACE_B_PREALLOC(sb->id)
68129059Smarcel}
69129059Smarcel
70115013Smarcelstruct uwx_scoreboard *uwx_alloc_scoreboard(struct uwx_env *env)
71115013Smarcel{
72115013Smarcel    struct uwx_scoreboard *sb;
73115013Smarcel    int i;
74115013Smarcel
75115013Smarcel    if (env->free_scoreboards != 0) {
76115013Smarcel	sb = env->free_scoreboards;
77115013Smarcel	env->free_scoreboards = sb->nextfree;
78115013Smarcel	TRACE_B_REUSE(sb->id)
79115013Smarcel    }
80115013Smarcel    else {
81115013Smarcel	if (env->allocate_cb == 0)
82115013Smarcel	    sb = (struct uwx_scoreboard *)
83115013Smarcel			malloc(sizeof(struct uwx_scoreboard));
84115013Smarcel	else
85115013Smarcel	    sb = (struct uwx_scoreboard *)
86115013Smarcel			(*env->allocate_cb)(sizeof(struct uwx_scoreboard));
87115013Smarcel	if (sb == 0)
88115013Smarcel	    return 0;
89115013Smarcel	sb->id = env->nscoreboards++;
90115013Smarcel	sb->nextused = env->used_scoreboards;
91160157Smarcel	sb->prealloc = 0;
92115013Smarcel	env->used_scoreboards = sb;
93115013Smarcel	TRACE_B_ALLOC(sb->id)
94115013Smarcel    }
95115013Smarcel
96115013Smarcel    sb->nextstack = 0;
97115013Smarcel    sb->nextlabel = 0;
98115013Smarcel    for (i = 0; i < env->nsbreg; i++)
99115013Smarcel	sb->rstate[i] = UWX_DISP_NONE;
100115013Smarcel    sb->rstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_BR(0));
101115013Smarcel    sb->rstate[SBREG_PSP] = UWX_DISP_SPPLUS(0);
102120925Smarcel    sb->rstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_AR_PFS);
103120925Smarcel    sb->rstate[SBREG_PRIUNAT] = UWX_DISP_REG(UWX_REG_AR_UNAT);
104115013Smarcel    sb->label = 0;
105115013Smarcel    return sb;
106115013Smarcel}
107115013Smarcel
108160163Smarcelstatic
109115013Smarcelvoid uwx_reclaim_scoreboards(struct uwx_env *env)
110115013Smarcel{
111115013Smarcel    struct uwx_scoreboard *sb;
112115013Smarcel
113115013Smarcel    env->free_scoreboards = 0;
114115013Smarcel    for (sb = env->used_scoreboards; sb != 0; sb = sb->nextused) {
115115013Smarcel	sb->nextfree = env->free_scoreboards;
116115013Smarcel	env->free_scoreboards = sb;
117115013Smarcel    }
118115013Smarcel    env->labeled_scoreboards = 0;
119115013Smarcel}
120115013Smarcel
121115013Smarcelstruct uwx_scoreboard *uwx_init_scoreboards(struct uwx_env *env)
122115013Smarcel{
123115013Smarcel    struct uwx_scoreboard *sb;
124115013Smarcel
125115013Smarcel    uwx_reclaim_scoreboards(env);
126115013Smarcel    sb = uwx_alloc_scoreboard(env);
127115013Smarcel    return sb;
128115013Smarcel}
129115013Smarcel
130115013Smarcelstruct uwx_scoreboard *uwx_new_scoreboard(
131115013Smarcel    struct uwx_env *env,
132115013Smarcel    struct uwx_scoreboard *prevsb)
133115013Smarcel{
134115013Smarcel    int i;
135115013Smarcel    struct uwx_scoreboard *sb;
136115013Smarcel
137115013Smarcel    sb = uwx_alloc_scoreboard(env);
138115013Smarcel    if (sb == 0)
139115013Smarcel	return 0;
140115013Smarcel    sb->nextstack = prevsb;
141115013Smarcel    for (i = 0; i < env->nsbreg; i++)
142115013Smarcel	sb->rstate[i] = prevsb->rstate[i];
143115013Smarcel    return sb;
144115013Smarcel}
145115013Smarcel
146115013Smarcelstruct uwx_scoreboard *uwx_pop_scoreboards(
147115013Smarcel    struct uwx_env *env,
148115013Smarcel    struct uwx_scoreboard *sb,
149115013Smarcel    int ecount)
150115013Smarcel{
151115013Smarcel    struct uwx_scoreboard *next;
152115013Smarcel
153115013Smarcel    while (ecount > 0) {
154115013Smarcel	next = sb->nextstack;
155115013Smarcel	TRACE_B_POP(sb->id)
156115013Smarcel	sb->nextstack = 0;
157115013Smarcel	sb->nextfree = env->free_scoreboards;
158115013Smarcel	env->free_scoreboards = sb;
159115013Smarcel	sb = next;
160115013Smarcel	if (sb == 0)
161115013Smarcel	    return 0;
162115013Smarcel	ecount--;
163115013Smarcel    }
164115013Smarcel    return sb;
165115013Smarcel}
166115013Smarcel
167115013Smarcelint uwx_label_scoreboard(
168115013Smarcel    struct uwx_env *env,
169115013Smarcel    struct uwx_scoreboard *sb,
170115013Smarcel    int label)
171115013Smarcel{
172115013Smarcel    struct uwx_scoreboard *new;
173115013Smarcel    struct uwx_scoreboard *back;
174115013Smarcel    struct uwx_scoreboard *next;
175115013Smarcel    int i;
176115013Smarcel
177115013Smarcel    TRACE_B_LABEL(label)
178115013Smarcel
179115013Smarcel    /* Copy the current stack, storing reverse links */
180115013Smarcel    /* in the "nextstack" field. */
181115013Smarcel
182115013Smarcel    back = 0;
183160163Smarcel    new = 0;
184115013Smarcel    while (sb != 0) {
185115013Smarcel	TRACE_B_LABEL_COPY(sb->id)
186115013Smarcel	new = uwx_alloc_scoreboard(env);
187115013Smarcel	if (new == 0)
188115013Smarcel	    return UWX_ERR_NOMEM;
189115013Smarcel	new->nextstack = back;
190115013Smarcel	for (i = 0; i < env->nsbreg; i++)
191115013Smarcel	    new->rstate[i] = sb->rstate[i];
192115013Smarcel	sb = sb->nextstack;
193115013Smarcel	back = new;
194115013Smarcel    }
195115013Smarcel
196115013Smarcel    /* The "new" pointer now points to the bottom of the new stack, */
197115013Smarcel    /* and the "nextstack" links lead towards the top. */
198115013Smarcel    /* Now go back down the stack, reversing the stack links to their */
199115013Smarcel    /* proper direction. */
200115013Smarcel
201115013Smarcel    back = 0;
202115013Smarcel    while (new != 0) {
203115013Smarcel	next = new->nextstack;
204115013Smarcel	new->nextstack = back;
205115013Smarcel	TRACE_B_LABEL_REVERSE(back, new)
206115013Smarcel	back = new;
207115013Smarcel	new = next;
208115013Smarcel    }
209115013Smarcel
210115013Smarcel    /* The "back" pointer now points to the top of the stack. */
211115013Smarcel
212115013Smarcel    back->label = label;
213115013Smarcel    back->nextlabel = env->labeled_scoreboards;
214115013Smarcel    env->labeled_scoreboards = back;
215115013Smarcel    return UWX_OK;
216115013Smarcel}
217115013Smarcel
218115013Smarcelint uwx_copy_scoreboard(
219115013Smarcel    struct uwx_env *env,
220115013Smarcel    struct uwx_scoreboard *sb,
221115013Smarcel    int label)
222115013Smarcel{
223115013Smarcel    struct uwx_scoreboard *next;
224115013Smarcel    struct uwx_scoreboard *next2;
225115013Smarcel    struct uwx_scoreboard *lsb;
226115013Smarcel    struct uwx_scoreboard *new;
227115013Smarcel    struct uwx_scoreboard *back;
228115013Smarcel    int i;
229115013Smarcel
230115013Smarcel    TRACE_B_COPY(label, sb->id)
231115013Smarcel
232115013Smarcel    /* Free the existing stack. */
233115013Smarcel
234115013Smarcel    next = sb->nextstack;
235115013Smarcel    while (next != 0) {
236115013Smarcel	TRACE_B_COPY_FREE(next->id)
237115013Smarcel	next2 = next->nextstack;
238115013Smarcel	next->nextstack = 0;
239115013Smarcel	next->nextfree = env->free_scoreboards;
240115013Smarcel	env->free_scoreboards = next;
241115013Smarcel	next = next2;
242115013Smarcel    }
243115013Smarcel
244115013Smarcel    /* Find the scoreboard with the requested label. */
245115013Smarcel
246115013Smarcel    for (lsb = env->labeled_scoreboards; lsb != 0; lsb = lsb->nextlabel) {
247115013Smarcel	if (lsb->label == label)
248115013Smarcel	    break;
249115013Smarcel    }
250115013Smarcel
251115013Smarcel    if (lsb == 0)
252115013Smarcel	return UWX_ERR_UNDEFLABEL;
253115013Smarcel
254115013Smarcel    TRACE_B_COPY_FOUND(lsb->id)
255115013Smarcel
256115013Smarcel    /* Copy the labeled scoreboard. */
257115013Smarcel
258115013Smarcel    sb->nextstack = 0;
259115013Smarcel    sb->nextlabel = 0;
260115013Smarcel    for (i = 0; i < env->nsbreg; i++)
261115013Smarcel	sb->rstate[i] = lsb->rstate[i];
262115013Smarcel    sb->label = 0;
263115013Smarcel
264115013Smarcel    /* Now copy its stack, storing reverse links in the nextstack field. */
265115013Smarcel
266115013Smarcel    back = sb;
267160163Smarcel    new = 0;
268115013Smarcel    for (next = lsb->nextstack; next != 0; next = next->nextstack) {
269115013Smarcel	TRACE_B_COPY_COPY(next->id)
270115013Smarcel	new = uwx_alloc_scoreboard(env);
271115013Smarcel	if (new == 0)
272115013Smarcel	    return UWX_ERR_NOMEM;
273115013Smarcel	new->nextstack = back;
274115013Smarcel	for (i = 0; i < env->nsbreg; i++)
275115013Smarcel	    new->rstate[i] = next->rstate[i];
276115013Smarcel	back = new;
277115013Smarcel    }
278115013Smarcel
279115013Smarcel    /* The "new" pointer now points to the bottom of the new stack, */
280115013Smarcel    /* and the "nextstack" links lead towards the top. */
281115013Smarcel    /* Now go back down the stack, reversing the nextstack links to their */
282115013Smarcel    /* proper direction. */
283115013Smarcel
284115013Smarcel    back = 0;
285115013Smarcel    while (new != 0) {
286115013Smarcel	next = new->nextstack;
287115013Smarcel	new->nextstack = back;
288115013Smarcel	TRACE_B_COPY_REVERSE(back, new)
289115013Smarcel	back = new;
290115013Smarcel	new = next;
291115013Smarcel    }
292115013Smarcel
293115013Smarcel    return UWX_OK;
294115013Smarcel}
295115013Smarcel
296115013Smarcelvoid uwx_free_scoreboards(struct uwx_env *env)
297115013Smarcel{
298115013Smarcel    struct uwx_scoreboard *sb;
299115013Smarcel    struct uwx_scoreboard *next;
300115013Smarcel
301115013Smarcel    for (sb = env->used_scoreboards; sb != 0; sb = next) {
302115013Smarcel	TRACE_B_FREE(sb->id)
303115013Smarcel	next = sb->nextused;
304160157Smarcel	if (!sb->prealloc) {
305160157Smarcel	    if (env->free_cb == 0)
306160157Smarcel		free((void *)sb);
307160157Smarcel	    else
308160157Smarcel		(*env->free_cb)((void *)sb);
309160157Smarcel	}
310115013Smarcel    }
311115013Smarcel    env->free_scoreboards = 0;
312115013Smarcel    env->used_scoreboards = 0;
313115013Smarcel    env->labeled_scoreboards = 0;
314115013Smarcel}
315115013Smarcel
316