New option stuff.
[coreboot.git] / util / newconfig / config.g
1 import sys
2 import os
3 import re
4 import string
5
6 debug = 0
7
8 arch = ''
9 ldscriptbase = ''
10 payloadfile = ''
11
12 makeoptions = {}
13 makeexpressions = []
14
15 # Key is the rule name. Value is a mkrule object.
16 makebaserules = {}
17
18 # List of targets in the order defined by makerule commands.
19 makerule_targets = {}
20
21 treetop = ''
22 target_dir = ''
23
24 sources = {}
25 objectrules = {}
26 # make these a hash so they will be unique.
27 driverrules = {}
28 ldscripts = []
29 userdefines = []
30 curpart = 0
31 root = 0
32
33 globalvars = {}       # We will globals here
34 parts = {}
35
36 options = {}
37 # options in order defined. These will be unique due to use of hash 
38 # for options. 
39 options_by_order = []
40 crt0includes = []
41 partinstance = 0
42 curdir = '' 
43 dirstack = []
44 config_file_list = []
45
46 local_path = re.compile(r'^\.')
47
48 # -----------------------------------------------------------------------------
49 #                    Error Handling
50 # -----------------------------------------------------------------------------
51
52 class location:
53         class place:
54                 def __init__(self, file, line, command):
55                         self.file = file
56                         self.line = line
57                         self.command = command
58                 def next_line(self, command):
59                         self.line = self.line + 1
60                         self.command = command
61                 def at(self):
62                         return "%s:%d" % (self.file, self.line)
63         
64         def __init__ (self):
65                 self.stack = []
66
67         def file(self):
68                 return self.stack[-1].file
69         def line(self):
70                  return self.stack[-1].line
71         def command(self):
72                 return self.stack[-1].command
73
74         def push_file(self, file):
75                 self.stack.append(self.place(file, 0, ""))
76         def pop_file(self):
77                 self.stack.pop()
78         def next_line(self, command):
79                 self.stack[-1].next_line(command)
80         def at(self):
81                 return self.stack[-1].at()
82 loc = location()
83
84 class makerule:
85         def __init__ (self, target):
86                 self.target = target
87                 self.dependency = []
88                 self.actions = []
89
90         def addaction(self, action):
91                 self.actions.append(action)
92
93         def adddependency(self, dependency):
94                 self.dependency.append(dependency)
95
96         def gtarget(self):
97                 return self.target
98
99         def gdependency(self):
100                 return self.dependency
101
102         def gaction(self):
103                 return self.actions
104
105 class option:
106         def __init__ (self, name):
107                 self.name = name        # name of option
108                 self.loc = 0            # current location
109                 self.value = 0          # option value
110                 self.set = 0            # option has been set
111                 self.default = 0        # option has default value (otherwise
112                                         # it is undefined)
113                 self.comment = ''       # description of option
114                 self.export = 0         # option is able to be exported
115                 self.exported = 0       # option is exported
116                 self.defined = 0        # option has a value
117                 self.format = '%s'      # option print format
118
119         def setvalue(self, value, loc):
120                 if (self.set):
121                         print "Option %s: " % self.name
122                         print "Attempt to set %s at %s" % (value, loc.at()) 
123                         print "Already set to %s at %s" % \
124                                         (self.value, self.loc.at())
125                         sys.exit(1)
126                 self.set = 1
127                 self.value = value
128                 self.defined = 1
129                 self.loc = loc
130
131         def getvalue(self, part):
132                 global curpart
133                 if (not (type(self.value) is str)):
134                         return self.value
135                 if (self.value == '' or self.value[0] != '{'):
136                         return self.value
137                 # evaluate expression
138                 a = re.sub("^{", "", self.value)
139                 a = re.sub("}$", "", a)
140                 # save curpart so we can evaluate expression
141                 # in context of part
142                 s = curpart
143                 curpart = part
144                 v = parse('value', a)
145                 curpart = s
146                 return v
147
148         def setdefault(self, value, loc):
149                 if (self.default):
150                         print "%s: " % self.name
151                         print "Attempt to default %s at %s" % (value, loc) 
152                         print "Already defaulted to %s at %s" %  \
153                                         (self.value, self.loc.at())
154                         print "Warning only"
155                 if (self.set):
156                         print "%s: " % self.name
157                         print "Attempt to default %s at %s" % (value, loc) 
158                         print "Already set to %s at %s" % \
159                                         (self.value, self.loc.at())
160                         print "Warning only"
161                         return
162                 self.value = value
163                 self.defined = 1
164                 self.default = 1
165                 self.loc = loc
166
167         def setnodefault(self, loc):
168                 self.default = 1
169                 self.defined = 0
170                 self.loc = loc
171
172         def where(self):
173                 return self.loc
174
175         def setcomment(self, value, loc):
176                 if (self.comment != ''):
177                         print "%s: " % self.name
178                         print "Attempt to modify comment at %s" % loc 
179                         return
180                 self.comment = value
181
182         def setexport(self):
183                 self.export = 1
184
185         def setexported(self):
186                 self.export = 1
187                 self.exported = 1
188
189         def setnoexport(self):
190                 self.export = 0
191                 self.exported = 0
192
193         def setformat(self, fmt):
194                 self.format = fmt
195
196         def getformat(self):
197                 return self.format
198
199         def used(self):
200                 if (self.export):
201                         self.exported = 1
202
203         def isexported(self):
204                 return (self.exported and self.defined)
205
206         def isdefined(self):
207                 return (self.defined)
208
209         def isset(self):
210                 return (self.set)
211
212 class partobj:
213         def __init__ (self, dir, parent, type):
214                 global partinstance
215                 if (debug):
216                         print "partobj dir %s parent %s type %s" %(dir,parent,type)
217                 self.children = []
218                 self.initcode = []
219                 self.registercode = []
220                 self.siblings = 0
221                 self.type = type
222                 self.objects = []
223                 self.dir = dir
224                 self.irq = 0
225                 self.instance = partinstance + 1
226                 partinstance = partinstance + 1
227                 self.devfn = 0  
228                 self.private = 0        
229                 self.options = {}
230                 if (parent):
231                         if (debug):
232                                 print "add to parent"
233                         self.parent   = parent
234                         parent.children.append(self)
235                 else:
236                         self.parent = self
237
238         def dumpme(self, lvl):
239                 print "%d: type %s" % (lvl, self.type)
240                 print "%d: dir %s" % (lvl,self.dir)
241                 print "%d: parent %s" % (lvl,self.parent.type)
242                 print "%d: parent dir %s" % (lvl,self.parent.dir)
243                 print "%d: initcode " % lvl
244                 for i in self.initcode:
245                         print "  %s" % i
246                 print "%d: registercode " % lvl
247                 for i in self.registercode:
248                         print "  %s" % i
249
250         def gencode(self):
251                 print "struct cdev dev%d = {" % self.instance
252                 print "/* %s %s */" % (self.type, self.dir)
253                 print "  .devfn = %d" % self.devfn
254                 if (self.siblings):
255                         print "  .next = &dev%d" % self.sibling.instance
256                 if (self.children):
257                         print "  .children = &dev%d" %  \
258                                         self.children[0].instance
259                 if (self.private):
260                         print "  .private = private%d" % self.instance
261                 print "};"
262
263                 
264         def irq(self, irq):
265                 self.irq = irq
266        
267         def addinit(self, code):
268                 self.initcode.append(code)
269                 
270         def addregister(self, code):
271                 self.registercode.append(code)
272
273         def usesoption(self, name):
274                 o = getvalue(options, name)
275                 if (o == 0):
276                         fatal("Error: can't use undefined option %s" % name)
277                 o.used()
278                 setvalue(self.options, name, o)
279                 if (debug):
280                         print "option %s used in %s" % (name, self)
281
282 class partsstack:
283         def __init__ (self):
284                 self.stack = []
285
286         def push(self, part):
287                 self.stack.append(part)
288
289         def pop(self):
290                 return self.stack.pop()
291
292         def tos(self):
293                 return self.stack[-1]
294 pstack = partsstack()
295
296 def fatal(string):      
297         global loc
298         size = len(loc.stack)
299         i = 0
300         while(i < size -1): 
301                 print loc.stack[i].at()
302                 i = i + 1
303         print "%s: %s"% (loc.at(), string)
304         sys.exit(1)
305
306 def warning(string):
307         global loc
308         print "===> Warning:"
309         size = len(loc.stack)
310         i = 0
311         while(i < size -1):
312                 print loc.stack[i].at()
313                 i = i + 1
314         print "%s: %s"% (loc.at(), string)
315
316
317 # -----------------------------------------------------------------------------
318 #                    statements 
319 # -----------------------------------------------------------------------------
320
321 def getvalue(dict, name):
322         if name not in dict.keys(): 
323                 if (debug >1):
324                         print 'Undefined:', name
325                 return 0
326         v = dict.get(name, 0)
327         if (debug > 1):
328                 print "getvalue %s returning %s" % (name, v)
329         return v
330
331 def setvalue(dict, name, value):
332         if name in dict.keys(): 
333                 print "Warning, %s previously defined" % name
334         if (debug > 1):
335                 print "setvalue sets %s to %s" % (name, value)
336         dict[name] = value
337
338 # options. 
339 # to create an option, it has to not exist. 
340 # When an option value is fetched, the fact that it was used is 
341 # remembered. 
342 # Legal things to do:
343 # set a default value, then set a real value before the option is used.
344 # set a value, try to set a default, default silently fails.
345 # Illegal:
346 # use the value, then try to set the value
347
348 def newoption(name):
349         o = getvalue(options, name)
350         if (o):
351                 print "option %s already defined" % name
352                 sys.exit(1)
353         o = option(name)
354         setvalue(options, name, o)
355         options_by_order.append(name)
356
357 # option must be declared before being used in a part
358 # if we're not processing a part, then we must
359 # be at the top level where all options are available
360 def getoption(name, part):
361         global options
362         if (part):
363                 o = getvalue(part.options, name)
364         else:
365                 o = getvalue(options, name)
366         if (o == 0 or not o.defined):
367                 fatal( "Error: Option %s Undefined." % name)
368         v = o.getvalue(part)
369         if (debug > 2):
370                 print "getoption returns %s" % v
371                 print "%s" % o.where()
372         return v
373
374 # setoptionstmt only allowed at top level
375 def setoptionstmt(name, value):
376         global curpart
377         if (curpart != root):
378                 fatal("Error: options can only be set in target configuration file")
379         setoption(name, value)
380
381 def setoption(name, value):
382         global loc
383         o = getvalue(options, name)
384         if (o == 0):
385                 fatal("Error: attempt set nonexistent option %s" % name)
386         o.setvalue(value, loc)
387
388 def setdefault(name, value):
389         global loc
390         o = getvalue(options, name)
391         if (not o):
392                 return
393         if (o.default):
394                 print "setdefault: attempt to duplicate default for %s" % name
395                 return
396         o.setdefault(value, loc)
397
398 def setnodefault(name):
399         global loc
400         o = getvalue(options, name)
401         if (not o):
402                 return
403         if (o.default):
404                 print "setdefault: attempt to duplicate default for %s" % name
405                 return
406         o.setnodefault(loc)
407
408 def setcomment(name, value):
409         o = getvalue(options, name)
410         if (not o):
411                 fatal("setcomment: %s not here" % name)
412         o.setcomment(value, loc)
413
414 def setexported(name):
415         o = getvalue(options, name)
416         if (not o):
417                 fatal("setexported: %s not here" % name)
418         o.setexported()
419
420 def setnoexport(name):
421         o = getvalue(options, name)
422         if (not o):
423                 fatal("setnoexport: %s not here" % name)
424         o.setnoexport()
425
426 def setexport(name):
427         o = getvalue(options, name)
428         if (not o):
429                 fatal("setexport: %s not here" % name)
430         o.setexport()
431
432 def setformat(name, fmt):
433         o = getvalue(options, name)
434         if (not o):
435                 fatal("setexport: %s not here" % name)
436         o.setformat(fmt)
437
438 def getformated(name, part):
439         global options
440         if (part):
441                 o = getvalue(part.options, name)
442         else:
443                 o = getvalue(options, name)
444         if (o == 0 or not o.defined):
445                 fatal( "Error: Option %s Undefined." % name)
446         v = o.getvalue(part)
447         f = o.getformat()
448         return (f % v)
449
450 def isexported(name, part):
451         if (part):
452                 o = getvalue(part.options, name)
453         else:
454                 o = getvalue(options, name)
455         if (o):
456                 return o.isexported()
457         return 0
458
459 def isdefined(name, part):
460         if (part):
461                 o = getvalue(part.options, name)
462         else:
463                 o = getvalue(options, name)
464         if (o):
465                 return o.isdefined()
466         return 0
467
468 def isset(name, part):
469         if (part):
470                 o = getvalue(part.options, name)
471         else:
472                 o = getvalue(options, name)
473         if (o):
474                 return o.isset()
475         return 0
476
477 def usesoption(name):
478         global curpart
479         curpart.usesoption(name)
480
481 def validdef(name, defval):
482         o = getvalue(options, name)
483         if (not o):
484                 fatal("validdef: %s not here" % name)
485         if ((defval & 1) != 1):
486             fatal("Error: must specify default value for option %s" % name)
487         if ((defval & 2) != 2):
488             fatal("Error: must specify export for option %s" % name)
489         if ((defval & 4) != 4):
490             fatal("Error: must specify comment for option %s" % name)
491
492 def loadoptions():
493         global treetop
494         optionsfile = os.path.join(treetop, 'src', 'config', 'Options.lb')
495         loc.push_file(optionsfile)
496         if (not parse('options', open(optionsfile, 'r').read())):
497                 fatal("Error: Could not parse file")
498         loc.pop_file()
499
500 # we do the crt0include as a dictionary, so that if needed we
501 # can trace who added what when. Also it makes the keys
502 # nice and unique. 
503 def addcrt0include(path):
504         global crt0includes
505         #fullpath = os.path.join(curdir, path)
506         #fullpath = path
507         #setvalue(crt0includes, fullpath, loc)
508         # oh shoot. Order matters. All right, we'll worry about this 
509         # later. 
510         fullpath = path
511         if (debug > 2):
512                 print "ADDCRT0: %s" % fullpath
513         crt0includes.append(fullpath)
514
515 def addldscript(path):
516         global ldscripts
517         if (path[0] == '/'):
518                 fullpath =  treetop + '/src/' + path
519         else:
520                 fullpath = curdir + '/' + path
521         #fullpath = os.path.join(curdir, path)
522         #setvalue(ldscripts, fullpath, loc)
523         if (debug):
524                 print "fullpath :%s: curdir :%s: path :%s:" % (fullpath, curdir, path)
525         ldscripts.append(fullpath)
526
527 def payload(path):
528         global payloadfile
529         adduserdefine("PAYLOAD:=%s"%path)
530 #       addrule('payload')
531 #       adddep('payload', path)
532 #       addaction('payload', 'cp $< $@')
533
534 # this is called with an an object name. 
535 # the easiest thing to do is add this object to the current 
536 # component.
537 # such kludgery. If the name starts with '.' then make the 
538 # dependency be on ./thing.x gag me.
539 def addobjectdriver(dict, object_name):
540         suffix = object_name[-2:]
541         if (suffix == '.o'):
542                 suffix = '.c'
543         base = object_name[:-2]
544         if (object_name[0] == '.'):
545                 source = base + suffix
546         else:
547                 source = os.path.join(curdir, base + suffix)
548         object = base + '.o'
549         if (debug):
550                 print "add object %s source %s" % (object_name, source)
551         setvalue(dict, base, [object, source])
552
553 def addobject(object_name):
554         addobjectdriver(objectrules, object_name)
555
556 def adddriver(driver_name):
557         addobjectdriver(driverrules, driver_name)
558
559 def target(targ_name):
560         global target_dir
561         global curpart
562         global root
563         print "Configuring TARGET %s" % targ_name
564         target_dir = os.path.join(os.path.dirname(loc.file()), targ_name)
565         if not os.path.isdir(target_dir):
566                 print "Creating directory" % target_dir
567                 os.makedirs(target_dir)
568         print "Will place Makefile, crt0.S, etc. in %s" % target_dir
569         root = partobj(target_dir, 0, 'board')
570         curpart = root
571
572 def part(name, path, file):
573         global curpart,curdir,treetop
574         dirstack.append(curdir)
575         curdir = os.path.join(treetop, 'src', name, path)
576         newpart = partobj(curdir, curpart, name)
577         print "Configuring PART %s" % name
578         if (debug):
579                 print "PUSH part %s %s" % (name, curpart.dir)
580         pstack.push(curpart)
581         curpart = newpart
582         doconfigfile(curdir, file)
583
584 def partpop():
585         global curpart,curdir
586         curpart = pstack.pop()
587         curdir = dirstack.pop()
588         if (debug):
589                 print "POP PART %s" % curpart.dir
590
591 # dodir is like part but there is no new part
592 def dodir(path, file):
593         global curdir,  treetop
594         # if the first char is '/', it is relative to treetop, 
595         # else relative to curdir
596         # os.path.join screws up if the name starts with '/', sigh.
597         if (path[0] == '/'):
598                 fullpath = treetop + '/src/' + path 
599         else:
600                 fullpath = os.path.join(curdir,  path)
601         if (debug):
602                 print "DODIR: path %s, fullpath %s" % (path, fullpath)
603                 print "DODIR: curdis %s treetop %s" % (curdir, treetop)
604         dirstack.append(curdir)
605         curdir = fullpath
606         file = os.path.join(fullpath, file)
607         config_file_list.append(file)
608         doconfigfile(fullpath, file)
609         curdir = dirstack.pop()
610
611 def ternary(expr, yes, no):
612         if (debug):
613                 print "ternary %s" % expr
614         a = tohex(expr) # expr # eval(expr)
615         if (debug):
616                 print "expr %s a %d yes %d no %d"% (expr, a, yes, no)
617         if (a == 0):
618                 if (debug):
619                     print "Ternary returns %d" % yes
620                 return yes
621         else:
622                 if (debug):
623                         print "Ternary returns %d" % no
624                 return no
625
626 # atoi is in the python library, but not strtol? Weird!
627 def tohex(name):
628         return eval('int(%s)' % name)
629
630 def IsInt( str ):
631         """ Is the given string an integer?"""
632         try:
633                 num = int(str)
634                 return 1
635         except ValueError:
636                 return 0
637
638 def addrule(id):
639         o = makerule(id)
640         setvalue(makebaserules, id, o)
641         
642 def adduserdefine(str):
643         userdefines.append(str)
644
645 def dequote(str):
646         a = re.sub("^\"", "", str)
647         a = re.sub("\"$", "", a)
648         # highly un-intuitive, need four \!
649         a = re.sub("\\\\\"", "\"", a)
650         return a
651
652 def addaction(id, str):
653         o = getvalue(makebaserules, id)
654         a = dequote(str)
655         o.addaction(a)
656
657 def adddep(id, str):
658         o = getvalue(makebaserules, id)
659         a = dequote(str)
660         o.adddependency(a)
661
662 # If the first part of <path> matches treetop, replace that part with "$(TOP)"
663 def topify(path):
664         global treetop
665         if path[0:len(treetop)] == treetop:
666                 path = path[len(treetop):len(path)]
667                 if (path[0:1] == "/"):
668                         path = path[1:len(path)]
669                 path = "$(TOP)/" + path
670         return path
671
672 # arch is 'different' ... darn it.
673 def set_arch(my_arch):
674         global arch
675         global curdir
676         arch = my_arch
677         setoption('ARCH', my_arch)
678         part('arch', my_arch, 'config/make.base.lb')
679
680
681 def mainboard(path):
682         global mainboard_dir, treetop
683         mainboard_dir = path
684         full_mainboard_dir = os.path.join(treetop, 'src/mainboard', path)
685         setoption('MAINBOARD', full_mainboard_dir)
686         vendor = re.sub("/.*", "", path)
687         mainboard_part_number = re.sub("[^/]/", "", path)
688         setoption('MAINBOARD_VENDOR', vendor)
689         setoption('MAINBOARD_PART_NUMBER', mainboard_part_number)
690         part('mainboard', path, 'Config.lb')
691
692 #=============================================================================
693 #               FILE OUTPUT 
694 #=============================================================================
695 def writemakefileheader(file, fname):
696         file.write("# File: %s\n" % fname)
697         file.write("# This file was generated by '%s %s %s'\n\n"
698                 % (sys.argv[0], sys.argv[1], sys.argv[2]))
699
700
701 def writemakefilesettings(path):
702         global treetop, arch, mainboard_dir, target_dir, options_by_order, root
703         # Write Makefile.settings to seperate the settings
704         # from the actual makefile creation
705         # In practice you need to rerun NLBConfig.py to change
706         # these but in theory you shouldn't need to.
707
708         filename = os.path.join(path, "Makefile.settings")
709         print "Creating", filename
710         file = open(filename, 'w+')
711         writemakefileheader(file, filename)
712         file.write("TOP:=%s\n" % (treetop))
713         #file.write("ARCH:=%s\n" % (arch))
714         #file.write("MAINBOARD:=%s\n" % (mainboard_dir))
715         file.write("TARGET_DIR:=%s\n" % (target_dir))
716         for i in options_by_order:
717                 if (isexported(i, 0)):
718                         file.write("export %s:=%s\n" % (i, getformated(i, 0)))
719         file.write("export VARIABLES := ")
720         for i in options.keys():
721                 if (isexported(i, 0)):
722                         file.write("%s " % i)
723         file.write("\n")
724 #       file.write("CPUFLAGS := ")
725 #       for i in options.keys():
726 #               o = options[i]
727 #               file.write("-D%s=%s " % (i, o.getvalue()))
728 #       file.write("\n")
729         file.close()
730
731
732 # write the makefile
733 # let's try the Makefile
734 # first, dump all the -D stuff
735
736 def writemakefile(path):
737         global root
738         makefilepath = os.path.join(path, "Makefile")
739         print "Creating", makefilepath
740         file = open(makefilepath, 'w+')
741         writemakefileheader(file, makefilepath)
742
743         # file.write("include Makefile.settings\n")
744         # file.write("include cpuflags\n")
745         # Putting "include cpuflags" in the Makefile has the problem that the
746         # cpuflags file would be generated _after_ we want to include it.
747         # Instead, let make do the work of computing CPUFLAGS:
748         file.write("""\
749 # Get the value of TOP, VARIABLES, and several other variables.
750 include Makefile.settings
751
752 # Function to create an item like -Di586 or -DMAX_CPUS='1' or -Ui686
753 D_item = $(if $(subst undefined,,$(origin $1)),-D$1$(if $($1),='$($1)',),-U$1)
754
755 # Compute the value of CPUFLAGS here during make's first pass.
756 CPUFLAGS := $(foreach _var_,$(VARIABLES),$(call D_item,$(_var_)))
757 """)
758
759         for i in userdefines:
760                 file.write("%s\n" %i)
761         file.write("\n")
762
763         # print out all the object dependencies
764         file.write("\n# object dependencies (objectrules:)\n")
765         file.write("OBJECTS :=\n")
766         file.write("DRIVERS :=\n")
767         for objrule in objectrules.keys():
768                 obj = objectrules[objrule]
769                 obj_name = obj[0]
770                 obj_source = obj[1]
771                 file.write("OBJECTS-1 += %s\n" % (obj_name))
772
773         for driverrule in driverrules.keys():
774                 driver = driverrules[driverrule]
775                 obj_name = driver[0]
776                 obj_source = driver[1]
777                 file.write("DRIVER += %s\n" % (obj_name))
778
779         # Print out all ldscript.ld dependencies.
780         file.write("\n# ldscript.ld dependencies:\n")
781         file.write("LDSUBSCRIPTS-1 := \n" )
782         for script in ldscripts:
783                 file.write("LDSUBSCRIPTS-1 += %s\n" % topify(script))
784
785         # Print out the dependencies for crt0_includes.h
786         file.write("\n# Dependencies for crt0_includes.h\n")
787         file.write("CRT0_INCLUDES:=\n")
788         for i in crt0includes:
789                 if (local_path.match(i)):
790                         file.write("CRT0_INCLUDES += %s\n" % i)
791                 else:
792                         file.write("CRT0_INCLUDES += $(TOP)/src/%s\n" % i)
793
794         file.write("\nSOURCES=\n")
795         #for source in sources:
796                 #file.write("SOURCES += %s\n" % source)
797         
798         # Print out the user defines.
799         file.write("\n# userdefines:\n")
800         #for udef in userdefines:
801                 #file.write("%s\n" % udef)
802                 
803         # Print out the base rules.
804         # Need to have a rule that counts on 'all'.
805         file.write("\n# mainrulelist:")
806         #file.write("\nmainrule: %s\n" % mainrulelist)
807
808         # Print out any user rules.
809         file.write("\n# From makerule or docipl commands:\n")
810         # Old way (hash order): for target in makebaserules.keys():
811         # New way (config file order):
812         #for target in makerule_targets:
813                 #makebaserules[target].write(file)
814
815         file.write("\n# objectrules:\n")
816         for objrule in objectrules.keys():
817                 obj = objectrules[objrule]
818                 source = topify(obj[1])
819                 file.write("%s: %s\n" % (obj[0], source))
820                 file.write("\t$(CC) -c $(CFLAGS) -o $@ $<\n")
821                 #file.write("%s\n" % objrule[2])
822
823         for driverrule in driverrules.keys():
824                 driver = driverrules[driverrule]
825                 source = topify(driver[1])
826                 file.write("%s: %s\n" % (driver[0], source))
827                 #file.write("%s\n" % objrule[2])
828
829         # Print out the rules that will make cause the files
830         # generated by NLBConfig.py to be remade if any dependencies change.
831
832         file.write("\n# Remember the automatically generated files\n")
833         file.write("GENERATED:=\n")
834         for genfile in [ 'Makefile',
835                         'Makefile.settings',
836                         'crt0_includes.h',
837                         'nsuperio.c',
838                          'chip.c', 
839                         'LinuxBIOSDoc.config' ]:
840                 file.write("GENERATED += %s\n" % genfile)
841
842         file.write("\n# Remake Makefile (and the other files generated by\n")
843         file.write("# NLBConfig.py) if any config dependencies change.\n")
844
845         for cfile in config_file_list:
846                 file.write("$(GENERATED): %s\n" % topify(cfile))
847
848         for depfile in [ '%s' % top_config_file,    # This a duplicate, remove?
849                         '$(TOP)/util/config/NLBConfig.py',
850                         '$(TOP)/src/arch/$(ARCH)/config/make.base' ]:
851                 file.write("$(GENERATED): %s\n" % depfile)
852
853         file.write("$(GENERATED):\n")
854         file.write("\tpython $(TOP)/util/config/NLBConfig.py %s $(TOP)\n"
855                         % top_config_file)
856
857         keys = root.options.keys()
858         keys.sort()
859         file.write("\necho:\n")
860         for key in keys:
861                  file.write("\t@echo %s='$(%s)'\n"% (key,key))
862         
863
864         for i in makebaserules.keys():
865                 m = makebaserules[i]
866                 file.write("%s: " %i)
867                 for i in m.dependency:
868                         file.write("%s " % i)
869                 file.write("\n")
870                 for i in m.actions:
871                         file.write("\t%s\n" % i)
872         file.close()
873
874 # Write out crt0_includes.h (top-level assembly language) include file.
875 def writecrt0_includes(path):
876         crt0filepath = os.path.join(path, "crt0_includes.h")
877         print "Creating", crt0filepath
878         file = open(crt0filepath, 'w+')
879
880         for i in crt0includes:
881                 file.write("#include <%s>\n" % i)
882
883         file.close()
884
885
886 %%
887 parser Config:
888     ignore:                     r'\s+'
889     ignore:                     "#.*?\r?\n"
890
891     # less general tokens should come first, otherwise they get matched
892     # by the re's
893     token ACT:                  'act'
894     token ADDACTION:            'addaction'
895     token ALWAYS:               'always'
896     token ARCH:                 'arch'
897     token COMMENT:              'comment'
898     token CPU:                  'cpu'
899     token DEFAULT:              'default'
900     token DEFINE:               'define'
901     token DEP:                  'dep'
902     token DIR:                  'dir'
903     token DRIVER:               'driver'
904     token END:                  '$|end'
905     token EQ:                   '='
906     token EXPORT:               'export'
907     token FORMAT:               'format'
908     token IF:                   'if'
909     token INIT:                 'init'
910     token LDSCRIPT:             'ldscript'
911     token LOADOPTIONS:          'loadoptions'
912     token MAINBOARD:            'mainboard'
913     token MAINBOARDINIT:        'mainboardinit'
914     token MAKEDEFINE:           'makedefine'
915     token MAKERULE:             'makerule'
916     token NEVER:                'never'
917     token NONE:                 'none'
918     token NORTHBRIDGE:          'northbridge'
919     token OBJECT:               'object'
920     token OPTION:               'option'
921     token PAYLOAD:              'payload'
922     token PMC:                  'pmc'
923     token REGISTER:             'register'
924     token SOUTHBRIDGE:          'southbridge'
925     token SUPERIO:              'superio'
926     token TARGET:               'target'
927     token USED:                 'used'
928     token USES:                 'uses'
929     token NUM:                  r'[0-9]+'
930     token XNUM:                 r'0x[0-9a-fA-F]+'
931     # Why is path separate? Because paths to resources have to at least
932     # have a slash, we thinks
933     token PATH:                 r'[a-zA-Z0-9_.][a-zA-Z0-9/_.]+[a-zA-Z0-9_.]+'
934     # Dir's on the other hand are abitrary
935     # this may all be stupid.
936     token DIRPATH:              r'[a-zA-Z0-9_$()./]+'
937     token ID:                   r'[a-zA-Z_.]+[a-zA-Z0-9_.]*'
938     token DELEXPR:              r'{([^}]+|\\.)*}'
939     token STR:                  r'"([^\\"]+|\\.)*"'
940     token RAWTEXT:              r'.*'
941
942     rule expr<<V>>:     logical<<V>>            {{ l = logical }}
943                         ( "&&" logical<<V>>     {{ l = l and logical }}
944                         | "||"  logical<<V>>    {{ l = l or logical }}
945                         )*                      {{ return l }}
946
947     rule logical<<V>>:  factor<<V>>             {{ n = factor }}
948                         ( "[+]" factor<<V>>     {{ n = n+factor }}
949                         | "-"  factor<<V>>      {{ n = n-factor }}
950                         )*                      {{ return n }}
951
952     rule factor<<V>>:   term<<V>>               {{ v = term }}
953                         ( "[*]" term<<V>>       {{ v = v*term }}
954                         | "/"  term<<V>>        {{ v = v/term }}
955                         | "<<"  term<<V>>       {{ v = v << term }}
956                         | ">=" term<<V>>        {{ v = (v < term)}}
957                         )*                      {{ return v }}
958
959     rule unop<<V>>:     "!" ID                  {{ return ternary(getoption(ID, curpart), 1, 0)}}
960
961     # A term is a number, variable, or an expression surrounded by parentheses
962     rule term<<V>>:     NUM                     {{ return atoi(NUM) }}
963                 |       XNUM                    {{ return tohex(XNUM) }}
964                 |       ID                      {{ return tohex(getoption(ID, curpart)) }}
965                 |       unop<<V>>               {{ return unop }}
966                 |       "\\(" expr<<V>> "\\)"   {{ return expr }}
967
968     rule partend<<C>>:  partstmts<<C>> END  
969
970     rule mainboard:     MAINBOARD PATH          {{ mainboard(PATH) }}
971                         partend<<1>>
972                         
973     rule northbridge<<C>>:
974                         NORTHBRIDGE PATH        {{ if (C): part('northbridge', PATH, 'Config.lb') }}
975                         partend<<C>>
976
977     rule superio<<C>>:  SUPERIO PATH            {{ if (C): part('superio', PATH, 'Config.lb') }}
978                         partend<<C>>
979
980     rule cpu<<C>>:      CPU ID                  {{ if (C): part('cpu', ID, 'Config.lb') }}
981                         partend<<C>>
982
983     rule pmc<<C>>:      PMC PATH                {{ if (C): part('pmc', PATH, 'Config.lb') }}
984                         partend<<C>>
985
986     rule arch<<C>>:     ARCH ID                 {{ if (C): set_arch(ID) }}
987                         partend<<C>>
988
989     rule southbridge<<C>>:
990                         SOUTHBRIDGE PATH        {{ if (C): part('southbridge', PATH, 'Config.lb')}}
991                         partend<<C>>
992
993     rule mainboardinit<<C>>: 
994                         MAINBOARDINIT DIRPATH   {{ if (C): addcrt0include(DIRPATH)}}
995
996     rule object<<C>>:   OBJECT DIRPATH          {{ if (C): addobject(DIRPATH)}}
997
998     rule driver<<C>>:   DRIVER DIRPATH          {{ if (C): adddriver(DIRPATH)}}
999
1000     rule dir<<C>>:      DIR DIRPATH             {{ if (C): dodir(DIRPATH, 'Config.lb') }}
1001
1002     rule ldscript<<C>>: LDSCRIPT DIRPATH        {{ if (C): addldscript(DIRPATH) }}
1003
1004     rule payload<<C>>:  PAYLOAD DIRPATH         {{ if (C): payload(DIRPATH) }}
1005
1006 # if is a bad id ....
1007 # needs to be C and ID, but nested if's are, we hope, not going to 
1008 # happen. IF so, possibly ID && C could be used.
1009     rule iif<<C>>:      IF ID                   {{ c = tohex(getoption(ID, curpart)) }} 
1010                         (stmt<<c>>)* END
1011
1012     rule depsacts<<ID, C>>:
1013                         ( DEP STR               {{ if (C): adddep(ID, STR) }}
1014                         | ACT STR               {{ if (C): addaction(ID, STR) }}
1015                         )*
1016
1017     rule makerule<<C>>: MAKERULE DIRPATH        {{ if (C): addrule(DIRPATH) }} 
1018                         depsacts<<DIRPATH, C>> 
1019
1020     rule makedefine<<C>>:
1021                         MAKEDEFINE RAWTEXT      {{ if (C): adduserdefine(RAWTEXT) }}
1022
1023     rule addaction<<C>>:
1024                         ADDACTION ID STR        {{ if (C): addaction(ID, STR) }}
1025
1026     rule init<<C>>:     INIT STR                {{ if (C): curpart.addinit(STR) }}
1027
1028     rule register<<C>>: REGISTER STR            {{ if (C): curpart.addregister(STR) }}
1029
1030 # to make if work without 2 passses, we use an old hack from SIMD, the 
1031 # context bit. If the bit is 1, then ops get done, otherwise
1032 # ops don't get done. From the top level, context is always
1033 # 1. In an if, context depends on eval of the if condition
1034     rule stmt<<C>>:     cpu<<C>>                {{ return cpu}}
1035                 |       pmc<<C>>                {{ return pmc}}
1036                 |       arch<<C>>               {{ return arch}}
1037                 |       northbridge<<C>>        {{ return northbridge }}
1038                 |       southbridge<<C>>        {{ return southbridge }}
1039                 |       superio<<C>>            {{ return superio }}
1040                 |       object<<C>>             {{ return object }}
1041                 |       driver<<C>>             {{ return driver }}
1042                 |       mainboardinit<<C>>      {{ return mainboardinit }}
1043                 |       makerule<<C>>           {{ return makerule }}
1044                 |       makedefine<<C>>         {{ return makedefine }}
1045                 |       addaction<<C>>          {{ return addaction }}
1046                 |       init<<C>>               {{ return init }}
1047                 |       register<<C>>           {{ return register}}
1048                 |       iif<<C>>                {{ return iif }}
1049                 |       dir<<C>>                {{ return dir}}
1050                 |       ldscript<<C>>           {{ return ldscript}}
1051                 |       payload<<C>>            {{ return payload}}
1052
1053     rule stmts<<C>>:    (stmt<<C>>)*            {{ }}
1054
1055     rule partstmts<<C>>:
1056                         (uses<<C>>)*
1057                         (stmt<<C>>)*            {{  partpop()}}
1058
1059 # need this to get from python to the rules, I think.
1060     rule pstmts:        (uses<<1>>)* stmts<<1>> {{ return 1 }}
1061
1062     rule usesid<<C>>:   ID                      {{ if (C): usesoption(ID) }}
1063
1064     rule uses<<C>>:     USES (usesid<<C>>)+
1065
1066     rule value:         STR                     {{ return dequote(STR) }} 
1067                 |       term<<[]>>              {{ return term }}
1068                 |       DELEXPR                 {{ return DELEXPR }}
1069
1070     rule option:        OPTION ID EQ value      {{ setoptionstmt(ID, value) }}
1071
1072     rule board:         LOADOPTIONS             {{ loadoptions() }}
1073                         TARGET DIRPATH          {{ target(DIRPATH) }}
1074                         (uses<<1>>)*
1075                         (option)*
1076                         mainboard               {{ return 1 }}
1077
1078     rule defstmts<<ID>>:                        {{ d = 0 }}
1079                         ( DEFAULT
1080                           ( value               {{ setdefault(ID, value) }}
1081                           | NONE                {{ setnodefault(ID) }}
1082                           )                     {{ d |= 1 }}
1083                         | FORMAT STR            {{ setformat(ID, dequote(STR)) }}
1084                         | EXPORT 
1085                           ( ALWAYS              {{ setexported(ID) }}
1086                           | USED                {{ setexport(ID) }}
1087                           | NEVER               {{ setnoexport(ID) }}
1088                           )                     {{ d |= 2 }}
1089                         | COMMENT STR           {{ setcomment(ID, dequote(STR)); d |= 4 }}
1090                         )+                      {{ return d }}
1091                 
1092     rule define:        DEFINE ID               {{ newoption(ID) }}
1093                         defstmts<<ID>> END      {{ validdef(ID, defstmts) }}
1094
1095     rule options:       (define)* END           {{ return 1 }}
1096 %%
1097
1098 def dumptree(part, lvl):
1099         if (debug):
1100                 print "DUMPTREE ME is"
1101         part.dumpme(lvl)
1102         # dump the siblings -- actually are there any? not sure
1103         # dump the kids
1104         if (debug):
1105                 print "DUMPTREE KIDS are"
1106         for kid in part.children:
1107                 dumptree(kid, lvl+1)
1108         if (debug):
1109                 print "DONE DUMPTREE"
1110
1111 def gencode(part):
1112         if (debug):
1113                 print "GENCODE ME is"
1114         if (debug):
1115                 part.gencode()
1116         # dump the siblings -- actually are there any? not sure
1117         # dump the kids
1118         if (debug):
1119                 print "GENCODE KIDS are"
1120         for kid in part.children:
1121                 gencode(kid)
1122         if (debug):
1123                 print "DONE GENCODE"
1124         
1125
1126 def doconfigfile(path, file):
1127         if (debug):
1128                 print "DOCONFIGFILE", path, " ", file
1129         filename = os.path.join(path, file)
1130         loc.push_file(filename)
1131         if (not parse('pstmts', open(filename, 'r').read())):
1132                 fatal("Error: Could not parse file")
1133
1134 if __name__=='__main__':
1135         from sys import argv
1136         if (len(argv) < 3):
1137                 print 'Args: <file> <path to linuxbios>'
1138                 sys.exit(1)
1139
1140         top_config_file = os.path.abspath(sys.argv[1])
1141
1142         treetop = os.path.abspath(sys.argv[2])
1143
1144         # Now read in the customizing script...
1145         loc.push_file(argv[1])
1146         if (not parse('board', open(argv[1], 'r').read())):
1147                 fatal("Error: Could not parse file")
1148
1149         if (debug):
1150                 print "DEVICE TREE:"
1151                 dumptree(root, 0)
1152
1153         gencode(root)
1154
1155         for i in options.keys():
1156                 if (isexported(i, 0) and not isset(i, 0)):
1157                         print "WARNING: Option %s using default value %s" % (i, getformated(i, 0))
1158
1159         # crt0 includes
1160         if (debug):
1161                 for i in crt0includes:
1162                         print "crt0include file %s" % (i)
1163                 for i in driverrules.keys():
1164                         print "driver file %s" % (i)
1165                 for i in ldscripts:
1166                         print "ldscript file %s" % (i)
1167                 for i in makebaserules.keys():
1168                         m = makebaserules[i]
1169                         print " makerule %s dep %s act %s" % (i, m.dependency, m.actions)
1170
1171         writemakefilesettings(target_dir)
1172         writecrt0_includes(target_dir)
1173         writemakefile(target_dir)