# -*- 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('/')[-4:], '/')
	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('/')[-4:], '/')
	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)