This patch creates static.dot visualizing the coreboot device tree (v2)
I created it do debug problems with the device/resource allocator.

create pngs with
 $ fdp -o static.png -Tpng static.dot
or
 $ dot -o static.png -Tpng static.dot

TODO/ideas:
 re-introduce colored links again, dropped for now
 node colors according to device type?
 add an agenda

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>

Index: util/newconfig/config.g
===================================================================
--- util/newconfig/config.g	(revision 536)
+++ util/newconfig/config.g	(working copy)
@@ -93,6 +93,7 @@
 	dict = 4
 	statement = 5
 	dump = 6
+	gengraph = 7
 
 	def __init__(self, *level):
 		self.__level = level
@@ -682,6 +683,18 @@
 		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"""
@@ -2254,7 +2267,9 @@
 	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()
 
@@ -2278,6 +2293,75 @@
 		kid = kid.next_sibling
 	debug.info(debug.gencode, "DONE GENCODE")
 
+def writegraph(image):
+	filename = os.path.join(img_dir, "static.dot")
+	print "Creating", filename
+	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)
+
 def verifyparse():
 	"""Add any run-time checks to verify that parsing the configuration
 	was successful"""
@@ -2343,6 +2427,7 @@
 		writeinitincludes(image)
 		writeimagemakefile(image)
 		writeldoptions(image)
+		writegraph(image)
 
 	writemakefilesettings(target_dir)
 	writemakefile(target_dir)
