| # -*- python -*- |
| import sys |
| import os |
| import re |
| import string |
| import types |
| |
| import traceback |
| |
| warnings = 0 |
| errors = 0 |
| |
| treetop = '' |
| full_mainboard_path = '' |
| mainboard_path = '' |
| romimages = {} |
| curimage = 0 |
| |
| # ----------------------------------------------------------------------------- |
| # Utility Classes |
| # ----------------------------------------------------------------------------- |
| |
| class stack: |
| """Used to keep track of the current part or dir""" |
| class __stack_iter: |
| def __init__ (self, stack): |
| self.index = 0 |
| self.len = len(stack) |
| self.stack = stack |
| |
| def __iter__ (self): |
| return self |
| |
| def next (self): |
| if (self.index < self.len): |
| s = self.stack[self.index] |
| self.index = self.index + 1 |
| return s |
| raise StopIteration |
| |
| def __init__ (self): |
| self.stack = [] |
| |
| def __len__ (self): |
| return len(self.stack) |
| |
| def __getitem__ (self, i): |
| return self.stack[i] |
| |
| def __iter__ (self): |
| return self.__stack_iter(self.stack) |
| |
| def push(self, part): |
| self.stack.append(part) |
| |
| def pop(self): |
| try: |
| return self.stack.pop() |
| except IndexError: |
| return 0 |
| |
| def tos(self): |
| try: |
| return self.stack[-1] |
| except IndexError: |
| return 0 |
| |
| def empty(self): |
| return (len(self.stack) == 0) |
| partstack = stack() |
| |
| class debug_info: |
| none = 0 |
| gencode = 1 |
| dumptree = 2 |
| object = 3 |
| dict = 4 |
| statement = 5 |
| dump = 6 |
| gengraph = 7 |
| |
| def __init__(self, *level): |
| self.__level = level |
| |
| def setdebug(self, *level): |
| self.__level = level |
| |
| def level(self, level): |
| return level in self.__level |
| |
| def info(self, level, str): |
| if level in self.__level: |
| print str |
| |
| global debug |
| debug = debug_info(debug_info.none) |
| #debug = debug_info(debug_info.dumptree) |
| #debug = debug_info(debug_info.object) |
| #debug = debug_info(debug_info.gencode) |
| |
| # ----------------------------------------------------------------------------- |
| # Error Handling |
| # ----------------------------------------------------------------------------- |
| |
| def error(string): |
| """Print error message""" |
| global errors, loc |
| errors = errors + 1 |
| print "===> ERROR: %s" % string |
| |
| def fatal(string): |
| """Print error message and exit""" |
| error(string) |
| exitiferrors() |
| |
| def warning(string): |
| """Print warning message""" |
| global warnings, loc |
| warnings = warnings + 1 |
| print "===> WARNING: %s" % string |
| |
| def exitiferrors(): |
| """Exit parser if an error has been encountered""" |
| if (errors != 0): |
| sys.exit(1) |
| |
| def safe_open(file, mode): |
| try: |
| return open(file, mode) |
| except IOError: |
| fatal("Could not open file \"%s\"" % file) |
| |
| # ----------------------------------------------------------------------------- |
| # Main classes |
| # ----------------------------------------------------------------------------- |
| |
| class romimage: |
| """A rom image is the ultimate goal of coreboot""" |
| def __init__ (self, name): |
| # name of this rom image |
| self.name = name |
| |
| # instance counter for parts |
| self.partinstance = 0 |
| |
| # chip config files included by the 'config' directive |
| self.configincludes = {} |
| |
| # root of part tree |
| self.root = 0 |
| |
| # Last device built |
| self.last_device = 0 |
| |
| def getname(self): |
| return self.name |
| |
| def addconfiginclude(self, part, path): |
| setdict(self.configincludes, part, path) |
| |
| def getconfigincludes(self): |
| return self.configincludes |
| |
| def getincludefilename(self): |
| if (self.useinitincludes): |
| return "crt0.S" |
| else: |
| return "crt0_includes.h" |
| |
| def newformat(self): |
| return self.useinitincludes |
| |
| def numparts(self): |
| return self.partinstance |
| |
| def newpartinstance(self): |
| i = self.partinstance |
| self.partinstance = self.partinstance + 1 |
| return i |
| |
| def setroot(self, part): |
| self.root = part |
| |
| def getroot(self): |
| return self.root |
| |
| class partobj: |
| """A configuration part""" |
| def __init__ (self, image, dir, parent, part, type_name, instance_name, chip_or_device): |
| if (parent): |
| debug.info(debug.object, "partobj dir %s parent %s part %s" \ |
| % (dir, parent.instance_name, part)) |
| else: |
| debug.info(debug.object, "partobj dir %s part %s" \ |
| % (dir, part)) |
| |
| # romimage that is configuring this part |
| self.image = image |
| |
| # links for static device tree |
| self.children = 0 |
| self.prev_sibling = 0 |
| self.next_sibling = 0 |
| self.prev_device = 0 |
| self.next_device = 0 |
| self.chip_or_device = chip_or_device |
| |
| # initializers for static device tree |
| self.registercode = {} |
| |
| # part name |
| self.part = part |
| |
| # type name of this part |
| self.type_name = type_name |
| |
| # directory containing part files |
| self.dir = dir |
| |
| # instance number, used to distinguish anonymous |
| # instances of this part |
| self.instance = image.newpartinstance() |
| debug.info(debug.object, "INSTANCE %d" % self.instance) |
| |
| # Name of chip config file (0 if not needed) |
| self.chipconfig = 0 |
| |
| # Flag to indicate that we have generated type |
| # definitions for this part (only want to do it once) |
| self.done_types = 0 |
| |
| # Path to the device |
| self.path = "" |
| |
| # Resources of the device |
| self.resoruce = "" |
| self.resources = 0 |
| |
| # Enabled state of the device |
| self.enabled = 1 |
| |
| # Flag if I am a duplicate device |
| self.dup = 0 |
| |
| # If there is a chip.h file, we will create an |
| # include for it. |
| if (dir): |
| chiph = os.path.join(dir, "chip.h") |
| if (os.path.exists(chiph)): |
| debug.info(debug.object, "%s has chip at %s" % (self, dir)) |
| self.addconfig(chiph) |
| |
| # If no instance name is supplied then generate |
| # a unique name |
| if (instance_name == 0): |
| self.instance_name = self.type_name + \ |
| "_dev%d" % self.instance |
| self.chipinfo_name = "%s_info_%d" \ |
| % (self.type_name, self.instance) |
| else: |
| self.instance_name = instance_name |
| self.chipinfo_name = "%s_info_%d" % (self.instance_name, self.instance) |
| |
| # Link this part into the device list |
| if (self.chip_or_device == 'device'): |
| if (image.last_device): |
| image.last_device.next_device = self |
| self.prev_device = image.last_device |
| image.last_device = self |
| |
| # Link this part into the tree |
| if (parent and (part != 'arch')): |
| debug.info(debug.gencode, "add to parent") |
| self.parent = parent |
| # add current child as my sibling, |
| # me as the child. |
| if (parent.children): |
| debug.info(debug.gencode, "add %s (%d) as sibling" % (parent.children.dir, parent.children.instance)) |
| youngest = parent.children |
| while(youngest.next_sibling): |
| youngest = youngest.next_sibling |
| youngest.next_sibling = self |
| self.prev_sibling = youngest |
| else: |
| parent.children = self |
| else: |
| self.parent = self |
| |
| def info(self): |
| return "%s: %s" % (self.part, self.type) |
| def type(self): |
| return self.chip_or_device |
| |
| def readable_name(self): |
| name = "" |
| name = "%s_%d" % (self.type_name, self.instance) |
| if (self.chip_or_device == 'chip'): |
| name = "%s %s %s" % (name, self.part, self.dir) |
| else: |
| name = "%s %s" % (name, self.path) |
| return name |
| |
| def graph_name(self): |
| name = "{ {_dev%d|" % self.instance |
| if (self.part): |
| name = "%s%s" % (name, self.part) |
| else: |
| name = "%s%s" % (name, self.chip_or_device) |
| if (self.type_name): |
| name = "%s}|%s}" % (name, self.type_name) |
| else: |
| name = "%s}|%s}" % (name, self.parent.type_name) |
| return name |
| |
| def dumpme(self, lvl): |
| """Dump information about this part for debugging""" |
| print "%d: %s" % (lvl, self.readable_name()) |
| print "%d: part %s" % (lvl, self.part) |
| print "%d: instance %d" % (lvl, self.instance) |
| print "%d: chip_or_device %s" % (lvl, self.chip_or_device) |
| print "%d: dir %s" % (lvl,self.dir) |
| print "%d: type_name %s" % (lvl,self.type_name) |
| print "%d: parent: %s" % (lvl, self.parent.readable_name()) |
| if (self.children): |
| print "%d: child %s" % (lvl, self.children.readable_name()) |
| if (self.next_sibling): |
| print "%d: siblings %s" % (lvl, self.next_sibling.readable_name()) |
| print "%d: registercode " % lvl |
| for f, v in self.registercode.items(): |
| print "\t%s = %s" % (f, v) |
| print "%d: chipconfig %s" % (lvl, self.chipconfig) |
| print "\n" |
| |
| def firstchilddevice(self): |
| """Find the first device in the children link.""" |
| kid = self.children |
| while (kid): |
| if (kid.chip_or_device == 'device'): |
| return kid |
| else: |
| kid = kid.children |
| return 0 |
| |
| def firstparentdevice(self): |
| """Find the first device in the parent link.""" |
| parent = self.parent |
| while (parent and (parent.parent != parent) and (parent.chip_or_device != 'device')): |
| parent = parent.parent |
| if ((parent.parent != parent) and (parent.chip_or_device != 'device')): |
| parent = 0 |
| while(parent and (parent.dup == 1)): |
| parent = parent.prev_sibling |
| if (not parent): |
| fatal("Device %s has no device parent; this is a config file error" % self.readable_name()) |
| return parent |
| |
| def firstparentdevicelink(self): |
| """Find the first device in the parent link and record which link it is.""" |
| link = 0 |
| parent = self.parent |
| while (parent and (parent.parent != parent) and (parent.chip_or_device != 'device')): |
| parent = parent.parent |
| if ((parent.parent != parent) and (parent.chip_or_device != 'device')): |
| parent = 0 |
| while(parent and (parent.dup == 1)): |
| parent = parent.prev_sibling |
| link = link + 1 |
| if (not parent): |
| fatal("Device %s has no device parent; this is a config file error" % self.readable_name()) |
| return link |
| |
| |
| def firstparentchip(self): |
| """Find the first chip in the parent link.""" |
| parent = self.parent |
| while (parent): |
| if ((parent.parent == parent) or (parent.chip_or_device == 'chip')): |
| return parent |
| else: |
| parent = parent.parent |
| fatal("Device %s has no chip parent; this is a config file error" % self.readable_name()) |
| |
| def firstsiblingdevice(self): |
| """Find the first device in the sibling link.""" |
| sibling = self.next_sibling |
| while(sibling and (sibling.path == self.path)): |
| sibling = sibling.next_sibling |
| if ((not sibling) and (self.parent.chip_or_device == 'chip')): |
| sibling = self.parent.next_sibling |
| while(sibling): |
| if (sibling.chip_or_device == 'device'): |
| return sibling |
| else: |
| sibling = sibling.children |
| return 0 |
| |
| def gencode(self, file, pass_num): |
| """Generate static initalizer code for this part. Two passes |
| are used - the first generates type information, and the second |
| generates instance information""" |
| if (pass_num == 0): |
| if (self.chip_or_device == 'chip'): |
| return; |
| else: |
| if (self.instance): |
| file.write("struct device %s;\n" \ |
| % self.instance_name) |
| else: |
| file.write("struct device dev_root;\n") |
| return |
| # This is pass the second, which is pass number 1 |
| # this is really just a case statement ... |
| |
| if (self.chip_or_device == 'chip'): |
| if (self.chipconfig): |
| debug.info(debug.gencode, "gencode: chipconfig(%d)" % \ |
| self.instance) |
| file.write("struct %s_config %s" % (self.type_name ,\ |
| self.chipinfo_name)) |
| if (self.registercode): |
| file.write("\t= {\n") |
| for f, v in self.registercode.items(): |
| file.write( "\t.%s = %s,\n" % (f, v)) |
| file.write("};\n") |
| else: |
| file.write(";") |
| file.write("\n") |
| |
| if (self.instance == 0): |
| self.instance_name = "dev_root" |
| file.write("struct device **last_dev_p = &%s.next;\n" % (self.image.last_device.instance_name)) |
| file.write("struct device dev_root = {\n") |
| file.write("\t.ops = &default_dev_ops_root,\n") |
| file.write("\t.bus = &dev_root.link[0],\n") |
| file.write("\t.path = { .type = DEVICE_PATH_ROOT },\n") |
| file.write("\t.enabled = 1,\n\t.links = 1,\n") |
| file.write("\t.on_mainboard = 1,\n") |
| file.write("\t.link = {\n\t\t[0] = {\n") |
| file.write("\t\t\t.dev=&dev_root,\n\t\t\t.link = 0,\n") |
| file.write("\t\t\t.children = &%s,\n" % self.firstchilddevice().instance_name) |
| file.write("\t\t},\n") |
| file.write("\t},\n") |
| if (self.chipconfig): |
| file.write("\t.chip_ops = &%s_ops,\n" % self.type_name) |
| file.write("\t.chip_info = &%s_info_%s,\n" % (self.type_name, self.instance)) |
| file.write("\t.next = &%s,\n" % self.firstchilddevice().instance_name) |
| file.write("};\n") |
| return |
| |
| # Don't print duplicate devices, just print their children |
| if (self.dup): |
| return |
| |
| file.write("struct device %s = {\n" % self.instance_name) |
| file.write("\t.ops = 0,\n") |
| file.write("\t.bus = &%s.link[%d],\n" % \ |
| (self.firstparentdevice().instance_name, \ |
| self.firstparentdevicelink())) |
| file.write("\t.path = {%s},\n" % self.path) |
| file.write("\t.enabled = %d,\n" % self.enabled) |
| file.write("\t.on_mainboard = 1,\n") |
| if (self.resources): |
| file.write("\t.resources = %d,\n" % self.resources) |
| file.write("\t.resource = {%s\n\t },\n" % self.resource) |
| file.write("\t.link = {\n"); |
| links = 0 |
| bus = self |
| while(bus and (bus.path == self.path)): |
| child = bus.firstchilddevice() |
| if (child or (bus != self) or (bus.next_sibling and (bus.next_sibling.path == self.path))): |
| file.write("\t\t[%d] = {\n" % links) |
| file.write("\t\t\t.link = %d,\n" % links) |
| file.write("\t\t\t.dev = &%s,\n" % self.instance_name) |
| if (child): |
| file.write("\t\t\t.children = &%s,\n" %child.instance_name) |
| file.write("\t\t},\n") |
| links = links + 1 |
| if (1): |
| bus = bus.next_sibling |
| else: |
| bus = 0 |
| file.write("\t},\n") |
| file.write("\t.links = %d,\n" % (links)) |
| sibling = self.firstsiblingdevice(); |
| if (sibling): |
| file.write("\t.sibling = &%s,\n" % sibling.instance_name) |
| chip = self.firstparentchip() |
| if (chip and chip.chipconfig): |
| file.write("\t.chip_ops = &%s_ops,\n" % chip.type_name) |
| file.write("\t.chip_info = &%s_info_%s,\n" % (chip.type_name, chip.instance)) |
| if (self.next_device): |
| file.write("\t.next=&%s\n" % self.next_device.instance_name) |
| file.write("};\n") |
| return |
| |
| def addconfig(self, path): |
| """Add chip config file to this part""" |
| self.chipconfig = os.path.join(self.dir, path) |
| self.image.addconfiginclude(self.type_name, self.chipconfig) |
| |
| def addregister(self, field, value): |
| """Register static initialization information""" |
| if (self.chip_or_device != 'chip'): |
| fatal("Only chips can have register values") |
| field = dequote(field) |
| value = dequote(value) |
| setdict(self.registercode, field, value) |
| |
| def set_enabled(self, enabled): |
| self.enabled = enabled |
| |
| def start_resources(self): |
| self.resource = "" |
| self.resources = 0 |
| |
| def end_resources(self): |
| self.resource = "%s" % (self.resource) |
| |
| def add_resource(self, type, index, value): |
| """ Add a resource to a device """ |
| self.resource = "%s\n\t\t{ .flags=%s, .index=0x%x, .base=0x%x}," % (self.resource, type, index, value) |
| self.resources = self.resources + 1 |
| |
| def set_path(self, path): |
| self.path = path |
| if (self.prev_sibling and (self.prev_sibling.path == self.path)): |
| self.dup = 1 |
| if (self.prev_device): |
| self.prev_device.next_device = self.next_device |
| if (self.next_device): |
| self.next_device.prev_device = self.prev_device |
| if (self.image.last_device == self): |
| self.image.last_device = self.prev_device |
| self.prev_device = 0 |
| self.next_device = 0 |
| |
| def addpcipath(self, slot, function): |
| """ Add a relative pci style path from our parent to this device """ |
| if ((slot < 0) or (slot > 0x1f)): |
| fatal("Invalid device id") |
| if ((function < 0) or (function > 7)): |
| fatal("Invalid pci function %s" % function ) |
| self.set_path(".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}" % (slot, function)) |
| |
| def addpnppath(self, port, device): |
| """ Add a relative path to a pnp device hanging off our parent """ |
| if ((port < 0) or (port > 65536)): |
| fatal("Invalid port") |
| if ((device < 0) or (device > 0xffff)): |
| fatal("Invalid device") |
| self.set_path(".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}" % (port, device)) |
| |
| def addi2cpath(self, device): |
| """ Add a relative path to a i2c device hanging off our parent """ |
| if ((device < 0) or (device > 0x7f)): |
| fatal("Invalid device") |
| self.set_path(".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x }}" % (device)) |
| |
| def addapicpath(self, apic_id): |
| """ Add a relative path to a cpu device hanging off our parent """ |
| if ((apic_id < 0) or (apic_id > 255)): |
| fatal("Invalid device") |
| self.set_path(".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}" % (apic_id)) |
| |
| def addpci_domainpath(self, pci_domain): |
| """ Add a pci_domain number to a chip """ |
| if ((pci_domain < 0) or (pci_domain > 0xffff)): |
| fatal("Invalid pci_domain: 0x%x is out of the range 0 to 0xffff" % pci_domain) |
| self.set_path(".type=DEVICE_PATH_PCI_DOMAIN,{.pci_domain={ .domain = 0x%x }}" % (pci_domain)) |
| |
| def addapic_clusterpath(self, cluster): |
| """ Add an apic cluster to a chip """ |
| if ((cluster < 0) or (cluster > 15)): |
| fatal("Invalid apic cluster: %d is out of the range 0 to ff" % cluster) |
| self.set_path(".type=DEVICE_PATH_APIC_CLUSTER,{.apic_cluster={ .cluster = 0x%x }}" % (cluster)) |
| |
| def addcpupath(self, cpu_id): |
| """ Add a relative path to a cpu device hanging off our parent """ |
| if ((cpu_id < 0) or (cpu_id > 255)): |
| fatal("Invalid device") |
| self.set_path(".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}" % (cpu_id)) |
| |
| |
| def addcpu_buspath(self, id): |
| """ Add a cpu_bus to a chip """ |
| if ((id < 0) or (id > 255)): |
| fatal("Invalid device") |
| self.set_path(".type=DEVICE_PATH_CPU_BUS,{.cpu_bus={ .id = 0x%x }}" % (id)) |
| |
| |
| # ----------------------------------------------------------------------------- |
| # statements |
| # ----------------------------------------------------------------------------- |
| |
| def getdict(dict, name): |
| if name not in dict.keys(): |
| debug.info(debug.dict, "Undefined: %s" % name) |
| return 0 |
| v = dict.get(name, 0) |
| debug.info(debug.dict, "getdict %s returning %s" % (name, v)) |
| return v |
| |
| def setdict(dict, name, value): |
| debug.info(debug.dict, "setdict sets %s to %s" % (name, value)) |
| if name in dict.keys(): |
| print "Duplicate in dict: %s" % name |
| dict[name] = value |
| |
| |
| def addconfig(path): |
| global partstack |
| curpart = partstack.tos() |
| curpart.addconfig(path) |
| |
| def addregister(field, value): |
| global partstack |
| curpart = partstack.tos() |
| curpart.addregister(field, value) |
| |
| def devicepart(type): |
| global curimage, partstack |
| newpart = partobj(curimage, 0, partstack.tos(), type, \ |
| '', 0, 'device') |
| #print "Configuring PART %s" % (type) |
| partstack.push(newpart) |
| #print " new PART tos is now %s\n" %partstack.tos().info() |
| # just push TOS, so that we can pop later. |
| |
| def part(type, path, file, name): |
| global curimage, partstack |
| partdir = os.path.join(type, path) |
| srcdir = os.path.join(treetop, 'src') |
| fulldir = os.path.join(srcdir, partdir) |
| type_name = flatten_name(partdir) |
| #print "PART(%s, %s, %s, %s)\n" % (type, path, file, name) |
| newpart = partobj(curimage, fulldir, partstack.tos(), type, \ |
| type_name, name, 'chip') |
| #print "Configuring PART %s, path %s" % (type, path) |
| partstack.push(newpart) |
| |
| def partpop(): |
| global partstack |
| curpart = partstack.tos() |
| if (curpart == 0): |
| fatal("Trying to pop non-existent part") |
| #print "End PART %s" % curpart.part |
| oldpart = partstack.pop() |
| #print "partstack.pop, TOS is now %s\n" % oldpart.info() |
| |
| #============================================================================= |
| # MISC FUNCTIONS |
| #============================================================================= |
| def dequote(str): |
| a = re.sub("^\"", "", str) |
| a = re.sub("\"$", "", a) |
| # highly un-intuitive, need four \! |
| a = re.sub("\\\\\"", "\"", a) |
| return a |
| |
| def flatten_name(str): |
| a = re.sub("[/-]", "_", str) |
| return a |
| %% |
| parser Config: |
| ignore: r'\s+' |
| ignore: "#.*?\r?\n" |
| |
| # less general tokens should come first, otherwise they get matched |
| # by the re's |
| token COMMENT: 'comment' |
| token CPU: 'cpu' |
| token CPU_BUS: 'cpu_bus' |
| token CHIP: 'chip' |
| token DEVICE: 'device' |
| token DEVICE_ID: 'device_id' |
| token DRQ: 'drq' |
| token END: 'end' |
| token EOF: '$' |
| token EQ: '=' |
| token FORMAT: 'format' |
| token IO: 'io' |
| token IRQ: 'irq' |
| token MEM: 'mem' |
| token NEVER: 'never' |
| token NONE: 'none' |
| token PMC: 'pmc' |
| token PRINT: 'print' |
| token REGISTER: 'register' |
| token VENDOR_ID: 'vendor_id' |
| token WRITE: 'write' |
| token NUM: '[0-9]+' |
| token HEX_NUM: '[0-9a-fA-F]+' |
| token HEX_PREFIX: '0x' |
| # Why is path separate? Because paths to resources have to at least |
| # have a slash, we thinks |
| token PATH: r'[-a-zA-Z0-9_.][-a-zA-Z0-9/_.]+[-a-zA-Z0-9_.]+' |
| # Dir's on the other hand are abitrary |
| # this may all be stupid. |
| token RULE: r'[-a-zA-Z0-9_$()./]+[-a-zA-Z0-9_ $()./]+[-a-zA-Z0-9_$()./]+' |
| token ID: r'[a-zA-Z_.]+[a-zA-Z0-9_.]*' |
| token STR: r'"([^\\"]+|\\.)*"' |
| token RAWTEXT: r'.*' |
| token ON: 'on' |
| token OFF: 'off' |
| token PCI: 'pci' |
| token PNP: 'pnp' |
| token I2C: 'i2c' |
| token APIC: 'apic' |
| token APIC_CLUSTER: 'apic_cluster' |
| token CPU: 'cpu' |
| token CPU_BUS: 'cpu_bus' |
| token PCI_DOMAIN: 'pci_domain' |
| |
| |
| rule expr: logical {{ l = logical }} |
| ( "&&" logical {{ l = l and logical }} |
| | "[|][|]" logical {{ l = l or logical }} |
| )* {{ return l }} |
| |
| rule logical: factor {{ n = factor }} |
| ( "[+]" factor {{ n = n+factor }} |
| | "-" factor {{ n = n-factor }} |
| )* {{ return n }} |
| |
| rule factor: term {{ v = term }} |
| ( "[*]" term {{ v = v*term }} |
| | "/" term {{ v = v/term }} |
| | "<<" term {{ v = v << term }} |
| | ">=" term {{ v = (v < term)}} |
| )* {{ return v }} |
| |
| # A term is a number, variable, or an expression surrounded by parentheses |
| rule term: NUM {{ return long(NUM, 10) }} |
| | HEX_PREFIX HEX_NUM {{ return long(HEX_NUM, 16) }} |
| | ID {{ return lookup(ID) }} |
| | unop {{ return unop }} |
| | "\\(" expr "\\)" {{ return expr }} |
| |
| rule unop: "!" expr {{ return not(expr) }} |
| |
| rule partend<<C>>: (stmt<<C>>)* END {{ if (C): partpop()}} |
| |
| # This is needed because the legacy cpu command could not distinguish |
| # between cpu vendors. It should just be PATH, but getting this change |
| # into the source tree will be tricky... |
| # DO NOT USE ID AS IT MAY GO AWAY IN THE FUTURE |
| rule partid: ID {{ return ID }} |
| | PATH {{ return PATH }} |
| |
| rule parttype: CHIP {{ return '' }} |
| |
| rule partdef<<C>>: {{ name = 0 }} |
| parttype partid |
| [ STR {{ name = dequote(STR) }} |
| ] {{ if (C): part(parttype, partid, 'Config.lb', name) }} |
| partend<<C>> |
| |
| rule field: STR {{ return STR }} |
| |
| rule register<<C>>: REGISTER field '=' STR {{ if (C): addregister(field, STR) }} |
| |
| rule enable<<C>>: {{ val = 1 }} |
| ( ON {{ val = 1 }} |
| | OFF {{ val = 0 }} |
| ) {{ if(C): partstack.tos().set_enabled(val) }} |
| |
| rule resource<<C>>: {{ type = "" }} |
| ( IO {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO" }} |
| | MEM {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_MEM" }} |
| | IRQ {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IRQ" }} |
| | DRQ {{ type = "IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_DRQ" }} |
| ) |
| term '=' {{ index = term }} |
| term {{ value = term }} |
| {{ if (C): partstack.tos().add_resource(type, index, value) }} |
| |
| |
| rule resources<<C>>: {{ if (C): partstack.tos().start_resources() }} |
| ( resource<<C>> )* |
| {{ if (C): partstack.tos().end_resources() }} |
| |
| |
| rule pci<<C>>: PCI {{ if (C): devicepart('pci') }} |
| |
| HEX_NUM {{ slot = int(HEX_NUM,16) }} |
| '.' HEX_NUM {{ function = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addpcipath(slot, function) }} |
| rule pci_domain<<C>>: |
| PCI_DOMAIN {{ if (C): devicepart('pci_domain') }} |
| HEX_NUM {{ pci_domain = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addpci_domainpath(pci_domain) }} |
| |
| rule pnp<<C>>: PNP {{ if (C): devicepart('pnp') }} |
| HEX_NUM {{ port = int(HEX_NUM,16) }} |
| '.' HEX_NUM {{ device = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addpnppath(port, device) }} |
| |
| rule i2c<<C>>: I2C {{ if (C): devicepart('i2c') }} |
| HEX_NUM {{ device = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addi2cpath(device) }} |
| |
| rule apic<<C>>: APIC {{ if (C): devicepart('apic') }} |
| HEX_NUM {{ apic_id = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addapicpath(apic_id) }} |
| |
| rule apic_cluster<<C>>: APIC_CLUSTER {{ if (C): devicepart('apic_cluster') }} |
| HEX_NUM {{ cluster = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addapic_clusterpath(cluster) }} |
| |
| rule cpu<<C>>: CPU {{ if (C): devicepart('cpu') }} |
| HEX_NUM {{ id = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addcpupath(id) }} |
| |
| rule cpu_bus<<C>>: CPU_BUS {{ if (C): devicepart('cpu_bus') }} |
| HEX_NUM {{ id = int(HEX_NUM, 16) }} |
| {{ if (C): partstack.tos().addcpu_buspath(id) }} |
| |
| rule dev_path<<C>>: |
| pci<<C>> {{ return pci }} |
| | pci_domain<<C>> {{ return pci_domain }} |
| | pnp<<C>> {{ return pnp }} |
| | i2c<<C>> {{ return i2c }} |
| | apic<<C>> {{ return apic }} |
| | apic_cluster<<C>> {{ return apic_cluster }} |
| | cpu<<C>> {{ return cpu }} |
| | cpu_bus<<C>> {{ return cpu_bus }} |
| |
| rule prtval: expr {{ return str(expr) }} |
| | STR {{ return STR }} |
| |
| rule prtlist: prtval {{ el = "%(" + prtval }} |
| ( "," prtval {{ el = el + "," + prtval }} |
| )* {{ return el + ")" }} |
| |
| rule prtstmt<<C>>: PRINT STR {{ val = STR }} |
| [ "," prtlist {{ val = val + prtlist }} |
| ] {{ if (C): print eval(val) }} |
| |
| rule device<<C>>: DEVICE dev_path<<C>> |
| enable<<C>> |
| resources<<C>> |
| partend<<C>> |
| |
| rule stmt<<C>>: |
| partdef<<C>> {{ return partdef }} |
| | prtstmt<<C>> {{ return prtstmt }} |
| | register<<C>> {{ return register }} |
| | device<<C>> {{ return device }} |
| |
| rule value: STR {{ return dequote(STR) }} |
| | expr {{ return expr }} |
| |
| rule devicetree: partdef<<1>> |
| EOF {{ return 1 }} |
| |
| rule wrstr<<ID>>: STR {{ setwrite(ID, dequote(STR)) }} |
| |
| %% |
| |
| #============================================================================= |
| # FILE OUTPUT |
| #============================================================================= |
| |
| def dumptree(part, lvl): |
| debug.info(debug.dumptree, "DUMPTREE ME is") |
| print "%s " % part |
| part.dumpme(lvl) |
| # dump the siblings -- actually are there any? not sure |
| # siblings are: |
| debug.info(debug.dumptree, "DUMPTREE SIBLINGS are") |
| kid = part.next_sibling |
| while (kid): |
| kid.dumpme(lvl) |
| kid = kid.next_sibling |
| # dump the kids |
| debug.info(debug.dumptree, "DUMPTREE KIDS are") |
| #for kid in part.children: |
| if (part.children): |
| dumptree(part.children, lvl+1) |
| kid = part.next_sibling |
| while (kid): |
| if (kid.children): |
| dumptree(kid.children, lvl + 1) |
| kid = kid.next_sibling |
| debug.info(debug.dumptree, "DONE DUMPTREE") |
| |
| def writecode(image): |
| filename = os.path.join(img_dir, "static.c") |
| print " SCONFIG ", join(filename.split('/')[-5:], '/') |
| file = safe_open(filename, 'w+') |
| file.write("#include <device/device.h>\n") |
| file.write("#include <device/pci.h>\n") |
| for path in image.getconfigincludes().values(): |
| file.write("#include \"%s\"\n" % path) |
| file.write("\n/* pass 0 */\n") |
| gencode(image.getroot(), file, 0) |
| file.write("\n/* pass 1 */\n") |
| gencode(image.getroot(), file, 1) |
| file.close() |
| |
| def gencode(part, file, pass_num): |
| debug.info(debug.gencode, "GENCODE ME is") |
| part.gencode(file, pass_num) |
| # dump the siblings -- actually are there any? not sure |
| debug.info(debug.gencode, "GENCODE SIBLINGS are") |
| kid = part.next_sibling |
| while (kid): |
| kid.gencode(file, pass_num) |
| kid = kid.next_sibling |
| # now dump the children |
| debug.info(debug.gencode, "GENCODE KIDS are") |
| if (part.children): |
| gencode(part.children, file, pass_num) |
| kid = part.next_sibling |
| while (kid): |
| if (kid.children): |
| gencode(kid.children, file, pass_num) |
| kid = kid.next_sibling |
| debug.info(debug.gencode, "DONE GENCODE") |
| |
| def writegraph(image): |
| filename = os.path.join(img_dir, "static.dot") |
| print " SCONFIG ", join(filename.split('/')[-5:], '/') |
| file = safe_open(filename, 'w+') |
| file.write("digraph devicetree {\n") |
| file.write(" rankdir=LR\n") |
| genranks(image.getroot(), file, 0) |
| gennodes(image.getroot(), file) |
| gengraph(image.getroot(), file) |
| file.write("}\n") |
| file.close() |
| |
| def genranks(part, file, level): |
| #file.write(" # Level %d\n" % level ) |
| file.write(" { rank = same; \"dev_%s_%d\"" % (part.type_name,part.instance )) |
| sib = part.next_sibling |
| while (sib): |
| file.write("; \"dev_%s_%d\"" % (sib.type_name, sib.instance)) |
| sib = sib.next_sibling |
| file.write("}\n" ) |
| # now dump the children |
| if (part.children): |
| genranks(part.children, file, level + 1) |
| |
| kid = part.next_sibling |
| while (kid): |
| if (kid.children): |
| genranks(kid.children, file, level + 1) |
| kid = kid.next_sibling |
| |
| |
| def gennodes(part, file): |
| file.write(" dev_%s_%d[shape=record, label=\"%s\"];\n" % (part.type_name,part.instance,part.graph_name() )) |
| sib = part.next_sibling |
| while (sib): |
| file.write(" dev_%s_%d[shape=record, label=\"%s\"];\n" % (sib.type_name,sib.instance,sib.graph_name() )) |
| sib = sib.next_sibling |
| # now dump the children |
| if (part.children): |
| gennodes(part.children, file) |
| |
| kid = part.next_sibling |
| while (kid): |
| if (kid.children): |
| gennodes(kid.children, file) |
| kid = kid.next_sibling |
| |
| |
| def gengraph(part, file): |
| if (part.parent != part): |
| file.write(" dev_%s_%d -> dev_%s_%d;\n" % \ |
| (part.parent.type_name, part.parent.instance, \ |
| part.type_name, part.instance )) |
| sib = part.next_sibling |
| while (sib): |
| file.write(" dev_%s_%d -> dev_%s_%d;\n" % \ |
| (sib.parent.type_name, sib.parent.instance, \ |
| sib.type_name, sib.instance )) |
| sib = sib.next_sibling |
| |
| kid = part.next_sibling |
| while (kid): |
| if (kid.children): |
| gengraph(kid.children, file) |
| kid = kid.next_sibling |
| |
| if (part.children): |
| gengraph(part.children, file) |
| |
| #============================================================================= |
| # MAIN PROGRAM |
| #============================================================================= |
| if __name__=='__main__': |
| from sys import argv |
| if (len(argv) < 4): |
| fatal("Args: <file> <path to coreboot> <output-dir>") |
| |
| file = "devicetree.cb" |
| partdir = os.path.join("mainboard", sys.argv[1]) |
| treetop = argv[2] |
| srcdir = os.path.join(treetop, 'src') |
| fulldir = os.path.join(srcdir, partdir) |
| type_name = flatten_name(partdir) |
| config_file = os.path.join(fulldir, file) |
| |
| curimage = romimage("new") |
| image = curimage |
| |
| newpart = partobj(curimage, fulldir, partstack.tos(), 'mainboard', \ |
| 'mainboard', 0, 'chip') |
| #print "Configuring PART %s, path %s" % (type, path) |
| image.setroot(newpart); |
| partstack.push(newpart) |
| |
| fp = safe_open(config_file, 'r') |
| if (not parse('devicetree', fp.read())): |
| fatal("Could not parse file") |
| partstack.pop() |
| |
| img_dir = argv[3] |
| |
| #debug.info(debug.dumptree, "DEVICE TREE:") |
| #dumptree(curimage.getroot(), 0) |
| |
| writecode(image) |
| writegraph(image) |
| |
| sys.exit(0) |