// Copyright (c) 2008 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Gabe Black

def template MicroRomConstructor {{

    %(define_generators)s
    const MicroPC X86ISA::MicrocodeRom::numMicroops = %(num_microops)s;

    X86ISA::MicrocodeRom::MicrocodeRom()
    {
        using namespace RomLabels;
        genFuncs = new GenFunc[numMicroops];
        %(alloc_generators)s;
    }
}};

let {{
    from micro_asm import Rom

    class X86MicrocodeRom(Rom):
        def __init__(self, name):
            super(X86MicrocodeRom, self).__init__(name)
            self.directives = {}

        def add_microop(self, mnemonic, microop):
            microop.mnemonic = mnemonic
            microop.micropc = len(self.microops)
            self.microops.append(microop)


        def getDeclaration(self):
            declareLabels = "namespace RomLabels {\n"
            for (label, microop) in self.labels.items():
                declareLabels += "const static uint64_t label_%s = %d;\n" \
                                  % (label, microop.micropc)
            for (label, microop) in self.externs.items():
                declareLabels += \
                    "const static MicroPC extern_label_%s = %d;\n" \
                        % (label, microop.micropc)
            declareLabels += "}\n"
            return declareLabels;

        def getDefinition(self):
            numMicroops = len(self.microops)
            allocGenerators = ''
            micropc = 0
            define_generators = '''
                namespace
                {
                    static const char romMnemonic[] = "Microcode_ROM";
            '''
            for op in self.microops:
                define_generators += op.getGeneratorDef(micropc)
                allocGenerators += "genFuncs[%d] = %s;\n" % \
                        (micropc, op.getGenerator(micropc))
                micropc += 1
            define_generators += "}\n"
            iop = InstObjParams(self.name, self.name, "MicrocodeRom",
                                {"code" : "",
                                 "define_generators" : define_generators,
                                 "num_microops" : numMicroops,
                                 "alloc_generators" : allocGenerators
                                })
            return MicroRomConstructor.subst(iop);
}};
