1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Register Table Generator			File: makereg.c
5    *
6    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
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 <stdio.h>
52#include <string.h>
53#include <malloc.h>
54#include <stdlib.h>
55
56#if defined(_MSC_VER) || defined(__CYGWIN__)
57#define TEXTMODE "t"
58#else
59#define TEXTMODE ""
60#endif
61
62typedef struct Cons {
63    char *str;
64    int num;
65} CONS;
66
67typedef struct RegInfo {
68    unsigned long reg_mask;
69    char *reg_agent;
70    int reg_agentidx;
71    char *reg_addr;
72    char *reg_inst;
73    char *reg_subinst;
74    char *reg_printfunc;
75    char *reg_description;
76} REGINFO;
77
78typedef struct ConstInfo {
79    char *name;
80    unsigned int value;
81} CONSTINFO;
82
83#define MAXCONST 64
84CONSTINFO constants[MAXCONST];
85int constcnt = 0;
86
87#define MAXREGS 2000
88REGINFO allregs[MAXREGS];
89int regcnt = 0;
90
91int maskcnt = 0;
92
93#define MAXAGENTS 32
94char *agentnames[MAXAGENTS];
95int agentcnt;
96
97#define CMD_AGENT	1
98#define CMD_ENDAGENT	2
99
100CONS commands[] = {
101    {"!agent",CMD_AGENT},
102    {"!endagent",CMD_ENDAGENT},
103    {NULL,0}};
104
105
106int assoc(CONS *list,char *str)
107{
108    while (list->str) {
109	if (strcmp(list->str,str) == 0) return list->num;
110	list++;
111	}
112
113    return -1;
114}
115
116char *gettoken(char **ptr)
117{
118    char *p = *ptr;
119    char *ret;
120
121    /* skip white space */
122
123    while (*p && isspace(*p)) p++;
124    ret = p;
125
126    /* check for end of string */
127
128    if (!*p) {
129	*ptr = p;
130	return NULL;
131	}
132
133    /* skip non-whitespace */
134
135    while (*p) {
136	if (isspace(*p)) break;
137
138	/* do quoted strings */
139
140	if (*p == '"') {
141	    p++;
142	    ret = p;
143	    while (*p && (*p != '"')) p++;
144	    if (*p == '"') *p = '\0';
145	    }
146
147        p++;
148
149	}
150
151    if (*p) {
152        *p++ = '\0';
153        }
154    *ptr = p;
155
156    return ret;
157}
158
159static int readline(FILE *str,char *dest,int destlen)
160{
161    char *x;
162
163    for (;;) {
164	if (!fgets(dest,destlen,str)) return -1;
165	if (x = strchr(dest,'\n')) *x = '\0';
166	if (dest[0] == '\0') continue;
167	if (dest[0] == ';') continue;
168	break;
169	}
170
171    return 0;
172}
173
174
175static void fatal(char *str,char *val)
176{
177    fprintf(stderr,"fatal error: %s %s\n",str,val ? val : "");
178    exit(1);
179}
180
181static unsigned int newmask(void)
182{
183    int res;
184
185    res = maskcnt;
186
187    if (maskcnt == 32) {
188	fatal("Out of mask bits",NULL);
189	}
190
191    maskcnt++;
192
193    return 1<<res;
194}
195
196static void addconst(char *name,unsigned int val)
197{
198    if (constcnt == MAXCONST) {
199	fatal("Out of constant space",NULL);
200	}
201
202    constants[constcnt].name = strdup(name);
203    constants[constcnt].value = val;
204
205    constcnt++;
206}
207
208static void addreg(
209    char *agentname,
210    int agentidx,
211    unsigned long mask,
212    char *addr,
213    char *inst,
214    char *subinst,
215    char *printfunc,
216    char *description)
217{
218    allregs[regcnt].reg_mask = mask;
219    allregs[regcnt].reg_addr = strdup(addr);
220    allregs[regcnt].reg_agent = strdup(agentname);
221    allregs[regcnt].reg_agentidx = agentidx;
222    allregs[regcnt].reg_inst = strdup(inst);
223    allregs[regcnt].reg_subinst = strdup(subinst);
224    allregs[regcnt].reg_printfunc = strdup(printfunc);
225    allregs[regcnt].reg_description = strdup(description);
226    regcnt++;
227}
228
229
230static void macroexpand(char *instr,char *exp,char *outstr)
231{
232    while (*instr) {
233	if (*instr == '$') {
234	    strcpy(outstr,exp);
235	    outstr += strlen(outstr);
236	    instr++;
237	    }
238	else {
239	    *outstr++ = *instr++;
240	    }
241	}
242
243    *outstr = '\0';
244}
245
246
247static void doagentcmd(FILE *str,char *line)
248{
249    char *agentname;
250    char *instances;
251    char *inst;
252    char *ptr;
253    char regline[500];
254    char cumlname[100];
255    REGINFO regs[100];
256    char temp[20];
257    int rmax = 0;
258    int idx;
259    unsigned int cumlmask;
260    int agentidx;
261
262    agentname = gettoken(&line);
263    instances = gettoken(&line);
264    if (!instances) {
265	strcpy(temp,"*");
266	instances = temp;
267	}
268
269    fprintf(stderr,"Agent %s Instances %s\n",agentname,instances);
270
271    if (agentcnt == MAXAGENTS) {
272	fatal("Out of agent slots\n",NULL);
273	}
274
275    agentnames[agentcnt] = strdup(agentname);
276    agentidx = agentcnt;
277    agentcnt++;
278
279    regline[0] = '\0';
280
281    while ((readline(str,regline,sizeof(regline)) >= 0) && (rmax < 100)) {
282	char *atext,*subinst,*pfunc,*descr;
283
284	if (regline[0] == '!') break;
285
286	ptr = regline;
287	atext = gettoken(&ptr);
288	subinst = gettoken(&ptr);
289	pfunc = gettoken(&ptr);
290	descr = gettoken(&ptr);
291
292	if (!descr) {
293	    fatal("Missing fields for ",atext);
294	    }
295
296	regs[rmax].reg_addr = strdup(atext);
297	regs[rmax].reg_subinst = strdup(subinst);
298	regs[rmax].reg_printfunc = strdup(pfunc);
299	regs[rmax].reg_description = strdup(descr);
300	regs[rmax].reg_mask = 0;
301	rmax++;
302	}
303
304    if (rmax == 100) fatal("Too many registers in section ",agentname);
305
306    inst = strtok(instances,",");
307
308    cumlmask = 0;
309    while (inst) {
310	char defname[100];
311	unsigned int curmask;
312
313	sprintf(defname,"SOC_AGENT_%s%s",
314		agentname,inst[0] == '*' ? "" : inst);
315
316	curmask = newmask();
317	cumlmask |= curmask;
318
319	addconst(defname,curmask);
320
321	for (idx = 0; idx < rmax; idx++) {
322	    char descr[100];
323	    char atext[200];
324
325	    macroexpand(regs[idx].reg_addr,inst,atext);
326	    strcpy(descr,regs[idx].reg_description);
327
328	    addreg(agentname,
329		   agentidx,
330		   curmask,
331		   atext,
332		   inst,
333		   regs[idx].reg_subinst,
334		   regs[idx].reg_printfunc,
335		   descr);
336	    }
337	inst = strtok(NULL,",");
338	}
339
340    if (instances[0] != '*') {
341	sprintf(cumlname,"SOC_AGENT_%s",agentname);
342	addconst(cumlname,cumlmask);
343	}
344}
345
346static void docommand(FILE *str,char *line)
347{
348    char *cmd;
349
350    cmd = gettoken(&line);
351    if (!cmd) return;
352
353    switch (assoc(commands,cmd)) {
354	case CMD_AGENT:
355	    doagentcmd(str,line);
356	    break;
357	default:
358	    fatal("Invalid command",cmd);
359	    break;
360	}
361
362}
363
364static int ingestfile(FILE *str)
365{
366    char line[500];
367
368    while (readline(str,line,sizeof(line)) >= 0) {
369	if (line[0] == '!') {
370	    docommand(str,line);
371	    }
372	else {
373	    fatal("Command string required before register data",NULL);
374	    }
375	}
376}
377
378
379void saveincfile(char *fname)
380{
381    FILE *str;
382    int idx;
383
384    str = fopen(fname,"w" TEXTMODE);
385    if (!str) {
386	perror(fname);
387	exit(1);
388	}
389
390    fprintf(str,"\n\n");
391
392    fprintf(str,"#ifndef %s\n",constants[0].name);
393    for (idx = 0; idx < constcnt; idx++) {
394	fprintf(str,"#define %s 0x%08X\n",constants[idx].name,
395		constants[idx].value);
396	}
397    fprintf(str,"#endif\n");
398
399    fprintf(str,"\n\n");
400
401    fprintf(str,"#ifdef _CFE_\n");
402    fprintf(str,"#ifdef __ASSEMBLER__\n");
403    fprintf(str,"\t.globl socstatetable\n");
404    fprintf(str,"socstatetable:\n");
405    for (idx = 0; idx < regcnt; idx++) {
406	fprintf(str,"\t\t.word 0x%08X,%s\n",
407		allregs[idx].reg_mask,allregs[idx].reg_addr);
408	}
409    fprintf(str,"\t\t.word 0,0\n");
410    fprintf(str,"#endif\n");
411
412    fprintf(str,"\n\n");
413    fprintf(str,"#ifndef __ASSEMBLER__\n");
414
415    /* Addr Agent Inst Subinst Mask Printfunc Descr */
416
417    fprintf(str,"char *socagents[] = {\n");
418    for (idx = 0; idx < agentcnt; idx++) {
419	fprintf(str,"\t\"%s\",\n",agentnames[idx]);
420	}
421    fprintf(str,"\tNULL};\n\n");
422
423    fprintf(str,"const socreg_t socregs[] = {\n");
424    for (idx = 0; idx < regcnt; idx++) {
425	fprintf(str,"   {%s,%d,\"%s\",\"%s\",\n     0x%08X,%s,\"%s\"},\n",
426		allregs[idx].reg_addr,
427		allregs[idx].reg_agentidx,
428		allregs[idx].reg_inst,
429		allregs[idx].reg_subinst,
430		allregs[idx].reg_mask,
431		allregs[idx].reg_printfunc,
432		allregs[idx].reg_description);
433	}
434    fprintf(str,"   {0,0,NULL,NULL,0,NULL,NULL}};\n\n");
435
436    fprintf(str,"#endif\n");
437    fprintf(str,"#endif\n");
438    fclose(str);
439}
440
441int main(int argc,char *argv[])
442{
443    FILE *str;
444    int idx;
445
446    if (argc != 3) {
447	fprintf(stderr,"usage: makereg inputfile outputfile\n");
448	exit(1);
449	}
450
451    str = fopen(argv[1],"r" TEXTMODE);
452
453    if (!str) {
454	perror(argv[1]);
455	exit(1);
456	}
457
458    ingestfile(str);
459
460    fclose(str);
461
462    fprintf(stderr,"Total registers: %d\n",regcnt);
463
464    saveincfile(argv[2]);
465
466    exit(0);
467    return 0;
468}
469