Index: misc/check-glob.py
===================================================================
--- misc/check-glob.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,82 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from pycparser import c_ast, c_generator, parse_file
-from re import sub
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class Visitor(c_ast.NodeVisitor):
-    gen = c_generator.CGenerator()
-
-    def __init__(self):
-        self.path = None
-        self.decl = {}
-        self.errs = []
-
-    def visit_Typedef(self, node):
-        return
-
-    def visit_Decl(self, node):
-        if node.coord.file != self.path or node.name is None:
-            return
-
-        node.init = None
-        node.storage = [x for x in node.storage if
-                        x != "static" and
-                        x != "extern"]
-
-        decl = sub(r"\[[^\]]+\]", "[]", self.gen.visit(node))
-
-        if node.name not in self.decl:
-            self.decl[node.name] = decl
-
-        elif self.decl[node.name] != decl:
-            self.errs.append("mismatch for {} in {}:{}: {} <-> {}". \
-                             format(node.name, node.coord.file, node.coord.line, \
-                                    self.decl[node.name], decl))
-
-    def visit_FuncDef(self, node):
-        if node.coord.file != self.path:
-            return
-
-        self.visit_Decl(node.decl)
-
-    def visit_path(self, path, ast):
-        self.path = path
-        self.visit(ast)
-        self.path = None
-
-    def show_errs(self):
-        for err in self.errs:
-            print(err)
-
-path_ast = []
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("parsing {}                    \r".format(path))
-        stdout.flush()
-
-        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
-        path_ast.append((path, ast))
-        # ast.show()
-
-    print("")
-
-vis = Visitor()
-
-for (path, ast) in path_ast:
-    stdout.write("visiting {}                    \r".format(path))
-    stdout.flush()
-
-    vis.visit_path(path, ast)
-
-print("")
-vis.show_errs()
Index: misc/fix-decls.py
===================================================================
--- misc/fix-decls.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,186 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from pycparser import c_ast, c_generator, parse_file
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class Visitor(c_ast.NodeVisitor):
-    gen = c_generator.CGenerator()
-
-    def __init__(self):
-        self.path = None
-
-        self.calls = {}
-        self.knows = {}
-
-        self.declares = {}
-        self.in_header = {}
-
-        self.decl = {}
-
-        self.max_decl = {}
-        self.max_head = {}
-
-        self.fix_head = {}
-        self.fix_decl = {}
-
-    def visit_FuncCall(self, node):
-        if node.coord.file != self.path:
-            return
-
-        if type(node.name) is not c_ast.ID:
-            return
-
-        if self.path not in self.calls:
-            self.calls[self.path] = set()
-
-        self.calls[self.path].add(node.name.name)
-        self.generic_visit(node)
-
-    def visit_path(self, path, ast):
-        self.path = path
-        self.visit(ast)
-        self.path = None
-
-        for node in ast.ext:
-            if type(node) is not c_ast.FuncDef:
-                continue
-
-            node.decl.storage = []
-            decl = self.gen.visit(node.decl)
-
-            if node.decl.name in self.decl and \
-               self.decl[node.decl.name] != decl:
-                raise Exception("declaration mismatch: {} vs. {}". \
-                                format(self.decl[node.decl.name], decl))
-
-            self.decl[node.decl.name] = decl
-
-        for node in ast.ext:
-            if type(node) is c_ast.Decl and \
-               type(node.type) is c_ast.FuncDecl:
-                decl = node
-
-            elif type(node) is c_ast.FuncDef:
-                decl = node.decl
-
-            else:
-                continue
-
-            if path not in self.knows:
-                self.knows[path] = set()
-
-            self.knows[path].add(decl.name)
-
-            if decl.coord.file != path:
-                continue
-
-            if type(node) is c_ast.Decl:
-                if path not in self.max_decl:
-                    self.max_decl[path] = -1;
-
-                if decl.coord.line > self.max_decl[path]:
-                    self.max_decl[path] = decl.coord.line
-
-            if path not in self.declares:
-                self.declares[path] = set()
-
-            self.declares[path].add(decl.name)
-
-            if path[-2:] == ".h":
-                if decl.name in self.in_header:
-                    raise Exception("duplicate definition of {}".format(decl.name))
-
-                self.in_header[decl.name] = path
-
-    def fix(self):
-        for path, calls in sorted(self.calls.items()):
-            knows = self.knows[path]
-            needs = calls - knows
-
-            for need in sorted(needs):
-                if need in self.in_header:
-                    if path not in self.fix_head:
-                        self.fix_head[path] = set()
-
-                    self.fix_head[path].add(self.in_header[need])
-
-                else:
-                    if path not in self.fix_decl:
-                        self.fix_decl[path] = set()
-
-                    self.fix_decl[path].add(self.decl[need])
-
-            no = 1
-
-            with open(path, "r") as f:
-                for line in f:
-                    if len(line) >= 8 and line[:8] == "#include":
-                        self.max_head[path] = no
-
-                    no += 1
-
-        for path, _ in sorted(self.calls.items()):
-            if path not in self.fix_head and path not in self.fix_decl:
-                continue
-
-            max_head = self.max_head[path] if path in self.max_head else None
-            max_decl = self.max_decl[path] if path in self.max_decl else None
-
-            if max_head is None:
-                max_head = max_decl
-
-            if max_decl is None:
-                max_decl = max_head
-
-            no = 1
-            out = []
-            extern = "extern "
-
-            with open(path, "r") as f:
-                for line in f:
-                    out.append(line)
-
-                    if "extern\t" in line:
-                        extern = "extern\t"
-
-                    if no == max_head and path in self.fix_head:
-                        out.append("\n")
-
-                        for head in sorted(self.fix_head[path]):
-                            out.append("#include \"{}\"\n".format(head.split("/")[-1]))
-
-                    if no == max_decl and path in self.fix_decl:
-                        out.append("\n")
-
-                        for decl in sorted(self.fix_decl[path]):
-                            out.append(extern + decl + ";\n")
-
-                    no += 1
-
-            with open(path, "w") as f:
-                for line in out:
-                    f.write(line)
-
-vis = Visitor()
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("parsing {}                    \r".format(path))
-        stdout.flush()
-
-        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
-        # ast.show()
-
-        vis.visit_path(path, ast)
-
-    print("")
-
-vis.fix()
Index: misc/fix-inc.py
===================================================================
--- misc/fix-inc.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,43 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        if path[-2:] != ".c":
-            continue
-
-        stdout.write("fixing {}                    \r".format(path))
-        stdout.flush()
-
-        with open(path, "r") as f:
-            lines = f.read().split("\n")
-
-        beg = None
-        end = None
-        idx = 0
-
-        for line in lines:
-            if len(line) >= 8 and line[:8] == "#include":
-                if beg is None:
-                    beg = idx
-
-                end = idx
-
-            elif len(line) != 0 and beg is not None:
-                break
-
-            idx += 1
-
-        if beg is not None:
-            out = lines[0 : beg] + ["#include \"all.h\""] + lines[end + 1:] + [""]
-
-            with open(path, "w") as f:
-                f.write("\n".join(out))
-
-    print("")
Index: misc/fix-proto.py
===================================================================
--- misc/fix-proto.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,202 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from os import unlink
-from pickle import load
-from pycparser import c_ast, parse_file, c_generator
-from re import subn, escape
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class Visitor(c_ast.NodeVisitor):
-    def reset(self):
-        self.path = None
-        self.orig = None
-        self.align = None
-
-        self.func_def = False
-        self.prev_line = 0
-        self.this_line = None
-        self.subs = []
-        self.sub_def = False
-
-    def __init__(self):
-        with open("proto.dat", "rb") as f:
-            proto = load(f)
-
-        self.proto = {}
-
-        for p in proto:
-            self.proto[p.name] = p
-
-        self.gen = c_generator.CGenerator()
-        self.reset()
-
-    def visit_Decl(self, node):
-        if node.coord.file != self.path:
-            return
-
-        sub_def = self.func_def
-        self.func_def = False
-
-        if type(node.type) is not c_ast.FuncDecl:
-            return
-
-        if node.coord.line <= self.prev_line:
-            return
-
-        if self.this_line is None:
-            self.this_line = node.coord.line
-
-        if node.coord.line != self.this_line:
-            return
-
-        self.sub_def = sub_def
-
-        self.generic_visit(node)
-        self.subs.append(node)
-
-    def visit_FuncDef(self, node):
-        if node.coord.file != self.path:
-            return
-
-        self.func_def = True
-        self.generic_visit(node)
-
-    def get_ast(self):
-        with open(self.path, "w") as f:
-            f.write(self.orig)
-
-        ast = parse_file(self.path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
-        # ast.show()
-
-        unlink(self.path)
-        return ast
-
-    def make_old_new(self, sub):
-        old = self.gen.visit(sub).replace("*" + sub.name, "* " + sub.name)
-
-        old_type = sub.type
-        sub.type = self.proto[sub.name].type
-
-        new = self.gen.visit(sub)
-        sub.type = old_type
-
-        print("{} -> {}".format(old, new))
-        return (old, new)
-
-    def replace_dec(self):
-        print("--- {}:{}:".format(self.path, self.this_line))
-
-        lines = self.orig.split("\n")
-        out = lines[:self.this_line - 1]
-
-        for sub in self.subs:
-            (_, new) = self.make_old_new(sub)
-
-            if self.align:
-                news_spa = new.split(" ")
-                news_tab = []
-
-                while news_spa[0] in ["extern", "char", "short", "int",
-                                      "unsigned", "long", "struct", "void",
-                                      "FILE", "PFS"]:
-                    is_struct = news_spa[0] == "struct"
-
-                    news_tab.append(news_spa[0])
-                    news_spa = news_spa[1:]
-
-                    if is_struct:
-                        news_tab.append(news_spa[0])
-                        news_spa = news_spa[1:]
-
-                new_spa = " ".join(news_spa)
-                new_tab = "\t".join(news_tab)
-                new = new_tab + "\t" + new_spa
-
-            out.append(new + ";")
-
-        out += lines[self.this_line:]
-        self.orig = "\n".join(out)
-
-        self.this_line += len(self.subs) - 1
-
-    def replace_def(self):
-        print("--- {}:{}:".format(self.path, self.this_line))
-
-        def make_re(olds, strip = None):
-            escs = [escape(x) for x in olds if x != strip]
-            re = "[\t\n ]*".join(escs) + "[^{/]*\n{"
-            # print("re {}".format(re))
-            return re
-
-        for sub in self.subs:
-            (old, new) = self.make_old_new(sub)
-
-            olds = old.split(" ")
-            new += "\n{"
-
-            (new_orig, n) = subn(make_re(olds), new, self.orig)
-
-            if n == 0 and "int" in olds:
-                (new_orig, n) = subn(make_re(olds, "int"), new, self.orig)
-
-            if n != 1:
-                raise Exception("error while replacing definition")
-
-            self.orig = new_orig
-
-    def fix(self, path, orig):
-        self.path = path
-        self.orig = orig
-        self.align = "extern\t" in orig or \
-                "char\t" in orig or \
-                "short\t" in orig or \
-                "int\t" in orig or \
-                "long\t" in orig
-
-        while True:
-            self.visit(self.get_ast())
-
-            if self.this_line is None:
-                break
-
-            if self.sub_def:
-                self.replace_def()
-            else:
-                self.replace_dec()
-
-            self.prev_line = self.this_line
-            self.this_line = None
-            self.subs = []
-            self.sub_def = False
-
-        fixed = self.orig
-        self.reset()
-        return fixed
-
-vis = Visitor()
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("fixing {}                    \r".format(path))
-        stdout.flush()
-
-        with open(path, "r") as f:
-            orig = f.read()
-
-        segs = path.split("/")
-        path_ = "/".join(segs[:-1] + ["_" + segs[-1]])
-
-        fixed = vis.fix(path_, orig)
-
-        with open(path, "w") as f:
-            f.write(fixed)
-
-    print("")
Index: misc/fix-types.py
===================================================================
--- misc/fix-types.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,140 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from os import unlink
-from pycparser import c_ast, parse_file
-from re import escape, subn
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class Visitor(c_ast.NodeVisitor):
-    def reset(self):
-        self.path = None
-        self.orig = None
-        self.subst = None
-
-    def __init__(self):
-        self.reset()
-
-    def visit_IdentifierType(self, node):
-        if node.coord.file != self.path or self.subst is not None:
-            return
-
-        new = None
-
-        if node.names == ["char"]:
-            new = "int8_t"
-
-        elif node.names == ["unsigned", "char"]:
-            new = "uint8_t"
-
-        elif node.names == ["short"] or \
-             node.names == ["int"]:
-            new = "int16_t"
-        elif node.names == ["unsigned", "short"] or \
-             node.names == ["unsigned", "int"] or \
-             node.names == ["unsigned"] or \
-             node.names == ["uint"] or \
-             node.names == ["UWORD16"]:
-            new = "uint16_t"
-
-        elif node.names == ["long"]:
-            new = "int32_t"
-
-        elif node.names == ["unsigned", "long"]:
-            new = "uint32_t"
-
-        elif node.names == ["void"] or \
-             node.names == ["int8_t"] or \
-             node.names == ["uint8_t"] or \
-             node.names == ["int16_t"] or \
-             node.names == ["uint16_t"] or \
-             node.names == ["int32_t"] or \
-             node.names == ["uint32_t"] or \
-             node.names == ["va_list"] or \
-             node.names == ["jmp_buf"] or \
-             node.names == ["BOOL"] or \
-             node.names == ["FILE"] or \
-             node.names == ["io_arg"] or \
-             node.names == ["LPF"]:
-            pass
-
-        else:
-            raise Exception("unknown type: {}".format(node.names))
-
-        if new is None:
-            self.generic_visit(node)
-            return
-
-        self.subst = (node.coord.line, node.names, new)
-
-    def get_ast(self):
-        with open(self.path, "w") as f:
-            f.write(self.orig)
-
-        ast = parse_file(self.path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
-        # ast.show()
-
-        unlink(self.path)
-        return ast
-
-    def fix(self, path, orig):
-        self.path = path
-        self.orig = orig
-
-        while True:
-            self.visit(self.get_ast())
-
-            if self.subst is None:
-                break
-
-            lines = self.orig.split("\n")
-            (line, old, new) = self.subst
-
-            beg = line - 3 if line > 3 else 0
-            end = line + 2 if line < len(lines) - 2 else len(lines)
-
-            focus = "\n".join(lines[beg : end])
-
-            old_re = "[\t ]".join([escape(x) for x in old]) + "([\t \)])"
-            (focus, n) = subn(old_re, new + "\g<1>", focus, 1)
-
-            if n != 1:
-                print(focus)
-                raise Exception("error while replacing {} with {} in {}:{}". \
-                                format(old_re, new, self.path, line))
-
-            self.orig = "\n".join(lines[: beg]) + \
-                        "\n" + focus + "\n" + \
-                        "\n".join(lines[end :])
-            self.subst = None
-
-        fixed = self.orig
-        self.reset()
-        return fixed
-
-vis = Visitor()
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("fixing {}                    \r".format(path))
-        stdout.flush()
-
-        with open(path, "r") as f:
-            orig = f.read()
-
-        segs = path.split("/")
-        path_ = "/".join(segs[:-1] + ["_" + segs[-1]])
-
-        fixed = vis.fix(path_, orig)
-
-        with open(path, "w") as f:
-            f.write(fixed)
-
-    print("")
Index: misc/gen-glob.py
===================================================================
--- misc/gen-glob.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,198 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from pycparser import c_ast, parse_file, c_generator
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class InclVis(c_ast.NodeVisitor):
-    def __init__(self, path):
-        self.path = path
-        self.typs = set()
-
-    def visit_Typedef(self, node):
-        if node.coord.file == self.path:
-            self.typs.add(node.name)
-
-        self.generic_visit(node)
-
-    def visit_Struct(self, node):
-        if node.coord.file == self.path and \
-           node.name is not None and node.decls is not None:
-            self.typs.add(node.name)
-
-        self.generic_visit(node)
-
-    def get_typs(self):
-        return self.typs
-
-typ_map = {
-    "void": None
-}
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if len(path) < 8 or path[:8] != "include/":
-            continue
-
-        stdout.write("parsing {}                    \r".format(path))
-        stdout.flush()
-
-        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include"])
-        # ast.show()
-
-        vis = InclVis(path)
-        vis.visit(ast)
-
-        for typ in vis.get_typs():
-            if typ in typ_map:
-                raise Exception("redefinition of {}".format(typ))
-
-            typ_map[typ] = path[8:]
-
-class DeclVis(c_ast.NodeVisitor):
-    def __init__(self, typ_map):
-        self.typ_map = typ_map
-        self.typs = set()
-
-    def visit_IdentifierType(self, node):
-        if node.names[0] not in self.typ_map:
-            raise Exception("unknown type {} in {}:{}". \
-                            format(node.names[0], node.coord.file, node.coord.line))
-
-        self.typs.add(node.names[0])
-        self.generic_visit(node)
-
-    def visit_Struct(self, node):
-        if node.name not in self.typ_map:
-            raise Exception("unknown struct {} in {}:{}". \
-                            format(node.name, node.coord.file, node.coord.line))
-
-        self.typs.add(node.name)
-        self.generic_visit(node)
-
-    def get_typs(self):
-        return self.typs
-
-gen = c_generator.CGenerator()
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if len(path) >= 8 and path[:8] == "include/":
-            continue
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("reading {}                    \r".format(path))
-        stdout.flush()
-
-        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include"])
-        # ast.show()
-
-        incs = set()
-        funs = {}
-        vars = {}
-
-        for node in ast.ext:
-            if type(node) is c_ast.Decl and \
-               (type(node.type) is c_ast.TypeDecl or \
-                type(node.type) is c_ast.PtrDecl or \
-                type(node.type) is c_ast.ArrayDecl):
-                decl = node
-                dest = vars
-
-            elif type(node) is c_ast.FuncDef:
-                decl = node.decl
-                dest = funs
-
-            else:
-                continue
-
-            if "extern" in decl.storage or \
-               "static" in decl.storage:
-                continue
-
-            vis = DeclVis(typ_map)
-            vis.visit(decl)
-
-            for typ in vis.get_typs():
-                if typ_map[typ] is not None:
-                    incs.add(typ_map[typ])
-
-            decl.storage = ["extern"]
-            decl.init = None
-
-            toks = gen.visit(decl).split(" ")
-            alig = ""
-
-            alig += toks[0] + "\t"
-            toks = toks[1:]
-
-            if toks[0] == "struct":
-                if len(toks[1]) > 7:
-                    raise Exception("identifier too long: {}".format(toks[1]))
-
-                alig += toks[0] + "\t" + toks[1] + "\t"
-                toks = toks[2:]
-
-            else:
-                alig += toks[0] + ("\t\t" if len(toks[0]) < 8 else "\t")
-                toks = toks[1:]
-
-            dest[decl.name] = alig + " ".join(toks) + ";"
-
-        file = path.split("/")[-1]
-        glob = []
-
-        if len(vars) > 0:
-            glob.append("/*")
-            glob.append("   =============================================================================")
-            glob.append("\t" + file + " -- global variables")
-            glob.append("   =============================================================================")
-            glob.append("*/")
-            glob.append("")
-
-            for _, out in sorted(vars.items()):
-                glob.append(out)
-
-            glob.append("")
-
-        if len(funs) > 0:
-            glob.append("/*")
-            glob.append("   =============================================================================")
-            glob.append("\t" + file + " -- global functions")
-            glob.append("   =============================================================================")
-            glob.append("*/")
-            glob.append("")
-
-            for _, out in sorted(funs.items()):
-                glob.append(out)
-
-            glob.append("")
-
-        if len(glob) == 0:
-            continue
-
-        head = []
-        head.append("#pragma once")
-        head.append("")
-
-        if len(incs) > 0:
-            for inc in sorted(incs):
-                head.append("#include \"{}\"".format(inc))
-
-            head.append("")
-
-        glob = head + glob
-
-        with open(path[:-2] + ".x", "w") as f:
-            f.write("\n".join(glob))
-
-    print("")
Index: misc/gen-proto.py
===================================================================
--- misc/gen-proto.py	(revision 6aa430b53ee38cdae99301c5e14c358ac29b4f87)
+++ 	(revision )
@@ -1,93 +1,0 @@
-#!/usr/bin/env python3
-
-from sys import stdout
-from pickle import dump
-from pycparser import c_ast, parse_file
-
-cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
-
-class Visitor(c_ast.NodeVisitor):
-    def __init__(self):
-        self.path = None
-        self.void = True
-        self.proto = []
-
-    def visit_Return(self, node):
-        if node.expr is not None:
-            self.void = False
-
-        self.generic_visit(node)
-
-    def visit_Decl(self, node):
-        node.storage = [x for x in node.storage if
-                        x != "register" and
-                        x != "static" and
-                        x != "extern"]
-
-        self.generic_visit(node)
-
-    def visit_FuncDef(self, node):
-        if node.coord.file != self.path:
-            return
-
-        self.generic_visit(node)
-
-        # Convert K&R parameter declarations to ANSI.
-
-        if node.param_decls is not None:
-            node.decl.type.args.params = node.param_decls
-            node.param_decls = None
-
-        # Turn "foobar()" into "foobar(void)".
-
-        if node.decl.type.args is None:
-            node.decl.type.args = c_ast.Typename(None, [],
-                                                 c_ast.TypeDecl(None, [],
-                                                                c_ast.ID("void")))
-
-        # Override default int type, if necessary.
-
-        if self.void:
-            node.decl.type.type.type = c_ast.ID("void")
-
-        self.proto.append(node.decl)
-        self.void = True
-
-    def visit_path(self, path, ast):
-        self.path = path
-        self.visit(ast)
-        self.path = None
-
-    def store_proto(self, path):
-        with open(path, "wb") as f:
-            dump(self.proto, f)
-
-path_ast = []
-
-with open("misc/c-files.txt", "r") as f:
-    for path in f:
-        path = path.rstrip()
-
-        if path == "ram/wdfield.c": # breaks pycparser
-            continue
-
-        stdout.write("parsing {}                    \r".format(path))
-        stdout.flush()
-
-        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
-                         cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
-        path_ast.append((path, ast))
-        # ast.show()
-
-    print("")
-
-vis = Visitor()
-
-for (path, ast) in path_ast:
-    stdout.write("visiting {}                    \r".format(path))
-    stdout.flush()
-
-    vis.visit_path(path, ast)
-
-print("")
-vis.store_proto("proto.dat")
Index: misc/gen-x.py
===================================================================
--- misc/gen-x.py	(revision e877e55993af7ec31a186b7407b09bed7f85689c)
+++ misc/gen-x.py	(revision e877e55993af7ec31a186b7407b09bed7f85689c)
@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+
+from sys import stdout
+from pycparser import c_ast, parse_file, c_generator
+
+cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
+
+class InclVis(c_ast.NodeVisitor):
+    def __init__(self, path):
+        self.path = path
+        self.typs = set()
+
+    def visit_Typedef(self, node):
+        if node.coord.file == self.path:
+            self.typs.add(node.name)
+
+        self.generic_visit(node)
+
+    def visit_Struct(self, node):
+        if node.coord.file == self.path and \
+           node.name is not None and node.decls is not None:
+            self.typs.add(node.name)
+
+        self.generic_visit(node)
+
+    def get_typs(self):
+        return self.typs
+
+typ_map = {
+    "void": None
+}
+
+with open("misc/c-files.txt", "r") as f:
+    for path in f:
+        path = path.rstrip()
+
+        if len(path) < 8 or path[:8] != "include/":
+            continue
+
+        stdout.write("parsing {}                    \r".format(path))
+        stdout.flush()
+
+        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
+                         cpp_args = ["-E", "-I", "include"])
+        # ast.show()
+
+        vis = InclVis(path)
+        vis.visit(ast)
+
+        for typ in vis.get_typs():
+            if typ in typ_map:
+                raise Exception("redefinition of {}".format(typ))
+
+            typ_map[typ] = path[8:]
+
+class DeclVis(c_ast.NodeVisitor):
+    def __init__(self, typ_map):
+        self.typ_map = typ_map
+        self.typs = set()
+
+    def visit_IdentifierType(self, node):
+        if node.names[0] not in self.typ_map:
+            raise Exception("unknown type {} in {}:{}". \
+                            format(node.names[0], node.coord.file, node.coord.line))
+
+        self.typs.add(node.names[0])
+        self.generic_visit(node)
+
+    def visit_Struct(self, node):
+        if node.name not in self.typ_map:
+            raise Exception("unknown struct {} in {}:{}". \
+                            format(node.name, node.coord.file, node.coord.line))
+
+        self.typs.add(node.name)
+        self.generic_visit(node)
+
+    def get_typs(self):
+        return self.typs
+
+gen = c_generator.CGenerator()
+
+with open("misc/c-files.txt", "r") as f:
+    for path in f:
+        path = path.rstrip()
+
+        if len(path) >= 8 and path[:8] == "include/":
+            continue
+
+        if path == "ram/wdfield.c": # breaks pycparser
+            continue
+
+        stdout.write("reading {}                    \r".format(path))
+        stdout.flush()
+
+        ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
+                         cpp_args = ["-E", "-I", "include"])
+        # ast.show()
+
+        incs = set()
+        funs = {}
+        vars = {}
+
+        for node in ast.ext:
+            if type(node) is c_ast.Decl and \
+               (type(node.type) is c_ast.TypeDecl or \
+                type(node.type) is c_ast.PtrDecl or \
+                type(node.type) is c_ast.ArrayDecl):
+                decl = node
+                dest = vars
+
+            elif type(node) is c_ast.FuncDef:
+                decl = node.decl
+                dest = funs
+
+            else:
+                continue
+
+            if "extern" in decl.storage or \
+               "static" in decl.storage:
+                continue
+
+            vis = DeclVis(typ_map)
+            vis.visit(decl)
+
+            for typ in vis.get_typs():
+                if typ_map[typ] is not None:
+                    incs.add(typ_map[typ])
+
+            decl.storage = ["extern"]
+            decl.init = None
+
+            toks = gen.visit(decl).split(" ")
+            alig = ""
+
+            alig += toks[0] + "\t"
+            toks = toks[1:]
+
+            if toks[0] == "struct":
+                if len(toks[1]) > 7:
+                    raise Exception("identifier too long: {}".format(toks[1]))
+
+                alig += toks[0] + "\t" + toks[1] + "\t"
+                toks = toks[2:]
+
+            else:
+                alig += toks[0] + ("\t\t" if len(toks[0]) < 8 else "\t")
+                toks = toks[1:]
+
+            dest[decl.name] = alig + " ".join(toks) + ";"
+
+        file = path.split("/")[-1]
+        glob = []
+
+        if len(vars) > 0:
+            glob.append("/*")
+            glob.append("   =============================================================================")
+            glob.append("\t" + file + " -- global variables")
+            glob.append("   =============================================================================")
+            glob.append("*/")
+            glob.append("")
+
+            for _, out in sorted(vars.items()):
+                glob.append(out)
+
+            glob.append("")
+
+        if len(funs) > 0:
+            glob.append("/*")
+            glob.append("   =============================================================================")
+            glob.append("\t" + file + " -- global functions")
+            glob.append("   =============================================================================")
+            glob.append("*/")
+            glob.append("")
+
+            for _, out in sorted(funs.items()):
+                glob.append(out)
+
+            glob.append("")
+
+        if len(glob) == 0:
+            continue
+
+        head = []
+        head.append("#pragma once")
+        head.append("")
+
+        if len(incs) > 0:
+            for inc in sorted(incs):
+                head.append("#include \"{}\"".format(inc))
+
+            head.append("")
+
+        glob = head + glob
+
+        with open(path[:-2] + ".x", "w") as f:
+            f.write("\n".join(glob))
+
+    print("")
