1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Register Table Generator			File: makereg.c
5    *
6    *  Author:  Mitch Lichtenberg
7    *
8    *  Warning: don't eat your lunch before reading this program.
9    *  It's nasty!
10    *
11    *  This program generates tables of SOC registers and values
12    *  that are easy for us to display.
13    *
14    *********************************************************************
15    *
16    *  Copyright 2000,2001,2002,2003
17    *  Broadcom Corporation. All rights reserved.
18    *
19    *  This software is furnished under license and may be used and
20    *  copied only in accordance with the following terms and
21    *  conditions.  Subject to these conditions, you may download,
22    *  copy, install, use, modify and distribute modified or unmodified
23    *  copies of this software in source and/or binary form.  No title
24    *  or ownership is transferred hereby.
25    *
26    *  1) Any source code used, modified or distributed must reproduce
27    *     and retain this copyright notice and list of conditions
28    *     as they appear in the source file.
29    *
30    *  2) No right is granted to use any trade name, trademark, or
31    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
32    *     name may not be used to endorse or promote products derived
33    *     from this software without the prior written permission of
34    *     Broadcom Corporation.
35    *
36    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
37    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
38    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
39    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
40    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
41    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
42    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
44    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
45    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
46    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
47    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
48    *     THE POSSIBILITY OF SUCH DAMAGE.
49    ********************************************************************* */
50
51#include <ctype.h>
52#include <stdio.h>
53#include <string.h>
54#include <malloc.h>
55#include <stdlib.h>
56
57#if defined(_MSC_VER) || defined(__CYGWIN__)
58#define TEXTMODE "t"
59#else
60#define TEXTMODE ""
61#endif
62
63#define FALSE 0
64#define TRUE 1
65
66typedef struct Cons {
67    char *str;
68    int num;
69} CONS;
70
71typedef struct RegInfo {
72    unsigned int reg_mask;
73    char *reg_agent;
74    int reg_agentidx;
75    char *reg_addr;
76    char *reg_inst;
77    char *reg_subinst;
78    char *reg_printfunc;
79    char *reg_description;
80} REGINFO;
81
82typedef struct ConstInfo {
83    char *name;
84    unsigned int value;
85} CONSTINFO;
86
87#define MAXCONST 256
88CONSTINFO constants[MAXCONST];
89int constcnt = 0;
90
91#define MAXREGS 5000
92REGINFO allregs[MAXREGS];
93int regcnt = 0;
94
95int maskcnt = 0;
96
97#define MAXAGENTS 64
98char *agentnames[MAXAGENTS];
99int agentcnt;
100
101#define CMD_AGENT	1
102#define CMD_ENDAGENT	2
103#define CMD_AGENT_NOMASK 3
104
105CONS commands[] = {
106    {"!agent",CMD_AGENT},
107    {"!agent_nomask",CMD_AGENT_NOMASK},
108    {"!endagent",CMD_ENDAGENT},
109    {NULL,0}};
110
111static int assoc(CONS *list,char *str)
112{
113    while (list->str) {
114	if (strcmp(list->str,str) == 0) return list->num;
115	list++;
116	}
117
118    return -1;
119}
120
121static char *gettoken(char **ptr)
122{
123    char *p = *ptr;
124    char *ret;
125
126    /* skip white space */
127
128    while (*p && isspace(*p)) p++;
129    ret = p;
130
131    /* check for end of string */
132
133    if (!*p) {
134	*ptr = p;
135	return NULL;
136	}
137
138    /* skip non-whitespace */
139
140    while (*p) {
141	if (isspace(*p)) break;
142
143	/* do quoted strings */
144
145	if (*p == '"') {
146	    p++;
147	    ret = p;
148	    while (*p && (*p != '"')) p++;
149	    if (*p == '"') *p = '\0';
150	    }
151
152        p++;
153
154	}
155
156    if (*p) {
157        *p++ = '\0';
158        }
159    *ptr = p;
160
161    return ret;
162}
163
164static int readline(FILE *str,char *dest,int destlen)
165{
166    char *x;
167
168    for (;;) {
169	if (!fgets(dest,destlen,str)) return -1;
170	if ((x = strchr(dest,'\n')) != NULL) *x = '\0';
171	if (dest[0] == '\0') continue;
172	if (dest[0] == ';') continue;
173	break;
174	}
175
176    return 0;
177}
178
179
180static void fatal(char *str,char *val)
181{
182    fprintf(stderr,"fatal error: %s %s\n",str,val ? val : "");
183    exit(1);
184}
185
186static unsigned int newmask(void)
187{
188    int res;
189
190    res = maskcnt;
191
192    if (maskcnt == 32) {
193	fatal("Out of mask bits",NULL);
194	}
195
196    maskcnt++;
197
198    return 1<<res;
199}
200
201static void addconst(char *name,unsigned int val)
202{
203    if (constcnt == MAXCONST) {
204	fatal("Out of constant space",NULL);
205	}
206
207    constants[constcnt].name = strdup(name);
208    constants[constcnt].value = val;
209
210    constcnt++;
211}
212
213static void addreg(
214    char *agentname,
215    int agentidx,
216    unsigned long mask,
217    char *addr,
218    char *inst,
219    char *subinst,
220    char *printfunc,
221    char *description)
222{
223    allregs[regcnt].reg_mask = mask;
224    allregs[regcnt].reg_addr = strdup(addr);
225    allregs[regcnt].reg_agent = strdup(agentname);
226    allregs[regcnt].reg_agentidx = agentidx;
227    allregs[regcnt].reg_inst = strdup(inst);
228    allregs[regcnt].reg_subinst = strdup(subinst);
229    allregs[regcnt].reg_printfunc = strdup(printfunc);
230    allregs[regcnt].reg_description = strdup(description);
231    regcnt++;
232}
233
234
235static void macroexpand(char *instr,char *exp,char *outstr)
236{
237    while (*instr) {
238	if (*instr == '$') {
239	    strcpy(outstr,exp);
240	    outstr += strlen(outstr);
241	    instr++;
242	    }
243	else {
244	    *outstr++ = *instr++;
245	    }
246	}
247
248    *outstr = '\0';
249}
250
251
252static void doagentcmd(FILE *str,char *line,int nomask)
253{
254    char *agentname;
255    char *instances;
256    char *inst;
257    char *ptr;
258    char regline[500];
259    char cumlname[100];
260    REGINFO regs[100];
261    char temp[20];
262    int rmax = 0;
263    int idx;
264    unsigned int cumlmask;
265    int agentidx;
266
267    agentname = gettoken(&line);
268    instances = gettoken(&line);
269    if (!instances) {
270	strcpy(temp,"*");
271	instances = temp;
272	}
273
274    fprintf(stderr,"Agent %s Instances %s\n",agentname,instances);
275
276    if (agentcnt == MAXAGENTS) {
277	fatal("Out of agent slots\n",NULL);
278	}
279
280    agentnames[agentcnt] = strdup(agentname);
281    agentidx = agentcnt;
282    agentcnt++;
283
284    regline[0] = '\0';
285
286    while ((readline(str,regline,sizeof(regline)) >= 0) && (rmax < 100)) {
287	char *atext,*subinst,*pfunc,*descr;
288
289	if (regline[0] == '!') break;
290
291	ptr = regline;
292	atext = gettoken(&ptr);
293	subinst = gettoken(&ptr);
294	pfunc = gettoken(&ptr);
295	descr = gettoken(&ptr);
296
297	if (!descr) {
298	    fatal("Missing fields for ",atext);
299	    }
300
301	regs[rmax].reg_addr = strdup(atext);
302	regs[rmax].reg_subinst = strdup(subinst);
303	regs[rmax].reg_printfunc = strdup(pfunc);
304	regs[rmax].reg_description = strdup(descr);
305	regs[rmax].reg_mask = 0;
306	rmax++;
307	}
308
309    if (rmax == 100) fatal("Too many registers in section ",agentname);
310
311    inst = strtok(instances,",");
312
313    cumlmask = 0;
314    while (inst) {
315	char defname[100];
316	unsigned int curmask;
317
318	sprintf(defname,"SOC_AGENT_%s%s",
319		agentname,inst[0] == '*' ? "" : inst);
320
321	if (nomask) {
322	    curmask = 0;
323	    }
324	else {
325	    curmask = newmask();
326	    cumlmask |= curmask;
327	    }
328
329	addconst(defname,curmask);
330
331	for (idx = 0; idx < rmax; idx++) {
332	    char descr[100];
333	    char atext[200];
334
335	    macroexpand(regs[idx].reg_addr,inst,atext);
336#if 0
337	    strcpy(descr,agentname);
338	    if (inst[0] != '*') {
339		strcat(descr,inst);
340		}
341	    strcat(descr," ");
342	    if (regs[idx].reg_subinst[0] != '*') {
343		strcat(descr,regs[idx].reg_subinst);
344		strcat(descr," ");
345		}
346	    strcat(descr,regs[idx].reg_description);
347#else
348	    strcpy(descr,regs[idx].reg_description);
349#endif
350
351	    addreg(agentname,
352		   agentidx,
353		   curmask,
354		   atext,
355		   inst,
356		   regs[idx].reg_subinst,
357		   regs[idx].reg_printfunc,
358		   descr);
359	    }
360	inst = strtok(NULL,",");
361	}
362
363    if (instances[0] != '*') {
364	sprintf(cumlname,"SOC_AGENT_%s",agentname);
365	addconst(cumlname,cumlmask);
366	}
367}
368
369static void docommand(FILE *str,char *line)
370{
371    char *cmd;
372
373    cmd = gettoken(&line);
374    if (!cmd) return;
375
376    switch (assoc(commands,cmd)) {
377	case CMD_AGENT:
378	    doagentcmd(str,line,FALSE);
379	    break;
380	case CMD_AGENT_NOMASK:
381	    doagentcmd(str,line,TRUE);
382	    break;
383	default:
384	    fatal("Invalid command",cmd);
385	    break;
386	}
387
388}
389
390static void ingestfile(FILE *str)
391{
392    char line[500];
393
394    while (readline(str,line,sizeof(line)) >= 0) {
395	if (line[0] == '!') {
396	    docommand(str,line);
397	    }
398	else {
399	    fatal("Command string required before register data",NULL);
400	    }
401	}
402}
403
404
405static void saveincfile(char *fname, char *header)
406{
407    FILE *str;
408    int idx;
409
410    str = fopen(fname,"w" TEXTMODE);
411    if (!str) {
412	perror(fname);
413	exit(1);
414	}
415
416    fprintf(str,"\n\n");
417
418    if (header != NULL) {
419	fprintf(str, "#include \"%s\"\n", header);
420	fprintf(str,"\n\n");
421	}
422
423    fprintf(str,"#ifndef %s\n",constants[0].name);
424    for (idx = 0; idx < constcnt; idx++) {
425	fprintf(str,"#define %s 0x%08X\n",constants[idx].name,
426		constants[idx].value);
427	}
428    fprintf(str,"#endif\n");
429
430    fprintf(str,"\n\n");
431
432    fprintf(str,"#ifdef _CFE_\n");
433    fprintf(str,"#ifdef __ASSEMBLER__\n");
434    fprintf(str,"\t.globl socstatetable\n");
435    fprintf(str,"socstatetable:\n");
436    for (idx = 0; idx < regcnt; idx++) {
437	fprintf(str,"\t\t.word 0x%08X,%s\n",
438		allregs[idx].reg_mask,allregs[idx].reg_addr);
439	}
440    fprintf(str,"\t\t.word 0,0\n");
441    fprintf(str,"#endif\n");
442
443    fprintf(str,"\n\n");
444    fprintf(str,"#ifndef __ASSEMBLER__\n");
445
446    /* Addr Agent Inst Subinst Mask Printfunc Descr */
447
448    fprintf(str,"char *socagents[] = {\n");
449    for (idx = 0; idx < agentcnt; idx++) {
450	fprintf(str,"\t\"%s\",\n",agentnames[idx]);
451	}
452    fprintf(str,"\tNULL};\n\n");
453
454    fprintf(str,"const socreg_t socregs[] = {\n");
455    for (idx = 0; idx < regcnt; idx++) {
456	fprintf(str,"   {%s,%d,\"%s\",\"%s\",\n     0x%08X,%s,\"%s\"},\n",
457		allregs[idx].reg_addr,
458		allregs[idx].reg_agentidx,
459		allregs[idx].reg_inst,
460		allregs[idx].reg_subinst,
461		allregs[idx].reg_mask,
462		allregs[idx].reg_printfunc,
463		allregs[idx].reg_description);
464	}
465    fprintf(str,"   {0,0,NULL,NULL,0,NULL,NULL}};\n\n");
466
467    fprintf(str,"#endif\n");
468    fprintf(str,"#endif\n");
469    fclose(str);
470}
471
472int main(int argc,char *argv[])
473{
474    FILE *str;
475
476    if (argc != 3 && argc != 4) {
477	fprintf(stderr,"usage: makereg inputfile outputfile [header]\n");
478	exit(1);
479	}
480
481    str = fopen(argv[1],"r" TEXTMODE);
482
483    if (!str) {
484	perror(argv[1]);
485	exit(1);
486	}
487
488    ingestfile(str);
489
490    fclose(str);
491
492    fprintf(stderr,"Total registers: %d\n",regcnt);
493
494    saveincfile(argv[2], argc > 3 ? argv[3] : NULL);
495
496    exit(0);
497    return 0;
498}
499