#!/usr/bin/env python ## ## This file is part of Nolimips, a MIPS simulator with unlimited registers ## Copyright (C) 2003, 2004, 2005 Benoit Perrot ## ## Nolimips is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## Nolimips is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## import string import sys, os.path, filecmp, shutil from xml.sax import ContentHandler, make_parser ## --------------------------------------------------------------------------- license = """// // This file is part of Nolimips, a MIPS simulator with unlimited registers // Copyright (C) 2004, 2005 Benoit Perrot // // Nolimips is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Nolimips is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //""" ## --------------------------------------------------------------------------- def depth(root): if len(root) == 0: return [] res = [] children = [ [] ] if len(root) > 1: children = depth(root[1:]) for e in root[0]: for child in children: res.append([e] + child) return res ## Overwrite file if different def lazy_overwrite(ref, new): if not os.path.isfile(ref) or \ not filecmp.cmp(ref, new): print "> Overwrite: " + ref shutil.copy(new, ref) ## Return a conventional macro identifier def define_id(s): return string.upper(s) ## Return a conventional C++ class identifier def class_id(s): # Rename j as jmp for convenience if s == "j": return "Jmp" res = "" non_ascii = True for i in range(0, len(s)): if s[i] in string.ascii_letters or s[i] in string.digits: if non_ascii: res = res + string.upper(s[i]) non_ascii = False else: res = res + s[i] else: non_ascii = True return res ## Return a conventional file name def file_id(s): return string.lower(s) ## Return a valid C++ variable name def var_id(s): s = string.lower(s) if s in ["and", "or", "xor"]: s = s + "_"; return s ## ------------------------------------- class Attribute: def __init__(self, type, restriction, name, value): self.type = type self.restriction = restriction self.name = name self.value = value # FIXME: useless def __str__(self): return "" class AttributeBuilder: def reset(self): self.type = "" self.restriction = "" self.name = "" self.value = ""# FIXME: useless def __init__(self): self.reset() def get(self): assert(self.type != "" and self.name != "") return Attribute(self.type, self.restriction, self.name, self.value) class Format: def __init__(self, type, attributes): self.type = type self.attributes = attributes def __str__(self): res = " " for p in self.attributes: res = res + "\n " + str(p) return res + "\n " class FormatBuilder: def reset(self): self.type = "" self.attributes = [] def __init__(self): self.reset() def set_to_predefined(self, template): self.type = template if template == "register": self.attributes = [ Attribute("Register", "", "dest", ""), Attribute("Register", "", "src1", ""), Attribute("Register", "", "src2", "")] elif template == "immediate": self.attributes = [ Attribute("Register", "", "dest", ""), Attribute("Register", "", "src", ""), Attribute("Exp", "", "imm", "")] elif template == "jump": self.attributes = [ Attribute("Register", "", "src1", ""), Attribute("Register", "", "src2", ""), Attribute("Exp", "", "label", "")] else: assert(False) def get(self): return Format(self.type, self.attributes) ## ------------------------------------- class Token: def __init__(self, kind, name, value, default): self.kind = kind self.name = name self.value = value self.default = default def __str__(self): res = "" class TokenBuilder: def reset(self): self.kind = "" self.name = "" self.value = "" self.default = "" def __init__(self): self.reset() def get(self): assert(self.kind != "") return Token(self.kind, self.name, self.value, self.default) class Syntax: def __init__(self, tokens, alias, level): self.tokens = tokens self.alias = alias self.level = level def __str__(self): res = " " for t in self.tokens: res = res + "\n " + str(t) return res + "\n " class SyntaxBuilder: def reset(self): self.tokens = [] self.alias = "" self.level = "" def __init__(self): self.reset() def set_to_predefined(self, template, alias, level): self.alias = alias self.level = level if template == "register": self.tokens = [ Token("register", "dest", "", ""), Token("register", "", "", "${dest}"), Token("register", "", "", "")] elif template == "immediate": self.tokens = [ Token("register", "dest", "", ""), Token("register", "", "", "${dest}"), Token("immediate", "", "", "")] elif template == "jump": self.tokens = [ Token("register", "", "", ""), Token("register", "", "", ""), Token("label", "", "", "")] else: assert(False) def get(self): return Syntax(self.tokens, self.alias, self.level) ## ------------------------------------- class Instruction: def __init__(self, opcode, level, kind, desc, format, syntaxes): self.opcode = opcode self.level = level self.kind = kind self.desc = desc self.format = format self.syntaxes = syntaxes def __str__(self): res = "\n" + \ " " + self.desc + "\n" + \ str(self.format) + "\n" for s in self.syntaxes: res = res + str(s) + "\n" return res + "" class InstructionBuilder: def reset(self): self.opcode = "" self.level = "" self.kind = "" self.desc = "" self.format = Format("", []) self.syntaxes = [] def __init__(self): self.reset() def get(self): assert(self.opcode != "" and self.level != "" and self.kind != "" and (self.level != "native" or self.format.type != "")) return Instruction(self.opcode, self.level, self.kind, self.desc, self.format, self.syntaxes) ## ------------------------------------- class InstructionSetHandler(ContentHandler): def reset(self): self.attr_b = AttributeBuilder() self.format_b = None self.token_b = TokenBuilder() self.syntax_b = SyntaxBuilder() self.inst_b = InstructionBuilder() self.instructions = [] self.content = "" def __init__(self): self.reset() def startElement(self, name, attrs): if name == "instruction": self.inst_b.reset() self.inst_b.opcode = attrs["opcode"] self.inst_b.level = attrs["level"] self.inst_b.kind = attrs["kind"] elif name == "description": self.content = "" elif name == "format": self.format_b = FormatBuilder() if attrs.has_key("type"): self.format_b.type = attrs["type"] elif name == "predefinedAttributes": self.format_b = FormatBuilder() self.format_b.set_to_predefined(attrs["template"]) elif name == "attribute": self.attr_b.reset() self.attr_b.type = attrs["type"] if attrs.has_key("restriction"): self.attr_b.restriction = attrs["restriction"] self.attr_b.name = attrs["name"] elif name == "syntax": self.syntax_b.reset() if attrs.has_key("alias"): self.syntax_b.alias = attrs["alias"] if attrs.has_key("level"): self.syntax_b.level = attrs["level"] else: self.syntax_b.level = self.inst_b.level elif name == "predefinedSyntax": alias = "" if attrs.has_key("alias"): alias = attrs["alias"] level = "" if attrs.has_key("level"): level = attrs["level"] else: level = self.inst_b.level self.syntax_b.set_to_predefined(attrs["template"], alias, level) elif name == "token": self.token_b.reset() self.token_b.kind = attrs["kind"] if attrs.has_key("name"): self.token_b.name = attrs["name"] if attrs.has_key("default"): self.token_b.default = attrs["default"] if attrs.has_key("value"): self.token_b.value = attrs["value"] def endElement(self, name): if name == "token": self.syntax_b.tokens.append(self.token_b.get()) elif name == "syntax" or name == "predefinedSyntax": self.inst_b.syntaxes.append(self.syntax_b.get()) if name == "attribute": self.format_b.attributes.append(self.attr_b.get()) elif name == "predefinedAttributes": self.inst_b.format = self.format_b.get() elif name == "format": self.inst_b.format = self.format_b.get() elif name == "description": self.inst_b.desc = self.content elif name == "instruction": self.instructions.append(self.inst_b.get()) def characters (self, content): self.content = self.content + content class InstructionSetParser: def parse(self, file): # Create a parser parser = make_parser() # Create the handler h = InstructionSetHandler() # Tell the parser to use our handler parser.setContentHandler(h) # Parse the input parser.parse(file) # Return Instruction set return h.instructions