1/*	$NetBSD: platid_gen.c,v 1.9 2009/03/18 10:22:28 cegger Exp $	*/
2
3/*-
4 * Copyright (c) 1999
5 *         Shin Takemura and PocketBSD Project. 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, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the PocketBSD project
18 *	and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: platid_gen.c,v 1.9 2009/03/18 10:22:28 cegger Exp $");
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <strings.h>
43#include <unistd.h>
44
45#include "platid_gen.h"
46
47/*
48 * constants
49 */
50#define SEARCH_IGNORECASE	(1<<0)
51
52#define NMODES	2
53#define MAXNEST	4
54#define MAXLEN	1024
55
56enum { FORM_GENHDR, FORM_MASK_H, FORM_MASK_C, FORM_NAME_C, FORM_PARSE_ONLY };
57
58/*
59 * data type definitions
60 */
61struct genctx_t {
62	int num;
63	const char *alt;
64	const char *node_name[2];
65	char sym[MAXLEN];
66	char name[MAXLEN];
67} genctx[NMODES][MAXNEST];
68
69/*
70 * function prototypes
71 */
72void	gen_list(node_t *);
73void	gen_output(void);
74void	gen_header(void);
75void	gen_mask_h(void);
76void	gen_mask_c(void);
77void	gen_name_c(void);
78void	gen_comment(FILE *);
79void	enter(void);
80void	leave(void);
81
82/*
83 * global data
84 */
85node_t*	def_tree;
86int nest;
87int mode;
88FILE *fp_out;
89int form;
90int count;
91
92#define MODE_INVALID	-1
93#define MODE_CPU	0
94#define MODE_MACHINE	1
95char* mode_names[] = {
96	"CPU", "MACHINE", NULL
97};
98#define PREFIX	"PLATID"
99char* prefix_names[] = {
100	"CPU", "MACH",
101};
102char* shift_names[NMODES][MAXNEST] = {
103	{
104		"PLATID_CPU_ARCH_SHIFT",
105		"PLATID_CPU_SERIES_SHIFT",
106		"PLATID_CPU_MODEL_SHIFT",
107		"PLATID_CPU_SUBMODEL_SHIFT",
108	},
109	{
110		"PLATID_VENDOR_SHIFT",
111		"PLATID_SERIES_SHIFT",
112		"PLATID_MODEL_SHIFT",
113		"PLATID_SUBMODEL_SHIFT",
114	},
115};
116
117/*
118 * program entry
119 */
120int
121main(int argc, char *argv[])
122{
123	int i;
124
125	form = FORM_GENHDR;
126	fp_out = stdout;
127	count = 0;
128
129	for (i = 1; i < argc; i++) {
130		if (strcmp(argv[i], "-header") == 0) {
131			form = FORM_GENHDR;
132		} else if (strcmp(argv[i], "-mask_h") == 0) {
133			form = FORM_MASK_H;
134		} else if (strcmp(argv[i], "-mask_c") == 0) {
135			form = FORM_MASK_C;
136		} else if (strcmp(argv[i], "-name_c") == 0) {
137			form = FORM_NAME_C;
138		} else if (strcmp(argv[i], "-parse_only") == 0) {
139			form = FORM_PARSE_ONLY;
140		} else {
141		usage:
142			fprintf(stderr, "usage platid_gen <option>\n");
143			fprintf(stderr, "  option: -header\n");
144			fprintf(stderr, "          -mask_h\n");
145			fprintf(stderr, "          -mask_c\n");
146			fprintf(stderr, "          -name_c\n");
147			fprintf(stderr, "          -parse_only\n");
148			exit(1);
149		}
150	}
151
152	if (read_def()) {
153		exit(1);
154	}
155
156	if (form == FORM_PARSE_ONLY) {
157		dump_node("", def_tree);
158		exit (0);
159	}
160
161	gen_comment(fp_out);
162	switch (form) {
163	case FORM_GENHDR:
164		break;
165	case FORM_MASK_H:
166		break;
167	case FORM_MASK_C:
168		fprintf(fp_out, "#include <machine/platid.h>\n");
169		fprintf(fp_out, "#include <machine/platid_mask.h>\n");
170		break;
171	case FORM_NAME_C:
172		fprintf(fp_out, "#include <machine/platid.h>\n");
173		fprintf(fp_out, "#include <machine/platid_mask.h>\n");
174		fprintf(fp_out,"struct platid_name platid_name_table[] = {\n");
175		break;
176	}
177
178	nest = -1;
179	enter(); /* XXX */
180	mode = MODE_INVALID;
181	genctx[MODE_CPU][nest].alt = NULL;
182	genctx[MODE_MACHINE][nest].alt = NULL;
183	gen_list((node_t*)def_tree->ptr1);
184
185	switch (form) {
186	case FORM_GENHDR:
187	case FORM_MASK_H:
188	case FORM_MASK_C:
189		break;
190	case FORM_NAME_C:
191		fprintf(fp_out, "};\n");
192		fprintf(fp_out, "int platid_name_table_size = sizeof(platid_name_table)/sizeof(*platid_name_table);\n");
193		break;
194	}
195	fclose(fp_out);
196
197	exit(0);
198}
199
200int
201table_getnum(char **table, const char *s, int def, int opt)
202{
203	int num;
204
205	num = 0;
206	while (table[num]) {
207		int diff;
208		if (opt & SEARCH_IGNORECASE) {
209			diff = strcmp(table[num], s);
210		} else {
211			diff = strcasecmp(table[num], s);
212		}
213		if (diff == 0) {
214			return (num);
215		}
216		num++;
217	}
218	return def;
219}
220
221#define GET_MODE(s) \
222	table_getnum(mode_names, (s), MODE_INVALID, SEARCH_IGNORECASE)
223#define GET_ALT(s) \
224	table_getnum(mode_names, (s), MODE_INVALID, SEARCH_IGNORECASE)
225
226void
227enter(void)
228{
229	nest++;
230	if (MAXNEST <= nest) {
231		fprintf(stderr, "too much nest\n");
232		exit(1);
233	}
234	genctx[mode][nest].num = 0;
235	genctx[mode][nest].alt = NULL;
236	genctx[mode][nest].node_name[0] = NULL;
237	genctx[mode][nest].node_name[1] = NULL;
238	if (0 < nest) {
239		genctx[mode][nest].alt = genctx[mode][nest - 1].alt;
240	}
241}
242
243void
244leave(void)
245{
246	nest--;
247	if (nest < 0) {
248		fprintf(stderr, "internal error (nest=%d)\n", nest);
249		exit(1);
250	}
251}
252
253void
254gen_comment(FILE *fp)
255{
256	fprintf(fp, "/*\n");
257	fprintf(fp, " *  Do not edit.\n");
258	fprintf(fp, " *  This file is automatically generated by platid.awk.\n");
259	fprintf(fp, " */\n");
260}
261
262int
263gen_name(char *buf, struct genctx_t ctx[], int nest, int name, char *punct,
264    int ignr)
265{
266	int i;
267	buf[0] = '\0';
268	for (i = 0; i <= nest; i++) {
269		if (!(ignr <= i && nest != i)) {
270			if (i != 0) {
271				strcat(buf, punct);
272			}
273			strcat(buf, ctx[i].node_name[name]);
274		}
275	}
276}
277
278void
279gen_list(node_t* np)
280{
281	int i, t;
282
283	for ( ; np; np = np->link) {
284		switch (np->type) {
285		case N_LABEL:
286			if ((mode = GET_MODE(np->ptr1)) == MODE_INVALID) {
287				fprintf(stderr, "invalid mode '%s'\n",
288				    np->ptr1);
289				exit(1);
290			}
291			break;
292		case N_MODIFIER:
293			t = GET_ALT(np->ptr1);
294			if (t == MODE_INVALID) {
295				fprintf(stderr, "unknown alternater '%s'\n",
296				    np->ptr1);
297				exit(1);
298			}
299			if (t == mode) {
300				fprintf(stderr,
301				    "invalid alternater '%s' (ignored)\n",
302				    np->ptr1);
303				exit(1);
304			}
305			genctx[mode][nest].alt = np->ptr2;
306			break;
307		case N_ENTRY:
308			if (np->ptr2 == NULL) {
309				char buf[MAXLEN];
310				sprintf(buf, "%s%s",
311				    nest == 0 ? "" : " ",
312				    np->ptr1);
313		  		np->ptr2 = strdup(buf);
314				if (nest == 3)
315					np->val = 1;
316			}
317			touppers((char*)np->ptr1);
318
319			genctx[mode][nest].num++;
320		  	genctx[mode][nest].node_name[0] = np->ptr1;
321			genctx[mode][nest].node_name[1] = np->ptr2;
322			gen_name(genctx[mode][nest].sym, genctx[mode],
323			    nest, 0, "_", nest == 3 ? 2 : nest);
324			gen_name(genctx[mode][nest].name, genctx[mode],
325			    nest, 1, "", nest - np->val);
326			gen_output();
327			break;
328		case N_LIST:
329			enter();
330			gen_list((node_t*)np->ptr1);
331			leave();
332			break;
333		case N_DIRECTIVE:
334			fprintf(fp_out, "%s", np->ptr1);
335			break;
336		default:
337			fprintf(stderr, "internal error (type=%d)\n", np->type);
338			exit(1);
339			break;
340		}
341	}
342}
343
344void
345gen_output(void)
346{
347	switch (form) {
348	case FORM_GENHDR:
349		gen_header();
350		break;
351	case FORM_MASK_H:
352		gen_mask_h();
353		break;
354	case FORM_MASK_C:
355		gen_mask_c();
356		break;
357	case FORM_NAME_C:
358		gen_name_c();
359		break;
360	}
361}
362
363/*
364 * platid_generated.h
365 *
366 * #define PLATID_CPU_XXX_NUM	1
367 * #define PLATID_CPU_XXX	\
368 *   ((PLATID_CPU_XXX_NUM << PLATID_CPU_ARCH_SHIFT))
369 * #define PLATID_CPU_XXX_YYY	\
370 *   ((PLATID_CPU_XXX_YYY_NUM << PLATID_CPU_SERIES_SHIFT)| \
371 *     PLATID_CPU_XXX)
372 *
373 * #ifndef SPEC_PLATFORM
374 * #define SPEC_MACH_XXX
375 * #endif
376 * #define PLATID_MACH_XXX_NUM	1
377 * #define PLATID_MACH_XXX	\
378 *   ((PLATID_MACH_XXX_NUM << PLATID_MACH_ARCH_SHIFT))
379 * #define PLATID_MACH_XXX_YYY	\
380 *   ((PLATID_MACH_XXX_YYY_NUM << PLATID_MACH_SERIES_SHIFT)| \
381 *     PLATID_MACH_XXX)
382 */
383void
384gen_header(void)
385{
386	char *prefix = prefix_names[mode];
387	char *name = genctx[mode][nest].sym;
388
389	if (mode == MODE_MACHINE) {
390		fprintf(fp_out, "#ifndef SPEC_PLATFORM\n");
391		fprintf(fp_out, "#define %s_%s_%s\n", "SPEC", prefix, name);
392		fprintf(fp_out, "#endif /* !SPEC_PLATFORM */\n");
393	}
394	fprintf(fp_out, "#define %s_%s_%s_NUM\t%d\n", PREFIX, prefix, name,
395	    genctx[mode][nest].num);
396	fprintf(fp_out, "#define %s_%s_%s\t\\\n", PREFIX, prefix, name);
397	fprintf(fp_out, "  ((%s_%s_%s_NUM << %s)", PREFIX, prefix, name,
398	    shift_names[mode][nest]);
399	if (0 < nest) {
400		fprintf(fp_out, "| \\\n    %s_%s_%s",
401		    PREFIX, prefix, genctx[mode][nest - 1].sym);
402	}
403	fprintf(fp_out, ")\n");
404}
405
406/*
407 * platid_mask.h:
408 *
409 * extern platid_t platid_mask_CPU_MIPS;
410 * #ifdef PLATID_DEFINE_MASK_NICKNAME
411 * #  define GENERIC_MIPS ((int)&platid_mask_CPU_MIPS)
412 * #endif
413 */
414void
415gen_mask_h(void)
416{
417	char *name = genctx[mode][nest].sym;
418
419	fprintf(fp_out, "extern platid_t platid_mask_%s_%s;\n",
420	    prefix_names[mode], name);
421	fprintf(fp_out, "#ifdef PLATID_DEFINE_MASK_NICKNAME\n");
422	fprintf(fp_out, "#  define %s%s ((int)&platid_mask_%s_%s)\n",
423	    (mode == MODE_CPU)?"GENERIC_":"",
424	    name, prefix_names[mode], name);
425	fprintf(fp_out, "#endif\n");
426}
427
428/*
429 * platid_mask.c:
430 *
431 * platid_t platid_mask_CPU_MIPS = {{
432 * 	PLATID_CPU_MIPS,
433 *	PLATID_WILD
434 * }};
435 */
436void
437gen_mask_c(void)
438{
439	char *name = genctx[mode][nest].sym;
440
441	fprintf(fp_out, "platid_t platid_mask_%s_%s = {{\n",
442	    prefix_names[mode], name);
443	switch (mode) {
444	case MODE_CPU:
445		fprintf(fp_out, "\t%s_CPU_%s,\n", PREFIX, name);
446		if (genctx[mode][nest].alt == NULL)
447			fprintf(fp_out, "\t%s_WILD\n", PREFIX);
448		else
449			fprintf(fp_out, "\t%s_MACH_%s,\n", PREFIX,
450			    genctx[mode][nest].alt);
451		break;
452	case MODE_MACHINE:
453		if (genctx[mode][nest].alt == NULL)
454			fprintf(fp_out, "\t%s_WILD,\n", PREFIX);
455		else
456			fprintf(fp_out, "\t%s_CPU_%s,\n", PREFIX,
457			    genctx[mode][nest].alt);
458		fprintf(fp_out, "\t%s_MACH_%s\n", PREFIX, name);
459		break;
460	}
461	fprintf(fp_out, "}};\n");
462}
463
464/*
465 * platid_name.c:
466 */
467void
468gen_name_c(void)
469{
470	fprintf(fp_out, "\t{ &platid_mask_%s_%s,\n",
471	    prefix_names[mode], genctx[mode][nest].sym);
472	fprintf(fp_out, "\t TEXT(\"%s\") },\n", genctx[mode][nest].name);
473	count++;
474}
475