Пример #1
0
def addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs):
    archDWordType = self.bitSizes[0]
    archWordType = self.bitSizes[1]
    archHWordType = self.bitSizes[2]
    archByteType = self.bitSizes[3]

    addressParam = cxx_writer.Parameter('address',
                                        archWordType.makeRef().makeConst())
    userParams = [
        cxx_writer.Parameter(paramName, paramAttr[0], initValue=paramAttr[2])
        for paramName, paramAttr in self.memoryParams.items()
    ]

    for methName in readMethodNames + readMethodNames_dbg:
        if methName in methodsCode.keys() and methName in methodsAttrs.keys():
            readMethod = cxx_writer.Method(
                methName,
                methodsCode[methName],
                methodTypes[methName],
                'public', [addressParam] + userParams,
                inline='inline' in methodsAttrs[methName],
                pure='pure' in methodsAttrs[methName],
                virtual='virtual' in methodsAttrs[methName],
                const=len(self.tlmPorts) == 0,
                noException='noexc' in methodsAttrs[methName])
            localMemoryMembers.append(readMethod)

    for methName in writeMethodNames + writeMethodNames_dbg:
        if methName in methodsCode.keys() and methName in methodsAttrs.keys():
            datumParam = cxx_writer.Parameter('datum', methodTypes[methName])
            writeMethod = cxx_writer.Method(
                methName,
                methodsCode[methName],
                cxx_writer.voidType,
                'public', [addressParam, datumParam] + userParams,
                inline='inline' in methodsAttrs[methName],
                pure='pure' in methodsAttrs[methName],
                virtual='virtual' in methodsAttrs[methName],
                noException='noexc' in methodsAttrs[methName])
            localMemoryMembers.append(writeMethod)

    for methName in genericMethodNames:
        if methName in methodsCode.keys() and methName in methodsAttrs.keys():
            lockMethod = cxx_writer.Method(methName,
                                           methodsCode[methName],
                                           cxx_writer.voidType,
                                           'public',
                                           inline='inline'
                                           in methodsAttrs[methName],
                                           pure='pure'
                                           in methodsAttrs[methName],
                                           virtual='virtual'
                                           in methodsAttrs[methName],
                                           noException='noexc'
                                           in methodsAttrs[methName])
            localMemoryMembers.append(lockMethod)
Пример #2
0
 def testInlineFunction(self):
     code = cxx_writer.Code(
         'if (works) {\nprintf(\"hummm\\n\");\nreturn 1;\n} else {\nreturn 0;\n}'
     )
     intType = cxx_writer.intType
     parameters = [cxx_writer.Parameter('param1', intType)]
     function = cxx_writer.Function('dummy_func',
                                    code,
                                    intType,
                                    parameters,
                                    inline=True)
     function.writeDeclaration(self.writer)
     self.writer.flush()
     testFile = open('prova.cpp', 'r')
     lines = testFile.readlines()
     testFile.close()
     self.assertEqual(len(lines), 8)
     self.assertEqual(lines[0], 'inline int dummy_func(int param1) {\n')
     self.assertEqual(lines[1], '    if (works) {\n')
     self.assertEqual(lines[2], '        printf(\"hummm\\n\");\n')
     self.assertEqual(lines[3], '        return 1;\n')
     self.assertEqual(lines[4], '    } else {\n')
     self.assertEqual(lines[5], '        return 0;\n')
     self.assertEqual(lines[6], '    }\n')
     self.assertEqual(lines[7], '} // dummy_func()\n')
Пример #3
0
    def getCPPDecoder(self, fetchSizeType, instructionCache, namespace = ''):
        """Returns the class representing the decoder."""
        import cxx_writer

        # Go over the decoding tree.
        if self.rootNode.splitFunction.pattern:
            codeString = self.createPatternDecoder(self.rootNode)
        else:
            codeString = self.createTableDecoder(self.rootNode)
        codeString += '// Invalid pattern\nreturn '
        if self.invalid_instr:
            codeString += str(self.invalid_instr.id)
        else:
            codeString += str(self.instrNum)
        codeString += ';\n'
        code = cxx_writer.Code(codeString)
        parameters = [cxx_writer.Parameter('instr_code', fetchSizeType)]
        decodeMethod = cxx_writer.Method('decode', code, cxx_writer.intType, 'public', parameters, const = True, noException = True)
        decodeClass = cxx_writer.ClassDeclaration('Decoder', [decodeMethod], namespaces = [namespace])
        decodeClass.addDocString(brief = 'Decoder Class', detail = 'Implements the state-machine that decodes an instruction string and returns an ID specifying the instruction.')

        # Declare the type which shall be contained in the cache.
        if instructionCache:
            emptyBody = cxx_writer.Code('')
            InstructionTypePtr = cxx_writer.Type('Instruction', '#include \"instructions.hpp\"').makePointer()
            instrAttr = cxx_writer.Attribute('instr', InstructionTypePtr, 'public')
            countAttr = cxx_writer.Attribute('count', cxx_writer.uintType, 'public')
            cacheTypeElements = [instrAttr, countAttr]
            cacheType = cxx_writer.ClassDeclaration('CacheElem', cacheTypeElements, namespaces = [namespace])
            instrParam = cxx_writer.Parameter('instr', InstructionTypePtr)
            countParam = cxx_writer.Parameter('count', cxx_writer.uintType)
            cacheTypeConstr = cxx_writer.Constructor(emptyBody, 'public', [instrParam, countParam], ['instr(instr)', 'count(count)'])
            cacheType.addConstructor(cacheTypeConstr)
            emptyCacheTypeConstr = cxx_writer.Constructor(emptyBody, 'public', [], ['instr(NULL)', 'count(1)'])
            cacheType.addConstructor(emptyCacheTypeConstr)

        if instructionCache:
            return [cacheType, decodeClass]
        else:
            return [decodeClass]
Пример #4
0
 def testFunctionDoc(self):
     intType = cxx_writer.intType
     code = cxx_writer.Code('')
     parameters = [cxx_writer.Parameter('param1', intType)]
     function = cxx_writer.Function('dummy_func', code, intType, parameters)
     function.addDocString('Documentation test\nanother line\n')
     function.writeImplementation(self.writer)
     self.writer.flush()
     testFile = open('prova.cpp', 'r')
     lines = testFile.readlines()
     testFile.close()
     self.assertEqual(len(lines), 5)
     self.assertEqual(lines[0], '/// Documentation test\n')
     self.assertEqual(lines[1], '/// another line\n')
     self.assertEqual(lines[2], 'int dummy_func(int param1) {\n')
     self.assertEqual(lines[3], '\n')
     self.assertEqual(lines[4], '} // dummy_func()\n')
Пример #5
0
 def testSCModuleImpl(self):
     intDecl = cxx_writer.intType
     stringDecl = cxx_writer.stringType
     module_nameDecl = cxx_writer.sc_module_nameType
     privateVar = cxx_writer.Attribute('pippo', intDecl, 'private')
     emptyBody = cxx_writer.Code('end_module();')
     publicConstr = cxx_writer.Constructor(emptyBody, 'public', [cxx_writer.Parameter('name', module_nameDecl)], ['std::string()', 'sc_module(name)'])
     classDecl = cxx_writer.SCModule('MyClass', [privateVar], [stringDecl])
     classDecl.addConstructor(publicConstr)
     classDecl.writeImplementation(self.writer)
     self.writer.flush()
     testFile = open('prova.cpp', 'r')
     lines = testFile.readlines()
     testFile.close()
     self.assertEqual(len(lines), 6)
     self.assertEqual(lines[0], 'MyClass::MyClass(sc_module_name name) :\n')
     self.assertEqual(lines[1], '    std::string(),\n')
     self.assertEqual(lines[2], '    sc_module(name) {\n')
     self.assertEqual(lines[3], '    end_module();\n')
     self.assertEqual(lines[4], '} // MyClass()\n')
Пример #6
0
 def testSCModuleDecl(self):
     intDecl = cxx_writer.intType
     stringDecl = cxx_writer.stringType
     module_nameDecl = cxx_writer.sc_module_nameType
     privateVar = cxx_writer.Attribute('pippo', intDecl, 'private')
     emptyBody = cxx_writer.Code('end_module();')
     publicConstr = cxx_writer.Constructor(emptyBody, 'public', [cxx_writer.Parameter('name', module_nameDecl)], ['std::string()'])
     classDecl = cxx_writer.SCModule('MyClass', [privateVar], [stringDecl])
     classDecl.addConstructor(publicConstr)
     classDecl.writeDeclaration(self.writer)
     self.writer.flush()
     testFile = open('prova.cpp', 'r')
     lines = testFile.readlines()
     testFile.close()
     self.assertEqual(len(lines), 10)
     self.assertEqual(lines[0], 'class MyClass : public std::string, public sc_module {\n')
     self.assertEqual(lines[1], '    public:\n')
     self.assertEqual(lines[2], '    SC_HAS_PROCESS(MyClass);\n')
     self.assertEqual(lines[3], '    MyClass(sc_module_name name);\n')
     self.assertEqual(lines[4], '\n')
     self.assertEqual(lines[5], '    private:\n')
     self.assertEqual(lines[6], '    int pippo;\n')
     self.assertEqual(lines[7], '\n')
     self.assertEqual(lines[8], '}; // class MyClass\n')
Пример #7
0
    def setSignature(self, retType=cxx_writer.Type('void'), parameters=[]):
        """Sets the function signature. The return type has to be an instance of
        cxx_writer.Type or a string representing a bit type. The parameters can
        either be cxx_writer.Parameter or a string representing a bit type."""
        if isinstance(retType, str):
            self.retType = resolveBitType(retType)
        else:
            self.retType = retType
        for param in parameters:
            if isinstance(param, type(())):
                param = cxx_writer.Parameter(param[0],
                                             resolveBitType(param[1]))

            for instrVar in self.localvars:
                if param.name == instrVar.name:
                    raise Exception('Cannot add parameter ' + param.name +
                                    ' to operation ' + self.name +
                                    '. Variable already exists in operation.')
            for lparam in self.parameters:
                if param.name == lparam.name:
                    raise Exception('Cannot add parameter ' + param.name +
                                    ' to operation ' + self.name +
                                    '. Parameter already exists in operation.')
            self.parameters.append(param)
Пример #8
0
def getCPPPipeline(self, trace, combinedTrace, model, namespace):
    # Returns the class representing a pipeline stage.

    from registerWriter import registerType, aliasType, registerContainerType
    InstructionType = cxx_writer.Type('Instruction', includes = ['#include \"instructions.hpp\"', 'iomanip'])
    pipeType = cxx_writer.Type('BasePipeStage')

    #---------------------------------------------------------------------------
    ## @name Pipeline Base Class
    #  @{

    pipeClasses = []
    pipeBaseMembers = []
    pipeBaseCtorParams = []
    pipeBaseCtorValues = ''
    pipeBaseCtorInit = []
    pipeBaseCtorCode = ''

    # Attributes and Initialization
    for pipe in self.pipes:
        otherStageAttr = cxx_writer.Attribute('stage_' + pipe.name, pipeType.makePointer(), 'protected')
        pipeBaseMembers.append(otherStageAttr)
        otherStageParam = cxx_writer.Parameter('stage_' + pipe.name, pipeType.makePointer())
        pipeBaseCtorParams.append(otherStageParam)
        pipeBaseCtorValues += 'stage_' + pipe.name + ', '
        pipeBaseCtorInit.append('stage_' + pipe.name + '(stage_' + pipe.name + ')')

    stageAttr = cxx_writer.Attribute('prev_stage', pipeType.makePointer(), 'public')
    pipeBaseMembers.append(stageAttr)
    stageParam = cxx_writer.Parameter('prev_stage', pipeType.makePointer())#, initValue = 'NULL')
    pipeBaseCtorParams.append(stageParam)
    pipeBaseCtorValues += 'prev_stage, '
    pipeBaseCtorInit.append('prev_stage(prev_stage)')

    stageAttr = cxx_writer.Attribute('succ_stage', pipeType.makePointer(), 'public')
    pipeBaseMembers.append(stageAttr)
    stageParam = cxx_writer.Parameter('succ_stage', pipeType.makePointer())#, initValue = 'NULL')
    pipeBaseCtorParams.append(stageParam)
    pipeBaseCtorValues += 'succ_stage, '
    pipeBaseCtorInit.append('succ_stage(succ_stage)')

    stageBeginEventAttr = cxx_writer.Attribute('stage_begin_event', cxx_writer.sc_eventType, 'public')
    pipeBaseMembers.append(stageBeginEventAttr)

    stageEndedEventAttr = cxx_writer.Attribute('stage_end_event', cxx_writer.sc_eventType, 'public')
    pipeBaseMembers.append(stageEndedEventAttr)

    stageBeginningAttr = cxx_writer.Attribute('stage_beginning', cxx_writer.boolType, 'public')
    pipeBaseMembers.append(stageBeginningAttr)
    pipeBaseCtorCode += 'this->stage_beginning = false;\n'

    stageEndedAttrFlag = cxx_writer.Attribute('stage_ended', cxx_writer.boolType, 'public')
    pipeBaseMembers.append(stageEndedAttrFlag)
    pipeBaseCtorCode += 'this->stage_ended = false;\n'

    hasToFlushAttr = cxx_writer.Attribute('has_to_flush', cxx_writer.boolType, 'public')
    pipeBaseMembers.append(hasToFlushAttr)
    pipeBaseCtorCode += 'this->has_to_flush = false;\n'

    stalledAttr = cxx_writer.Attribute('stalled', cxx_writer.boolType, 'public')
    pipeBaseMembers.append(stalledAttr)
    pipeBaseCtorCode += 'this->stalled = false;\n'

    latencyAttr = cxx_writer.Attribute('latency', cxx_writer.sc_timeType, 'protected')
    pipeBaseMembers.append(latencyAttr)
    latencyParam = cxx_writer.Parameter('latency', cxx_writer.sc_timeType.makeRef())
    pipeBaseCtorParams.append(latencyParam)
    pipeBaseCtorValues += 'latency, '
    pipeBaseCtorInit.append('latency(latency)')

    registerAttr = cxx_writer.Attribute('R', registerContainerType.makeRef(), 'protected')
    pipeBaseMembers.append(registerAttr)
    registerParam = cxx_writer.Parameter('R', registerContainerType.makeRef())
    pipeBaseCtorParams.append(registerParam)
    pipeBaseCtorValues += 'R, '
    pipeBaseCtorInit.append('R(R)')

    NOPInstrType = cxx_writer.Type('NOPInstruction', '#include \"instructions.hpp\"')
    NOPInstrAttr = cxx_writer.Attribute('NOP_instr', NOPInstrType.makePointer(), 'public')
    pipeBaseMembers.append(NOPInstrAttr)
    pipeBaseCtorCode += 'this->NOP_instr = NULL;\n'

    # Declare the interrupt instructions if any and the corresponding signal
    # attribute.
    for irq in self.irqs:
        IRQInstrType = cxx_writer.Type(irq.name + 'IntrInstruction', '#include \"instructions.hpp\"')
        IRQInstrAttr = cxx_writer.Attribute(irq.name + '_instr', IRQInstrType.makePointer(), 'public')
        pipeBaseMembers.append(IRQInstrAttr)
        pipeBaseCtorCode += 'this->' + irq.name + '_instr = NULL;\n'

    curInstrAttr = cxx_writer.Attribute('cur_instr', InstructionType.makePointer(), 'public')
    pipeBaseMembers.append(curInstrAttr)
    pipeBaseCtorCode += 'cur_instr = NULL;\n'
    nextInstrAttr = cxx_writer.Attribute('next_instr', InstructionType.makePointer(), 'public')
    pipeBaseMembers.append(nextInstrAttr)
    pipeBaseCtorCode += 'this->next_instr = NULL;\n'

    # Constructors and Destructors
    pipeBaseCtor = cxx_writer.Constructor(cxx_writer.Code(pipeBaseCtorCode), 'public', pipeBaseCtorParams, pipeBaseCtorInit)

    # Methods: flush()
    flushCode = """this->has_to_flush = true;
    if (this->prev_stage != NULL) {
        this->prev_stage->flush();
    }
    """
    flushMethod = cxx_writer.Method('flush', cxx_writer.Code(flushCode), cxx_writer.voidType, 'public', noException = True)
    pipeBaseMembers.append(flushMethod)

    # Class
    pipeBaseClass = cxx_writer.ClassDeclaration('BasePipeStage', pipeBaseMembers, namespaces = [namespace])
    pipeBaseClass.addConstructor(pipeBaseCtor)
    pipeClasses.append(pipeBaseClass)

    ## @} Pipeline Base Class
    #---------------------------------------------------------------------------
    ## @name Pipeline Stage Classes
    #  @{

    from procWriter import pipeFetchAttrs, pipeCtorParams, pipeFetchCtorParams
    hasHazard = False
    hazardStarted = False
    seenStages = 0

    for pipeStage in self.pipes:
        if pipeStage.regsStage:
            if self.pipes.index(pipeStage) + 1 < len(self.pipes):
                # There exist stages between the beginning and the end of the hazard.
                if not self.pipes[self.pipes.index(pipeStage) + 1].wbStage:
                    hasHazard = True

    for pipeStage in self.pipes:
        seenStages += 1
        pipeMembers = []
        pipeCtorInit = []
        if pipeStage.fetchStage:
            for attr in pipeFetchAttrs:
                pipeMembers.append(attr)
                pipeCtorInit.append(attr.name + '(' + attr.name + ')')
        pipeCtorCode = ''

        # Methods: behavior()
        Code = """cur_instr = this->NOP_instr;
        this->next_instr = this->NOP_instr;

        // Wait for SystemC infrastructure, otherwise register callbacks will crash.
        wait(SC_ZERO_TIME);
        """

        if pipeStage.fetchStage:
            Code += 'unsigned num_NOPs = 0;\n'
            if self.instructionCache:
                Code += 'template_map< ' + str(self.bitSizes[1]) + ', CacheElem>::iterator icache_end = this->instr_cache.end();\n\n'

        Code += """while(true) {
        // Wait for other pipeline stages to begin.
        this->wait_pipe_begin();

        unsigned num_cycles = 0;
        """

        if pipeStage.fetchStage:
            Code +='this->instr_executing = true;\n'
            # Tool-induced Stall Detection
            Code += 'bool will_stall = false;\n'
        else:
            Code += """cur_instr = this->next_instr;
            bool instr_annulled = false;
            """

        # Hazard Detection
        if hasHazard and pipeStage.decodeStage:
            Code += """
            // Hazard Detection
            bool was_stalled = this->stalled, will_stall = false;
            // Check read registers.
            if (cur_instr->check_regs() > 0) {
                will_stall = true;
            // Lock write registers: Only if read registers are available, otherwise do not lock yet.
            } else if (!cur_instr->lock_regs()) {
                will_stall = true;
            }

            // Just discovered stall: Stall registers:
            if (!was_stalled && will_stall) {
              R.stall(""" + str(self.pipes.index(pipeStage)) + """);
            // Just discovered end of stall: Advance registers.
            } else if (was_stalled && !will_stall) {
              R.advance();
            }

            // Stall this pipeline stage.
            this->stalled = will_stall;
            """

        if hasHazard:
            Code += 'if (!this->stalled) {\n'

        if pipeStage.fetchStage:
            # Interrupts
            # If an interrupt is raised, we need to deal with it in the correct
            # stage, i.e. we need to create a special instruction that reaches
            # the correct stage and deals with the interrupt properly.
            Code += getInterruptCode(self, trace, pipeStage)
            if self.irqs:
                Code += 'else /* !IRQ */ {\n'

            # Instruction Fetch Address
            Code += getFetchAddressCode(self, model)

            # Logging and Tracing: Update cycle count.
            Code += """// Logging and Tracing: Update cycle count.
            if (cur_PC == this->profiler_start_addr) {
                this->profiler_time_start = sc_time_stamp();
            }
            if (cur_PC == this->profiler_end_addr) {
                this->profiler_time_end = sc_time_stamp();
            }
            """

            # Tools: Check whether the tools require the pipeline to be empty
            # before proceeding with execution.
            Code += """
                #ifndef DISABLE_TOOLS
                // Check whether the tools require the pipeline to be empty before proceeding with execution.
                if (this->tool_manager.is_pipeline_empty(cur_PC)) {
                    // Pipeline is already emptying.
                    if (num_NOPs) {
                        num_NOPs--;
                        will_stall = true;
                        // Just discovered end of stall: Advance registers.
                        if (!num_NOPs) {
                            will_stall = false;
                            // Do not advance registers if stall was initiated in a succeeding stage.
                            if (!this->stalled) {
                                R.advance();
                            }
                        }
                    }
                    // Pipeline has to be emptied.
                    else {
                        num_NOPs = """ + str(len(self.pipes)-self.pipes.index(pipeStage)-1)+ """;
                        // Stall might be shorter if pipeline already contains a bubble for some other reason.
                        BasePipeStage* stage = this->succ_stage;
                        while (stage) {
                            if (stage->cur_instr != this->NOP_instr)
                                break;
                            num_NOPs--;
                            stage = stage->succ_stage;
                        }
                        if (num_NOPs) {
                            // Stall this pipeline stage.
                            will_stall = true;
                            // Just discovered stall: Stall registers:
                            R.stall(""" + str(self.pipes.index(pipeStage)) + """);
                        }
                    }
                } else {
                    num_NOPs = 0;
                }
                if (num_NOPs > 0 && num_NOPs < """ + str(len(self.pipes)) + """) {
                    std::cerr << std::setw(15) << std::left << \"Stage=""" + pipeStage.name + """\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_PC << \", Instruction=NOP       , Mnemonic=NOP: Propagating NOP as required by tools.\" << std::endl;
                    wait(this->latency);
                """

            Code += """} else {
                    num_NOPs = 0;
                #endif
                    // Either the pipeline is actually empty or no tool requires it to be so. Proceed with execution.
                    wait((""" + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + """)*this->latency);
            """

            # Tools: Instruction History
            Code += """
            // Tools: Instruction History
            #ifdef ENABLE_HISTORY
            HistoryInstrType instr_queue_elem;
            if (this->history_en) {
                instr_queue_elem.cycle = (unsigned)(sc_time_stamp()/this->latency);
                instr_queue_elem.address = cur_PC;
            }
            #endif
            """

            # Instruction Fetch and Issue
            # Computes the correct memory and/or memory port from which to
            # perform the fetch.
            doFetchCode = getDoFetchCode(self)
            # Perform the fetch only if the cache is not used or if the index of
            # the cache is the current instruction.
            if not (self.instructionCache and self.fastFetch):
                Code += doFetchCode

            # Two fetch paths are possible: the instruction buffer or the normal
            # instruction stream.
            # getPipeInstrIssueCode() executes this stage's instruction behavior.
            if self.instructionCache:
                Code += getCacheInstrFetchCode(self, doFetchCode, trace, combinedTrace, getPipeInstrIssueCode, hasHazard, pipeStage)
            else:
                Code += getDoDecodeCode(self, trace, combinedTrace, getPipeInstrIssueCode, hasHazard, pipeStage)

            if trace:
                if combinedTrace:
                    Code += 'if (cur_instr != this->NOP_instr) {\n'
                Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \'.\' << std::endl;\n'
                Code += 'cur_instr->print_trace();\n'
                if combinedTrace:
                    Code += '}\n'

        else:
            Code += 'wait((' + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n'
            if trace:
                if not combinedTrace:
                    Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_instr->fetch_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \'.\' << std::endl;\n'

            # Instruction Issue: Execute this stage's instruction behavior.
            Code += getPipeInstrIssueCode(self, trace, combinedTrace, hasHazard, pipeStage)

        # User-defined Operations
        if pipeStage.operation:
            Code += '\n// User-defined Operations\n'
            Code += 'this->R.set_stage(' + str(self.pipes.index(pipeStage)) + ');\n'
            Code += pipeStage.operation
            Code += 'this->R.unset_stage();\n'

        if pipeStage.fetchStage:
            # Tools: Instruction History
            # Check if it is time to save the instruction queue to file.
            Code += """
            // Tools: Instruction History
            #ifdef ENABLE_HISTORY
            if (this->history_en) {
                // Add current instruction to history queue.
                this->history_instr_queue.push_back(instr_queue_elem);
                // In case a queue dump file has been specified, check if it needs to be saved.
                if (this->history_file) {
                    this->history_undumped_elements++;
                    if (history_undumped_elements == this->history_instr_queue.capacity()) {
                        boost::circular_buffer<HistoryInstrType>::const_iterator history_it, history_end;
                        for (history_it = this->history_instr_queue.begin(), history_end = this->history_instr_queue.end(); history_it != history_end; history_it++) {
                            this->history_file << history_it->get_mnemonic() << std::endl;
                        }
                        this->history_undumped_elements = 0;
                    }
                }
            }
            #endif
            """

        # Synchronize with other stages.
        Code += """// Instruction-induced Latency
        wait((num_cycles + """ + str(float(seenStages - 1)/(len(self.pipes) - 1)) + """)*this->latency);
        """

        if pipeStage.fetchStage:
            Code += """this->num_instructions++;
                #ifndef DISABLE_TOOLS
                } // Pipeline is empty or no tools require it to be so.
                #endif
            """

            # Interrupts
            if self.irqs:
                Code += '} // if (!IRQ)\n'

        if pipeStage.fetchStage or (hasHazard and pipeStage.decodeStage):
            Code += """
            // Stall pipeline stages.
            BasePipeStage* stage = this;
            while (stage) {
                stage->stalled = this->stalled || will_stall;
                stage = stage->prev_stage;
            }
            """

        Code += """
        // Wait for other pipeline stages to end.
        this->wait_pipe_end();
        """

        if not pipeStage.fetchStage:
            Code += """
            // Flush pipeline.
            if (instr_annulled) {
                cur_instr->flush_pipeline = false;
                // Flush preceding pipeline stages.
                this->prev_stage->flush();
                // Flush registers from this stage downwards.
                R.flush(""" + str(self.pipes.index(pipeStage)) + """);
            } else if (cur_instr->flush_pipeline) {
                cur_instr->flush_pipeline = false;
                // Flush preceding pipeline stages.
                this->prev_stage->flush();
                // Flush registers from the preceding stage downwards.
                R.flush(""" + str(self.pipes.index(pipeStage)-1) + """);
            }
            """

        # Stalled Due to Hazard
        if hasHazard:
            Code += """} else {
                // One of the following stages is blocked due to a data hazard, so the current stage is not doing anything.
                wait(this->latency);
            """

            if trace:
                if combinedTrace and pipeStage.fetchStage:
                    Code += 'if (cur_instr != this->NOP_instr) {\n'
                if not combinedTrace or pipeStage.decodeStage:
                    Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_instr->fetch_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \": Stalled on a data hazard.\" << std::endl;\n'
                if pipeStage.decodeStage:
                    Code += 'std::cerr << "                 Stalled registers: " << cur_instr->print_busy_regs() << std::endl;'
                if pipeStage.fetchStage:
                    Code += 'cur_instr->print_trace();\n'
                if combinedTrace and pipeStage.fetchStage:
                    Code += '}\n'

            if pipeStage.fetchStage or pipeStage.decodeStage:
                Code += """
                // Stall pipeline stages.
                BasePipeStage* stage = this;
                while (stage) {
                    stage->stalled = this->stalled || will_stall;
                    stage = stage->prev_stage;
                }
                """

            Code += """
                // Wait for other pipeline stages to end.
                this->wait_pipe_end();
            } // if (this->stalled)
            """

        Code += """
        // Instruction Propagation
        if (this->has_to_flush) {
            if (cur_instr->to_destroy) {
                delete cur_instr;
            } else {
                cur_instr->in_pipeline = false;
            }
            this->has_to_flush = false;
            cur_instr = this->NOP_instr;
            this->next_instr = this->NOP_instr;
            this->succ_stage->next_instr = this->NOP_instr;
        }"""
        if pipeStage.fetchStage or (hasHazard and pipeStage.decodeStage):
            Code += """ else if (will_stall) {
                // Propagate NOP because the stall is caused by the instruction in this stage.
                this->succ_stage->next_instr = this->NOP_instr;
            }"""
        if hasHazard and not pipeStage.decodeStage and pipeStage != self.pipes[-1]:
            Code += """ else if (this->stalled) {
                // Retain next_instr = cur_instr in the following stage.
                this->succ_stage->next_instr = this->succ_stage->cur_instr;
            }"""
        if pipeStage != self.pipes[-1]:
            Code += """ else {
                this->succ_stage->next_instr = cur_instr;
            }
            """

        #if hasHazard and pipeStage.decodeStage:
        #    Code += """ else if (will_stall) {
        #        // Propagate NOP because the stall is caused by the instruction in this stage.
        #        this->succ_stage->next_instr = this->NOP_instr;
        #    } else {
        #        this->succ_stage->next_instr = cur_instr;
        #    }
        #    """
        #elif hasHazard and pipeStage != self.pipes[-1]:
        #    Code += """ else if (this->stalled) {
        #        // Retain next_instr = cur_instr in the following stage.
        #        this->succ_stage->next_instr = this->succ_stage->cur_instr;
        #    } else {
        #        this->succ_stage->next_instr = cur_instr;
        #    }
        #    """
        #elif pipeStage != self.pipes[-1]:
        #    Code += '\nthis->succ_stage->next_instr = cur_instr;\n'

        if pipeStage.fetchStage:
            # Register Propagation and Instruction Execution State
            Code += """
            // Register Propagation
            this->refresh_registers();
            this->instr_executing = false;
            this->instr_end_event.notify();
            """

        if pipeStage.fetchStage and trace and not combinedTrace:
            Code += 'std::cerr << \"------------------------------------------------------------------------\" << std::endl << std::endl;\n'

        Code += '} // while (true)\n'

        if pipeStage.regsStage:
            hazardStarted = True

        behaviorMethod = cxx_writer.Method('behavior', cxx_writer.Code(Code), cxx_writer.voidType, 'public')
        pipeMembers.append(behaviorMethod)
        pipeCtorCode += 'SC_THREAD(behavior);\n'

        # Methods: wait_pipe_begin()
        Code = """this->stage_beginning = true;
        this->stage_begin_event.notify();
        """
        for pipeStageInner in self.pipes:
            if pipeStageInner != pipeStage:
                Code += """if (!this->stage_""" + pipeStageInner.name + """->stage_beginning) {
                    wait(this->stage_""" + pipeStageInner.name + """->stage_begin_event);
                }
                """
        Code += 'this->stage_ended = false;'
        waitPipeBeginMethod = cxx_writer.Method('wait_pipe_begin', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True)
        pipeMembers.append(waitPipeBeginMethod)

        # Methods: wait_pipe_end()
        Code = """this->stage_beginning = false;
        this->stage_ended = true;
        this->stage_end_event.notify();
        """
        for pipeStageInner in self.pipes:
            if pipeStageInner != pipeStage:
                Code += """if (!this->stage_""" + pipeStageInner.name + """->stage_ended) {
                    wait(this->stage_""" + pipeStageInner.name + """->stage_end_event);
                }
                """
        waitPipeEndMethod = cxx_writer.Method('wait_pipe_end', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True)
        pipeMembers.append(waitPipeEndMethod)

        # Methods: refresh_registers() for fetch stage
        # Propagates the register latches forward. Honors bypasses.
        if pipeStage.fetchStage:
            Code = """// Update the registers to propagate the values in the pipeline.
            R.clock_cycle();
            """
            refreshRegistersMethod = cxx_writer.Method('refresh_registers', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True)
            pipeMembers.append(refreshRegistersMethod)

            # Fetch Stage Attributes, Constructors and Destructors
            decoderAttr = cxx_writer.Attribute('decoder', cxx_writer.Type('Decoder', '#include \"decoder.hpp\"'), 'public')
            pipeMembers.append(decoderAttr)

            if self.instructionCache:
                CacheElemType = cxx_writer.Type('CacheElem')
                template_mapType = cxx_writer.TemplateType('template_map', [self.bitSizes[1], CacheElemType], hash_map_include)
                cacheAttr = cxx_writer.Attribute('instr_cache', template_mapType, 'private')
                pipeMembers.append(cacheAttr)

            profilerStartAddrAttr = cxx_writer.Attribute('profiler_start_addr', self.bitSizes[1], 'public')
            pipeMembers.append(profilerStartAddrAttr)
            pipeCtorCode += 'this->profiler_start_addr = (' + str(self.bitSizes[1]) + ')-1;\n'

            profilerEndAddrAttr = cxx_writer.Attribute('profiler_end_addr', self.bitSizes[1], 'public')
            pipeCtorCode += 'this->profiler_end_addr = (' + str(self.bitSizes[1]) + ')-1;\n'
            pipeMembers.append(profilerEndAddrAttr)

            # Here are the attributes for the instruction history queue
            historyFileAttr = cxx_writer.Attribute('history_file', cxx_writer.ofstreamType, 'public')
            pipeMembers.append(historyFileAttr)

            historyEnabledAttr = cxx_writer.Attribute('history_en', cxx_writer.boolType, 'public')
            pipeMembers.append(historyEnabledAttr)
            pipeCtorCode += 'this->history_en = false;\n'

            historyQueueType = cxx_writer.Type('HistoryInstrType', 'modules/instruction.hpp')
            histQueueType = cxx_writer.TemplateType('boost::circular_buffer', [historyQueueType], 'boost/circular_buffer.hpp')
            historyQueueAttr = cxx_writer.Attribute('history_instr_queue', histQueueType, 'public')
            pipeMembers.append(historyQueueAttr)
            pipeCtorCode += 'this->history_instr_queue.set_capacity(1000);\n'

            historyUndumpedElementsAttr = cxx_writer.Attribute('history_undumped_elements', cxx_writer.uintType, 'public')
            pipeMembers.append(historyUndumpedElementsAttr)
            pipeCtorCode += 'this->history_undumped_elements = 0;\n'

            # Close history dump file before destruction.
            pipeDtorCode = """#ifdef ENABLE_HISTORY
            if (this->history_en) {
                // In case a queue dump file has been specified, check if it needs to be saved.
                if (this->history_file) {
                    if (this->history_undumped_elements > 0) {
                        std::vector<std::string> history_vector;
                        boost::circular_buffer<HistoryInstrType>::const_reverse_iterator history_it, history_end;
                        unsigned history_read = 0;
                        for (history_read = 0, history_it = this->history_instr_queue.rbegin(), history_end = this->history_instr_queue.rend(); history_it != history_end && history_read < this->history_undumped_elements; history_it++, history_read++) {
                            history_vector.push_back(history_it->get_mnemonic());
                        }
                        std::vector<std::string>::const_reverse_iterator history_vector_it, history_vector_end;
                        for (history_vector_it = history_vector.rbegin(), history_vector_end = history_vector.rend(); history_vector_it != history_vector_end; history_vector_it++) {
                            this->history_file << *history_vector_it << std::endl;
                        }
                    }
                    this->history_file.flush();
                    this->history_file.close();
                }
            }
            #endif
            """
            # Constructors and Destructors
            pipeCtorInit = ['sc_module(pipe_name)', 'BasePipeStage(' + pipeBaseCtorValues[:-2] + ')'] + pipeCtorInit
            pipeCtorBody = cxx_writer.Code(pipeCtorCode + 'end_module();')
            pipeCtor = cxx_writer.Constructor(pipeCtorBody, 'public', pipeCtorParams + pipeFetchCtorParams, pipeCtorInit)
            pipeDtor = cxx_writer.Destructor(cxx_writer.Code(pipeDtorCode), 'public')
        else:
            # Constructors and Destructors
            pipeCtorInit = ['sc_module(pipe_name)', 'BasePipeStage(' + pipeBaseCtorValues[:-2] + ')'] + pipeCtorInit
            pipeCtorBody = cxx_writer.Code(pipeCtorCode + 'end_module();')
            pipeCtor = cxx_writer.Constructor(pipeCtorBody, 'public', pipeCtorParams, pipeCtorInit)

        # Class
        pipeClass = cxx_writer.SCModule(pipeStage.name + 'PipeStage', pipeMembers, [pipeType], namespaces = [namespace])
        pipeClass.addDocString(brief = 'Pipeline Class', detail = 'Implements a pipeline stage. Addresses hazards.')
        pipeClass.addConstructor(pipeCtor)
        if pipeStage.fetchStage:
            pipeClass.addDestructor(pipeDtor)
        pipeClasses.append(pipeClass)

    ## @} Pipeline Stage Classes
    #---------------------------------------------------------------------------

    return pipeClasses
Пример #9
0
def getCPPMemoryIf(self, model, namespace):
    """Creates the necessary structures for communicating with the memory: An
    array in case of an internal memory or a TLM port for TLM memories."""

    archDWordType = self.bitSizes[0]
    archWordType = self.bitSizes[1]
    archHWordType = self.bitSizes[2]
    archByteType = self.bitSizes[3]

    global methodTypes, methodTypeLen
    methodTypes = {
        'read_dword': archDWordType,
        'read_word': archWordType,
        'read_half': archHWordType,
        'read_byte': archByteType,
        'read_instr': archWordType,
        'read_dword_dbg': archDWordType,
        'read_word_dbg': archWordType,
        'read_half_dbg': archHWordType,
        'read_byte_dbg': archByteType,
        'write_dword': archDWordType,
        'write_word': archWordType,
        'write_half': archHWordType,
        'write_byte': archByteType,
        'write_dword_dbg': archDWordType,
        'write_word_dbg': archWordType,
        'write_half_dbg': archHWordType,
        'write_byte_dbg': archByteType
    }
    methodTypeLen = {
        'read_dword': self.wordSize * 2,
        'read_word': self.wordSize,
        'read_half': self.wordSize / 2,
        'read_byte': 1,
        'read_instr': self.wordSize,
        'read_dword_dbg': self.wordSize * 2,
        'read_word_dbg': self.wordSize,
        'read_half_dbg': self.wordSize / 2,
        'read_byte_dbg': 1,
        'write_dword': self.wordSize * 2,
        'write_word': self.wordSize,
        'write_half': self.wordSize / 2,
        'write_byte': 1,
        'write_dword_dbg': self.wordSize * 2,
        'write_word_dbg': self.wordSize,
        'write_half_dbg': self.wordSize / 2,
        'write_byte_dbg': 1
    }

    #---------------------------------------------------------------------------
    ## @name Memory Interface Class
    #  @{

    memoryClasses = []
    memoryIfMembers = []
    emptyBody = cxx_writer.Code('')

    # Methods: read(), write()
    methodsCode = {}
    methodsAttrs = {}
    for methName in readMethodNames + writeMethodNames:
        methodsAttrs[methName] = ['pure', 'noexc']
        methodsCode[methName] = emptyBody
    for methName in readMethodNames_dbg:
        methodsAttrs[methName] = ['virtual']
        methodsCode[methName] = cxx_writer.Code('return this->' +
                                                methName[:-4] + '(address);')
    for methName in writeMethodNames_dbg:
        methodsAttrs[methName] = ['virtual']
        methodsCode[methName] = cxx_writer.Code('this->' + methName[:-4] +
                                                '(address, datum);')
    for methName in genericMethodNames:
        methodsAttrs[methName] = ['pure']
        methodsCode[methName] = emptyBody
    addMemoryMethods(self, memoryIfMembers, methodsCode, methodsAttrs)

    # Methods: swap_endianess()
    for cur_type in [archWordType, archHWordType]:
        swapEndianessCode = str(archByteType) + """ helper_byte = 0;
        for (unsigned i = 0; i < sizeof(""" + str(cur_type) + """)/2; i++) {
            helper_byte = ((""" + str(archByteType) + """ *)&datum)[i];
            ((""" + str(archByteType) + """ *)&datum)[i] = ((""" + str(
            archByteType) + """ *)&datum)[sizeof(""" + str(
                cur_type) + """) -1 -i];
            ((""" + str(archByteType) + """ *)&datum)[sizeof(""" + str(
                    cur_type) + """) -1 -i] = helper_byte;
        }
        """
        swapEndianessBody = cxx_writer.Code(swapEndianessCode)
        swapEndianessParam = cxx_writer.Parameter('datum', cur_type.makeRef())
        swapEndianessMethod = cxx_writer.Method('swap_endianess',
                                                swapEndianessBody,
                                                cxx_writer.voidType,
                                                'public', [swapEndianessParam],
                                                inline=True,
                                                noException=True,
                                                const=True)
        memoryIfMembers.append(swapEndianessMethod)

    # Constructors and Destructors
    memoryIfDtor = cxx_writer.Destructor(emptyBody, 'public', True)

    # Class
    memoryIfClass = cxx_writer.ClassDeclaration('MemoryInterface',
                                                memoryIfMembers,
                                                namespaces=[namespace])
    memoryIfClass.addDestructor(memoryIfDtor)
    memoryClasses.append(memoryIfClass)

    ## @} Memory Interface Class
    #---------------------------------------------------------------------------
    ## @name Local Memory Class
    #  @{

    from registerWriter import registerType, aliasType, registerContainerType
    MemoryToolsIfType = cxx_writer.TemplateType('MemoryToolsIf',
                                                [str(archWordType)],
                                                'common/tools_if.hpp')

    localMemoryMembers = []
    aliasAttrs = []
    aliasParams = []
    aliasInit = []

    # Attributes and Initialization
    if self.memAlias:
        aliasAttrs.append(
            cxx_writer.Attribute('R', registerContainerType.makeRef(),
                                 'private'))
        aliasParams.append(
            cxx_writer.Parameter('R', registerContainerType.makeRef()))
        aliasInit.append('R(R)')

    localMemoryMembers.append(
        cxx_writer.Attribute('debugger', MemoryToolsIfType.makePointer(),
                             'private'))

    # Methods: set_debugger()
    Code = 'this->debugger = debugger;'
    localMemoryMembers.append(
        cxx_writer.Method('set_debugger', cxx_writer.Code(Code),
                          cxx_writer.voidType, 'public', [
                              cxx_writer.Parameter(
                                  'debugger', MemoryToolsIfType.makePointer())
                          ]))

    # Methods: Building Blocks
    checkAddressCode = 'if (address >= this->size) {\nTHROW_ERROR("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n'
    checkAddressCodeException = 'if (address >= this->size) {\nTHROW_EXCEPTION("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n'

    checkWatchPointCode = """if (this->debugger != NULL) {
        this->debugger->notify_address(address, sizeof(datum));
    }
    """

    swapEndianessCode = '// Endianess conversion: The processor is always modeled with the host endianess. In case they are different, the endianess is swapped.\n'
    if self.isBigEndian:
        swapEndianessDefine = '#ifdef LITTLE_ENDIAN_BO\n'
    else:
        swapEndianessDefine = '#ifdef BIG_ENDIAN_BO\n'
    swapEndianessCode += swapEndianessDefine + 'this->swap_endianess(datum);\n#endif\n'

    if self.isBigEndian:
        swapDEndianessCode = '#ifdef LITTLE_ENDIAN_BO\n'
    else:
        swapDEndianessCode = '#ifdef BIG_ENDIAN_BO\n'
    swapDEndianessCode += str(archWordType) + ' datum1 = (' + str(
        archWordType) + ')(datum);\nthis->swap_endianess(datum1);\n'
    swapDEndianessCode += str(archWordType) + ' datum2 = (' + str(
        archWordType) + ')(datum >> ' + str(
            self.wordSize *
            self.byteSize) + ');\nthis->swap_endianess(datum2);\n'
    swapDEndianessCode += 'datum = datum1 | (((' + str(
        archDWordType) + ')datum2) << ' + str(
            self.wordSize * self.byteSize) + ');\n#endif\n'

    endianessCode = {
        'read_dword': swapDEndianessCode,
        'read_word': swapEndianessCode,
        'read_half': swapEndianessCode,
        'read_byte': '',
        'read_instr': swapEndianessCode,
        'read_dword_dbg': swapDEndianessCode,
        'read_word_dbg': swapEndianessCode,
        'read_half_dbg': swapEndianessCode,
        'read_byte_dbg': '',
        'write_dword': swapDEndianessCode,
        'write_word': swapEndianessCode,
        'write_half': swapEndianessCode,
        'write_byte': '',
        'write_dword_dbg': swapDEndianessCode,
        'write_word_dbg': swapEndianessCode,
        'write_half_dbg': swapEndianessCode,
        'write_byte_dbg': ''
    }

    readAliasCode = {}
    readMemAliasCode = ''
    for alias in self.memAlias:
        readMemAliasCode += 'if (address == ' + hex(long(
            alias.address)) + ') {\nreturn this->' + alias.alias + ';\n}\n'
    readAliasCode['read_dword'] = readMemAliasCode
    readAliasCode['read_word'] = readMemAliasCode
    readAliasCode['read_dword_dbg'] = readMemAliasCode
    readAliasCode['read_word_dbg'] = readMemAliasCode
    readAliasCode['read_instr'] = readMemAliasCode
    readMemAliasCode = ''
    for alias in self.memAlias:
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str(
            archHWordType) + ')' + alias.alias + '_temp;\n}\n'
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + self.wordSize / 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(
            archHWordType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n'
    readAliasCode['read_half_dbg'] = readMemAliasCode
    readAliasCode['read_half'] = readMemAliasCode
    readMemAliasCode = ''
    for alias in self.memAlias:
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str(
            archByteType) + ')' + alias.alias + '_temp;\n}\n'
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 1
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(
            archByteType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n'
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(
            archByteType) + ' *)&(' + alias.alias + '_temp)) + 2);\n}\n'
        readMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 3
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(
            archByteType) + ' *)&(' + alias.alias + '_temp)) + 3);\n}\n'
    readAliasCode['read_byte_dbg'] = readMemAliasCode
    readAliasCode['read_byte'] = readMemAliasCode

    writeAliasCode = {}
    writeMemAliasCode = ''
    for alias in self.memAlias:
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address
                 )) + ') {\n this->' + alias.alias + ' = datum;\nreturn;\n}\n'
    writeAliasCode['write_dword'] = writeMemAliasCode
    writeAliasCode['write_word'] = writeMemAliasCode
    writeAliasCode['write_dword_dbg'] = writeMemAliasCode
    writeAliasCode['write_word_dbg'] = writeMemAliasCode
    writeMemAliasCode = swapEndianessDefine
    for alias in self.memAlias:
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + self.wordSize / 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(
            archHWordType
        ) + ' *)&' + alias.alias + '_temp) = (' + str(
            archHWordType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archHWordType
        ) + ' *)&' + alias.alias + '_temp) + 1) = (' + str(
            archHWordType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
    writeMemAliasCode += '#else\n'
    for alias in self.memAlias:
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(
            archHWordType
        ) + ' *)&' + alias.alias + '_temp) = (' + str(
            archHWordType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + self.wordSize / 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archHWordType
        ) + ' *)&' + alias.alias + '_temp) + 1) = (' + str(
            archHWordType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
    writeMemAliasCode += '#endif\n'
    writeAliasCode['write_half'] = writeMemAliasCode
    writeAliasCode['write_half_dbg'] = writeMemAliasCode
    writeMemAliasCode = swapEndianessDefine
    for alias in self.memAlias:
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 3
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(
            archByteType) + '*)&' + alias.alias + '_temp) = (' + str(
                archByteType) + ')datum;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 1) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 1
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 2) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 3) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
    writeMemAliasCode += '#else\n'
    for alias in self.memAlias:
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address)
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(
            archByteType) + '*)&' + alias.alias + '_temp) = (' + str(
                archByteType) + ')datum;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 1
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 1) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 2
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 2) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
        writeMemAliasCode += 'if (address == ' + hex(
            long(alias.address) + 3
        ) + ') {\n' + str(
            archWordType
        ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(
            archByteType
        ) + '*)&' + alias.alias + '_temp) + 3) = (' + str(
            archByteType
        ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n'
    writeMemAliasCode += '#endif\n'
    writeAliasCode['write_byte'] = writeMemAliasCode
    writeAliasCode['write_byte_dbg'] = writeMemAliasCode

    # If there is no memory or debugging is disabled.
    if not self.memories or not any(memAttr[1] == True
                                    for memAttr in self.memories.values()):
        # Methods: read(), write(), lock(), unlock()
        methodsCode = {}
        methodsAttrs = {}
        for methName in readMethodNames + readMethodNames_dbg:
            methodsAttrs[methName] = []
            if methName.endswith('_gdb'):
                readBody = cxx_writer.Code(
                    readAliasCode[methName] + checkAddressCodeException +
                    '\n' + str(methodTypes[methName]) + ' datum = *(' +
                    str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address);\n' +
                    endianessCode[methName] + '\nreturn datum;')
            else:
                methodsAttrs[methName].append('noexc')
                readBody = cxx_writer.Code(
                    readAliasCode[methName] + checkAddressCode + '\n' +
                    str(methodTypes[methName]) + ' datum = *(' +
                    str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address);\n' +
                    endianessCode[methName] + '\nreturn datum;')
                if methName == 'read_word':
                    methodsAttrs[methName].append('inline')
            readBody.addInclude('common/report.hpp')
            methodsCode[methName] = readBody
        for methName in writeMethodNames + writeMethodNames_dbg:
            methodsAttrs[methName] = []
            if methName.endswith('_gdb'):
                methodsCode[methName] = cxx_writer.Code(
                    writeAliasCode[methName] + checkAddressCodeException +
                    checkWatchPointCode + '\n' + endianessCode[methName] +
                    '\n*(' + str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address) = datum;')
            else:
                methodsAttrs[methName].append('noexc')
                methodsCode[methName] = cxx_writer.Code(
                    writeAliasCode[methName] + checkAddressCode +
                    checkWatchPointCode + '\n' + endianessCode[methName] +
                    '\n*(' + str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address) = datum;')
                if methName == 'write_word':
                    methodsAttrs[methName].append('inline')
        for methName in genericMethodNames:
            methodsAttrs[methName] = []
            methodsCode[methName] = emptyBody
        addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs)

        # Attributes and Initialization
        arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType,
                                         'private')
        localMemoryMembers.append(arrayAttr)

        sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private')
        localMemoryMembers.append(sizeAttr)

        # Constructors and Destructors
        localMemoryCtorParams = [
            cxx_writer.Parameter('size', cxx_writer.uintType)
        ]
        localMemoryCtorBody = cxx_writer.Code(
            'this->memory = new char[size];\nthis->debugger = NULL;')
        localMemoryCtor = cxx_writer.Constructor(
            localMemoryCtorBody, 'public', localMemoryCtorParams + aliasParams,
            ['size(size)'] + aliasInit)
        localMemoryDtorBody = cxx_writer.Code('delete [] this->memory;')
        localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public',
                                                True)

        # Class
        localMemoryClass = cxx_writer.ClassDeclaration(
            'LocalMemory',
            localMemoryMembers + aliasAttrs, [memoryIfClass.getType()],
            namespaces=[namespace])
        localMemoryClass.addDocString(
            brief='Memory Interface Class',
            detail=
            'Interface used by the core to communicate with memory. Defines the required TLM ports.'
        )
        localMemoryClass.addConstructor(localMemoryCtor)
        localMemoryClass.addDestructor(localMemoryDtor)
        memoryClasses.append(localMemoryClass)

    # Debugging is enabled.
    else:
        # Methods: read(), write(), lock()
        dumpCode1 = '\n\nMemAccessType dump_info;\n'
        if not self.systemc and not model.startswith(
                'acc') and not model.endswith('AT'):
            dumpCode1 += 'dump_info.simulation_time = cur_cycle;\n'
        else:
            dumpCode1 += 'dump_info.simulation_time = sc_time_stamp().to_double();\n'
        if [
                memName for memName, memAttr in self.memories.items()
                if memAttr[2] != ''
        ]:
            dumpCode1 += 'dump_info.program_counter = this->' + self.memories[
                memName][2] + ';\n'
        else:
            dumpCode1 += 'dump_info.program_counter = 0;\n'
        dumpCode1 += 'for (unsigned i = 0; i < '
        dumpCode2 = """; i++) {
            dump_info.address = address + i;
            dump_info.val = (char)((datum & (0xFF << i*8)) >> i*8);
            this->dump_file.write((char*)&dump_info, sizeof(MemAccessType));
        }
        """
        methodsCode = {}
        methodsAttrs = {}
        for methName in readMethodNames + readMethodNames_dbg:
            methodsAttrs[methName] = ['noexc']
            if methName.endswith('_gdb'):
                readBody = cxx_writer.Code(
                    readAliasCode[methName] + checkAddressCodeException +
                    '\n' + str(methodTypes[methName]) + ' datum = *(' +
                    str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address);\n' +
                    endianessCode[methName] + '\nreturn datum;')
            else:
                readBody = cxx_writer.Code(
                    readAliasCode[methName] + checkAddressCode + '\n' +
                    str(methodTypes[methName]) + ' datum = *(' +
                    str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address);\n' +
                    endianessCode[methName] + '\nreturn datum;')
                if methName == 'read_word':
                    methodsAttrs[methName].append('inline')
            readBody.addInclude('common/report.hpp')
            methodsCode[methName] = readBody
        for methName in writeMethodNames + writeMethodNames_dbg:
            methodsAttrs[methName] = []
            if methName.endswith('_gdb'):
                methodsCode[methName] = cxx_writer.Code(
                    writeAliasCode[methName] + checkAddressCodeException +
                    checkWatchPointCode + '\n' + endianessCode[methName] +
                    '\n*(' + str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address) = datum;' +
                    dumpCode1 + str(methodTypeLen[methName]) + dumpCode2)
            else:
                methodsAttrs[methName].append('noexc')
                methodsCode[methName] = cxx_writer.Code(
                    writeAliasCode[methName] + checkAddressCode +
                    checkWatchPointCode + '\n' + endianessCode[methName] +
                    '\n*(' + str(methodTypes[methName].makePointer()) +
                    ')(this->memory + (unsigned long)address) = datum;' +
                    dumpCode1 + str(methodTypeLen[methName]) + dumpCode2)
                if methName == 'write_word':
                    methodsAttrs[methName].append('inline')
        for methName in genericMethodNames:
            methodsAttrs[methName] = []
            methodsCode[methName] = emptyBody
        addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs)

        # Methods: end_of_simulation()
        endOfSimBody = cxx_writer.Code("""if (this->dump_file) {
           this->dump_file.flush();
           this->dump_file.close();
        }
        """)
        endOfSimMethod = cxx_writer.Method('end_of_simulation', endOfSimBody,
                                           cxx_writer.voidType, 'public')
        localMemoryMembers.append(endOfSimMethod)

        # Attributes and Initialization
        arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType,
                                         'private')
        localMemoryMembers.append(arrayAttr)

        sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private')
        localMemoryMembers.append(sizeAttr)

        dumpFileAttr = cxx_writer.Attribute('dump_file',
                                            cxx_writer.ofstreamType, 'private')
        localMemoryMembers.append(dumpFileAttr)

        if not self.systemc and not model.startswith(
                'acc') and not model.endswith('AT'):
            cycleAttr = cxx_writer.Attribute('cur_cycle',
                                             cxx_writer.uintType.makeRef(),
                                             'private')
            localMemoryCtorParams.append(
                cxx_writer.Parameter('cur_cycle',
                                     cxx_writer.uintType.makeRef()))
            localMemoryCtorInit.append('cur_cycle(cur_cycle)')
            localMemoryMembers.append(cycleAttr)

        if [
                memName for memName, memAttr in self.memories.items()
                if memAttr[2] != ''
        ]:
            # Find out type of fetch register.
            from processor import extractRegInterval
            fetchReg = self.memories[memName][2]
            fetchIndex = extractRegInterval(fetchReg)
            if fetchIndex: fetchReg = fetchReg[0:fetchReg.index('[')]
            fetchType = None
            if fetchReg in [i.name for i in self.regs + self.regBanks]:
                fetchType = registerType
            if fetchType == None and fetchReg in [
                    i.name for i in self.aliasRegs + self.aliasRegBanks
            ]:
                fetchType = aliasType
            localMemoryMembers.append(
                cxx_writer.Attribute(self.memories[memName][2],
                                     fetchType.makeRef(), 'private'))
            pcRegParam = [
                cxx_writer.Parameter(self.memories[memName][2],
                                     fetchType.makeRef())
            ]
            pcRegInit = [
                self.memories[memName][2] + '(' + self.memories[memName][2] +
                ')'
            ]

        # Constructors and Destructors
        localMemoryCtorParams = [
            cxx_writer.Parameter('size', cxx_writer.uintType)
        ]
        localMemoryCtorInit = ['size(size)']
        localMemoryCtorBody = cxx_writer.Code("""this->memory = new char[size];
            this->debugger = NULL;
            this->dump_file.open("memoryDump.dmp", ios::out | ios::binary | ios::ate);
            if (!this->dump_file) {
                THROW_EXCEPTION("Cannot open file memoryDump.dmp for writing.");
            }
        """)
        localMemoryCtor = cxx_writer.Constructor(
            localMemoryCtorBody, 'public',
            localMemoryCtorParams + aliasParams + pcRegParam,
            localMemoryCtorInit + aliasInit + pcRegInit)
        localMemoryDtorBody = cxx_writer.Code("""delete [] this->memory;
        if (this->dump_file) {
           this->dump_file.flush();
           this->dump_file.close();
        }
        """)
        localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public',
                                                True)

        # Class
        localMemoryClass = cxx_writer.ClassDeclaration(
            'LocalMemory',
            localMemoryMembers + aliasAttrs, [memoryIfClass.getType()],
            namespaces=[namespace])
        localMemoryClass.addDocString(
            brief='Memory Interface Class',
            detail=
            'Interface used by the core to communicate with memory. Defines the required TLM ports.'
        )
        localMemoryClass.addConstructor(localMemoryCtor)
        localMemoryClass.addDestructor(localMemoryDtor)
        memoryClasses.append(localMemoryClass)

    ## @} Local Memory Class
    #---------------------------------------------------------------------------

    return memoryClasses
Пример #10
0
def getCPPIRQInstr(self, model, trace, namespace):
    from procWriter import instrCtorParams, instrCtorValues
    instructionType = cxx_writer.Type('Instruction',
                                      '#include \"instructions.hpp\"')
    from registerWriter import registerType

    IRQInstrClasses = []
    emptyBody = cxx_writer.Code('')

    for irq in self.irqs:
        IRQInstrMembers = []

        # Methods: get_id()
        getIdBody = cxx_writer.Code('return (unsigned)-1;')
        getIdMethod = cxx_writer.Method('get_id',
                                        getIdBody,
                                        cxx_writer.uintType,
                                        'public',
                                        noException=True,
                                        const=True)
        IRQInstrMembers.append(getIdMethod)

        # Methods: get_name()
        getNameBody = cxx_writer.Code('return \"' + irq.name +
                                      'IntrInstruction\";')
        getNameMethod = cxx_writer.Method('get_name',
                                          getNameBody,
                                          cxx_writer.stringType,
                                          'public',
                                          noException=True,
                                          const=True)
        IRQInstrMembers.append(getNameMethod)

        # Methods: get_mnemonic()
        getMnemonicBody = cxx_writer.Code('return \"' + irq.name + '\";')
        getMnemonicMethod = cxx_writer.Method('get_mnemonic',
                                              getMnemonicBody,
                                              cxx_writer.stringType,
                                              'public',
                                              noException=True,
                                              const=True)
        IRQInstrMembers.append(getMnemonicMethod)

        # Methods: replicate()
        replicateBody = cxx_writer.Code('return new ' + irq.name +
                                        'IntrInstruction(' + instrCtorValues +
                                        ', this->' + irq.name + ');')
        replicateMethod = cxx_writer.Method(
            'replicate',
            replicateBody,
            instructionType.makePointer(),
            'public',
            parameters=[
                cxx_writer.Parameter('instr',
                                     instructionType.makePointer(),
                                     initValue='NULL')
            ],
            noException=True,
            const=True)
        IRQInstrMembers.append(replicateMethod)

        # Methods: behavior()
        for pipeStage in self.pipes:
            behaviorUserCode = ''
            if irq.operation.has_key(pipeStage.name):
                behaviorUserCode += '{\nunsigned num_cycles = 0;\n'
                behaviorUserCode += str(irq.operation[pipeStage.name])
                behaviorUserCode += 'this->'
                if model.startswith('acc'):
                    behaviorUserCode += 'num_stage_cycles'
                else:
                    behaviorUserCode += 'num_instr_cycles'
                behaviorUserCode += ' += num_cycles;\n}\n'

            if model.startswith('acc'):
                behaviorCode = 'this->num_stage_cycles = 0;\n'
                if behaviorUserCode:
                    # Set the pipeline stage so that the usage of the registers
                    # is transparent to the user.
                    behaviorCode += '\nR.set_stage(' + str(
                        self.pipes.index(pipeStage)) + ');\n'
                    behaviorCode += behaviorUserCode
                    behaviorCode += '\nR.unset_stage();\n'
                behaviorCode += 'return this->num_stage_cycles;\n'
                behaviorBody = cxx_writer.Code(behaviorCode)
                behaviorMethod = cxx_writer.Method(
                    'behavior_' + pipeStage.name, behaviorBody,
                    cxx_writer.uintType, 'public')
                IRQInstrMembers.append(behaviorMethod)
        if not model.startswith('acc'):
            behaviorCode = 'this->num_instr_cycles = 0;\n'
            behaviorCode += behaviorUserCode
            behaviorCode += 'return this->num_instr_cycles;\n'
            behaviorBody = cxx_writer.Code(behaviorCode)
            behaviorMethod = cxx_writer.Method('behavior', behaviorBody,
                                               cxx_writer.uintType, 'public')
            IRQInstrMembers.append(behaviorMethod)

        # Methods: set_interrupt_value()
        # Sets the value of the received interrupt and the related attribute.
        from isa import resolveBitType
        irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>')
        IRQAttr = cxx_writer.Attribute(irq.name, irqWidthType.makeRef(),
                                       'public')
        IRQInstrMembers.append(IRQAttr)
        IRQInstrCtorParams = [
            cxx_writer.Parameter(irq.name, irqWidthType.makeRef())
        ]
        IRQInstrCtorInit = [irq.name + '(' + irq.name + ')']
        InterruptValueParam = cxx_writer.Parameter(
            'interrupt_value',
            irqWidthType.makeRef().makeConst())
        setInterruptValueBody = cxx_writer.Code('this->' + irq.name +
                                                ' = interrupt_value;')
        setInterruptValueMethod = cxx_writer.Method('set_interrupt_value',
                                                    setInterruptValueBody,
                                                    cxx_writer.voidType,
                                                    'public',
                                                    [InterruptValueParam],
                                                    noException=True,
                                                    inline=True)
        IRQInstrMembers.append(setInterruptValueMethod)

        # Attributes
        for var in irq.variables:
            IRQInstrMembers.append(
                cxx_writer.Attribute(var.name, var.varType, 'protected',
                                     var.static))

        # Constructors and Destructors
        IRQInstrCtor = cxx_writer.Constructor(
            emptyBody,
            'public',
            parameters=instrCtorParams + IRQInstrCtorParams,
            initList=['Instruction(' + instrCtorValues + ')'] +
            IRQInstrCtorInit)
        IRQInstrDtor = cxx_writer.Destructor(emptyBody, 'public', True)

        # Class
        IRQInstrClass = cxx_writer.ClassDeclaration(
            irq.name + 'IntrInstruction',
            IRQInstrMembers, [instructionType],
            namespaces=[namespace])
        IRQInstrClass.addDocString(
            brief='IRQ Instruction Class',
            detail=
            'Wraps IRQ exception handling behavior as a dummy instruction.')
        IRQInstrClass.addConstructor(IRQInstrCtor)
        IRQInstrClass.addDestructor(IRQInstrDtor)
        IRQInstrClasses.append(IRQInstrClass)

    return IRQInstrClasses
Пример #11
0
def getPipeClockCycleFunction(self, registerMaxBitwidth):
    """In the accurate (pipelined) model, register values are propagated every
    cycle according to the three following specifications:

    1. Default behavior:
       a. Propagation to stages after wb:
          wbStage is considered the stable value and fed forward to all stages
          from [wbStage+1..lastStage]. This is only for consistency, since
          registers should obviously neither be read nor written after wbStage
          (last write).
       b. Propagation to stages before and up to regsStage:
          wbStage is also fed back to all stages from [0..regsStage]. This is
          only for consistency, since registers should obviously neither be read
          nor written before regsStage (first read).
       c. Regular step-wise forward propagation:
          Each register from regsStage to wbStage propagates one stage forward
          every cycle. A stalled pipeline is split into three sections: The
          stalled stages (ideally [0..regsStage]) retain their values, the
          following stages containing bubbles (NOPs) either retain their stale
          values or explicitly reset them (they will be overwritten anyway), the
          non-stalled stages propagate normally.

    2. Common feedback loops via <processor>Arch.py:<pipe>.setWbStageOrder():
       Aside from the default behavior in (1), TRAP interprets <pipe>.
       setWbStageOrder() as a backward path from each stage in the list back to
       <pipe> for all registers. Hence, the default behavior still executes but
       the pipe forwarding paths take precedence in case of contention. If the
       forwarding stage is stalled, the bypass is deactivated.

    3. Register-specific feedback loops via <reg>.setWbStageOrder():
       the common pipe behavior in (1) and (2) does not run except for the step-
       wise forward propagation, in which case all stages propagate, not just
       [regsStage..wbStage] If <reg>.setWbStageOrder() is used, care should
       therefore be taken to re-define all feedback loops as required. If the
       forwarding stage is stalled, the bypass is deactivated.

    This function generates the callback function containing default propagation
    logic (1) as well as any forwarding specified by <pipe>.setWbStageOrder(
    ['pipe_x', ... 'pipe_0']) as described in (2). The list of stages is
    interpreted in order of decreasing precedence. The calling sequence is:
       pipeline.cpp:            <fetchStage>::behavior()
    -> registers.cpp:           clock_cycle()
    -> register_abstraction.hpp:clock_cycle()
    -> registers.cpp:           regs_clock_cycle()
    The fetch stage calls a clock_cycle function which iterates through all
    registers and calls their clock_cycle() method defined in
    register_abstraction.hpp. This, in turn, calls the callback function
    regs_clock_cycle, generated by TRAP in the registers.cpp file."""

    if not self.pipes: return

    regsStage = 0
    wbStage = len(self.pipes) - 1
    pipeNumbers = {}
    i = 0
    for pipeStage in self.pipes:
        if pipeStage.regsStage:
            regsStage = self.pipes.index(pipeStage)
        if pipeStage.wbStage:
            wbStage = self.pipes.index(pipeStage)
        pipeNumbers[pipeStage.name] = i
        i += 1

    Code = """bool has_changes = false;

    // Copy over old values, just in case stalls should prevent propagation.
    for (unsigned i = 0; i < """ + str(len(self.pipes)) + """; ++i) {
      temp_values[i] = values[i];
      temp_time_stamps[i] = time_stamps[i];
    }
    """

    # 1a. Default behavior: Propagation to stages after wb.
    if wbStage == len(self.pipes) - 2:
        Code += """
        // Feed stable value to all stages after write-back. This is only for consistency.
        if (!(nop_stages & """ + hex(1 << wbStage) + """)) {
          if (time_stamps[""" + str(wbStage) + """] >= time_stamps[""" + str(
            wbStage + 1) + """]) {
            temp_values[""" + str(wbStage +
                                  1) + """] = values[""" + str(wbStage) + """];
            temp_time_stamps[""" + str(wbStage +
                                       1) + """] = time_stamps[""" + str(
                                           wbStage) + """];
            has_changes = true;
          }
        }
        """
    elif wbStage < len(self.pipes) - 2:
        Code += """
        // Feed stable value to all stages after write-back. This is only for consistency.
        if (!(nop_stages & """ + hex(1 << wbStage) + """)) {
          for (unsigned i = """ + str(wbStage +
                                      1) + """; i < this->m_num_stages; ++i) {
            if (time_stamps[""" + str(wbStage) + """] >= time_stamps[i]) {
              temp_values[i] = values[""" + str(wbStage) + """];
              temp_time_stamps[i] = time_stamps[""" + str(wbStage) + """];
              has_changes = true;
            }
          }
        }
        """

    # 1b. Default behavior: Propagation to stages before and up to regsStage.
    if regsStage == 0:
        Code += """
        // Feed stable value back to first-read.
        if (!(cur_nop_stages & """ + hex(1 << wbStage) + """)) {
          if (time_stamps[""" + str(wbStage) + """] >= time_stamps[0]) {
            temp_values[0] = values[""" + str(wbStage) + """];
            temp_time_stamps[0] = time_stamps[""" + str(wbStage) + """];
            has_changes = true;
          }
        }
        """
    elif regsStage > 1:
        Code += """
        // Feed stable value to first-read and all stages before. The latter is only for consistency.
        if (!(cur_nop_stages & """ + hex(1 << wbStage) + """)) {
          for (unsigned i = 0; i <= """ + str(regsStage) + """; ++i) {
            if (time_stamps[""" + str(wbStage) + """] >= time_stamps[i]) {
              temp_values[i] = values[""" + str(wbStage) + """];
              temp_time_stamps[i] = time_stamps[""" + str(wbStage) + """];
              has_changes = true;
            }
          }
        }
        """

    # 1c. Default Behavior: Regular step-wise forward propagation.
    Code += """
      // Regular step-wise forward propagation.
      for (int i = """ + str(regsStage +
                             1) + """; i <= """ + str(wbStage) + """; ++i) {
        // The stage will contain a bubble.
        if (next_nop_stages & (1 << i)) {
          temp_values[i] = 0;
          temp_time_stamps[i] = 0;
        } else if ((i > stall_stage) && (time_stamps[i-1] >= time_stamps[i])) {
          temp_values[i] = values[i-1];
          temp_time_stamps[i] = time_stamps[i-1];
          has_changes = true;
        }
      }
      """

    # 2. Common feedback loops via <processor>Arch.py:<pipe>.setWbStageOrder().
    for toStage in self.pipes:
        if toStage.wbStageOrder:
            for fromStage in reversed(toStage.wbStageOrder):
                Code += """
                  // Feedback path """ + fromStage + """ -> """ + toStage.name + """
                  if (!(cur_nop_stages & """ + hex(
                    1 << pipeNumbers[fromStage]) + """)) {
                    if (time_stamps[""" + str(
                        pipeNumbers[fromStage]
                    ) + """] >= temp_time_stamps[""" + str(
                        pipeNumbers[toStage.name]) + """]) {
                      temp_values[""" + str(pipeNumbers[
                            toStage.name]) + """] = values[""" + str(
                                pipeNumbers[fromStage]) + """];
                      temp_time_stamps[""" + str(
                                    pipeNumbers[toStage.name]
                                ) + """] = time_stamps[""" + str(
                                    pipeNumbers[fromStage]) + """];
                        has_changes = true;
                    }
                  }
                  """

    Code += '\nreturn has_changes;\n'
    pipeClockCycleValueParam = cxx_writer.Parameter(
        'values', registerMaxBitwidth.makePointer())
    pipeClockCycleTempValueParam = cxx_writer.Parameter(
        'temp_values', registerMaxBitwidth.makePointer())
    pipeClockCycleTimeStampParam = cxx_writer.Parameter(
        'time_stamps', cxx_writer.ulonglongPtrType)
    pipeClockCycleTempTimeStampParam = cxx_writer.Parameter(
        'temp_time_stamps', cxx_writer.ulonglongPtrType)
    pipeClockCycleStallStageParam = cxx_writer.Parameter(
        'stall_stage', cxx_writer.intType)
    pipeClockCycleCurNopStagesParam = cxx_writer.Parameter(
        'cur_nop_stages', cxx_writer.uintType)
    pipeClockCycleNextNopStagesParam = cxx_writer.Parameter(
        'next_nop_stages', cxx_writer.uintType)
    pipeClockCycleFunction = cxx_writer.Function(
        'regs_clock_cycle', cxx_writer.Code(Code), cxx_writer.boolType, [
            pipeClockCycleValueParam, pipeClockCycleTempValueParam,
            pipeClockCycleTimeStampParam, pipeClockCycleTempTimeStampParam,
            pipeClockCycleStallStageParam, pipeClockCycleCurNopStagesParam,
            pipeClockCycleNextNopStagesParam
        ])

    return pipeClockCycleFunction
Пример #12
0
# *******
opCode = cxx_writer.Code("""
shifted = toShift >> shift_amm;
//Controlling the sign extensions
if((toShift & 0x80000000) != 0){
    shifted |= (((unsigned)0xFFFFFFFF) << (32 - shift_amm));
}
else{
    shifted &= (((unsigned)0xFFFFFFFF) >> shift_amm);
}
return shifted;
""")
AShiftRight_method = trap.HelperMethod('ArithmeticShiftRight', opCode,
                                       'execute')
AShiftRight_method.setSignature(('BIT<32>'), [
    cxx_writer.Parameter('shift_amm', cxx_writer.uintType),
    ('toShift', 'BIT<32>')
])
AShiftRight_method.addVariable(('shifted', 'BIT<32>'))

opCode = cxx_writer.Code("""
if((bitSeq & (1 << (bitSeq_length - 1))) != 0)
    bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length);
return bitSeq;
""")
SignExtend_method = trap.HelperMethod('SignExtend', opCode, 'execute')
SignExtend_method.setSignature(
    ('BIT<32>'), [('bitSeq', 'BIT<32>'),
                  cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)])

opCode = cxx_writer.Code("""
Пример #13
0
def getRegisterClockCycleFunction(self, regName, wbStageOrder,
                                  registerMaxBitwidth):
    """Generates the callback function set by
    <reg>.setWbStageOrder({'pipe_n': ['pipe_x', ... 'pipe_0']}))
    as described in @see getPipeClockCycleFunction (3). The list of stages is
    interpreted in order of decreasing precedence. Note that step-wise forward
    propagation (1c) still takes place, but the feed-forward/-back from wb is
    not implicitly assumed. The user therefore needs to explicitly define all
    stage connections.
    The calling sequence is:
       pipeline.cpp:            <fetchStage>::behavior()
    -> registers.cpp:           clock_cycle()
    -> register_abstraction.hpp:clock_cycle()
    -> registers.cpp:           <reg>_clock_cycle()
    The fetch stage calls a clock_cycle function which iterates through all
    registers and calls their clock_cycle() method defined in
    register_abstraction.hpp. This, in turn, calls the register-specific
    callback function <reg>_clock_cycle, generated by TRAP in the registers.cpp
    file."""

    if not wbStageOrder: return

    pipeNumbers = {}
    i = 0
    for pipeStage in self.pipes:
        pipeNumbers[pipeStage.name] = i
        i += 1

    Code = """bool has_changes = false;

    // Copy over old values, just in case stalls should prevent propagation.
    for (unsigned i = 0; i < """ + str(len(self.pipes)) + """; ++i) {
      temp_values[i] = values[i];
      temp_time_stamps[i] = time_stamps[i];
    }
    """

    # 1c. Default Behavior: Regular step-wise forward propagation.
    # Note that in this case, all stages propagate, not just [regsStage..
    # wbStage]
    Code += """
      // Regular step-wise forward propagation.
      for (int i = 1; i <= """ + str(len(self.pipes) - 1) + """; ++i) {
        // The stage will contain a bubble.
        if (next_nop_stages & (1 << i)) {
          temp_values[i] = 0;
          temp_time_stamps[i] = 0;
        } else if ((i > stall_stage) && (time_stamps[i-1] >= time_stamps[i])) {
          temp_values[i] = values[i-1];
          temp_time_stamps[i] = time_stamps[i-1];
          has_changes = true;
        }
      }
      """

    # 3. Register-specific feedback loops via <reg>.setWbStageOrder():
    #for fromStage in sorted(wbStageOrder, key=lambda x: [pipe.name for pipe in self.pipes].index(x), reverse = True):
    for toStage, fromStages in wbStageOrder.items():
        for fromStage in reversed(fromStages):
            Code += """
              // """ + fromStage + """ -> """ + toStage + """
              if (!(cur_nop_stages & """ + hex(
                1 << pipeNumbers[fromStage]) + """)) {
                if (time_stamps[""" + str(
                    pipeNumbers[fromStage]
                ) + """] >= temp_time_stamps[""" + str(
                    pipeNumbers[toStage]) + """]) {
                  temp_values[""" + str(
                        pipeNumbers[toStage]
                    ) + """] = values[""" + str(pipeNumbers[fromStage]) + """];
                  temp_time_stamps[""" + str(
                        pipeNumbers[toStage]) + """] = time_stamps[""" + str(
                            pipeNumbers[fromStage]) + """];
                    has_changes = true;
                }
              }
              """
    Code += '\nreturn has_changes;\n'
    registerClockCycleValueParam = cxx_writer.Parameter(
        'values', registerMaxBitwidth.makePointer())
    registerClockCycleTempValueParam = cxx_writer.Parameter(
        'temp_values', registerMaxBitwidth.makePointer())
    registerClockCycleTimeStampParam = cxx_writer.Parameter(
        'time_stamps', cxx_writer.ulonglongPtrType)
    registerClockCycleTempTimeStampParam = cxx_writer.Parameter(
        'temp_time_stamps', cxx_writer.ulonglongPtrType)
    registerClockCycleStallStageParam = cxx_writer.Parameter(
        'stall_stage', cxx_writer.intType)
    registerClockCycleCurNopStagesParam = cxx_writer.Parameter(
        'cur_nop_stages', cxx_writer.uintType)
    registerClockCycleNextNopStagesParam = cxx_writer.Parameter(
        'next_nop_stages', cxx_writer.uintType)
    registerClockCycleFunction = cxx_writer.Function(
        regName.lower() + '_clock_cycle', cxx_writer.Code(Code),
        cxx_writer.boolType, [
            registerClockCycleValueParam, registerClockCycleTempValueParam,
            registerClockCycleTimeStampParam,
            registerClockCycleTempTimeStampParam,
            registerClockCycleStallStageParam,
            registerClockCycleCurNopStagesParam,
            registerClockCycleNextNopStagesParam
        ])

    return registerClockCycleFunction
Пример #14
0
# accessed by any instruction
#-------------------------------------------------------
# *******
# Here we define some helper methods, which are not directly part of the
# instructions, but which can be called by the instruction body
# *******

opCode = cxx_writer.Code("""
if((bitSeq & (1 << (bitSeq_length - 1))) != 0)
    bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length);
return bitSeq;
""")
SignExtend_method = trap.HelperMethod('SignExtend', opCode, 'execute')
SignExtend_method.setSignature(
    ('BIT<32>'), [('bitSeq', 'BIT<32>'),
                  cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)])

# PC increment
opCode = cxx_writer.Code("""
if (TARGET == 0xffffffff) {
	PC = PC + 4;
	DSFLAG = 0x0;
} else {
	PC = TARGET;
	TARGET = 0xffffffff;
	DSFLAG = 0x1;
}
""")
IncrementPC = trap.HelperOperation('IncrementPC', opCode, inline=False)

opCode = cxx_writer.Code("""
Пример #15
0
def getCPPRegisters(self, trace, combinedTrace, model, namespace):
    """Creates a container register bank for all registers, register banks,
    aliases and alias register banks of a processor. This encapsulates the
    register instantiation details (defining fields, etc) away from the
    processor. It also eases passes the registers to instructions, since only
    the container class needs to be passed.
    @see trap/runtime/modules/register/register_bank.hpp for a discussion."""

    #---------------------------------------------------------------------------
    ## @name Preprocessing
    #  @{

    # Abstraction Level
    abstractionType = cxx_writer.Type(
        'trap::amba_layer_ids',
        'register_abstraction.hpp')  #'amba_parameters.h')
    abstraction = ''
    if model.startswith('acc'):
        abstraction = 'trap::amba_CT'
    elif model.startswith('func'):
        if model.endswith('AT'):
            abstraction = 'trap::amba_AT'
        else:
            abstraction = 'trap::amba_LT'

    # Register Types
    regLen = 0
    # Determine the register with the largest bitwidth.
    for reg in self.regs + self.regBanks:
        if reg.bitWidth > regLen:
            regLen = reg.bitWidth
    from isa import resolveBitType
    global registerInterfaceType, registerType, aliasType
    registerMaxBitwidth = resolveBitType('BIT<' + str(regLen) + '>')
    registerFieldType = cxx_writer.TemplateType('trap::RegisterField',
                                                [registerMaxBitwidth],
                                                'modules/register.hpp')
    registerInterfaceType = cxx_writer.TemplateType(
        'trap::RegisterInterface', [registerMaxBitwidth, registerFieldType],
        'modules/register.hpp')
    registerType = cxx_writer.TemplateType('trap::Register',
                                           [registerMaxBitwidth],
                                           'modules/register.hpp')
    aliasType = cxx_writer.TemplateType('trap::RegisterAlias',
                                        [registerMaxBitwidth],
                                        'modules/register.hpp')

    # Alias Register and Alias Register Bank Initialization Order
    # Aliases that depend on each other need to be initialized in order. We
    # therefore create a dependency graph for both alias registers and alias
    # register banks.
    if nxVersion < 0.99:
        aliasUnsortedGraph = NX.XDiGraph()
    else:
        aliasUnsortedGraph = NX.DiGraph()
    for alias in self.aliasRegs + self.aliasRegBanks:
        aliasUnsortedGraph.add_node(alias)
    for alias in self.aliasRegs + self.aliasRegBanks:
        aliasPredecessors = []
        if isinstance(alias.initAlias, str):
            bracketIdx = alias.initAlias.find('[')
            if bracketIdx > 0:
                aliasPredecessors.append(alias.initAlias[:bracketIdx])
            else:
                aliasPredecessors.append(alias.initAlias)
        else:
            for aliasPredecessor in alias.initAlias:
                bracketIdx = aliasPredecessor.find('[')
                if bracketIdx > 0:
                    aliasPredecessors.append(aliasPredecessor[:bracketIdx])
                else:
                    aliasPredecessors.append(aliasPredecessor)
        for aliasPredecessor in aliasPredecessors:
            for aliasTarget in self.aliasRegs + self.aliasRegBanks:
                if aliasPredecessor == aliasTarget.name:
                    aliasUnsortedGraph.add_edge(aliasTarget, alias)
    # Check for circular dependencies.
    # NOTE: We might have some false positives here. We discarded indices for
    # banks, so a perfectly valid REGS1[x1]->REGS2[y1]; REGS2[y2]->REGS1[x2]
    # with ((x1 != x2) || (y1 != y2)) will be stored as REG1->REGS2;
    # REGS2->REGS1 and raise an error.
    # In reality, this will probably never happen anyway, since the visibility
    # of banks as a whole tends to be hierarchical.
    if not NX.is_directed_acyclic_graph(aliasUnsortedGraph):
        raise Exception(
            'Detected circular dependence in alias initializations.')
    # Sort dependency graph.
    global aliasGraph
    aliasGraph = NX.topological_sort(aliasUnsortedGraph)

    registerElements = []
    # reg_clock_cycle()
    # @see getPipeClockCycleFunction.
    pipeClockCycleFunction = getPipeClockCycleFunction(self,
                                                       registerMaxBitwidth)
    if model.startswith('acc'):
        registerElements.append(pipeClockCycleFunction)

    ## @} Preprocessing
    #---------------------------------------------------------------------------
    ## @name Attributes and Initialization
    #  @{

    from processor import extractRegInterval
    registerMembers = []
    registerCtorParams = []
    registerCtorInit = []
    registerCtorCode = ''

    # Registers
    registerCtorCode += '// Initialize registers.\n'
    for reg in self.regs:
        # Attribute Declaration
        registerMembers.append(
            cxx_writer.Attribute(reg.name.lower(), registerType, 'public'))

        # Constructor Parameters
        if isinstance(reg.constValue, str):
            if reg.constValue not in [
                    param.name for param in registerCtorParams
            ]:
                registerCtorParams.append(
                    cxx_writer.Parameter(reg.constValue, registerMaxBitwidth))
        # Iterable element, i.e. initialization with a constant and an offset.
        # TODO: Some of the default values are processor variables such as
        # ENTRY_POINT and MPROC_ID. These are sadly globals and set by the
        # loader at some point. The current solution passes uninitialized
        # values. There are several options:
        # 1. Force program loading before processor construction. Easy but
        #    limits the user.
        # 2. Keep the current proc if, but pass a reference instead of a value.
        #    Create a stub bool = 0 for all other registers. Minimal impact but
        #    ugly.
        # 3. Create processor.load(), which sets both the processor vars and
        #    resets the registers. Works for the PC, but not for others. Also
        #    still ugly, as the register should do its own resetting.
        # 4. Create a processor.load(), which calls a register.
        #    set_reset_value(). 1) Clean processor if, 2) keeps the reset value
        #    in the register and 3) works for both const and non-const reset
        #    values.
        if isinstance(reg.defValue, tuple):
            if reg.defValue[0] not in [
                    param.name for param in registerCtorParams
            ]:
                registerCtorParams.append(
                    cxx_writer.Parameter(str(reg.defValue[0]),
                                         registerMaxBitwidth))
        elif isinstance(reg.defValue, str):
            if reg.defValue not in [
                    param.name for param in registerCtorParams
            ]:
                registerCtorParams.append(
                    cxx_writer.Parameter(str(reg.defValue),
                                         registerMaxBitwidth))

        # Constructor Initialization List
        # name, abstraction
        Code = '("' + reg.name.lower() + '", ' + abstraction + ', '
        # is_const
        if reg.constValue: Code += 'true, '
        else: Code += 'false, '
        # offset
        if reg.offset: Code += str(reg.offset) + ', '
        else: Code += '0, '
        # delay
        if reg.delay: Code += str(reg.delay) + ', '
        else: Code += '0, '
        # reset_val
        if reg.constValue != None:
            try:
                Code += hex(reg.constValue)
            except TypeError:
                Code += str(reg.constValue)
        elif reg.defValue != None:
            # Iterable element, i.e. initialization with a constant and an
            # offset.
            if isinstance(reg.defValue, tuple):
                Code += str(reg.defValue[0]) + ' + '
                try:
                    Code += hex(reg.defValue[1])
                except TypeError:
                    Code += str(reg.defValue[1])
            else:
                try:
                    Code += hex(reg.defValue)
                except TypeError:
                    Code += str(reg.defValue)
        else:
            Code += '0'
        Code += ', '
        # num_pipe_stages
        if self.pipes: Code += str(len(self.pipes))
        else: Code += '1'
        if model.startswith('acc'):
            if reg.isGlobal:
                Code += ', NULL, true'
            elif reg.wbStageOrder:
                registerClockCycleFunction = getRegisterClockCycleFunction(
                    self, reg.name, reg.wbStageOrder, registerMaxBitwidth)
                registerElements.append(registerClockCycleFunction)
                Code += ', ' + registerClockCycleFunction.name
            elif pipeClockCycleFunction:
                Code += ', ' + pipeClockCycleFunction.name
        Code += ')'
        registerCtorInit.append(reg.name.lower() + Code)

        # Constructor Body: Add fields
        if reg.bitMask:
            for registerFieldMaskName, registerFieldMaskPos in reg.bitMask.items(
            ):
                registerCtorCode += reg.name.lower(
                ) + '.add_field("' + registerFieldMaskName + '", ' + str(
                    registerFieldMaskPos[1]) + ', ' + str(
                        registerFieldMaskPos[0]) + ');\n'
            registerCtorCode += '\n'

    # Register Banks
    registerCtorCode += '// Initialize register banks.\n'
    for regBank in self.regBanks:
        # Attribute Declaration
        registerMembers.append(
            cxx_writer.Attribute(
                regBank.name.lower() + '[' + str(regBank.numRegs) + ']',
                registerType, 'public'))

        # Constructor Parameters
        for regConstValue in regBank.constValue.values():
            if isinstance(regConstValue, str):
                if regConstValue not in [
                        param.name for param in registerCtorParams
                ]:
                    registerCtorParams.append(
                        cxx_writer.Parameter(regConstValue,
                                             registerMaxBitwidth))
        for regDefaultValue in regBank.defValues:
            # Iterable element, i.e. initialization with a constant and an
            # offset.
            if isinstance(regDefaultValue, tuple):
                if regDefaultValue[0] not in [
                        param.name for param in registerCtorParams
                ]:
                    registerCtorParams.append(
                        cxx_writer.Parameter(str(regDefaultValue[0]),
                                             registerMaxBitwidth))
            elif isinstance(regDefaultValue, str):
                if regDefaultValue not in [
                        param.name for param in registerCtorParams
                ]:
                    registerCtorParams.append(
                        cxx_writer.Parameter(str(regDefaultValue),
                                             registerMaxBitwidth))

        # Constructor Initialization List
        Code = ''
        for reg in range(0, regBank.numRegs):
            # name, abstraction
            Code += '{"' + regBank.name.lower() + '[' + str(
                reg) + ']", ' + abstraction + ', '
            # is_const
            if regBank.constValue.has_key(reg): Code += 'true, '
            else: Code += 'false, '
            # offset
            if regBank.offset: Code += str(regBank.offset) + ', '
            else: Code += '0, '
            # delay
            if regBank.delay.has_key(reg):
                Code += str(regBank.delay[reg]) + ', '
            else:
                Code += '0, '
            # reset_val
            if regBank.constValue.has_key(reg):
                try:
                    Code += hex(regBank.constValue[reg])
                except TypeError:
                    Code += str(regBank.constValue[reg])
            elif regBank.defValues[reg] != None:
                # Iterable element, i.e. initialization with a constant and an
                # offset.
                if isinstance(regBank.defValues[reg], tuple):
                    Code += str(regBank.defValues[reg][0]) + ' + '
                    try:
                        Code += hex(regBank.defValues[reg][1])
                    except TypeError:
                        Code += str(regBank.defValues[reg][1])
                else:
                    try:
                        Code += hex(regBank.defValues[reg])
                    except TypeError:
                        Code += str(regBank.defValues[reg])
            else:
                Code += '0'
            Code += ', '
            # num_pipe_stages
            if self.pipes: Code += str(len(self.pipes))
            else: Code += '1'
            if model.startswith('acc'):
                if regBank.isGlobal:
                    Code += ', NULL, true'
                elif regBank.wbStageOrder.has_key(reg):
                    registerClockCycleFunction = getRegisterClockCycleFunction(
                        self, regBank.name + str(reg),
                        regBank.wbStageOrder[reg], registerMaxBitwidth)
                    registerElements.append(registerClockCycleFunction)
                    Code += ', ' + registerClockCycleFunction.name
                elif pipeClockCycleFunction:
                    Code += ', ' + pipeClockCycleFunction.name
            Code += '},\n'
        registerCtorInit.append(regBank.name.lower() + ' {' + Code[:-2] + '}')

        # Constructor Body: Add fields.
        if regBank.bitMask:
            registerCtorCode += 'for (unsigned i = 0; i < ' + str(
                regBank.numRegs) + '; ++i) {\n'

            for registerFieldMaskName, registerFieldMaskPos in regBank.bitMask.items(
            ):
                registerCtorCode += regBank.name.lower(
                ) + '[i].add_field("' + registerFieldMaskName + '", ' + str(
                    registerFieldMaskPos[1]) + ', ' + str(
                        registerFieldMaskPos[0]) + ');\n'

            registerCtorCode += '}\n\n'

    # Alias Registers
    for alias in self.aliasRegs:
        # Attribute Declaration
        #aliasType = cxx_writer.TemplateType('std::reference_wrapper', [registerType], 'functional')
        #aliasBankType = cxx_writer.TemplateType('std::vector', [aliasType], 'vector')
        registerMembers.append(
            cxx_writer.Attribute(alias.name.lower(), aliasType, 'public'))

        # Constructor Initialization List
        registerCtorInit.append(alias.name.lower() + '("' +
                                alias.name.lower() + '")')

    # Alias Register Banks
    for aliasBank in self.aliasRegBanks:
        # Attribute Declaration
        registerMembers.append(
            cxx_writer.Attribute(
                aliasBank.name.lower() + '[' + str(aliasBank.numRegs) + ']',
                aliasType, 'public'))

        # Constructor Initialization List
        Code = ''
        for aliasIdx in range(0, aliasBank.numRegs):
            Code += '{"' + aliasBank.name.lower() + '[' + str(
                aliasIdx) + ']"},'
        registerCtorInit.append(aliasBank.name.lower() + ' {' + Code[:-1] +
                                '}')

    # Alias Registers and Alias Register Banks
    # Constructor Body: Update alias targets.
    registerCtorCode += '// Initialize alias registers and alias register banks.\n'
    for alias in aliasGraph:
        if isinstance(alias.initAlias, str):
            regName = alias.initAlias[:alias.initAlias.find('[')]
            regRange = extractRegInterval(alias.initAlias)
            # REGBANK[n], REGBANK[n:m], REGBANK
            if regRange or regName in self.regBanks + self.aliasRegBanks:
                aliasIdx = 0
                if regRange:
                    regStart = regRange[0]
                    regEnd = regRange[1] + 1
                else:
                    regStart = 0
                    regEnd = reg.numRegs
                for regIdx in range(regStart, regEnd):
                    registerCtorCode += 'this->' + alias.name.lower()
                    if alias in self.aliasRegBanks:
                        registerCtorCode += '[' + str(aliasIdx) + ']'
                    registerCtorCode += '.update_alias(this->' + regName.lower(
                    ) + '[' + str(regIdx) + ']'
                    if alias in self.aliasRegs:
                        registerCtorCode += ', ' + str(alias.offset)
                    elif alias.offsets.has_key(aliasIdx):
                        registerCtorCode += ', ' + str(alias.offsets[aliasIdx])
                    else:
                        registerCtorCode += ', 0'
                    registerCtorCode += ');\n'
                    aliasIdx = aliasIdx + 1
            # REG
            else:
                registerCtorCode += 'this->' + alias.name.lower(
                ) + '.update_alias(this->' + regName.lower()
                if alias in self.aliasRegs:
                    registerCtorCode += ', ' + str(alias.offset)
                elif alias.offsets.has_key(aliasIdx):
                    registerCtorCode += ', ' + str(alias.offsets[aliasIdx])
                else:
                    registerCtorCode += ', 0'
                registerCtorCode += ');\n'
        else:
            aliasIdx = 0
            for reg in alias.initAlias:
                regName = reg[:reg.find('[')]
                regRange = extractRegInterval(reg)
                # REGBANK[n], REGBANK[n:m], REGBANK
                if regRange or regName in self.regBanks + self.aliasRegBanks:
                    if regRange:
                        regStart = regRange[0]
                        regEnd = regRange[1] + 1
                    else:
                        regStart = 0
                        regEnd = reg.numRegs
                    for regIdx in range(regStart, regEnd):
                        registerCtorCode += 'this->' + alias.name.lower(
                        ) + '[' + str(
                            aliasIdx
                        ) + '].update_alias(this->' + regName.lower(
                        ) + '[' + str(regIdx) + ']'
                        if alias.offsets.has_key(aliasIdx):
                            registerCtorCode += ', ' + str(
                                alias.offsets[aliasIdx])
                        else:
                            registerCtorCode += ', 0'
                        registerCtorCode += ');\n'
                        aliasIdx = aliasIdx + 1
                # REG
                else:
                    registerCtorCode += 'this->' + alias.name.lower(
                    ) + '[' + str(
                        aliasIdx) + '].update_alias(this->' + regName.lower()
                    if alias.offsets.has_key(aliasIdx):
                        registerCtorCode += ', ' + str(alias.offsets[aliasIdx])
                    else:
                        registerCtorCode += ', 0'
                    registerCtorCode += ');\n'
                    aliasIdx = aliasIdx + 1

    # Constructor
    registerCtor = cxx_writer.Constructor(cxx_writer.Code(registerCtorCode),
                                          'public',
                                          parameters=registerCtorParams,
                                          initList=registerCtorInit)

    ## @} Attributes and Initialization
    #---------------------------------------------------------------------------
    ## @name Methods
    #  Access and Modification: reset(), write(), write_dbg(), write_force()
    #  Observer: execute_callbacks(), set_stage(), unset_stage(), clock_cycle()
    #  Information and Helper: operator<<()
    #  @{

    # TODO: Consider a visitor pattern, where the function visiting the
    # registers is passed as a parameter.
    # Method Bodies: Registers
    registerResetCode = '// Reset registers.\n'
    registerWriteCode = 'bool ret = true;\n\n// Write registers.\n'
    registerWriteDbgCode = 'bool ret = true;\n\n// Write registers.\n'
    registerWriteForceCode = 'bool ret = true;\n\n// Write registers.\n'
    registerExecuteCallbacksCode = '// Execute callbacks on registers.\n'
    registerSetStageCode = '// Set pipeline stage for registers.\n'
    registerUnsetStageCode = '// Unset pipeline stage for registers.\n'
    registerClockCycleCode = '// Propagate pipeline stage for registers.\n'
    registerStallCode = '// Stall pipeline for registers.\n'
    registerAdvanceCode = '// Advance pipeline for registers.\n'
    registerFlushCode = '// Flush registers.\n'
    registerPrintCode = 'os << std::hex << std::showbase;\n\n// Print registers.\n'
    for reg in self.regs:
        if reg.constValue == None:
            registerResetCode += reg.name.lower() + '.reset();\n'
            registerWriteCode += 'ret = ret && ' + reg.name.lower(
            ) + '.write(data);\n'
            registerWriteDbgCode += 'ret = ret && ' + reg.name.lower(
            ) + '.write_dbg(data);\n'
            registerWriteForceCode += 'ret = ret && ' + reg.name.lower(
            ) + '.write_force(data);\n'
        registerExecuteCallbacksCode += reg.name.lower(
        ) + '.execute_callbacks(type, 0, sizeof(' + registerMaxBitwidth.name.lower(
        ) + '));\n'
        registerSetStageCode += reg.name.lower(
        ) + '.get_strategy()->set_stage(stage);\n'
        registerUnsetStageCode += reg.name.lower(
        ) + '.get_strategy()->unset_stage();\n'
        registerClockCycleCode += reg.name.lower() + '.clock_cycle();\n'
        registerStallCode += reg.name.lower() + '.stall(stage);\n'
        registerAdvanceCode += reg.name.lower() + '.advance();\n'
        registerFlushCode += reg.name.lower() + '.flush(stage);\n'
        registerPrintCode += 'os << ' + reg.name.lower(
        ) + '.name() << ": " << ' + reg.name.lower(
        ) + '.read_dbg() << \'\\n\';\n'

    # Method Bodies: Register Banks
    registerResetCode += '\n// Reset register banks.\n'
    registerWriteCode += '\n// Write register banks.\n'
    registerWriteDbgCode += '\n// Write register banks.\n'
    registerWriteForceCode += '\n// Write register banks.\n'
    registerExecuteCallbacksCode += '\n// Execute callbacks on register banks.\n'
    registerSetStageCode += '\n// Set pipeline stage for register banks.\n'
    registerUnsetStageCode += '\n// Unset pipeline stage for register banks.\n'
    registerClockCycleCode += '// Propagate pipeline stage for register banks.\n'
    registerStallCode += '// Stall pipeline for register banks.\n'
    registerAdvanceCode += '// Advance pipeline for register banks.\n'
    registerFlushCode += '// Flush register banks.\n'
    registerPrintCode += '\n// Print register banks.\n'
    for regBank in self.regBanks:
        registerResetCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerResetCode += regBank.name.lower() + '[i].reset();\n'
        registerResetCode += '}\n\n'
        registerWriteCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerWriteCode += 'ret = ret && ' + regBank.name.lower(
        ) + '[i].write(data);\n'
        registerWriteCode += '}\n\n'
        registerWriteDbgCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerWriteDbgCode += 'ret = ret && ' + regBank.name.lower(
        ) + '[i].write_dbg(data);\n'
        registerWriteDbgCode += '}\n\n'
        registerWriteForceCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerWriteForceCode += 'ret = ret && ' + regBank.name.lower(
        ) + '[i].write_force(data);\n'
        registerWriteForceCode += '}\n\n'
        registerExecuteCallbacksCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerExecuteCallbacksCode += regBank.name.lower(
        ) + '[i].execute_callbacks(type, 0, sizeof(' + registerMaxBitwidth.name.lower(
        ) + '));\n'
        registerExecuteCallbacksCode += '}\n\n'
        registerSetStageCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerSetStageCode += regBank.name.lower(
        ) + '[i].set_stage(stage);\n'
        registerSetStageCode += '}\n\n'
        registerUnsetStageCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerUnsetStageCode += regBank.name.lower() + '[i].unset_stage();\n'
        registerUnsetStageCode += '}\n\n'
        registerClockCycleCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerClockCycleCode += regBank.name.lower() + '[i].clock_cycle();\n'
        registerClockCycleCode += '}\n\n'
        registerStallCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerStallCode += regBank.name.lower() + '[i].stall(stage);\n'
        registerStallCode += '}\n\n'
        registerAdvanceCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerAdvanceCode += regBank.name.lower() + '[i].advance();\n'
        registerAdvanceCode += '}\n\n'
        registerFlushCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerFlushCode += regBank.name.lower() + '[i].flush(stage);\n'
        registerFlushCode += '}\n\n'
        registerPrintCode += 'for (int i = 0; i < ' + str(
            regBank.numRegs) + '; ++i) {\n'
        registerPrintCode += 'os << ' + regBank.name.lower(
        ) + '[i].name() << ": " << ' + regBank.name.lower(
        ) + '[i].read_dbg() << \'\\n\';\n'
        registerPrintCode += '}\n\n'
    registerWriteCode += 'return ret;\n'
    registerWriteDbgCode += 'return ret;\n'
    registerWriteForceCode += 'return ret;\n'
    registerPrintCode += 'os << std::dec;\nreturn os;\n'

    # Method Declarations
    registerResetMethod = cxx_writer.Method('reset',
                                            cxx_writer.Code(registerResetCode),
                                            cxx_writer.voidType, 'public')
    registerMembers.append(registerResetMethod)

    registerWriteDataParam = cxx_writer.Parameter(
        'data',
        registerMaxBitwidth.makeConst().makeRef())
    registerWriteMethod = cxx_writer.Method('write',
                                            cxx_writer.Code(registerWriteCode),
                                            cxx_writer.boolType, 'public',
                                            [registerWriteDataParam])
    registerMembers.append(registerWriteMethod)
    registerWriteDbgMethod = cxx_writer.Method(
        'write_dbg', cxx_writer.Code(registerWriteDbgCode),
        cxx_writer.boolType, 'public', [registerWriteDataParam])
    registerMembers.append(registerWriteDbgMethod)
    registerWriteForceMethod = cxx_writer.Method(
        'write_force', cxx_writer.Code(registerWriteForceCode),
        cxx_writer.boolType, 'public', [registerWriteDataParam])
    registerMembers.append(registerWriteForceMethod)

    registerExecuteCallbacksUint32RefType = cxx_writer.Type(
        'uint32_t', const=True).makeRef()
    registerExecuteCallbacksMethod = cxx_writer.Method(
        'execute_callbacks', cxx_writer.Code(registerExecuteCallbacksCode),
        cxx_writer.voidType, 'public', [
            cxx_writer.Parameter(
                'type',
                cxx_writer.Type('scireg_ns::scireg_callback_type',
                                const=True).makeRef()),
            cxx_writer.Parameter('offset',
                                 registerExecuteCallbacksUint32RefType,
                                 initValue='0'),
            cxx_writer.Parameter('size',
                                 cxx_writer.Type('uint32_t',
                                                 const=True).makeRef(),
                                 initValue='0')
        ])
    registerMembers.append(registerExecuteCallbacksMethod)

    registerSetStageMethod = cxx_writer.Method(
        'set_stage', cxx_writer.Code(registerSetStageCode),
        cxx_writer.voidType, 'public',
        [cxx_writer.Parameter('stage', cxx_writer.uintType)])
    registerMembers.append(registerSetStageMethod)
    registerUnsetStageMethod = cxx_writer.Method(
        'unset_stage', cxx_writer.Code(registerUnsetStageCode),
        cxx_writer.voidType, 'public')
    registerMembers.append(registerUnsetStageMethod)
    registerClockCycleMethod = cxx_writer.Method(
        'clock_cycle', cxx_writer.Code(registerClockCycleCode),
        cxx_writer.voidType, 'public')
    registerMembers.append(registerClockCycleMethod)
    registerStallMethod = cxx_writer.Method(
        'stall', cxx_writer.Code(registerStallCode), cxx_writer.voidType,
        'public', [cxx_writer.Parameter('stage', cxx_writer.uintType)])
    registerMembers.append(registerStallMethod)
    registerAdvanceMethod = cxx_writer.Method(
        'advance', cxx_writer.Code(registerAdvanceCode), cxx_writer.voidType,
        'public')
    registerMembers.append(registerAdvanceMethod)
    registerFlushMethod = cxx_writer.Method(
        'flush', cxx_writer.Code(registerFlushCode), cxx_writer.voidType,
        'public', [cxx_writer.Parameter('stage', cxx_writer.uintType)])
    registerMembers.append(registerFlushMethod)

    registerPrintOstreamRefType = cxx_writer.Type('std::ostream',
                                                  'iostream').makeRef()
    registerPrintMethod = cxx_writer.MemberOperator(
        '<<',
        cxx_writer.Code(registerPrintCode),
        registerPrintOstreamRefType,
        'public', [cxx_writer.Parameter('os', registerPrintOstreamRefType)],
        const=True)
    registerMembers.append(registerPrintMethod)

    ## @} Methods
    #---------------------------------------------------------------------------

    registerClass = cxx_writer.ClassDeclaration('Registers',
                                                registerMembers,
                                                namespaces=[namespace])
    registerClass.addDocString(
        brief='Register Container Class',
        detail=
        'Contains all registers and register banks of the processor as member variables. It serves for encapsulating the instantiation details (defining fields, etc) away from the processor. It also simplifies passing the registers to the instructions, instead of passing each register individually.'
    )
    registerClass.addConstructor(registerCtor)
    return [registerClass] + registerElements
Пример #16
0
def getCPPIf(self, model, namespace):
    """Creates the interface used by the tools to access the processor core."""

    if not self.abi:
        return

    wordType = self.bitSizes[1]
    includes = wordType.getIncludes()
    pipeRegisterType = cxx_writer.Type('PipelineRegister',
                                       includes='#include \"registers.hpp\"')
    histInstrType = cxx_writer.Type('HistoryInstrType',
                                    'modules/instruction.hpp')
    histQueueType = cxx_writer.TemplateType('boost::circular_buffer',
                                            [histInstrType],
                                            'boost/circular_buffer.hpp')

    from procWriter import abiAttrs
    abiMembers = []
    abiCtorParams = []
    abiCtorInit = []
    abitCtorCode = ''
    regReadCode = '.read_force()'
    regWriteCode = '.write_force'

    #---------------------------------------------------------------------------
    ## @name Attributes and Initialization
    #  @{

    for attr in abiAttrs:
        abiMembers.append(attr)
        abiCtorParams.append(cxx_writer.Parameter(attr.name, attr.varType))
        abiCtorInit.append(attr.name + '(' + attr.name + ')')

    routineEntryStateAttr = cxx_writer.Attribute('routine_entry_state',
                                                 cxx_writer.intType, 'private')
    abiMembers.append(routineEntryStateAttr)

    routineExitStateAttr = cxx_writer.Attribute('routine_exit_state',
                                                cxx_writer.intType, 'private')
    abiMembers.append(routineExitStateAttr)

    abitCtorCode = """this->routine_entry_state = 0;
    this->routine_exit_state = 0;
    """

    StrVectorType = cxx_writer.TemplateType('std::vector',
                                            [cxx_writer.stringType], 'vector')
    StrVectorVectorType = cxx_writer.TemplateType('std::vector',
                                                  [StrVectorType], 'vector')

    routineEntrySequenceAttr = cxx_writer.Attribute('routine_entry_sequence',
                                                    StrVectorVectorType,
                                                    'private')
    abiMembers.append(routineEntrySequenceAttr)

    routineExitSequenceAttr = cxx_writer.Attribute('routine_exit_sequence',
                                                   StrVectorVectorType,
                                                   'private')
    abiMembers.append(routineExitSequenceAttr)

    exitValueAttr = cxx_writer.Attribute('exit_value', cxx_writer.uintType,
                                         'private')
    abiMembers.append(exitValueAttr)

    from isa import Instruction
    abitCtorCode = 'std::vector<std::string> temp_vec;\n'
    for instrList in self.abi.callInstr:
        abitCtorCode += 'temp_vec.clear();\n'
        if not instrList:
            abitCtorCode += 'temp_vec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            abitCtorCode += 'temp_vec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                abitCtorCode += 'temp_vec.push_back("' + instr.name + '");\n'
        abitCtorCode += 'this->routine_entry_sequence.push_back(temp_vec);\n'
    for instrList in self.abi.returnCallInstr:
        abitCtorCode += 'temp_vec.clear();\n'
        if not instrList:
            abitCtorCode += 'temp_vec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            abitCtorCode += 'temp_vec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                abitCtorCode += 'temp_vec.push_back("' + instr.name + '");\n'
        abitCtorCode += 'this->routine_exit_sequence.push_back(temp_vec);\n'

    ## @} Attributes and Initialization
    #---------------------------------------------------------------------------
    ## @name Interface Methods
    #  @{

    # num_gdb_regs()
    maxGDBId = 0
    numGDBRegsBody = cxx_writer.Code('return ' + str(maxGDBId + 1) + ';')
    numGDBRegsMethod = cxx_writer.Method('num_gdb_regs',
                                         numGDBRegsBody,
                                         cxx_writer.uintType,
                                         'public',
                                         noException=True,
                                         const=True)
    abiMembers.append(numGDBRegsMethod)

    # read_gdb_reg()
    Code = 'switch(gdb_id) {\n'
    sortedGDBRegs = sorted(self.abi.regCorrespondence.items(),
                           lambda x, y: cmp(x[1], y[1]))
    for reg, gdbId in sortedGDBRegs:
        if gdbId > maxGDBId:
            maxGDBId = gdbId
        Code += 'case ' + str(gdbId) + ': {\n'
        Code += 'return ' + reg
        if self.abi.offset.has_key(reg) and not model.startswith('acc'):
            Code += ' + ' + str(self.abi.offset[reg])
        Code += ';\nbreak;}\n'
    Code += 'default: {\nreturn 0;\n}\n}\n'
    readGDBRegBody = cxx_writer.Code(Code)
    readGDBRegBody.addInclude(includes)
    readGDBRegParam = cxx_writer.Parameter(
        'gdb_id',
        cxx_writer.uintType.makeRef().makeConst())
    readGDBRegMethod = cxx_writer.Method('read_gdb_reg',
                                         readGDBRegBody,
                                         wordType,
                                         'public', [readGDBRegParam],
                                         noException=True,
                                         const=True)
    abiMembers.append(readGDBRegMethod)

    # set_gdb_reg()
    Code = 'switch(gdb_id) {\n'
    for reg, gdbId in sortedGDBRegs:
        Code += 'case ' + str(gdbId) + ': {\n'
        Code += reg + regWriteCode + '(new_value'
        Code += ');\nbreak;}\n'
    Code += 'default: {\nTHROW_EXCEPTION(\"Register corresponding to GDB id \" << gdb_id << \" not found.\");\n}\n}\n'
    setGDBRegBody = cxx_writer.Code(Code)
    setGDBRegBody.addInclude(includes)
    setGDBRegParam1 = cxx_writer.Parameter('new_value',
                                           wordType.makeRef().makeConst())
    setGDBRegParam2 = cxx_writer.Parameter(
        'gdb_id',
        cxx_writer.uintType.makeRef().makeConst())
    setGDBRegMethod = cxx_writer.Method('set_gdb_reg',
                                        setGDBRegBody,
                                        cxx_writer.voidType,
                                        'public',
                                        [setGDBRegParam1, setGDBRegParam2],
                                        noException=True)
    abiMembers.append(setGDBRegMethod)

    addressParam = cxx_writer.Parameter('address',
                                        wordType.makeRef().makeConst())

    # read_args()
    vectorType = cxx_writer.TemplateType('std::vector', [wordType], 'vector')
    Code = str(vectorType) + ' args;\n'
    for arg in self.abi.args:
        Code += 'args.push_back(this->' + arg
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            Code += ' + ' + str(self.abi.offset[arg])
        Code += ');\n'
    Code += 'return args;\n'
    readArgsBody = cxx_writer.Code(Code)
    readArgsBody.addInclude(includes)
    readArgsMethod = cxx_writer.Method('read_args',
                                       readArgsBody,
                                       vectorType,
                                       'public',
                                       noException=True,
                                       const=True)
    abiMembers.append(readArgsMethod)

    # set_args()
    Code = 'if (args.size() > ' + str(
        len(self.abi.args)
    ) + ') {\nTHROW_EXCEPTION(\"Too many arguments for processor ABI, given \" << args.size() << \", expected up to ' + str(
        len(self.abi.args)) + ' .\");\n}\n'
    Code += str(
        vectorType
    ) + '::const_iterator arg_it = args.begin(), arg_end = args.end();\n'
    for arg in self.abi.args:
        Code += 'if (arg_it != arg_end) {\n'
        Code += arg + regWriteCode + '(*arg_it'
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            Code += ' - ' + str(self.abi.offset[arg])
        Code += ');\narg_it++;\n}\n'
    setArgsParam = cxx_writer.Parameter('args',
                                        vectorType.makeRef().makeConst())
    setArgsMethod = cxx_writer.Method('set_args',
                                      cxx_writer.Code(Code),
                                      cxx_writer.voidType,
                                      'public', [setArgsParam],
                                      noException=True)
    abiMembers.append(setArgsMethod)

    # read_<>(), set_<>()
    for elem in [
            self.abi.PC, self.abi.LR, self.abi.SP, self.abi.FP, self.abi.RetVal
    ]:
        if not elem:
            continue
        Code = 'return ' + elem
        if self.abi.offset.has_key(elem):
            Code += ' + ' + str(self.abi.offset[elem])
        Code += ';'
        readElemBody = cxx_writer.Code(Code)
        readElemBody.addInclude(includes)
        readElemMethod = cxx_writer.Method('read_' + self.abi.name[elem],
                                           readElemBody,
                                           wordType,
                                           'public',
                                           noException=True,
                                           const=True)
        abiMembers.append(readElemMethod)

        Code = elem + regWriteCode + '(new_value);'
        setElemBody = cxx_writer.Code(Code)
        setElemBody.addInclude(includes)
        setElemParam = cxx_writer.Parameter('new_value',
                                            wordType.makeRef().makeConst())
        setElemMethod = cxx_writer.Method('set_' + self.abi.name[elem],
                                          setElemBody,
                                          cxx_writer.voidType,
                                          'public', [setElemParam],
                                          noException=True)
        abiMembers.append(setElemMethod)

    # read_mem()
    Code = ''
    if not self.abi.memories:
        Code += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '.\");'
    else:
        if len(self.abi.memories) == 1:
            Code += 'return this->' + self.abi.memories.keys(
            )[0] + '.read_word_dbg(address);'
        else:
            for mem_name, mem_range in self.abi.memories.items():
                Code += 'if (address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + ') {\n'
                Code += 'return this->' + self.abi.memories.keys(
                )[0] + '.read_word_dbg(address);\n} else '
            Code += ' {\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range.\");\n}'
    readMemMethod = cxx_writer.Method('read_mem', cxx_writer.Code(Code),
                                      wordType, 'public', [addressParam])
    abiMembers.append(readMemMethod)

    # read_char_mem()
    Code = ''
    if not self.abi.memories:
        Code += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '.\");'
    else:
        if len(self.abi.memories) == 1:
            Code += 'return this->' + self.abi.memories.keys(
            )[0] + '.read_byte_dbg(address);'
        else:
            for mem_name, mem_range in self.abi.memories.items():
                Code += 'if (address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + ') {\n'
                Code += 'return this->' + self.abi.memories.keys(
                )[0] + '.read_byte_dbg(address);\n} else '
            Code += ' {\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range.\");\n}'
    readMemMethod = cxx_writer.Method('read_char_mem', cxx_writer.Code(Code),
                                      cxx_writer.ucharType, 'public',
                                      [addressParam])
    abiMembers.append(readMemMethod)

    # write_mem()
    Code = ''
    if not self.abi.memories:
        Code += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '.\");'
    else:
        if len(self.abi.memories) == 1:
            Code += 'this->' + self.abi.memories.keys(
            )[0] + '.write_word_dbg(address, datum);'
        else:
            for mem_name, mem_range in self.abi.memories.items():
                Code += 'if (address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + ') {\n'
                Code += 'this->' + self.abi.memories.keys(
                )[0] + '.write_word_dbg(address, datum);\n} else '
            Code += ' {\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range.\");\n}'
    writeMemBody = cxx_writer.Code(Code)
    writeMemBody.addInclude('common/report.hpp')
    datumParam = cxx_writer.Parameter('datum', wordType)
    writeMemMethod = cxx_writer.Method('write_mem', writeMemBody,
                                       cxx_writer.voidType, 'public',
                                       [addressParam, datumParam])
    abiMembers.append(writeMemMethod)

    # write_char_mem()
    Code = ''
    if not self.abi.memories:
        Code += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '.\");'
    else:
        if len(self.abi.memories) == 1:
            Code += 'this->' + self.abi.memories.keys(
            )[0] + '.write_byte_dbg(address, datum);'
        else:
            for mem_name, mem_range in self.abi.memories.items():
                Code += 'if (address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + ') {\n'
                Code += 'this->' + self.abi.memories.keys(
                )[0] + '.write_byte_dbg(address, datum);\n} else '
            Code += ' {\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range.\");\n}'
    datumParam = cxx_writer.Parameter('datum', cxx_writer.ucharType)
    writeMemMethod = cxx_writer.Method('write_char_mem', cxx_writer.Code(Code),
                                       cxx_writer.voidType, 'public',
                                       [addressParam, datumParam])
    abiMembers.append(writeMemMethod)

    # Methods necessary for saving and restoring the complete processor state.
    # Useful, for example, for implementing hardware context-switches, or
    # simulation checkpointing.

    # get_state()
    totalStateSize = 0
    for reg in self.regs:
        totalStateSize += reg.bitWidth / self.byteSize
    for regB in self.regBanks:
        totalStateSize += (regB.bitWidth * regB.numRegs) / self.byteSize
    Code = 'unsigned char* cur_state = new unsigned char[' + str(
        totalStateSize) + '];\n'
    Code += 'unsigned char* cur_state_temp = cur_state;\n'

    from processor import extractRegInterval
    stateIgnoreRegs = {}
    for reg in self.abi.stateIgnoreRegs:
        index = extractRegInterval(reg)
        if index:
            refName = reg[:reg.find('[')]
            if not refName in stateIgnoreRegs.keys():
                stateIgnoreRegs[refName] = []
            for i in range(index[0], index[1] + 1):
                stateIgnoreRegs[refName].append(i)
        else:
            stateIgnoreRegs[reg] = None

    from isa import resolveBitType
    for reg in self.regs:
        if not reg.name in stateIgnoreRegs.keys():
            regWType = resolveBitType('BIT<' + str(reg.bitWidth) + '>')
            Code += '*((' + str(
                regWType.makePointer()
            ) + ')cur_state_temp) = ' + reg.name + regReadCode + ';\ncur_state_temp += ' + str(
                reg.bitWidth / self.byteSize) + ';\n'
    for regB in self.regBanks:
        regWType = resolveBitType('BIT<' + str(regB.bitWidth) + '>')
        if not regB.name in stateIgnoreRegs.keys():
            for i in range(0, regB.numRegs):
                Code += '*((' + str(regWType.makePointer(
                )) + ')cur_state_temp) = ' + regB.name + '[' + str(
                    i) + ']' + regReadCode + ';\ncur_state_temp += ' + str(
                        regB.bitWidth / self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    Code += '*((' + str(regWType.makePointer(
                    )) + ')cur_state_temp) = ' + regB.name + '[' + str(
                        i) + ']' + regReadCode + ';\ncur_state_temp += ' + str(
                            regB.bitWidth / self.byteSize) + ';\n'
    Code += 'return cur_state;'
    getStateMethod = cxx_writer.Method('get_state',
                                       cxx_writer.Code(Code),
                                       cxx_writer.ucharPtrType,
                                       'public',
                                       noException=True,
                                       const=True)
    abiMembers.append(getStateMethod)

    # set_state()
    Code = 'unsigned char* cur_state_temp = state;\n'
    for reg in self.regs:
        if not reg.name in self.abi.stateIgnoreRegs:
            regWType = resolveBitType('BIT<' + str(reg.bitWidth) + '>')
            Code += reg.name + regWriteCode + '(*((' + str(
                regWType.makePointer(
                )) + ')cur_state_temp));\ncur_state_temp += ' + str(
                    reg.bitWidth / self.byteSize) + ';\n'
    for regB in self.regBanks:
        regWType = resolveBitType('BIT<' + str(regB.bitWidth) + '>')
        if not regB.name in stateIgnoreRegs.keys():
            for i in range(0, regB.numRegs):
                Code += regB.name + '[' + str(
                    i) + ']' + regWriteCode + '(*((' + str(
                        regWType.makePointer(
                        )) + ')cur_state_temp));\ncur_state_temp += ' + str(
                            regB.bitWidth / self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    Code += regB.name + '[' + str(
                        i) + ']' + regWriteCode + '(*((' + str(
                            regWType.makePointer()
                        ) + ')cur_state_temp));\ncur_state_temp += ' + str(
                            regB.bitWidth / self.byteSize) + ';\n'
    setStateParam = cxx_writer.Parameter('state', cxx_writer.ucharPtrType)
    setStateMethod = cxx_writer.Method('set_state',
                                       cxx_writer.Code(Code),
                                       cxx_writer.voidType,
                                       'public', [setStateParam],
                                       noException=True)
    abiMembers.append(setStateMethod)

    # get_exit_value()
    Code = 'return this->exit_value;'
    exitValueMethod = cxx_writer.Method('get_exit_value',
                                        cxx_writer.Code(Code),
                                        wordType,
                                        'public',
                                        noException=True)
    abiMembers.append(exitValueMethod)

    # set_exit_value()
    Code = 'this->exit_value = value;'
    exitValueParam = cxx_writer.Parameter('value', wordType)
    exitValueMethod = cxx_writer.Method('set_exit_value',
                                        cxx_writer.Code(Code),
                                        cxx_writer.voidType,
                                        'public', [exitValueParam],
                                        noException=True)
    abiMembers.append(exitValueMethod)

    # pre_call(), post_call(), return_from_call()
    if self.abi.preCallCode:
        abiMembers.append(
            cxx_writer.Method('pre_call',
                              cxx_writer.Code(self.abi.preCallCode),
                              cxx_writer.voidType,
                              'public',
                              noException=True))
    if self.abi.postCallCode:
        abiMembers.append(
            cxx_writer.Method('post_call',
                              cxx_writer.Code(self.abi.postCallCode),
                              cxx_writer.voidType,
                              'public',
                              noException=True))
    if self.abi.returnCallReg:
        returnCallCode = ''
        for returnReg in self.abi.returnCallReg:
            returnCallCode += returnReg[0] + regWriteCode + '(' + returnReg[
                1] + ' + ' + str(returnReg[2]) + ');\n'
        abiMembers.append(
            cxx_writer.Method('return_from_call',
                              cxx_writer.Code(returnCallCode),
                              cxx_writer.voidType,
                              'public',
                              noException=True))

    # is_executing_instr()
    isExecutingInstrBody = cxx_writer.Code('return this->instr_executing;')
    isExecutingInstrMethod = cxx_writer.Method('is_executing_instr',
                                               isExecutingInstrBody,
                                               cxx_writer.boolType,
                                               'public',
                                               noException=True,
                                               const=True)
    abiMembers.append(isExecutingInstrMethod)

    # wait_instr_end()
    if self.systemc:
        waitInstrEndBody = cxx_writer.Code(
            'if (this->instr_executing) {\nwait(this->instr_end_event);\n}\n')
        waitInstrEndBody.addInclude('systemc.h')
    else:
        waitInstrEndBody = cxx_writer.Code(
            'while(this->instr_executing) {\n;\n}\n')
    waitInstrEndMethod = cxx_writer.Method('wait_instr_end',
                                           waitInstrEndBody,
                                           cxx_writer.voidType,
                                           'public',
                                           noException=True,
                                           const=True)
    abiMembers.append(waitInstrEndMethod)

    # is_routine_entry()
    # Here is the code for recognizing if we are in the routine entry or exit.
    # The ABI behaves like a state machine, moving to the beginning when an
    # instruction out of the sequence is met.
    isRoutineEntryCode = """std::vector<std::string> next_names = this->routine_entry_sequence[this->routine_entry_state];
    std::vector<std::string>::const_iterator names_it, names_end;
    std::string cur_name = instr->get_name();
    for (names_it = next_names.begin(), names_end = next_names.end(); names_it != names_end; names_it++) {
        if (cur_name == *names_it || *names_it == "") {
            if (this->routine_entry_state == """ + str(
        len(self.abi.callInstr) - 1) + """) {
                this->routine_entry_state = 0;
                return true;
            }
            this->routine_entry_state++;
            return false;
        }
    }
    this->routine_entry_state = 0;
    return false;
    """
    isRoutineEntryBody = cxx_writer.Code(isRoutineEntryCode)
    InstructionBaseType = cxx_writer.Type('InstructionBase',
                                          'modules/instruction.hpp')
    InstructionParam = cxx_writer.Parameter(
        'instr',
        InstructionBaseType.makePointer().makeConst())
    isRoutineEntryMethod = cxx_writer.Method('is_routine_entry',
                                             isRoutineEntryBody,
                                             cxx_writer.boolType,
                                             'public', [InstructionParam],
                                             noException=True)
    abiMembers.append(isRoutineEntryMethod)

    # is_routine_exit()
    isRoutineExitCode = """std::vector<std::string> next_names = this->routine_exit_sequence[this->routine_exit_state];
    std::vector<std::string>::const_iterator names_it, names_end;
    std::string cur_name = instr->get_name();
    for (names_it = next_names.begin(), names_end = next_names.end(); names_it != names_end; names_it++) {
        if (cur_name == *names_it || *names_it == "") {
            if (this->routine_exit_state == """ + str(
        len(self.abi.returnCallInstr) - 1) + """) {
                this->routine_exit_state = 0;
                return true;
            }
            this->routine_exit_state++;
            return false;
        }
    }
    this->routine_exit_state = 0;
    return false;
    """
    isRoutineExitBody = cxx_writer.Code(isRoutineExitCode)
    isRoutineExitMethod = cxx_writer.Method('is_routine_exit',
                                            isRoutineExitBody,
                                            cxx_writer.boolType,
                                            'public', [InstructionParam],
                                            noException=True)
    abiMembers.append(isRoutineExitMethod)

    # get_history()
    Code = 'return this->history_instr_queue;'
    getInstructionHistoryMethod = cxx_writer.Method('get_history',
                                                    cxx_writer.Code(Code),
                                                    histQueueType.makeRef(),
                                                    'public')
    abiMembers.append(getInstructionHistoryMethod)

    # get_code_limit()
    Code = 'return this->PROGRAM_LIMIT;'
    codeLimitMethod = cxx_writer.Method('get_code_limit',
                                        cxx_writer.Code(Code), wordType,
                                        'public')
    abiMembers.append(codeLimitMethod)

    ## @} Interface Methods
    #---------------------------------------------------------------------------
    ## @name Information and Helper Methods
    #  @{

    # get_id()
    if self.abi.procIdCode:
        getIDBody = cxx_writer.Code('return (' + self.abi.procIdCode + ');\n')
        getIDMethod = cxx_writer.Method('get_id',
                                        getIDBody,
                                        cxx_writer.intType,
                                        'public',
                                        noException=True,
                                        const=True)
        abiMembers.append(getIDMethod)

    # is_little_endian()
    if self.isBigEndian:
        isLittleEndianBody = cxx_writer.Code('return false;')
    else:
        isLittleEndianBody = cxx_writer.Code('return true;')
    isLittleEndianMethod = cxx_writer.Method('is_little_endian',
                                             isLittleEndianBody,
                                             cxx_writer.boolType,
                                             'public',
                                             noException=True,
                                             const=True)
    abiMembers.append(isLittleEndianMethod)

    ## @} Information and Helper Methods
    #---------------------------------------------------------------------------
    ## @name Constructors and Destructors
    #  @{

    abiCtor = cxx_writer.Constructor(cxx_writer.Code(abitCtorCode), 'public',
                                     abiCtorParams, abiCtorInit)
    abiDtor = cxx_writer.Destructor(cxx_writer.Code(''), 'public', True)

    ## @} Constructors and Destructors
    #---------------------------------------------------------------------------

    abiType = cxx_writer.TemplateType('ABIIf', [wordType],
                                      'modules/abi_if.hpp')
    abiClass = cxx_writer.ClassDeclaration('Interface',
                                           abiMembers, [abiType],
                                           namespaces=[namespace])
    abiClass.addDocString(
        brief='Interface Class',
        detail=
        'Creates the interface used by TRAP-Gen tools to access the processor core.'
    )
    abiClass.addConstructor(abiCtor)
    abiClass.addDestructor(abiDtor)
    return abiClass
Пример #17
0
# Sign extends the input bitstring
opCode = cxx_writer.Code("""
if((bitSeq & (1 << (bitSeq_length - 1))) != 0)
    bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length);
return bitSeq;
""")
SignExtend_method = trap.HelperMethod('SignExtend',
                                      opCode,
                                      'execute',
                                      exception=False,
                                      const=True)
SignExtend_method.setSignature(
    cxx_writer.intType,
    [('bitSeq', 'BIT<32>'),
     cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)])

# Normal PC increment, used when not in a branch instruction; in a branch instruction
# I will directly modify both PC and nPC in case we are in a the cycle accurate model,
# while just nPC in case we are in the functional one; if the branch has the annuling bit
# set, then also in the functional model both the PC and nPC will be modified
raiseExcCode = """
if(PSR[PSR_ET] == 0){
    if(exceptionId < IRQ_LEV_15){
        // I print a core dump and then I signal an error: an exception happened while
        // exceptions were disabled in the processor core
        THROW_EXCEPTION("Exception " << exceptionId << " happened while the PSR[ET] = 0; PC = " << std::hex << std::showbase << PC << std::endl << "Instruction " << get_mnemonic());
    }
}
else{
    unsigned curPSR = PSR;