xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm_symbol.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
1 /*
2  * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
3  *
4  * Copyright (c) 1997 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice immediately at the beginning of the file, without modification,
12  *    this list of conditions, and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *      $Id$
32  */
33 
34 
35 #include <sys/types.h>
36 
37 #include <db.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sysexits.h>
43 
44 #include "symbol.h"
45 #include "aic7xxx_asm.h"
46 
47 static DB *symtable;
48 
49 symbol_t *
50 symbol_create(name)
51 	char *name;
52 {
53 	symbol_t *new_symbol;
54 
55 	new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
56 	if (new_symbol == NULL) {
57 		perror("Unable to create new symbol");
58 		exit(EX_SOFTWARE);
59 	}
60 	memset(new_symbol, 0, sizeof(*new_symbol));
61 	new_symbol->name = strdup(name);
62 	new_symbol->type = UNINITIALIZED;
63 	return (new_symbol);
64 }
65 
66 void
67 symbol_delete(symbol)
68 	symbol_t *symbol;
69 {
70 	if (symtable != NULL) {
71 		DBT	 key;
72 
73 		key.data = symbol->name;
74 		key.size = strlen(symbol->name);
75 		symtable->del(symtable, &key, /*flags*/0);
76 	}
77 	switch(symbol->type) {
78 	case SCBLOC:
79 	case SRAMLOC:
80 	case REGISTER:
81 		if (symbol->info.rinfo != NULL)
82 			free(symbol->info.rinfo);
83 		break;
84 	case ALIAS:
85 		if (symbol->info.ainfo != NULL)
86 			free(symbol->info.ainfo);
87 		break;
88 	case MASK:
89 	case BIT:
90 		if (symbol->info.minfo != NULL) {
91 			symlist_free(&symbol->info.minfo->symrefs);
92 			free(symbol->info.minfo);
93 		}
94 		break;
95 	case CONST:
96 		if (symbol->info.cinfo != NULL)
97 			free(symbol->info.cinfo);
98 		break;
99 	case LABEL:
100 		if (symbol->info.linfo != NULL)
101 			free(symbol->info.linfo);
102 		break;
103 	case UNINITIALIZED:
104 	default:
105 		break;
106 	}
107 	free(symbol->name);
108 	free(symbol);
109 }
110 
111 void
112 symtable_open()
113 {
114 	symtable = dbopen(/*filename*/NULL,
115 			  O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
116 			  /*openinfo*/NULL);
117 
118 	if (symtable == NULL) {
119 		perror("Symbol table creation failed");
120 		exit(EX_SOFTWARE);
121 		/* NOTREACHED */
122 	}
123 }
124 
125 void
126 symtable_close()
127 {
128 	if (symtable != NULL) {
129 		DBT	 key;
130 		DBT	 data;
131 
132 		while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
133 			symbol_t *cursym;
134 
135 			cursym = *(symbol_t **)data.data;
136 			symbol_delete(cursym);
137 		}
138 		symtable->close(symtable);
139 	}
140 }
141 
142 /*
143  * The semantics of get is to return an uninitialized symbol entry
144  * if a lookup fails.
145  */
146 symbol_t *
147 symtable_get(name)
148 	char *name;
149 {
150 	DBT	key;
151 	DBT	data;
152 	int	retval;
153 
154 	key.data = (void *)name;
155 	key.size = strlen(name);
156 
157 	if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
158 		if (retval == -1) {
159 			perror("Symbol table get operation failed");
160 			exit(EX_SOFTWARE);
161 			/* NOTREACHED */
162 		} else if (retval == 1) {
163 			/* Symbol wasn't found, so create a new one */
164 			symbol_t *new_symbol;
165 
166 			new_symbol = symbol_create(name);
167 			data.data = &new_symbol;
168 			data.size = sizeof(new_symbol);
169 			if (symtable->put(symtable, &key, &data,
170 					  /*flags*/0) !=0) {
171 				perror("Symtable put failed");
172 				exit(EX_SOFTWARE);
173 			}
174 			return (new_symbol);
175 		} else {
176 			perror("Unexpected return value from db get routine");
177 			exit(EX_SOFTWARE);
178 			/* NOTREACHED */
179 		}
180 	}
181 	return (*(symbol_t **)data.data);
182 }
183 
184 symbol_node_t *
185 symlist_search(symlist, symname)
186 	symlist_t *symlist;
187 	char	  *symname;
188 {
189 	symbol_node_t *curnode;
190 
191 	curnode = symlist->slh_first;
192 	while(curnode != NULL) {
193 		if (strcmp(symname, curnode->symbol->name) == 0)
194 			break;
195 		curnode = curnode->links.sle_next;
196 	}
197 	return (curnode);
198 }
199 
200 void
201 symlist_add(symlist, symbol, how)
202 	symlist_t *symlist;
203 	symbol_t  *symbol;
204 	int	  how;
205 {
206 	symbol_node_t *newnode;
207 
208 	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
209 	if (newnode == NULL) {
210 		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
211 		/* NOTREACHED */
212 	}
213 	newnode->symbol = symbol;
214 	if (how == SYMLIST_SORT) {
215 		symbol_node_t *curnode;
216 		int mask;
217 
218 		mask = FALSE;
219 		switch(symbol->type) {
220 		case REGISTER:
221 		case SCBLOC:
222 		case SRAMLOC:
223 			break;
224 		case BIT:
225 		case MASK:
226 			mask = TRUE;
227 			break;
228 		default:
229 			stop("symlist_add: Invalid symbol type for sorting",
230 			     EX_SOFTWARE);
231 			/* NOTREACHED */
232 		}
233 
234 		curnode = symlist->slh_first;
235 		if (curnode == NULL
236 		 || (mask && (curnode->symbol->info.minfo->mask >
237 		              newnode->symbol->info.minfo->mask))
238 		 || (!mask && (curnode->symbol->info.rinfo->address >
239 		               newnode->symbol->info.rinfo->address))) {
240 			SLIST_INSERT_HEAD(symlist, newnode, links);
241 			return;
242 		}
243 
244 		while (1) {
245 			if (curnode->links.sle_next == NULL) {
246 				SLIST_INSERT_AFTER(curnode, newnode,
247 						   links);
248 				break;
249 			} else {
250 				symbol_t *cursymbol;
251 
252 				cursymbol = curnode->links.sle_next->symbol;
253 				if ((mask && (cursymbol->info.minfo->mask >
254 				              symbol->info.minfo->mask))
255 				 || (!mask &&(cursymbol->info.rinfo->address >
256 				              symbol->info.rinfo->address))){
257 					SLIST_INSERT_AFTER(curnode, newnode,
258 							   links);
259 					break;
260 				}
261 			}
262 			curnode = curnode->links.sle_next;
263 		}
264 	} else {
265 		SLIST_INSERT_HEAD(symlist, newnode, links);
266 	}
267 }
268 
269 void
270 symlist_free(symlist)
271 	symlist_t *symlist;
272 {
273 	symbol_node_t *node1, *node2;
274 
275 	node1 = symlist->slh_first;
276 	while (node1 != NULL) {
277 		node2 = node1->links.sle_next;
278 		free(node1);
279 		node1 = node2;
280 	}
281 	SLIST_INIT(symlist);
282 }
283 
284 void
285 symlist_merge(symlist_dest, symlist_src1, symlist_src2)
286 	symlist_t *symlist_dest;
287 	symlist_t *symlist_src1;
288 	symlist_t *symlist_src2;
289 {
290 	symbol_node_t *node;
291 
292 	*symlist_dest = *symlist_src1;
293 	while((node = symlist_src2->slh_first) != NULL) {
294 		SLIST_REMOVE_HEAD(symlist_src2, links);
295 		SLIST_INSERT_HEAD(symlist_dest, node, links);
296 	}
297 
298 	/* These are now empty */
299 	SLIST_INIT(symlist_src1);
300 	SLIST_INIT(symlist_src2);
301 }
302 
303 void
304 symtable_dump(ofile)
305 	FILE *ofile;
306 {
307 	/*
308 	 * Sort the registers by address with a simple insertion sort.
309 	 * Put bitmasks next to the first register that defines them.
310 	 * Put constants at the end.
311 	 */
312 	symlist_t registers;
313 	symlist_t masks;
314 	symlist_t constants;
315 	symlist_t aliases;
316 
317 	SLIST_INIT(&registers);
318 	SLIST_INIT(&masks);
319 	SLIST_INIT(&constants);
320 	SLIST_INIT(&aliases);
321 
322 	if (symtable != NULL) {
323 		DBT	 key;
324 		DBT	 data;
325 		int	 flag = R_FIRST;
326 
327 		while (symtable->seq(symtable, &key, &data, flag) == 0) {
328 			symbol_t *cursym;
329 
330 			cursym = *(symbol_t **)data.data;
331 			switch(cursym->type) {
332 			case REGISTER:
333 			case SCBLOC:
334 			case SRAMLOC:
335 				symlist_add(&registers, cursym, SYMLIST_SORT);
336 				break;
337 			case MASK:
338 			case BIT:
339 				symlist_add(&masks, cursym, SYMLIST_SORT);
340 				break;
341 			case CONST:
342 				if (cursym->info.cinfo->define == FALSE) {
343 					symlist_add(&constants, cursym,
344 						    SYMLIST_INSERT_HEAD);
345 				}
346 				break;
347 			case ALIAS:
348 				symlist_add(&aliases, cursym,
349 					    SYMLIST_INSERT_HEAD);
350 			default:
351 				break;
352 			}
353 			flag = R_NEXT;
354 		}
355 
356 		/* Put in the masks and bits */
357 		while (masks.slh_first != NULL) {
358 			symbol_node_t *curnode;
359 			symbol_node_t *regnode;
360 			char *regname;
361 
362 			curnode = masks.slh_first;
363 			SLIST_REMOVE_HEAD(&masks, links);
364 
365 			regnode =
366 			    curnode->symbol->info.minfo->symrefs.slh_first;
367 			regname = regnode->symbol->name;
368 			regnode = symlist_search(&registers, regname);
369 			SLIST_INSERT_AFTER(regnode, curnode, links);
370 		}
371 
372 		/* Add the aliases */
373 		while (aliases.slh_first != NULL) {
374 			symbol_node_t *curnode;
375 			symbol_node_t *regnode;
376 			char *regname;
377 
378 			curnode = aliases.slh_first;
379 			SLIST_REMOVE_HEAD(&aliases, links);
380 
381 			regname = curnode->symbol->info.ainfo->parent->name;
382 			regnode = symlist_search(&registers, regname);
383 			SLIST_INSERT_AFTER(regnode, curnode, links);
384 		}
385 
386 		/* Output what we have */
387 		fprintf(ofile,
388 "/*
389   * DO NOT EDIT - This file is automatically generated.
390   */\n");
391 		while (registers.slh_first != NULL) {
392 			symbol_node_t *curnode;
393 			u_int8_t value;
394 			char *tab_str;
395 			char *tab_str2;
396 
397 			curnode = registers.slh_first;
398 			SLIST_REMOVE_HEAD(&registers, links);
399 			switch(curnode->symbol->type) {
400 			case REGISTER:
401 			case SCBLOC:
402 			case SRAMLOC:
403 				fprintf(ofile, "\n");
404 				value = curnode->symbol->info.rinfo->address;
405 				tab_str = "\t";
406 				tab_str2 = "\t\t";
407 				break;
408 			case ALIAS:
409 			{
410 				symbol_t *parent;
411 
412 				parent = curnode->symbol->info.ainfo->parent;
413 				value = parent->info.rinfo->address;
414 				tab_str = "\t";
415 				tab_str2 = "\t\t";
416 				break;
417 			}
418 			case MASK:
419 			case BIT:
420 				value = curnode->symbol->info.minfo->mask;
421 				tab_str = "\t\t";
422 				tab_str2 = "\t";
423 				break;
424 			default:
425 				value = 0; /* Quiet compiler */
426 				tab_str = NULL;
427 				tab_str2 = NULL;
428 				stop("symtable_dump: Invalid symbol type "
429 				     "encountered", EX_SOFTWARE);
430 				break;
431 			}
432 			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
433 				tab_str, curnode->symbol->name, tab_str2,
434 				value);
435 			free(curnode);
436 		}
437 		fprintf(ofile, "\n\n");
438 
439 		while (constants.slh_first != NULL) {
440 			symbol_node_t *curnode;
441 
442 			curnode = constants.slh_first;
443 			SLIST_REMOVE_HEAD(&constants, links);
444 			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
445 				curnode->symbol->name,
446 				curnode->symbol->info.cinfo->value);
447 			free(curnode);
448 		}
449 	}
450 }
451 
452