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#ifndef _KERNEL
26#include <stdlib.h>
27#endif
28
29#include "uwx_env.h"
30#include "uwx_scoreboard.h"
31#include "uwx_trace.h"
32
33#ifdef _KERNEL
34static unsigned short uwx_allocated;
35static struct uwx_scoreboard uwx_scoreboard[sizeof(uwx_allocated) << 3];
36
37static void
38free(struct uwx_scoreboard *p)
39{
40	int idx = p - uwx_scoreboard;
41	uwx_allocated &= ~(1 << idx);
42}
43
44static struct uwx_scoreboard *
45malloc(size_t sz)
46{
47	int idx;
48	if (sz != sizeof(struct uwx_scoreboard))
49		return (NULL);
50	for (idx = 0; idx < (sizeof(uwx_allocated) << 3); idx++) {
51		if ((uwx_allocated & (1 << idx)) == 0) {
52			uwx_allocated |= 1 << idx;
53			return (uwx_scoreboard + idx);
54		}
55	}
56	return (NULL);
57}
58#endif
59
60
61void uwx_prealloc_scoreboard(struct uwx_env *env, struct uwx_scoreboard *sb)
62{
63    sb->id = env->nscoreboards++;
64    sb->nextused = env->used_scoreboards;
65    sb->prealloc = 1;
66    env->used_scoreboards = sb;
67    TRACE_B_PREALLOC(sb->id)
68}
69
70struct uwx_scoreboard *uwx_alloc_scoreboard(struct uwx_env *env)
71{
72    struct uwx_scoreboard *sb;
73    int i;
74
75    if (env->free_scoreboards != 0) {
76	sb = env->free_scoreboards;
77	env->free_scoreboards = sb->nextfree;
78	TRACE_B_REUSE(sb->id)
79    }
80    else {
81	if (env->allocate_cb == 0)
82	    sb = (struct uwx_scoreboard *)
83			malloc(sizeof(struct uwx_scoreboard));
84	else
85	    sb = (struct uwx_scoreboard *)
86			(*env->allocate_cb)(sizeof(struct uwx_scoreboard));
87	if (sb == 0)
88	    return 0;
89	sb->id = env->nscoreboards++;
90	sb->nextused = env->used_scoreboards;
91	sb->prealloc = 0;
92	env->used_scoreboards = sb;
93	TRACE_B_ALLOC(sb->id)
94    }
95
96    sb->nextstack = 0;
97    sb->nextlabel = 0;
98    for (i = 0; i < env->nsbreg; i++)
99	sb->rstate[i] = UWX_DISP_NONE;
100    sb->rstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_BR(0));
101    sb->rstate[SBREG_PSP] = UWX_DISP_SPPLUS(0);
102    sb->rstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_AR_PFS);
103    sb->rstate[SBREG_PRIUNAT] = UWX_DISP_REG(UWX_REG_AR_UNAT);
104    sb->label = 0;
105    return sb;
106}
107
108static
109void uwx_reclaim_scoreboards(struct uwx_env *env)
110{
111    struct uwx_scoreboard *sb;
112
113    env->free_scoreboards = 0;
114    for (sb = env->used_scoreboards; sb != 0; sb = sb->nextused) {
115	sb->nextfree = env->free_scoreboards;
116	env->free_scoreboards = sb;
117    }
118    env->labeled_scoreboards = 0;
119}
120
121struct uwx_scoreboard *uwx_init_scoreboards(struct uwx_env *env)
122{
123    struct uwx_scoreboard *sb;
124
125    uwx_reclaim_scoreboards(env);
126    sb = uwx_alloc_scoreboard(env);
127    return sb;
128}
129
130struct uwx_scoreboard *uwx_new_scoreboard(
131    struct uwx_env *env,
132    struct uwx_scoreboard *prevsb)
133{
134    int i;
135    struct uwx_scoreboard *sb;
136
137    sb = uwx_alloc_scoreboard(env);
138    if (sb == 0)
139	return 0;
140    sb->nextstack = prevsb;
141    for (i = 0; i < env->nsbreg; i++)
142	sb->rstate[i] = prevsb->rstate[i];
143    return sb;
144}
145
146struct uwx_scoreboard *uwx_pop_scoreboards(
147    struct uwx_env *env,
148    struct uwx_scoreboard *sb,
149    int ecount)
150{
151    struct uwx_scoreboard *next;
152
153    while (ecount > 0) {
154	next = sb->nextstack;
155	TRACE_B_POP(sb->id)
156	sb->nextstack = 0;
157	sb->nextfree = env->free_scoreboards;
158	env->free_scoreboards = sb;
159	sb = next;
160	if (sb == 0)
161	    return 0;
162	ecount--;
163    }
164    return sb;
165}
166
167int uwx_label_scoreboard(
168    struct uwx_env *env,
169    struct uwx_scoreboard *sb,
170    int label)
171{
172    struct uwx_scoreboard *new;
173    struct uwx_scoreboard *back;
174    struct uwx_scoreboard *next;
175    int i;
176
177    TRACE_B_LABEL(label)
178
179    /* Copy the current stack, storing reverse links */
180    /* in the "nextstack" field. */
181
182    back = 0;
183    new = 0;
184    while (sb != 0) {
185	TRACE_B_LABEL_COPY(sb->id)
186	new = uwx_alloc_scoreboard(env);
187	if (new == 0)
188	    return UWX_ERR_NOMEM;
189	new->nextstack = back;
190	for (i = 0; i < env->nsbreg; i++)
191	    new->rstate[i] = sb->rstate[i];
192	sb = sb->nextstack;
193	back = new;
194    }
195
196    /* The "new" pointer now points to the bottom of the new stack, */
197    /* and the "nextstack" links lead towards the top. */
198    /* Now go back down the stack, reversing the stack links to their */
199    /* proper direction. */
200
201    back = 0;
202    while (new != 0) {
203	next = new->nextstack;
204	new->nextstack = back;
205	TRACE_B_LABEL_REVERSE(back, new)
206	back = new;
207	new = next;
208    }
209
210    /* The "back" pointer now points to the top of the stack. */
211
212    back->label = label;
213    back->nextlabel = env->labeled_scoreboards;
214    env->labeled_scoreboards = back;
215    return UWX_OK;
216}
217
218int uwx_copy_scoreboard(
219    struct uwx_env *env,
220    struct uwx_scoreboard *sb,
221    int label)
222{
223    struct uwx_scoreboard *next;
224    struct uwx_scoreboard *next2;
225    struct uwx_scoreboard *lsb;
226    struct uwx_scoreboard *new;
227    struct uwx_scoreboard *back;
228    int i;
229
230    TRACE_B_COPY(label, sb->id)
231
232    /* Free the existing stack. */
233
234    next = sb->nextstack;
235    while (next != 0) {
236	TRACE_B_COPY_FREE(next->id)
237	next2 = next->nextstack;
238	next->nextstack = 0;
239	next->nextfree = env->free_scoreboards;
240	env->free_scoreboards = next;
241	next = next2;
242    }
243
244    /* Find the scoreboard with the requested label. */
245
246    for (lsb = env->labeled_scoreboards; lsb != 0; lsb = lsb->nextlabel) {
247	if (lsb->label == label)
248	    break;
249    }
250
251    if (lsb == 0)
252	return UWX_ERR_UNDEFLABEL;
253
254    TRACE_B_COPY_FOUND(lsb->id)
255
256    /* Copy the labeled scoreboard. */
257
258    sb->nextstack = 0;
259    sb->nextlabel = 0;
260    for (i = 0; i < env->nsbreg; i++)
261	sb->rstate[i] = lsb->rstate[i];
262    sb->label = 0;
263
264    /* Now copy its stack, storing reverse links in the nextstack field. */
265
266    back = sb;
267    new = 0;
268    for (next = lsb->nextstack; next != 0; next = next->nextstack) {
269	TRACE_B_COPY_COPY(next->id)
270	new = uwx_alloc_scoreboard(env);
271	if (new == 0)
272	    return UWX_ERR_NOMEM;
273	new->nextstack = back;
274	for (i = 0; i < env->nsbreg; i++)
275	    new->rstate[i] = next->rstate[i];
276	back = new;
277    }
278
279    /* The "new" pointer now points to the bottom of the new stack, */
280    /* and the "nextstack" links lead towards the top. */
281    /* Now go back down the stack, reversing the nextstack links to their */
282    /* proper direction. */
283
284    back = 0;
285    while (new != 0) {
286	next = new->nextstack;
287	new->nextstack = back;
288	TRACE_B_COPY_REVERSE(back, new)
289	back = new;
290	new = next;
291    }
292
293    return UWX_OK;
294}
295
296void uwx_free_scoreboards(struct uwx_env *env)
297{
298    struct uwx_scoreboard *sb;
299    struct uwx_scoreboard *next;
300
301    for (sb = env->used_scoreboards; sb != 0; sb = next) {
302	TRACE_B_FREE(sb->id)
303	next = sb->nextused;
304	if (!sb->prealloc) {
305	    if (env->free_cb == 0)
306		free((void *)sb);
307	    else
308		(*env->free_cb)((void *)sb);
309	}
310    }
311    env->free_scoreboards = 0;
312    env->used_scoreboards = 0;
313    env->labeled_scoreboards = 0;
314}
315
316