Esempio n. 1
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
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
0
def getGetIRQInstr(self, model, trace, namespace):
    from pipelineWriter import hasCheckHazard
    instructionType = cxx_writer.writer_code.Type('Instruction',
                                                  'instructions.hpp')
    emptyBody = cxx_writer.writer_code.Code('')

    IRQInstrClasses = []

    for irq in self.irqs:
        IRQInstrElements = []

        # now I have to go over the behavior of this interrupt and create, like for the instructions,
        # the behavior for the different pipeline stages
        if not model.startswith('acc'):
            behaviorCode = 'this->totalInstrCycles = 0;\n'
        userDefineBehavior = ''
        for pipeStage in self.pipes:
            userDefineBehavior = ''
            if model.startswith('acc'):
                behaviorCode = 'this->stageCycles = 0;\n'
            if irq.operation.has_key(pipeStage.name):
                userDefineBehavior += str(irq.operation[pipeStage.name])
                if model.startswith('acc'):
                    # now I have to take all the resources and create a define which
                    # renames such resources so that their usage can be transparent
                    # to the developer
                    for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks:
                        behaviorCode += '#define ' + reg.name + ' ' + reg.name + '_' + pipeStage.name + '\n'
                    behaviorCode += '\n'

                behaviorCode += userDefineBehavior

                if model.startswith('acc'):
                    for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks:
                        behaviorCode += '#undef ' + reg.name + '\n'
            if model.startswith('acc'):
                behaviorCode += 'return this->stageCycles;\n\n'
                registerType = cxx_writer.writer_code.Type('Register')
                unlockQueueType = cxx_writer.writer_code.TemplateType(
                    'std::map', [
                        'unsigned int',
                        cxx_writer.writer_code.TemplateType(
                            'std::vector', [registerType.makePointer()],
                            'vector')
                    ], 'map')
                unlockQueueParam = cxx_writer.writer_code.Parameter(
                    'unlockQueue', unlockQueueType.makeRef())
                behaviorBody = cxx_writer.writer_code.Code(behaviorCode)
                behaviorDecl = cxx_writer.writer_code.Method(
                    'behavior_' + pipeStage.name, behaviorBody,
                    cxx_writer.writer_code.uintType, 'pu', [unlockQueueParam])
                IRQInstrElements.append(behaviorDecl)
        if not model.startswith('acc'):
            behaviorCode += 'return this->totalInstrCycles;'
            behaviorBody = cxx_writer.writer_code.Code(behaviorCode)
            behaviorDecl = cxx_writer.writer_code.Method(
                'behavior', behaviorBody, cxx_writer.writer_code.uintType,
                'pu')
            IRQInstrElements.append(behaviorDecl)

        # Standard Instruction methods, there is not much to do since the IRQ instruction does nothing special
        from procWriter import baseInstrInitElement
        replicateBody = cxx_writer.writer_code.Code('return new IRQ_' +
                                                    irq.name +
                                                    '_Instruction(' +
                                                    baseInstrInitElement +
                                                    ', this->' + irq.name +
                                                    ');')
        replicateDecl = cxx_writer.writer_code.Method(
            'replicate',
            replicateBody,
            instructionType.makePointer(),
            'pu',
            noException=True,
            const=True)
        IRQInstrElements.append(replicateDecl)
        setparamsParam = cxx_writer.writer_code.Parameter(
            'bitString', self.bitSizes[1].makeRef().makeConst())
        setparamsDecl = cxx_writer.writer_code.Method(
            'setParams',
            emptyBody,
            cxx_writer.writer_code.voidType,
            'pu', [setparamsParam],
            noException=True)
        IRQInstrElements.append(setparamsDecl)
        getIstructionNameBody = cxx_writer.writer_code.Code('return \"IRQ_' +
                                                            irq.name +
                                                            '_Instruction\";')
        getIstructionNameDecl = cxx_writer.writer_code.Method(
            'getInstructionName',
            getIstructionNameBody,
            cxx_writer.writer_code.stringType,
            'pu',
            noException=True,
            const=True)
        IRQInstrElements.append(getIstructionNameDecl)
        getMnemonicBody = cxx_writer.writer_code.Code('return \"irq_' +
                                                      irq.name + '\";')
        getMnemonicDecl = cxx_writer.writer_code.Method(
            'getMnemonic',
            getMnemonicBody,
            cxx_writer.writer_code.stringType,
            'pu',
            noException=True,
            const=True)
        IRQInstrElements.append(getMnemonicDecl)
        getIdBody = cxx_writer.writer_code.Code('return (unsigned int)-1;')
        getIdDecl = cxx_writer.writer_code.Method(
            'getId',
            getIdBody,
            cxx_writer.writer_code.uintType,
            'pu',
            noException=True,
            const=True)
        IRQInstrElements.append(getIdDecl)

        # Now we have all the methods related to data hazards detection and management:
        # TODO: is an implementation needed for the IRQ instruction?
        if model.startswith('acc'):
            if hasCheckHazard:
                for pipeStage in self.pipes:
                    checkHazardDecl = cxx_writer.writer_code.Method(
                        'checkHazard_' + pipeStage.name, emptyBody,
                        cxx_writer.writer_code.boolType, 'pu')
                    IRQInstrElements.append(checkHazardDecl)
                    lockDecl = cxx_writer.writer_code.Method(
                        'lockRegs_' + pipeStage.name, emptyBody,
                        cxx_writer.writer_code.voidType, 'pu')
                    IRQInstrElements.append(lockDecl)
                unlockHazard = False
                for pipeStage in self.pipes:
                    if pipeStage.checkHazard:
                        unlockHazard = True
                    if unlockHazard:
                        getUnlockDecl = cxx_writer.writer_code.Method(
                            'getUnlock_' + pipeStage.name, emptyBody,
                            cxx_writer.writer_code.voidType, 'pu',
                            [unlockQueueParam])
                        IRQInstrElements.append(getUnlockDecl)

            printBusyRegsDecl = cxx_writer.writer_code.Method(
                'printBusyRegs', cxx_writer.writer_code.Code('return "";'),
                cxx_writer.writer_code.stringType, 'pu')
            IRQInstrElements.append(printBusyRegsDecl)

        # Here I add a method to specify the value of the received interrupt and the related attribute
        from isa import resolveBitType
        irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>')
        IRQAttribute = cxx_writer.writer_code.Attribute(
            irq.name, irqWidthType.makeRef(), 'pu')
        IRQInstrElements.append(IRQAttribute)
        irqParams = [
            cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef())
        ]
        irqInit = [irq.name + '(' + irq.name + ')']
        InterruptValueParam = cxx_writer.writer_code.Parameter(
            'interruptValue',
            irqWidthType.makeRef().makeConst())
        setInterruptValueBody = cxx_writer.writer_code.Code(
            'this->' + irq.name + ' = interruptValue;')
        setInterruptValueDecl = cxx_writer.writer_code.Method(
            'setInterruptValue',
            setInterruptValueBody,
            cxx_writer.writer_code.voidType,
            'pu', [InterruptValueParam],
            noException=True,
            inline=True)
        IRQInstrElements.append(setInterruptValueDecl)

        # Now I declare the instruction variables for this IRQ instruction
        for var in irq.variables:
            IRQInstrElements.append(
                cxx_writer.writer_code.Attribute(var.name, var.varType, 'pro',
                                                 var.static))

        # Finally I can declare the IRQ class for this specific IRQ
        from procWriter import baseInstrInitElement
        from isaWriter import baseInstrConstrParams
        publicConstr = cxx_writer.writer_code.Constructor(
            emptyBody, 'pu', baseInstrConstrParams + irqParams,
            ['Instruction(' + baseInstrInitElement + ')'] + irqInit)
        IRQInstrClass = cxx_writer.writer_code.ClassDeclaration(
            'IRQ_' + irq.name + '_Instruction',
            IRQInstrElements, [instructionType],
            namespaces=[namespace])
        IRQInstrClass.addConstructor(publicConstr)
        publicDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True)
        IRQInstrClass.addDestructor(publicDestr)
        IRQInstrClasses.append(IRQInstrClass)

    return IRQInstrClasses
Esempio n. 5
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
Esempio n. 6
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
Esempio n. 7
0
def getGetIRQInstr(self, model, trace, namespace):
    from pipelineWriter import hasCheckHazard
    instructionType = cxx_writer.writer_code.Type('Instruction', 'instructions.hpp')
    emptyBody = cxx_writer.writer_code.Code('')

    IRQInstrClasses = []

    for irq in self.irqs:
        IRQInstrElements = []

        # now I have to go over the behavior of this interrupt and create, like for the instructions,
        # the behavior for the different pipeline stages
        if not model.startswith('acc'):
            behaviorCode = 'this->totalInstrCycles = 0;\n'
        userDefineBehavior = ''
        for pipeStage in self.pipes:
            userDefineBehavior = ''
            if model.startswith('acc'):
                behaviorCode = 'this->stageCycles = 0;\n'
            if irq.operation.has_key(pipeStage.name):
                userDefineBehavior += str(irq.operation[pipeStage.name])
                if model.startswith('acc'):
                    # now I have to take all the resources and create a define which
                    # renames such resources so that their usage can be transparent
                    # to the developer
                    for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks:
                        behaviorCode += '#define ' + reg.name + ' ' + reg.name + '_' + pipeStage.name + '\n'
                    behaviorCode += '\n'

                behaviorCode += userDefineBehavior

                if model.startswith('acc'):
                    for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks:
                        behaviorCode += '#undef ' + reg.name + '\n'
            if model.startswith('acc'):
                behaviorCode += 'return this->stageCycles;\n\n'
                registerType = cxx_writer.writer_code.Type('Register')
                unlockQueueType = cxx_writer.writer_code.TemplateType('std::map', ['unsigned int', cxx_writer.writer_code.TemplateType('std::vector', [registerType.makePointer()], 'vector')], 'map')
                unlockQueueParam = cxx_writer.writer_code.Parameter('unlockQueue', unlockQueueType.makeRef())
                behaviorBody = cxx_writer.writer_code.Code(behaviorCode)
                behaviorDecl = cxx_writer.writer_code.Method('behavior_' + pipeStage.name, behaviorBody, cxx_writer.writer_code.uintType, 'pu', [unlockQueueParam])
                IRQInstrElements.append(behaviorDecl)
        if not model.startswith('acc'):
            behaviorCode += 'return this->totalInstrCycles;'
            behaviorBody = cxx_writer.writer_code.Code(behaviorCode)
            behaviorDecl = cxx_writer.writer_code.Method('behavior', behaviorBody, cxx_writer.writer_code.uintType, 'pu')
            IRQInstrElements.append(behaviorDecl)

        # Standard Instruction methods, there is not much to do since the IRQ instruction does nothing special
        from procWriter import baseInstrInitElement
        replicateBody = cxx_writer.writer_code.Code('return new IRQ_' + irq.name + '_Instruction(' + baseInstrInitElement + ', this->' + irq.name + ');')
        replicateDecl = cxx_writer.writer_code.Method('replicate', replicateBody, instructionType.makePointer(), 'pu', noException = True, const = True)
        IRQInstrElements.append(replicateDecl)
        setparamsParam = cxx_writer.writer_code.Parameter('bitString', self.bitSizes[1].makeRef().makeConst())
        setparamsDecl = cxx_writer.writer_code.Method('setParams', emptyBody, cxx_writer.writer_code.voidType, 'pu', [setparamsParam], noException = True)
        IRQInstrElements.append(setparamsDecl)
        getIstructionNameBody = cxx_writer.writer_code.Code('return \"IRQ_' + irq.name + '_Instruction\";')
        getIstructionNameDecl = cxx_writer.writer_code.Method('getInstructionName', getIstructionNameBody, cxx_writer.writer_code.stringType, 'pu', noException = True, const = True)
        IRQInstrElements.append(getIstructionNameDecl)
        getMnemonicBody = cxx_writer.writer_code.Code('return \"irq_' + irq.name + '\";')
        getMnemonicDecl = cxx_writer.writer_code.Method('getMnemonic', getMnemonicBody, cxx_writer.writer_code.stringType, 'pu', noException = True, const = True)
        IRQInstrElements.append(getMnemonicDecl)
        getIdBody = cxx_writer.writer_code.Code('return (unsigned int)-1;')
        getIdDecl = cxx_writer.writer_code.Method('getId', getIdBody, cxx_writer.writer_code.uintType, 'pu', noException = True, const = True)
        IRQInstrElements.append(getIdDecl)

        # Now we have all the methods related to data hazards detection and management:
        # TODO: is an implementation needed for the IRQ instruction?
        if model.startswith('acc'):
            if hasCheckHazard:
                for pipeStage in self.pipes:
                    checkHazardDecl = cxx_writer.writer_code.Method('checkHazard_' + pipeStage.name, emptyBody, cxx_writer.writer_code.boolType, 'pu')
                    IRQInstrElements.append(checkHazardDecl)
                    lockDecl = cxx_writer.writer_code.Method('lockRegs_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu')
                    IRQInstrElements.append(lockDecl)
                unlockHazard = False
                for pipeStage in self.pipes:
                    if pipeStage.checkHazard:
                        unlockHazard = True
                    if unlockHazard:
                        getUnlockDecl = cxx_writer.writer_code.Method('getUnlock_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu', [unlockQueueParam])
                        IRQInstrElements.append(getUnlockDecl)

            printBusyRegsDecl = cxx_writer.writer_code.Method('printBusyRegs', cxx_writer.writer_code.Code('return "";'), cxx_writer.writer_code.stringType, 'pu')
            IRQInstrElements.append(printBusyRegsDecl)


        # Here I add a method to specify the value of the received interrupt and the related attribute
        from isa import resolveBitType
        irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>')
        IRQAttribute = cxx_writer.writer_code.Attribute(irq.name, irqWidthType.makeRef(), 'pu')
        IRQInstrElements.append(IRQAttribute)
        irqParams = [cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef())]
        irqInit = [irq.name + '(' + irq.name + ')']
        InterruptValueParam = cxx_writer.writer_code.Parameter('interruptValue', irqWidthType.makeRef().makeConst())
        setInterruptValueBody = cxx_writer.writer_code.Code('this->' + irq.name + ' = interruptValue;')
        setInterruptValueDecl = cxx_writer.writer_code.Method('setInterruptValue', setInterruptValueBody, cxx_writer.writer_code.voidType, 'pu', [InterruptValueParam], noException = True, inline = True)
        IRQInstrElements.append(setInterruptValueDecl)

        # Now I declare the instruction variables for this IRQ instruction
        for var in irq.variables:
            IRQInstrElements.append(cxx_writer.writer_code.Attribute(var.name, var.varType, 'pro',  var.static))

        # Finally I can declare the IRQ class for this specific IRQ
        from procWriter import baseInstrInitElement
        from isaWriter import baseInstrConstrParams
        publicConstr = cxx_writer.writer_code.Constructor(emptyBody, 'pu', baseInstrConstrParams + irqParams, ['Instruction(' + baseInstrInitElement + ')'] + irqInit)
        IRQInstrClass = cxx_writer.writer_code.ClassDeclaration('IRQ_' + irq.name + '_Instruction', IRQInstrElements, [instructionType], namespaces = [namespace])
        IRQInstrClass.addConstructor(publicConstr)
        publicDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True)
        IRQInstrClass.addDestructor(publicDestr)
        IRQInstrClasses.append(IRQInstrClass)

    return IRQInstrClasses
Esempio n. 8
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
Esempio n. 9
0
def getCPPIf(self, model, namespace):
    """creates the interface which is used by the tools
    to access the processor core"""
    if not self.abi:
        return

    if model.startswith('acc'):
        regWriteCode = '.writeAll'
        regReadCode = ''
    else:
        regWriteCode = '.immediateWrite'
        regReadCode = '.readNewValue()'

    from procWriter import resourceType

    wordType = self.bitSizes[1]
    includes = wordType.getIncludes()
    pipeRegisterType = cxx_writer.writer_code.Type('PipelineRegister',
                                                   'registers.hpp')

    instrHistType = cxx_writer.writer_code.Type('HistoryInstrType',
                                                'instructionBase.hpp')
    histQueueType = cxx_writer.writer_code.TemplateType(
        'boost::circular_buffer', [instrHistType], 'boost/circular_buffer.hpp')

    ifClassElements = []
    initElements = []
    baseInstrConstrParams = []

    ####################################################
    # Lets first of all decalre the variables and the attributes;
    # they are mainly references to the corresponding elements
    # of the processor or of the pipeline stage
    ####################################################
    progLimitAttr = cxx_writer.writer_code.Attribute('PROGRAM_LIMIT',
                                                     wordType.makeRef(), 'pri')
    ifClassElements.append(progLimitAttr)
    baseInstrConstrParams.append(
        cxx_writer.writer_code.Parameter('PROGRAM_LIMIT', wordType.makeRef()))
    initElements.append('PROGRAM_LIMIT(PROGRAM_LIMIT)')
    memIfType = cxx_writer.writer_code.Type('MemoryInterface', 'memory.hpp')
    for memName in self.abi.memories.keys():
        ifClassElements.append(
            cxx_writer.writer_code.Attribute(memName, memIfType.makeRef(),
                                             'pri'))
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(memName, memIfType.makeRef()))
        initElements.append(memName + '(' + memName + ')')
    for reg in self.regs:
        if model.startswith('acc'):
            curRegBType = pipeRegisterType
        else:
            curRegBType = resourceType[reg.name]
        attribute = cxx_writer.writer_code.Attribute(reg.name,
                                                     curRegBType.makeRef(),
                                                     'pri')
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(reg.name, curRegBType.makeRef()))
        initElements.append(reg.name + '(' + reg.name + ')')
        ifClassElements.append(attribute)
    for regB in self.regBanks:
        if (regB.constValue and len(regB.constValue) < regB.numRegs) or (
            (regB.delay and len(regB.delay) < regB.numRegs)
                and not model.startswith('acc')):
            if model.startswith('acc'):
                curRegBType = pipeRegisterType.makePointer()
            else:
                curRegBType = resourceType[regB.name].makeRef()
        else:
            if model.startswith('acc'):
                curRegBType = pipeRegisterType.makePointer()
            else:
                curRegBType = resourceType[regB.name]
        attribute = cxx_writer.writer_code.Attribute(regB.name, curRegBType,
                                                     'pri')
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(regB.name, curRegBType))
        initElements.append(regB.name + '(' + regB.name + ')')
        ifClassElements.append(attribute)
    for alias in self.aliasRegs:
        attribute = cxx_writer.writer_code.Attribute(
            alias.name, resourceType[alias.name].makeRef(), 'pri')
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(
                alias.name, resourceType[alias.name].makeRef()))
        initElements.append(alias.name + '(' + alias.name + ')')
        ifClassElements.append(attribute)
    for aliasB in self.aliasRegBanks:
        attribute = cxx_writer.writer_code.Attribute(
            aliasB.name, resourceType[aliasB.name].makePointer(), 'pri')
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(
                aliasB.name, resourceType[aliasB.name].makePointer()))
        initElements.append(aliasB.name + '(' + aliasB.name + ')')
        ifClassElements.append(attribute)
    attribute = cxx_writer.writer_code.Attribute(
        'instrExecuting', cxx_writer.writer_code.boolType.makeRef(), 'pri')
    baseInstrConstrParams.append(
        cxx_writer.writer_code.Parameter(
            'instrExecuting', cxx_writer.writer_code.boolType.makeRef()))
    initElements.append('instrExecuting(instrExecuting)')
    ifClassElements.append(attribute)
    if self.systemc:
        attribute = cxx_writer.writer_code.Attribute(
            'instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef(),
            'pri')
        baseInstrConstrParams.append(
            cxx_writer.writer_code.Parameter(
                'instrEndEvent',
                cxx_writer.writer_code.sc_eventType.makeRef()))
        initElements.append('instrEndEvent(instrEndEvent)')
        ifClassElements.append(attribute)
    instHistoryQueueAttr = cxx_writer.writer_code.Attribute(
        'instHistoryQueue', histQueueType.makeRef(), 'pri')
    ifClassElements.append(instHistoryQueueAttr)
    baseInstrConstrParams.append(
        cxx_writer.writer_code.Parameter('instHistoryQueue',
                                         histQueueType.makeRef()))
    initElements.append('instHistoryQueue(instHistoryQueue)')

    ###############################################################
    # Now lets move to the actual implementation of the methods which
    # enable communication of the interface with the processor
    ###############################################################
    if self.isBigEndian:
        endianessCode = cxx_writer.writer_code.Code('return false;')
    else:
        endianessCode = cxx_writer.writer_code.Code('return true;')
    endianessMethod = cxx_writer.writer_code.Method(
        'isLittleEndian',
        endianessCode,
        cxx_writer.writer_code.boolType,
        'pu',
        noException=True,
        const=True)
    ifClassElements.append(endianessMethod)

    # Here are the methods used to discriminate when an instruction is executing or not
    if self.abi.procIdCode:
        processorIDCode = cxx_writer.writer_code.Code('return (' +
                                                      self.abi.procIdCode +
                                                      ');\n')
        processorIDMethod = cxx_writer.writer_code.Method(
            'getProcessorID',
            processorIDCode,
            cxx_writer.writer_code.intType,
            'pu',
            noException=True,
            const=True)
        ifClassElements.append(processorIDMethod)
    instrExecutingCode = cxx_writer.writer_code.Code(
        'return this->instrExecuting;')
    instrExecutingMethod = cxx_writer.writer_code.Method(
        'isInstrExecuting',
        instrExecutingCode,
        cxx_writer.writer_code.boolType,
        'pu',
        noException=True,
        const=True)
    ifClassElements.append(instrExecutingMethod)
    if self.systemc:
        waitInstrEndCode = cxx_writer.writer_code.Code(
            'if(this->instrExecuting){\nwait(this->instrEndEvent);\n}\n')
        waitInstrEndCode.addInclude('systemc.h')
    else:
        waitInstrEndCode = cxx_writer.writer_code.Code(
            'while(this->instrExecuting){\n;\n}\n')
    waitInstrEndMethod = cxx_writer.writer_code.Method(
        'waitInstrEnd',
        waitInstrEndCode,
        cxx_writer.writer_code.voidType,
        'pu',
        noException=True,
        const=True)
    ifClassElements.append(waitInstrEndMethod)

    if self.abi.preCallCode:
        ifClassElements.append(
            cxx_writer.writer_code.Method('preCall',
                                          cxx_writer.writer_code.Code(
                                              self.abi.preCallCode),
                                          cxx_writer.writer_code.voidType,
                                          'pu',
                                          noException=True))
    if self.abi.postCallCode:
        ifClassElements.append(
            cxx_writer.writer_code.Method('postCall',
                                          cxx_writer.writer_code.Code(
                                              self.abi.postCallCode),
                                          cxx_writer.writer_code.voidType,
                                          'pu',
                                          noException=True))
    if self.abi.returnCallReg:
        returnCallCode = ''
        for returnReg in self.abi.returnCallReg:
            returnCallCode += returnReg[0] + regWriteCode + '(' + returnReg[
                1] + ' + ' + str(returnReg[2]) + ');\n'
        ifClassElements.append(
            cxx_writer.writer_code.Method(
                'returnFromCall',
                cxx_writer.writer_code.Code(returnCallCode),
                cxx_writer.writer_code.voidType,
                'pu',
                noException=True))

    # Here is the code for recognizing if we are in the routine entry or
    # exit; we behave like a state machine,moving to the beginning when
    # an instruction out of the sequence is met
    entryStateAttribute = cxx_writer.writer_code.Attribute(
        'routineEntryState', cxx_writer.writer_code.intType, 'pri')
    ifClassElements.append(entryStateAttribute)
    exitStateAttribute = cxx_writer.writer_code.Attribute(
        'routineExitState', cxx_writer.writer_code.intType, 'pri')
    ifClassElements.append(exitStateAttribute)
    vector_strType = cxx_writer.writer_code.TemplateType(
        'std::vector', [cxx_writer.writer_code.stringType], 'vector')
    vector_v_strType = cxx_writer.writer_code.TemplateType(
        'std::vector', [vector_strType], 'vector')
    entrySequenceAttribute = cxx_writer.writer_code.Attribute(
        'routineEntrySequence', vector_v_strType, 'pri')
    ifClassElements.append(entrySequenceAttribute)
    exitSequenceAttribute = cxx_writer.writer_code.Attribute(
        'routineExitSequence', vector_v_strType, 'pri')
    ifClassElements.append(exitSequenceAttribute)
    routineStatesInit = """this->routineExitState = 0;
    this->routineEntryState = 0;
    std::vector<std::string> tempVec;
    """
    from isa import Instruction
    for instrList in self.abi.callInstr:
        routineStatesInit += 'tempVec.clear();\n'
        if not instrList:
            routineStatesInit += 'tempVec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            routineStatesInit += 'tempVec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                routineStatesInit += 'tempVec.push_back("' + instr.name + '");\n'
        routineStatesInit += 'this->routineEntrySequence.push_back(tempVec);\n'
    for instrList in self.abi.returnCallInstr:
        routineStatesInit += 'tempVec.clear();\n'
        if not instrList:
            routineStatesInit += 'tempVec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            routineStatesInit += 'tempVec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                routineStatesInit += 'tempVec.push_back("' + instr.name + '");\n'
        routineStatesInit += 'this->routineExitSequence.push_back(tempVec);\n'
    instructionBaseType = cxx_writer.writer_code.Type('InstructionBase',
                                                      'instructionBase.hpp')
    baseInstrParam = cxx_writer.writer_code.Parameter(
        'instr',
        instructionBaseType.makePointer().makeConst())
    isRoutineEntryBody = """std::vector<std::string> nextNames = this->routineEntrySequence[this->routineEntryState];
    std::vector<std::string>::const_iterator namesIter, namesEnd;
    std::string curName = instr->getInstructionName();
    for(namesIter = nextNames.begin(), namesEnd = nextNames.end(); namesIter != namesEnd; namesIter++){
        if(curName == *namesIter || *namesIter == ""){
            if(this->routineEntryState == """ + str(
        len(self.abi.callInstr) - 1) + """){
                this->routineEntryState = 0;
                return true;
            }
            this->routineEntryState++;
            return false;
        }
    }
    this->routineEntryState = 0;
    return false;
    """
    isRoutineEntryCode = cxx_writer.writer_code.Code(isRoutineEntryBody)
    isRoutineEntryMethod = cxx_writer.writer_code.Method(
        'isRoutineEntry',
        isRoutineEntryCode,
        cxx_writer.writer_code.boolType,
        'pu', [baseInstrParam],
        noException=True)
    ifClassElements.append(isRoutineEntryMethod)
    isRoutineExitBody = """std::vector<std::string> nextNames = this->routineExitSequence[this->routineExitState];
    std::vector<std::string>::const_iterator namesIter, namesEnd;
    std::string curName = instr->getInstructionName();
    for(namesIter = nextNames.begin(), namesEnd = nextNames.end(); namesIter != namesEnd; namesIter++){
        if(curName == *namesIter || *namesIter == ""){
            if(this->routineExitState == """ + str(
        len(self.abi.returnCallInstr) - 1) + """){
                this->routineExitState = 0;
                return true;
            }
            this->routineExitState++;
            return false;
        }
    }
    this->routineExitState = 0;
    return false;
    """
    isRoutineExitCode = cxx_writer.writer_code.Code(isRoutineExitBody)
    isRoutineExitMethod = cxx_writer.writer_code.Method(
        'isRoutineExit',
        isRoutineExitCode,
        cxx_writer.writer_code.boolType,
        'pu', [baseInstrParam],
        noException=True)
    ifClassElements.append(isRoutineExitMethod)

    # Here I add the methods mecessary to save and restore the complete
    # processor status (useful, for example, to implement hardware context-switches,
    # or simulation chepointing)
    totalStateSize = 0
    for reg in self.regs:
        totalStateSize += reg.bitWidth / self.byteSize
    for regB in self.regBanks:
        totalStateSize += (regB.bitWidth * regB.numRegs) / self.byteSize
    getStateBody = 'unsigned char * curState = new unsigned char[' + str(
        totalStateSize) + '];\n'
    getStateBody += 'unsigned char * curStateTemp = curState;\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) + '>')
            getStateBody += '*((' + str(
                regWType.makePointer()
            ) + ')curStateTemp) = this->' + reg.name + regReadCode + ';\ncurStateTemp += ' + 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):
                getStateBody += '*((' + str(regWType.makePointer(
                )) + ')curStateTemp) = this->' + regB.name + '[' + str(
                    i) + ']' + regReadCode + ';\ncurStateTemp += ' + str(
                        regB.bitWidth / self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    getStateBody += '*((' + str(regWType.makePointer(
                    )) + ')curStateTemp) = this->' + regB.name + '[' + str(
                        i) + ']' + regReadCode + ';\ncurStateTemp += ' + str(
                            regB.bitWidth / self.byteSize) + ';\n'
    getStateBody += 'return curState;'
    getStateCode = cxx_writer.writer_code.Code(getStateBody)
    getStateMethod = cxx_writer.writer_code.Method(
        'getState',
        getStateCode,
        cxx_writer.writer_code.ucharPtrType,
        'pu',
        noException=True,
        const=True)
    ifClassElements.append(getStateMethod)
    setStateBody = 'unsigned char * curStateTemp = state;\n'
    for reg in self.regs:
        if not reg.name in self.abi.stateIgnoreRegs:
            regWType = resolveBitType('BIT<' + str(reg.bitWidth) + '>')
            setStateBody += 'this->' + reg.name + regWriteCode + '(*((' + str(
                regWType.makePointer(
                )) + ')curStateTemp));\ncurStateTemp += ' + 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):
                setStateBody += 'this->' + regB.name + '[' + str(
                    i) + ']' + regWriteCode + '(*((' + str(
                        regWType.makePointer(
                        )) + ')curStateTemp));\ncurStateTemp += ' + str(
                            regB.bitWidth / self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    setStateBody += 'this->' + regB.name + '[' + str(
                        i) + ']' + regWriteCode + '(*((' + str(
                            regWType.makePointer(
                            )) + ')curStateTemp));\ncurStateTemp += ' + str(
                                regB.bitWidth / self.byteSize) + ';\n'
    setStateCode = cxx_writer.writer_code.Code(setStateBody)
    stateParam = cxx_writer.writer_code.Parameter(
        'state', cxx_writer.writer_code.ucharPtrType)
    setStateMethod = cxx_writer.writer_code.Method(
        'setState',
        setStateCode,
        cxx_writer.writer_code.voidType,
        'pu', [stateParam],
        noException=True)
    ifClassElements.append(setStateMethod)

    codeLimitCode = cxx_writer.writer_code.Code('return this->PROGRAM_LIMIT;')
    codeLimitMethod = cxx_writer.writer_code.Method('getCodeLimit',
                                                    codeLimitCode, wordType,
                                                    'pu')
    ifClassElements.append(codeLimitMethod)
    for elem in [
            self.abi.LR, self.abi.PC, self.abi.SP, self.abi.FP, self.abi.retVal
    ]:
        if not elem:
            continue
        readElemBody = 'return this->' + elem
        if self.abi.offset.has_key(elem):
            readElemBody += ' + ' + str(self.abi.offset[elem])
        readElemBody += ';'
        readElemCode = cxx_writer.writer_code.Code(readElemBody)
        readElemCode.addInclude(includes)
        readElemMethod = cxx_writer.writer_code.Method('read' +
                                                       self.abi.name[elem],
                                                       readElemCode,
                                                       wordType,
                                                       'pu',
                                                       noException=True,
                                                       const=True)
        ifClassElements.append(readElemMethod)
        setElemBody = 'this->' + elem + regWriteCode + '(newValue);'
        setElemCode = cxx_writer.writer_code.Code(setElemBody)
        setElemCode.addInclude(includes)
        setElemParam = cxx_writer.writer_code.Parameter(
            'newValue',
            wordType.makeRef().makeConst())
        setElemMethod = cxx_writer.writer_code.Method(
            'set' + self.abi.name[elem],
            setElemCode,
            cxx_writer.writer_code.voidType,
            'pu', [setElemParam],
            noException=True)
        ifClassElements.append(setElemMethod)
    vectorType = cxx_writer.writer_code.TemplateType('std::vector', [wordType],
                                                     'vector')
    readArgsBody = str(vectorType) + ' args;\n'
    for arg in self.abi.args:
        readArgsBody += 'args.push_back(this->' + arg
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            readArgsBody += ' + ' + str(self.abi.offset[arg])
        readArgsBody += ');\n'
    readArgsBody += 'return args;\n'
    readArgsCode = cxx_writer.writer_code.Code(readArgsBody)
    readArgsCode.addInclude(includes)
    readArgsMethod = cxx_writer.writer_code.Method('readArgs',
                                                   readArgsCode,
                                                   vectorType,
                                                   'pu',
                                                   noException=True,
                                                   const=True)
    ifClassElements.append(readArgsMethod)
    setArgsBody = 'if(args.size() > ' + str(
        len(self.abi.args)
    ) + '){\nTHROW_EXCEPTION(\"ABI of processor supports up to ' + str(
        len(self.abi.args)
    ) + ' arguments: \" << args.size() << \" given\");\n}\n'
    setArgsBody += str(
        vectorType
    ) + '::const_iterator argIter = args.begin(), argEnd = args.end();\n'
    for arg in self.abi.args:
        setArgsBody += 'if(argIter != argEnd){\n'
        setArgsBody += 'this->' + arg + regWriteCode + '(*argIter'
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            setArgsBody += ' - ' + str(self.abi.offset[arg])
        setArgsBody += ');\nargIter++;\n}\n'
    setArgsCode = cxx_writer.writer_code.Code(setArgsBody)
    setArgsParam = cxx_writer.writer_code.Parameter(
        'args',
        vectorType.makeRef().makeConst())
    setArgsMethod = cxx_writer.writer_code.Method(
        'setArgs',
        setArgsCode,
        cxx_writer.writer_code.voidType,
        'pu', [setArgsParam],
        noException=True)
    ifClassElements.append(setArgsMethod)
    maxGDBId = 0
    readGDBRegBody = 'switch(gdbId){\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
        readGDBRegBody += 'case ' + str(gdbId) + ':{\n'
        readGDBRegBody += 'return ' + reg
        if self.abi.offset.has_key(reg) and not model.startswith('acc'):
            readGDBRegBody += ' + ' + str(self.abi.offset[reg])
        readGDBRegBody += ';\nbreak;}\n'
    readGDBRegBody += 'default:{\nreturn 0;\n}\n}\n'
    readGDBRegCode = cxx_writer.writer_code.Code(readGDBRegBody)
    readGDBRegCode.addInclude(includes)
    readGDBRegParam = cxx_writer.writer_code.Parameter(
        'gdbId',
        cxx_writer.writer_code.uintType.makeRef().makeConst())
    readGDBRegMethod = cxx_writer.writer_code.Method('readGDBReg',
                                                     readGDBRegCode,
                                                     wordType,
                                                     'pu', [readGDBRegParam],
                                                     noException=True,
                                                     const=True)
    ifClassElements.append(readGDBRegMethod)
    nGDBRegsCode = cxx_writer.writer_code.Code('return ' + str(maxGDBId + 1) +
                                               ';')
    nGDBRegsMethod = cxx_writer.writer_code.Method(
        'nGDBRegs',
        nGDBRegsCode,
        cxx_writer.writer_code.uintType,
        'pu',
        noException=True,
        const=True)
    ifClassElements.append(nGDBRegsMethod)
    setGDBRegBody = 'switch(gdbId){\n'
    for reg, gdbId in sortedGDBRegs:
        setGDBRegBody += 'case ' + str(gdbId) + ':{\n'
        setGDBRegBody += reg + regWriteCode + '(newValue'
        setGDBRegBody += ');\nbreak;}\n'
    setGDBRegBody += 'default:{\nTHROW_EXCEPTION(\"No register corresponding to GDB id \" << gdbId);\n}\n}\n'
    setGDBRegCode = cxx_writer.writer_code.Code(setGDBRegBody)
    setGDBRegCode.addInclude(includes)
    setGDBRegParam1 = cxx_writer.writer_code.Parameter(
        'newValue',
        wordType.makeRef().makeConst())
    setGDBRegParam2 = cxx_writer.writer_code.Parameter(
        'gdbId',
        cxx_writer.writer_code.uintType.makeRef().makeConst())
    setGDBRegMethod = cxx_writer.writer_code.Method(
        'setGDBReg',
        setGDBRegCode,
        cxx_writer.writer_code.voidType,
        'pu', [setGDBRegParam1, setGDBRegParam2],
        noException=True)
    ifClassElements.append(setGDBRegMethod)
    readMemBody = ''
    if not self.abi.memories:
        readMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            readMemBody += 'return this->' + self.abi.memories.keys(
            )[0] + '.read_word_dbg(address);'
        else:
            for memName, mem_range in self.abi.memories.items():
                readMemBody += 'if(address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + '){\n'
                readMemBody += 'return this->' + self.abi.memories.keys(
                )[0] + '.read_word_dbg(address);\n}\nelse '
            readMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    readMemCode = cxx_writer.writer_code.Code(readMemBody)
    readMemParam1 = cxx_writer.writer_code.Parameter(
        'address',
        wordType.makeRef().makeConst())
    readMemMethod = cxx_writer.writer_code.Method('readMem', readMemCode,
                                                  wordType, 'pu',
                                                  [readMemParam1])
    ifClassElements.append(readMemMethod)

    readByteMemBody = ''
    if not self.abi.memories:
        readByteMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            readByteMemBody += 'return this->' + self.abi.memories.keys(
            )[0] + '.read_byte_dbg(address);'
        else:
            for memName, mem_range in self.abi.memories.items():
                readByteMemBody += 'if(address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + '){\n'
                readByteMemBody += 'return this->' + self.abi.memories.keys(
                )[0] + '.read_byte_dbg(address);\n}\nelse '
            readByteMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    readByteMemCode = cxx_writer.writer_code.Code(readByteMemBody)
    readByteMemParam = cxx_writer.writer_code.Parameter(
        'address',
        wordType.makeRef().makeConst())
    readByteMemMethod = cxx_writer.writer_code.Method(
        'readCharMem', readByteMemCode, cxx_writer.writer_code.ucharType, 'pu',
        [readByteMemParam])
    ifClassElements.append(readByteMemMethod)

    writeMemBody = ''
    if not self.abi.memories:
        writeMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            writeMemBody += 'this->' + self.abi.memories.keys(
            )[0] + '.write_word_dbg(address, datum);'
        else:
            for memName, mem_range in self.abi.memories.items():
                writeMemBody += 'if(address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + '){\n'
                writeMemBody += 'this->' + self.abi.memories.keys(
                )[0] + '.write_word_dbg(address, datum);\n}\nelse '
            writeMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    writeMemCode = cxx_writer.writer_code.Code(writeMemBody)
    writeMemCode.addInclude('trap_utils.hpp')
    writeMemParam1 = cxx_writer.writer_code.Parameter(
        'address',
        wordType.makeRef().makeConst())
    writeMemParam2 = cxx_writer.writer_code.Parameter('datum', wordType)
    writeMemMethod = cxx_writer.writer_code.Method(
        'writeMem', writeMemCode, cxx_writer.writer_code.voidType, 'pu',
        [writeMemParam1, writeMemParam2])
    ifClassElements.append(writeMemMethod)
    writeMemBody = ''
    if not self.abi.memories:
        writeMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            writeMemBody += 'this->' + self.abi.memories.keys(
            )[0] + '.write_byte_dbg(address, datum);'
        else:
            for memName, mem_range in self.abi.memories.items():
                writeMemBody += 'if(address >= ' + hex(
                    mem_range[0]) + ' && address <= ' + hex(
                        mem_range[1]) + '){\n'
                writeMemBody += 'this->' + self.abi.memories.keys(
                )[0] + '.write_byte_dbg(address, datum);\n}\nelse '
            writeMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    writeMemCode = cxx_writer.writer_code.Code(writeMemBody)
    writeMemParam1 = cxx_writer.writer_code.Parameter(
        'address',
        wordType.makeRef().makeConst())
    writeMemParam2 = cxx_writer.writer_code.Parameter(
        'datum', cxx_writer.writer_code.ucharType)
    writeMemMethod = cxx_writer.writer_code.Method(
        'writeCharMem', writeMemCode, cxx_writer.writer_code.voidType, 'pu',
        [writeMemParam1, writeMemParam2])
    ifClassElements.append(writeMemMethod)

    getInstructionHistoryCode = cxx_writer.writer_code.Code(
        'return this->instHistoryQueue;')
    getInstructionHistoryMethod = cxx_writer.writer_code.Method(
        'getInstructionHistory', getInstructionHistoryCode,
        histQueueType.makeRef(), 'pu')
    ifClassElements.append(getInstructionHistoryMethod)

    ABIIfType = cxx_writer.writer_code.TemplateType('ABIIf', [wordType],
                                                    'ABIIf.hpp')
    ifClassDecl = cxx_writer.writer_code.ClassDeclaration(
        self.name + '_ABIIf',
        ifClassElements, [ABIIfType],
        namespaces=[namespace])
    publicIfConstr = cxx_writer.writer_code.Constructor(
        cxx_writer.writer_code.Code(routineStatesInit), 'pu',
        baseInstrConstrParams, initElements)
    emptyBody = cxx_writer.writer_code.Code('')
    opDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True)
    ifClassDecl.addDestructor(opDestr)
    ifClassDecl.addConstructor(publicIfConstr)
    return ifClassDecl
Esempio n. 10
0
def getGetPipelineStages(self, trace, combinedTrace, model, namespace):
    global hasCheckHazard
    global wbStage
    global chStage
    from procWriter import resourceType
    # Returns the code implementing the class representing a pipeline stage
    pipeCodeElements = []
    pipelineElements = []
    constructorCode = ''
    constructorParamsBase = []
    constructorInit = []
    baseConstructorInit = ''
    pipeType = cxx_writer.writer_code.Type('BasePipeStage')
    IntructionType = cxx_writer.writer_code.Type('Instruction', includes = ['instructions.hpp'])
    registerType = cxx_writer.writer_code.Type('Register', includes = ['registers.hpp'])

    stageEndedFlag = cxx_writer.writer_code.Attribute('stageEnded', cxx_writer.writer_code.boolType, 'pu')
    pipelineElements.append(stageEndedFlag)
    constructorCode += 'this->chStalled = false;\n'
    constructorCode += 'this->stalled = false;\n'
    constructorCode += 'this->stageEnded = false;\n'
    stageBeginningFlag = cxx_writer.writer_code.Attribute('stageBeginning', cxx_writer.writer_code.boolType, 'pu')
    pipelineElements.append(stageBeginningFlag)
    constructorCode += 'this->stageBeginning = false;\n'
    hasToFlush = cxx_writer.writer_code.Attribute('hasToFlush', cxx_writer.writer_code.boolType, 'pu')
    pipelineElements.append(hasToFlush)
    constructorCode += 'this->hasToFlush = false;\n'
    stageEndedEvent = cxx_writer.writer_code.Attribute('stageEndedEv', cxx_writer.writer_code.sc_eventType, 'pu')
    pipelineElements.append(stageEndedEvent)
    stageBeginningEvent = cxx_writer.writer_code.Attribute('stageBeginningEv', cxx_writer.writer_code.sc_eventType, 'pu')
    pipelineElements.append(stageBeginningEvent)

    NOPIntructionType = cxx_writer.writer_code.Type('NOPInstruction', 'instructions.hpp')
    NOPinstructionsAttribute = cxx_writer.writer_code.Attribute('NOPInstrInstance', NOPIntructionType.makePointer(), 'pu')
    pipelineElements.append(NOPinstructionsAttribute)
    constructorCode += 'this->NOPInstrInstance = NULL;\n'

    # Lets declare the interrupt instructions in case we have any and we also declare the signal attribute
    for irq in self.irqs:
        IRQIntructionType = cxx_writer.writer_code.Type('IRQ_' + irq.name + '_Instruction', 'instructions.hpp')
        IRQinstructionAttribute = cxx_writer.writer_code.Attribute(irq.name + '_irqInstr', IRQIntructionType.makePointer(), 'pu')
        pipelineElements.append(IRQinstructionAttribute)
        constructorCode += 'this->' + irq.name + '_irqInstr = NULL;\n'

    latencyAttribute = cxx_writer.writer_code.Attribute('latency', cxx_writer.writer_code.sc_timeType, 'pro')
    pipelineElements.append(latencyAttribute)
    latencyParam = cxx_writer.writer_code.Parameter('latency', cxx_writer.writer_code.sc_timeType.makeRef())
    constructorParamsBase.append(latencyParam)
    constructorInit.append('latency(latency)')
    baseConstructorInit += 'latency, '

    curInstrAttr = cxx_writer.writer_code.Attribute('curInstruction', IntructionType.makePointer(), 'pu')
    pipelineElements.append(curInstrAttr)
    constructorCode += 'this->curInstruction = NULL;\n'
    nextInstrAttr = cxx_writer.writer_code.Attribute('nextInstruction', IntructionType.makePointer(), 'pu')
    pipelineElements.append(nextInstrAttr)
    constructorCode += 'this->nextInstruction = NULL;\n'

    flushCode = """this->hasToFlush = true;
    if(this->prevStage != NULL){
        this->prevStage->flush();
    }
    """
    flushBody = cxx_writer.writer_code.Code(flushCode)
    flushDecl = cxx_writer.writer_code.Method('flush', flushBody, cxx_writer.writer_code.voidType, 'pu', noException = True)
    pipelineElements.append(flushDecl)

    for pipe in self.pipes:
        otherStageAttr = cxx_writer.writer_code.Attribute('stage_' + pipe.name, pipeType.makePointer(), 'pro')
        pipelineElements.append(otherStageAttr)
        otherStageParam = cxx_writer.writer_code.Parameter('stage_' + pipe.name, pipeType.makePointer())
        constructorParamsBase.append(otherStageParam)
        constructorInit.append('stage_' + pipe.name + '(stage_' + pipe.name + ')')
        baseConstructorInit += 'stage_' + pipe.name + ', '

    chStalledAttr = cxx_writer.writer_code.Attribute('chStalled', cxx_writer.writer_code.boolType, 'pu')
    pipelineElements.append(chStalledAttr)
    stalledAttr = cxx_writer.writer_code.Attribute('stalled', cxx_writer.writer_code.boolType, 'pu')
    pipelineElements.append(stalledAttr)
    stageAttr = cxx_writer.writer_code.Attribute('prevStage', pipeType.makePointer(), 'pu')
    pipelineElements.append(stageAttr)
    stageAttr = cxx_writer.writer_code.Attribute('succStage', pipeType.makePointer(), 'pu')
    pipelineElements.append(stageAttr)
    unlockQueueType = cxx_writer.writer_code.TemplateType('std::map', ['unsigned int', cxx_writer.writer_code.TemplateType('std::vector', [registerType.makePointer()], 'vector')], 'map')
    unlockQueueAttr = cxx_writer.writer_code.Attribute('unlockQueue', unlockQueueType, 'pro', static = True)
    pipelineElements.append(unlockQueueAttr)
    prevStageParam = cxx_writer.writer_code.Parameter('prevStage', pipeType.makePointer(), initValue = 'NULL')
    succStageParam = cxx_writer.writer_code.Parameter('succStage', pipeType.makePointer(), initValue = 'NULL')
    constructorParamsBase.append(prevStageParam)
    constructorParamsBase.append(succStageParam)
    constructorInit.append('prevStage(prevStage)')
    constructorInit.append('succStage(succStage)')
    baseConstructorInit += 'prevStage, '
    baseConstructorInit += 'succStage, '
    pipelineDecl = cxx_writer.writer_code.ClassDeclaration('BasePipeStage', pipelineElements, namespaces = [namespace])
    constructorBody = cxx_writer.writer_code.Code(constructorCode)
    publicPipelineConstr = cxx_writer.writer_code.Constructor(constructorBody, 'pu', constructorParamsBase, constructorInit)
    pipelineDecl.addConstructor(publicPipelineConstr)
    pipeCodeElements.append(pipelineDecl)

    hasCheckHazard = False
    hasWb = False
    for pipeStage in self.pipes:
        if pipeStage.checkHazard:
            if self.pipes.index(pipeStage) + 1 < len(self.pipes):
                if not self.pipes[self.pipes.index(pipeStage) + 1].endHazard:
                    hasCheckHazard = True
        if pipeStage.endHazard:
            if self.pipes.index(pipeStage) - 1 >= 0:
                if not self.pipes[self.pipes.index(pipeStage) - 1].checkHazard:
                    hasWb = True

    # Now lets determine the stages which need a call to check hazard
    #checkHazadsStagesDecl = []
    #if hasCheckHazard:
        #for instr in self.isa.instructions.values():
            #for stageName in instr.specialInRegs.keys():
                #if not stageName in checkHazadsStagesDecl:
                    #checkHazadsStagesDecl.append(stageName)
    # Remember that all the stages preceding the the last one where we check for
    # hazards have to check if the following stages are stalled.

    # Now I have to actually declare the different pipeline stages, all of them being equal a part from
    # the fecth stage which have to fetch instructions and check interrupts before calling
    # the appropriate behavior method
    checkHazardsMet = False
    wbStage = self.pipes[-1]
    chStage = self.pipes[0]
    seenStages = 0
    for pipeStage in self.pipes:
        seenStages += 1
        if pipeStage.wb:
            wbStage = pipeStage
        if pipeStage.checkHazard:
            chStage = pipeStage

        pipeNameParam = cxx_writer.writer_code.Parameter('pipeName', cxx_writer.writer_code.sc_module_nameType)
        curPipeElements = []
        constructorCode = ''
        constructorInit = []
        constructorParams = [pipeNameParam] + constructorParamsBase

        codeString = """this->curInstruction = this->NOPInstrInstance;
        this->nextInstruction = this->NOPInstrInstance;
        """
        if pipeStage == self.pipes[0]:
            # This is the fetch pipeline stage, I have to fetch instructions
            codeString += 'unsigned int numNOPS = 0;\n'
            codeString += 'bool startMet = false;\n'
            if self.instructionCache:
                codeString += 'template_map< ' + str(self.bitSizes[1]) + ', CacheElem >::iterator instrCacheEnd = this->instrCache.end();\n\n'
            codeString += 'while(true){\n'

            # Here is the code to notify start of the instruction execution
            codeString += 'this->instrExecuting = true;\n'

            codeString += 'unsigned int numCycles = 0;\n'
            if hasCheckHazard:
                codeString += 'if(!this->chStalled){\n'

            codeString += '\n// HERE WAIT FOR BEGIN OF ALL STAGES\nthis->waitPipeBegin();\n'

            # Here is the code to deal with interrupts; note one problem: if an interrupt is raised, we need to
            # deal with it in the correct stage, i.e. we need to create a special instruction reaching the correct
            # stage and dealing with it properly.
            codeString += getInterruptCode(self, trace, pipeStage)
            # computes the correct memory and/or memory port from which fetching the instruction stream
            fetchCode = computeFetchCode(self)
            # computes the address from which the next instruction shall be fetched
            fetchAddress = computeCurrentPC(self, model)
            codeString += str(self.bitSizes[1]) + ' curPC = ' + fetchAddress + ';\n'

            # Here is the code for updating cycle counts
            codeString += """if(!startMet && curPC == this->profStartAddr){
                this->profTimeStart = sc_time_stamp();
            }
            if(startMet && curPC == this->profEndAddr){
                this->profTimeEnd = sc_time_stamp();
            }
            """

            # Now lets start with the code necessary to check the tools, to see if they need
            # the pipeline to be empty before being able to procede with execution
            codeString += """
                #ifndef DISABLE_TOOLS
                // code necessary to check the tools, to see if they need
                // the pipeline to be empty before being able to procede with execution
                if(this->toolManager.emptyPipeline(curPC)){
                    numNOPS++;
                }
                else{
                    numNOPS = 0;
                }
                if(numNOPS > 0 && numNOPS < """ + str(len(self.pipes)) + """){
                    this->curInstruction = this->NOPInstrInstance;
                """
            if trace and not combinedTrace:
                codeString += 'std::cerr << \"PC: \" << std::hex << std::showbase << curPC << " propagating NOP because tools need it" << std::endl;\n'
            codeString += """}
                else{
                    numNOPS = 0;
                #endif
                    wait(this->latency);
                    //Ok, either the pipeline is empty or there is not tool which needs the pipeline
                    //to be empty: I can procede with the execution
            """

            # Lets start with the code for the instruction queue
            codeString += """#ifdef ENABLE_HISTORY
            HistoryInstrType instrQueueElem;
            if(this->historyEnabled){
                instrQueueElem.cycle = (unsigned int)(sc_time_stamp()/this->latency);
                instrQueueElem.address = curPC;
            }
            #endif
            """

            # We need to fetch the instruction ... 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):
                codeString += fetchCode
            if trace and not combinedTrace:
                codeString += 'std::cerr << \"Fetching PC: \" << std::hex << std::showbase << curPC << std::endl;\n'

            # Now lets starts the real instruction fetch: two paths are possible: the instruction buffer
            # and the normal instruction stream.
            if self.instructionCache:
                codeString += fetchWithCacheCode(self, fetchCode, trace, combinedTrace, getInstrIssueCodePipe, hasCheckHazard, pipeStage)
            else:
                codeString += standardInstrFetch(self, trace, combinedTrace, getInstrIssueCodePipe, hasCheckHazard, pipeStage)

            # Lets finish with the code for the instruction queue: I just still have to
            # check if it is time to save to file the instruction queue
            codeString += """#ifdef ENABLE_HISTORY
            if(this->historyEnabled){
                // First I add the new element to the queue
                this->instHistoryQueue.push_back(instrQueueElem);
                //Now, in case the queue dump file has been specified, I have to check if I need to save it
                if(this->histFile){
                    this->undumpedHistElems++;
                    if(undumpedHistElems == this->instHistoryQueue.capacity()){
                        boost::circular_buffer<HistoryInstrType>::const_iterator beg, end;
                        for(beg = this->instHistoryQueue.begin(), end = this->instHistoryQueue.end(); beg != end; beg++){
                            this->histFile << beg->toStr() << std::endl;
                        }
                        this->undumpedHistElems = 0;
                    }
                }
            }
            #endif
            """

            # Finally we have completed waiting for the other cycles in order to be able to go on
            # with this cycle.
            codeString += """this->numInstructions++;
                #ifndef DISABLE_TOOLS
                }
                #endif
            """
            if self.irqs:
                codeString += '}\n'
            codeString += """wait(numCycles*this->latency);
            // HERE WAIT FOR END OF ALL STAGES
            this->waitPipeEnd();

            """

            codeString += """
            // Now I have to propagate the instruction to the next cycle if
            // the next stage has completed elaboration
            if(this->hasToFlush){
                if(this->curInstruction->toDestroy){
                    delete this->curInstruction;
                }
                else{
                    this->curInstruction->inPipeline = false;
                }
                this->curInstruction = this->NOPInstrInstance;
                this->nextInstruction = this->NOPInstrInstance;
                this->hasToFlush = false;
            }
            """
            codeString += 'this->succStage->nextInstruction = this->curInstruction;\n'
            if hasCheckHazard:
                codeString += """}
                else{
                    //The current stage is not doing anything since one of the following stages
                    //is blocked to a data hazard.
                    this->waitPipeBegin();
                    //Note that I need to return controll to the scheduler, otherwise
                    //I will be impossible to procede, this thread will always execute
                    wait(this->latency);
                    this->waitPipeEnd();
                    if(this->hasToFlush){
                        if(this->curInstruction->toDestroy){
                            delete this->curInstruction;
                        }
                        else{
                            this->curInstruction->inPipeline = false;
                        }
                        this->curInstruction = this->NOPInstrInstance;
                        this->nextInstruction = this->NOPInstrInstance;
                        this->hasToFlush = false;
                    }
                }
            """
            # Here is the code to notify start of the instruction execution
            codeString += """this->refreshRegisters();
                this->instrExecuting = false;
                this->instrEndEvent.notify();
            """
            # Now I have to insert the code for checking the presence of hazards;
            # in particular I have to see if the instruction to be executed next in
            # the checkHazardsStage will lock
            if hasCheckHazard:
                codeString += 'Instruction * succToCheck = this->'
                for pipeStageTemp in self.pipes:
                    if pipeStageTemp.checkHazard:
                        break
                    else:
                        codeString += 'succStage->'
                codeString += 'nextInstruction;\n'
                codeString += 'if(!succToCheck->checkHazard_' + pipeStageTemp.name + '()){\n'
                codeTemp = 'this->'
                for pipeStageTemp in self.pipes:
                    codeString += codeTemp + 'chStalled = true;\n'
                    codeTemp += 'succStage->'
                    if pipeStageTemp.checkHazard:
                        break
                codeString += '}\nelse{\n'
                codeTemp = 'this->'
                for pipeStageTemp in self.pipes:
                    codeString += codeTemp + 'chStalled = false;\n'
                    codeTemp += 'succStage->'
                    if pipeStageTemp.checkHazard:
                        break
                codeString += '}\n'
            if trace and not combinedTrace:
                codeString += 'std::cerr << \"---------------------------------------------------------------\" << std::endl << std::endl;\n'
            codeString += '}\n'
        else:
            # This is a normal pipeline stage

            # First of all I have to wait for the completion of the other pipeline stages before being able
            # to go on.
            if hasCheckHazard and not checkHazardsMet:
                codeString += 'Instruction * nextStageInstruction;\n'
            codeString += """while(true){
            unsigned int numCycles = 0;
            bool flushAnnulled = false;

            // HERE WAIT FOR BEGIN OF ALL STAGES
            this->waitPipeBegin();

            this->curInstruction = this->nextInstruction;
            """

            if hasCheckHazard and not checkHazardsMet:
                codeString += 'if(!this->chStalled){\n'
            codeString += 'wait((' + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n'
            if trace and not combinedTrace:
                codeString += 'std::cerr << \"Stage ' + pipeStage.name + ' instruction at PC = \" << std::hex << std::showbase << this->curInstruction->fetchPC << std::endl;\n'

            #if hasCheckHazard and pipeStage.name in checkHazadsStagesDecl:
            if hasCheckHazard and pipeStage.checkHazard:
                codeString += 'this->curInstruction->lockRegs_' + pipeStage.name + '();\n'

            if trace and combinedTrace and pipeStage == self.pipes[-1]:
                codeString += 'if(this->curInstruction != this->NOPInstrInstance){\n'
                codeString += 'std::cerr << \"Current PC: \" << std::hex << std::showbase << this->curInstruction->fetchPC << std::endl;\n'
                codeString += '}\n'
            # Now we issue the instruction, i.e. we execute its behavior related to this pipeline stage
            codeString += getInstrIssueCodePipe(self, trace, combinedTrace, 'this->curInstruction', hasCheckHazard, pipeStage)
            # Finally I finalize the pipeline stage by synchrnonizing with the others
            codeString += 'wait((numCycles + ' + str(float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n'
            codeString += """// flushing current stage
            if(this->curInstruction->flushPipeline || flushAnnulled){
                this->curInstruction->flushPipeline = false;
                //Now I have to flush the preceding pipeline stages
                this->prevStage->flush();
            }
            """

            if not hasCheckHazard or checkHazardsMet:
                codeString += """// HERE WAIT FOR END OF ALL STAGES
                this->waitPipeEnd();

                """

            if pipeStage != self.pipes[-1]:
                codeString += """if(this->hasToFlush){
                        if(this->curInstruction->toDestroy){
                            delete this->curInstruction;
                        }
                        else{
                            this->curInstruction->inPipeline = false;
                        }
                        // First of all I have to free any used resource in case there are any
                        this->curInstruction = this->NOPInstrInstance;
                        this->nextInstruction = this->NOPInstrInstance;
                        this->hasToFlush = false;
                    }
                """
                if hasCheckHazard and not checkHazardsMet:
                    codeString += 'nextStageInstruction = this->curInstruction;\n'

            if pipeStage == self.pipes[-1]:
                # Here I have to check if it is the case of destroying the instruction
                codeString += 'if(this->curInstruction->toDestroy){\n'
                codeString += 'delete this->curInstruction;\n'
                codeString += '}\n'
                codeString += 'else{\n'
                codeString += 'this->curInstruction->inPipeline = false;\n'
                codeString += '}\n'
            if hasCheckHazard and not checkHazardsMet:
                codeString += """}
                else{
                    //The current stage is not doing anything since one of the following stages
                    //is blocked to a data hazard.
                    //Note that I need to return controll to the scheduler, otherwise
                    //I will be impossible to procede, this thread will always execute
                    wait(this->latency);
                """
                if trace and hasCheckHazard and pipeStage.checkHazard and not combinedTrace:
                    codeString += """std::cerr << "Stage: """ + pipeStage.name + """ - Instruction " << this->curInstruction->getInstructionName() << " Mnemonic = " << this->curInstruction->getMnemonic() << " at PC = " << std::hex << std::showbase << this->curInstruction->fetchPC << " stalled on a data hazard" << std::endl;
                    std::cerr << "Stalled registers: " << this->curInstruction->printBusyRegs() << std::endl << std::endl;
                    """
                codeString += """if(this->hasToFlush){
                        if(this->curInstruction->toDestroy){
                            delete this->curInstruction;
                        }
                        else{
                            this->curInstruction->inPipeline = false;
                        }
                        // First of all I have to free any used resource in case there are any
                        this->curInstruction = this->NOPInstrInstance;
                        this->nextInstruction = this->NOPInstrInstance;
                        this->hasToFlush = false;
                    }
                    nextStageInstruction = this->NOPInstrInstance;
                }
                """
            if hasCheckHazard and not checkHazardsMet:
                codeString += """// HERE WAIT FOR END OF ALL STAGES
                this->waitPipeEnd();

                """
            if pipeStage != self.pipes[-1]:
                if checkHazardsMet:
                    codeString += 'this->succStage->nextInstruction = this->curInstruction;\n'
                else:
                    codeString += 'this->succStage->nextInstruction = nextStageInstruction;\n'
            codeString += '}\n'
        if pipeStage.checkHazard:
            checkHazardsMet = True

        behaviorMethodBody = cxx_writer.writer_code.Code(codeString)
        behaviorMethodDecl = cxx_writer.writer_code.Method('behavior', behaviorMethodBody, cxx_writer.writer_code.voidType, 'pu')
        curPipeElements.append(behaviorMethodDecl)
        constructorCode += 'SC_THREAD(behavior);\n'

        waitPipeBeginCode = """this->stageBeginning = true;
        this->stageBeginningEv.notify();
        """
        for pipeStageInner in self.pipes:
            if pipeStageInner != pipeStage:
                waitPipeBeginCode += """if(!this->stage_""" + pipeStageInner.name + """->stageBeginning){
                    wait(this->stage_""" + pipeStageInner.name + """->stageBeginningEv);
                }
                """
        waitPipeBeginCode += 'this->stageEnded = false;'
        waitPipeBeginBody = cxx_writer.writer_code.Code(waitPipeBeginCode)
        waitPipeBeginDecl = cxx_writer.writer_code.Method('waitPipeBegin', waitPipeBeginBody, cxx_writer.writer_code.voidType, 'pri', noException = True)
        curPipeElements.append(waitPipeBeginDecl)

        waitPipeEndCode = """this->stageBeginning = false;
        this->stageEnded = true;
        this->stageEndedEv.notify();
        """
        for pipeStageInner in self.pipes:
            if pipeStageInner != pipeStage:
                waitPipeEndCode += """if(!this->stage_""" + pipeStageInner.name + """->stageEnded){
                    wait(this->stage_""" + pipeStageInner.name + """->stageEndedEv);
                }
                """
        waitPipeEndBody = cxx_writer.writer_code.Code(waitPipeEndCode)
        waitPipeEndDecl = cxx_writer.writer_code.Method('waitPipeEnd', waitPipeEndBody, cxx_writer.writer_code.voidType, 'pri', noException = True)
        curPipeElements.append(waitPipeEndDecl)

        IntructionType = cxx_writer.writer_code.Type('Instruction', 'instructions.hpp')
        IntructionTypePtr = IntructionType.makePointer()

        pipelineStageMap = {}
        notCheckStages = []
        checkHazardsStageMet = False
        for curPipeMap in self.pipes:
            pipelineStageMap[curPipeMap.name] = curPipeMap
            if checkHazardsStageMet:
                notCheckStages.append(curPipeMap.name)
            if curPipeMap.checkHazard:
                checkHazardsStageMet = True

        if pipeStage == self.pipes[0]:
            # I create the refreshRegisters method; note that in order to update the registers
            # i simply have to call the "propagate" method; I also have to deal with the update of the alias
            # by manually moving the pointer to the pipeline register from one stage alias to
            # the other to update the alias
            codeString = '// Now we update the registers to propagate the values in the pipeline\n'
            for reg in self.regs:
                codeString += 'if(this->' + reg.name + '.hasToPropagate){\n'
                ########
                if trace and not combinedTrace:
                    codeString += 'std::cerr << "Propagating register ' + reg.name + '" << std::endl;\n'
                ########
                codeString += 'this->' + reg.name + '.propagate();\n'
                codeString += '}\n'
            for regB in self.regBanks:
                codeString += 'for(int i = 0; i < ' + str(regB.numRegs) + '; i++){\n'
                codeString += 'if(this->' + regB.name + '[i].hasToPropagate){\n'
                ########
                if trace and not combinedTrace:
                    codeString += 'std::cerr << "Propagating register ' + regB.name + '[" << std::dec << i << "]" << std::endl;\n'
                ########
                codeString += 'this->' + regB.name + '[i].propagate();\n'
                codeString += '}\n}\n'
            # Now lets procede to the update of the alias: for each stage alias I have to copy the reference
            # of the general pipeline register from one stage to the other
            codeString += '\n//Here we update the aliases, so that what they point to is updated in the pipeline\n'
            for i in reversed(range(0, len(self.pipes) -1)):
                for alias in self.aliasRegs:
                    if not alias.isFixed:
                        codeString += 'if(this->' + alias.name + '_' + self.pipes[i + 1].name + '.getPipeReg() != this->' + alias.name + '_' + self.pipes[i].name + '.getPipeReg()){\n'
                        if trace and not combinedTrace:
                            codeString += 'std::cerr << "Updating alias ' + alias.name + '_' + self.pipes[i + 1].name + '" << std::endl;\n'
                        codeString += 'this->' + alias.name + '_' + self.pipes[i + 1].name + '.propagateAlias(*(this->' + alias.name + '_' + self.pipes[i].name + '.getPipeReg()));\n'
                        codeString += '}\n'
                for aliasB in self.aliasRegBanks:
                    checkContiguous = True
                    for j in range(0, len(aliasB.fixedIndices) - 1):
                        if aliasB.fixedIndices[j] + 1 != aliasB.fixedIndices[j + 1]:
                            checkContiguous = False
                            break
                    if checkContiguous:
                        if aliasB.fixedIndices[0] > 0:
                            if aliasB.checkGroup:
                                codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[0].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[0].getPipeReg()){\n'
                            codeString += 'for(int i = 0; i < ' + str(aliasB.fixedIndices[-1]) + '; i++){\n'
                            if not aliasB.checkGroup:
                                codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()){\n'
                            if trace and not combinedTrace:
                                codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << i << "]" << std::endl;\n'
                            codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()));\n'
                            codeString += '}\n'
                            codeString += '}\n'
                        if aliasB.fixedIndices[-1] + 1 < aliasB.numRegs:
                            if aliasB.checkGroup:
                                codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(aliasB.fixedIndices[-1] + 1) + '].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(aliasB.fixedIndices[-1] + 1) + '].getPipeReg()){\n'
                            codeString += 'for(int i = ' + str(aliasB.fixedIndices[-1] + 1) + '; i < ' + str(aliasB.numRegs) + '; i++){\n'
                            if not aliasB.checkGroup:
                                codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()){\n'
                            if trace and not combinedTrace:
                                codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << i << "]" << std::endl;\n'
                            codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()));\n'
                            codeString += '}\n'
                            codeString += '}\n'
                    else:
                        for j in range(0, aliasB.numRegs):
                            if not j in aliasB.fixedIndices:
                                codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(j) + '].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(j) + '].getPipeReg()){\n'
                                if trace and not combinedTrace:
                                    codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << ' + str(i) + ' << "]" << std::endl;\n'
                                codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(j) + '].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(j) + '].getPipeReg()));\n'
                                codeString += '}\n'
            # Now I have to produce the code for unlocking the registers in the unlockQueue
            codeString += """
            // Finally registers are unlocked, so that stalls due to data hazards can be resolved
            std::map<unsigned int, std::vector<Register *> >::iterator unlockQueueIter, unlockQueueEnd;
            for(unlockQueueIter = BasePipeStage::unlockQueue.begin(), unlockQueueEnd = BasePipeStage::unlockQueue.end(); unlockQueueIter != unlockQueueEnd; unlockQueueIter++){
                std::vector<Register *>::iterator regToUnlockIter, regToUnlockEnd;
                if(unlockQueueIter->first == 0){
                    for(regToUnlockIter = unlockQueueIter->second.begin(), regToUnlockEnd = unlockQueueIter->second.end(); regToUnlockIter != regToUnlockEnd; regToUnlockIter++){
                        (*regToUnlockIter)->unlock();
                    }
                }
                else{
                    for(regToUnlockIter = unlockQueueIter->second.begin(), regToUnlockEnd = unlockQueueIter->second.end(); regToUnlockIter != regToUnlockEnd; regToUnlockIter++){
                        (*regToUnlockIter)->unlock(unlockQueueIter->first);
                    }
                }
                unlockQueueIter->second.clear();
            }
            """
            refreshRegistersBody = cxx_writer.writer_code.Code(codeString)
            refreshRegistersDecl = cxx_writer.writer_code.Method('refreshRegisters', refreshRegistersBody, cxx_writer.writer_code.voidType, 'pri', noException = True)
            curPipeElements.append(refreshRegistersDecl)
            # Here I declare the references to the pipeline registers and to the alias
            pipeRegisterType = cxx_writer.writer_code.Type('PipelineRegister', 'registers.hpp')
            for reg in self.regs:
                if self.fetchReg[0] != reg.name:
                    attribute = cxx_writer.writer_code.Attribute(reg.name, pipeRegisterType.makeRef(), 'pri')
                    constructorParams = [cxx_writer.writer_code.Parameter(reg.name, pipeRegisterType.makeRef())] + constructorParams
                    constructorInit.append(reg.name + '(' + reg.name + ')')
                    curPipeElements.append(attribute)
            for regB in self.regBanks:
                attribute = cxx_writer.writer_code.Attribute(regB.name, pipeRegisterType.makePointer(), 'pri')
                constructorParams = [cxx_writer.writer_code.Parameter(regB.name, pipeRegisterType.makePointer())] + constructorParams
                constructorInit.append(regB.name + '(' + regB.name + ')')
                curPipeElements.append(attribute)
            aliasType = cxx_writer.writer_code.Type('Alias', 'alias.hpp')
            for pipeStageInner in self.pipes:
                for alias in self.aliasRegs:
                    attribute = cxx_writer.writer_code.Attribute(alias.name + '_' + pipeStageInner.name, aliasType.makeRef(), 'pri')
                    constructorParams = [cxx_writer.writer_code.Parameter(alias.name + '_' + pipeStageInner.name, aliasType.makeRef())] + constructorParams
                    constructorInit.append(alias.name + '_' + pipeStageInner.name + '(' + alias.name + '_' + pipeStageInner.name + ')')
                    curPipeElements.append(attribute)
                for aliasB in self.aliasRegBanks:
                    attribute = cxx_writer.writer_code.Attribute(aliasB.name + '_' + pipeStageInner.name, aliasType.makePointer(), 'pri')
                    constructorParams = [cxx_writer.writer_code.Parameter(aliasB.name + '_' + pipeStageInner.name, aliasType.makePointer())] + constructorParams
                    constructorInit.append(aliasB.name + '_' + pipeStageInner.name + '(' + aliasB.name + '_' + pipeStageInner.name + ')')
                    curPipeElements.append(attribute)
            # I have to also instantiate the reference to the memories, in order to be able to
            # fetch instructions
            if self.memory:
                # I perform the fetch from the local memory
                memName = self.memory[0]
                memType = cxx_writer.writer_code.Type('LocalMemory', 'memory.hpp').makeRef()
            else:
                for name, isFetch  in self.tlmPorts.items():
                    if isFetch:
                        memName = name
                        memType = cxx_writer.writer_code.Type('TLMMemory', 'externalPorts.hpp').makeRef()
            constructorParams = [cxx_writer.writer_code.Parameter(memName, memType)] + constructorParams
            constructorInit.append(memName + '(' + memName + ')')
            memRefAttr = cxx_writer.writer_code.Attribute(memName, memType, 'pri')
            curPipeElements.append(memRefAttr)
            decoderAttribute = cxx_writer.writer_code.Attribute('decoder', cxx_writer.writer_code.Type('Decoder', 'decoder.hpp'), 'pu')
            curPipeElements.append(decoderAttribute)
            # I also have to add the map containig the ISA instructions to this stage
            instructionsAttribute = cxx_writer.writer_code.Attribute('INSTRUCTIONS', IntructionTypePtr.makePointer().makeRef(), 'pri')
            curPipeElements.append(instructionsAttribute)
            constructorParams = [cxx_writer.writer_code.Parameter('INSTRUCTIONS', IntructionTypePtr.makePointer().makeRef())] + constructorParams
            constructorInit.append('INSTRUCTIONS(INSTRUCTIONS)')
            # fetch register;
            regsNames = [i.name for i in self.regBanks + self.regs]
            fetchRegType = resourceType[self.fetchReg[0]]
            if self.fetchReg[0] in regsNames:
                fetchRegType = pipeRegisterType
            fetchAttr = cxx_writer.writer_code.Attribute(self.fetchReg[0], fetchRegType.makeRef(), 'pri')
            constructorParams = [cxx_writer.writer_code.Parameter(self.fetchReg[0], fetchRegType.makeRef())] + constructorParams
            constructorInit.append(self.fetchReg[0] + '(' + self.fetchReg[0] + ')')
            curPipeElements.append(fetchAttr)
            numInstructions = cxx_writer.writer_code.Attribute('numInstructions', cxx_writer.writer_code.uintType.makeRef(), 'pri')
            constructorParams = [cxx_writer.writer_code.Parameter('numInstructions', cxx_writer.writer_code.uintType.makeRef())] + constructorParams
            constructorInit.append('numInstructions(numInstructions)')
            curPipeElements.append(numInstructions)
            attribute = cxx_writer.writer_code.Attribute('instrExecuting', cxx_writer.writer_code.boolType.makeRef(), 'pri')
            constructorParams = [cxx_writer.writer_code.Parameter('instrExecuting', cxx_writer.writer_code.boolType.makeRef())] + constructorParams
            constructorInit.append('instrExecuting(instrExecuting)')
            curPipeElements.append(attribute)
            attribute = cxx_writer.writer_code.Attribute('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef(), 'pri')
            constructorParams = [cxx_writer.writer_code.Parameter('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef())] + constructorParams
            constructorInit.append('instrEndEvent(instrEndEvent)')
            curPipeElements.append(attribute)

            for irq in self.irqs:
                from isa import resolveBitType
                irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>')
                IRQAttribute = cxx_writer.writer_code.Attribute(irq.name, irqWidthType.makeRef(), 'pri')
                constructorParams = [cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef())] + constructorParams
                constructorInit.append(irq.name + '(' + irq.name + ')')
                curPipeElements.append(IRQAttribute)
            if self.instructionCache:
                CacheElemType = cxx_writer.writer_code.Type('CacheElem')
                template_mapType = cxx_writer.writer_code.TemplateType('template_map', [self.bitSizes[1], CacheElemType], hash_map_include)
                cacheAttribute = cxx_writer.writer_code.Attribute('instrCache', template_mapType, 'pri')
                curPipeElements.append(cacheAttribute)

            # The fetch stage also contains the tools manager
            ToolsManagerType = cxx_writer.writer_code.TemplateType('ToolsManager', [self.bitSizes[1]], 'ToolsIf.hpp')
            toolManagerAttribute = cxx_writer.writer_code.Attribute('toolManager', ToolsManagerType.makeRef(), 'pri')
            curPipeElements.append(toolManagerAttribute)
            constructorParams = [cxx_writer.writer_code.Parameter('toolManager', ToolsManagerType.makeRef())] + constructorParams
            constructorInit.append('toolManager(toolManager)')
            # Lets finally declare the attributes and constructor parameters for counting the cycles in a specified time
            # frame
            profilingTimeStartAttribute = cxx_writer.writer_code.Attribute('profTimeStart', cxx_writer.writer_code.sc_timeRefType, 'pu')
            curPipeElements.append(profilingTimeStartAttribute)
            constructorParams = [cxx_writer.writer_code.Parameter('profTimeStart', cxx_writer.writer_code.sc_timeRefType)] + constructorParams
            constructorInit.append('profTimeStart(profTimeStart)')
            profilingTimeEndAttribute = cxx_writer.writer_code.Attribute('profTimeEnd', cxx_writer.writer_code.sc_timeRefType, 'pu')
            curPipeElements.append(profilingTimeEndAttribute)
            constructorParams = [cxx_writer.writer_code.Parameter('profTimeEnd', cxx_writer.writer_code.sc_timeRefType)] + constructorParams
            constructorInit.append('profTimeEnd(profTimeEnd)')
            profilingAddrStartAttribute = cxx_writer.writer_code.Attribute('profStartAddr', self.bitSizes[1], 'pu')
            curPipeElements.append(profilingAddrStartAttribute)
            constructorCode += 'this->profStartAddr = (' + str(self.bitSizes[1]) + ')-1;\n'
            profilingAddrEndAttribute = cxx_writer.writer_code.Attribute('profEndAddr', self.bitSizes[1], 'pu')
            constructorCode += 'this->profEndAddr = (' + str(self.bitSizes[1]) + ')-1;\n'
            curPipeElements.append(profilingAddrEndAttribute)
            # Here are the attributes for the instruction history queue
            instrQueueFileAttribute = cxx_writer.writer_code.Attribute('histFile', cxx_writer.writer_code.ofstreamType, 'pu')
            curPipeElements.append(instrQueueFileAttribute)
            historyEnabledAttribute = cxx_writer.writer_code.Attribute('historyEnabled', cxx_writer.writer_code.boolType, 'pu')
            curPipeElements.append(historyEnabledAttribute)
            constructorCode += 'this->historyEnabled = false;\n'
            instrHistType = cxx_writer.writer_code.Type('HistoryInstrType', 'instructionBase.hpp')
            histQueueType = cxx_writer.writer_code.TemplateType('boost::circular_buffer', [instrHistType], 'boost/circular_buffer.hpp')
            instHistoryQueueAttribute = cxx_writer.writer_code.Attribute('instHistoryQueue', histQueueType, 'pu')
            curPipeElements.append(instHistoryQueueAttribute)
            constructorCode += 'this->instHistoryQueue.set_capacity(1000);\n'
            undumpedHistElemsAttribute = cxx_writer.writer_code.Attribute('undumpedHistElems', cxx_writer.writer_code.uintType, 'pu')
            curPipeElements.append(undumpedHistElemsAttribute)
            constructorCode += 'this->undumpedHistElems = 0;\n'
            # Now, before the processor elements is destructed I have to make sure that the history dump file is correctly closed
            destrCode = """#ifdef ENABLE_HISTORY
            if(this->historyEnabled){
                //Now, in case the queue dump file has been specified, I have to check if I need to save it
                if(this->histFile){
                    if(this->undumpedHistElems > 0){
                        std::vector<std::string> histVec;
                        boost::circular_buffer<HistoryInstrType>::const_reverse_iterator beg, end;
                        unsigned int histRead = 0;
                        for(histRead = 0, beg = this->instHistoryQueue.rbegin(), end = this->instHistoryQueue.rend(); beg != end && histRead < this->undumpedHistElems; beg++, histRead++){
                            histVec.push_back(beg->toStr());
                        }
                        std::vector<std::string>::const_reverse_iterator histVecBeg, histVecEnd;
                        for(histVecBeg = histVec.rbegin(), histVecEnd = histVec.rend(); histVecBeg != histVecEnd; histVecBeg++){
                            this->histFile <<  *histVecBeg << std::endl;
                        }
                    }
                    this->histFile.flush();
                    this->histFile.close();
                }
            }
            #endif
            """
            destructorBody = cxx_writer.writer_code.Code(destrCode)
            publicDestr = cxx_writer.writer_code.Destructor(destructorBody, 'pu')

        constructorInit = ['sc_module(pipeName)', 'BasePipeStage(' + baseConstructorInit[:-2] + ')'] + constructorInit
        curPipeDecl = cxx_writer.writer_code.SCModule(pipeStage.name.upper() + '_PipeStage', curPipeElements, [pipeType], namespaces = [namespace])
        constructorBody = cxx_writer.writer_code.Code(constructorCode + 'end_module();')
        publicCurPipeConstr = cxx_writer.writer_code.Constructor(constructorBody, 'pu', constructorParams, constructorInit)
        if pipeStage == self.pipes[0]:
            curPipeDecl.addDestructor(publicDestr)
        curPipeDecl.addConstructor(publicCurPipeConstr)
        pipeCodeElements.append(curPipeDecl)

    return pipeCodeElements
Esempio n. 11
0
def getCPPIf(self, model, namespace):
    """creates the interface which is used by the tools
    to access the processor core"""
    if not self.abi:
        return

    if model.startswith('acc'):
        regWriteCode = '.writeAll'
        regReadCode = ''
    else:
        regWriteCode = '.immediateWrite'
        regReadCode = '.readNewValue()'

    from procWriter import resourceType

    wordType = self.bitSizes[1]
    includes = wordType.getIncludes()
    pipeRegisterType = cxx_writer.writer_code.Type('PipelineRegister', 'registers.hpp')

    instrHistType = cxx_writer.writer_code.Type('HistoryInstrType', 'instructionBase.hpp')
    histQueueType = cxx_writer.writer_code.TemplateType('boost::circular_buffer', [instrHistType], 'boost/circular_buffer.hpp')

    ifClassElements = []
    initElements = []
    baseInstrConstrParams = []

    ####################################################
    # Lets first of all decalre the variables and the attributes;
    # they are mainly references to the corresponding elements
    # of the processor or of the pipeline stage
    ####################################################
    progLimitAttr = cxx_writer.writer_code.Attribute('PROGRAM_LIMIT', wordType.makeRef(), 'pri')
    ifClassElements.append(progLimitAttr)
    baseInstrConstrParams.append(cxx_writer.writer_code.Parameter('PROGRAM_LIMIT', wordType.makeRef()))
    initElements.append('PROGRAM_LIMIT(PROGRAM_LIMIT)')
    memIfType = cxx_writer.writer_code.Type('MemoryInterface', 'memory.hpp')
    for memName in self.abi.memories.keys():
        ifClassElements.append(cxx_writer.writer_code.Attribute(memName, memIfType.makeRef(), 'pri'))
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter(memName, memIfType.makeRef()))
        initElements.append(memName + '(' + memName + ')')
    for reg in self.regs:
        if model.startswith('acc'):
            curRegBType = pipeRegisterType
        else:
            curRegBType = resourceType[reg.name]
        attribute = cxx_writer.writer_code.Attribute(reg.name, curRegBType.makeRef(), 'pri')
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter(reg.name, curRegBType.makeRef()))
        initElements.append(reg.name + '(' + reg.name + ')')
        ifClassElements.append(attribute)
    for regB in self.regBanks:
        if (regB.constValue and len(regB.constValue) < regB.numRegs)  or ((regB.delay and len(regB.delay) < regB.numRegs) and not model.startswith('acc')):
            if model.startswith('acc'):
                curRegBType = pipeRegisterType.makePointer()
            else:
                curRegBType = resourceType[regB.name].makeRef()
        else:
            if model.startswith('acc'):
                curRegBType = pipeRegisterType.makePointer()
            else:
                curRegBType = resourceType[regB.name]
        attribute = cxx_writer.writer_code.Attribute(regB.name, curRegBType, 'pri')
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter(regB.name, curRegBType))
        initElements.append(regB.name + '(' + regB.name + ')')
        ifClassElements.append(attribute)
    for alias in self.aliasRegs:
        attribute = cxx_writer.writer_code.Attribute(alias.name, resourceType[alias.name].makeRef(), 'pri')
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter(alias.name, resourceType[alias.name].makeRef()))
        initElements.append(alias.name + '(' + alias.name + ')')
        ifClassElements.append(attribute)
    for aliasB in self.aliasRegBanks:
        attribute = cxx_writer.writer_code.Attribute(aliasB.name, resourceType[aliasB.name].makePointer(), 'pri')
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter(aliasB.name, resourceType[aliasB.name].makePointer()))
        initElements.append(aliasB.name + '(' + aliasB.name + ')')
        ifClassElements.append(attribute)
    attribute = cxx_writer.writer_code.Attribute('instrExecuting', cxx_writer.writer_code.boolType.makeRef(), 'pri')
    baseInstrConstrParams.append(cxx_writer.writer_code.Parameter('instrExecuting', cxx_writer.writer_code.boolType.makeRef()))
    initElements.append('instrExecuting(instrExecuting)')
    ifClassElements.append(attribute)
    if self.systemc:
        attribute = cxx_writer.writer_code.Attribute('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef(), 'pri')
        baseInstrConstrParams.append(cxx_writer.writer_code.Parameter('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef()))
        initElements.append('instrEndEvent(instrEndEvent)')
        ifClassElements.append(attribute)
    instHistoryQueueAttr = cxx_writer.writer_code.Attribute('instHistoryQueue', histQueueType.makeRef(), 'pri')
    ifClassElements.append(instHistoryQueueAttr)
    baseInstrConstrParams.append(cxx_writer.writer_code.Parameter('instHistoryQueue', histQueueType.makeRef()))
    initElements.append('instHistoryQueue(instHistoryQueue)')

    ###############################################################
    # Now lets move to the actual implementation of the methods which
    # enable communication of the interface with the processor
    ###############################################################
    if self.isBigEndian:
        endianessCode = cxx_writer.writer_code.Code('return false;')
    else:
        endianessCode = cxx_writer.writer_code.Code('return true;')
    endianessMethod = cxx_writer.writer_code.Method('isLittleEndian', endianessCode, cxx_writer.writer_code.boolType, 'pu', noException = True, const = True)
    ifClassElements.append(endianessMethod)

    # Here are the methods used to discriminate when an instruction is executing or not
    if self.abi.procIdCode:
        processorIDCode = cxx_writer.writer_code.Code('return (' + self.abi.procIdCode + ');\n')
        processorIDMethod = cxx_writer.writer_code.Method('getProcessorID', processorIDCode, cxx_writer.writer_code.intType, 'pu', noException = True, const = True)
        ifClassElements.append(processorIDMethod)
    instrExecutingCode = cxx_writer.writer_code.Code('return this->instrExecuting;')
    instrExecutingMethod = cxx_writer.writer_code.Method('isInstrExecuting', instrExecutingCode, cxx_writer.writer_code.boolType, 'pu', noException = True, const = True)
    ifClassElements.append(instrExecutingMethod)
    if self.systemc:
        waitInstrEndCode = cxx_writer.writer_code.Code('if(this->instrExecuting){\nwait(this->instrEndEvent);\n}\n')
        waitInstrEndCode.addInclude('systemc.h')
    else:
        waitInstrEndCode = cxx_writer.writer_code.Code('while(this->instrExecuting){\n;\n}\n')
    waitInstrEndMethod = cxx_writer.writer_code.Method('waitInstrEnd', waitInstrEndCode, cxx_writer.writer_code.voidType, 'pu', noException = True, const = True)
    ifClassElements.append(waitInstrEndMethod)

    if self.abi.preCallCode:
        ifClassElements.append(cxx_writer.writer_code.Method('preCall', cxx_writer.writer_code.Code(self.abi.preCallCode), cxx_writer.writer_code.voidType, 'pu', noException = True))
    if self.abi.postCallCode:
        ifClassElements.append(cxx_writer.writer_code.Method('postCall', cxx_writer.writer_code.Code(self.abi.postCallCode), cxx_writer.writer_code.voidType, 'pu', noException = True))
    if self.abi.returnCallReg:
        returnCallCode = ''
        for returnReg in self.abi.returnCallReg:
            returnCallCode += returnReg[0] + regWriteCode + '(' + returnReg[1] + ' + ' + str(returnReg[2]) + ');\n'
        ifClassElements.append(cxx_writer.writer_code.Method('returnFromCall', cxx_writer.writer_code.Code(returnCallCode), cxx_writer.writer_code.voidType, 'pu', noException = True))

    # Here is the code for recognizing if we are in the routine entry or
    # exit; we behave like a state machine,moving to the beginning when
    # an instruction out of the sequence is met
    entryStateAttribute = cxx_writer.writer_code.Attribute('routineEntryState', cxx_writer.writer_code.intType, 'pri')
    ifClassElements.append(entryStateAttribute)
    exitStateAttribute = cxx_writer.writer_code.Attribute('routineExitState', cxx_writer.writer_code.intType, 'pri')
    ifClassElements.append(exitStateAttribute)
    vector_strType = cxx_writer.writer_code.TemplateType('std::vector', [cxx_writer.writer_code.stringType], 'vector')
    vector_v_strType = cxx_writer.writer_code.TemplateType('std::vector', [vector_strType], 'vector')
    entrySequenceAttribute = cxx_writer.writer_code.Attribute('routineEntrySequence', vector_v_strType, 'pri')
    ifClassElements.append(entrySequenceAttribute)
    exitSequenceAttribute = cxx_writer.writer_code.Attribute('routineExitSequence', vector_v_strType, 'pri')
    ifClassElements.append(exitSequenceAttribute)
    routineStatesInit = """this->routineExitState = 0;
    this->routineEntryState = 0;
    std::vector<std::string> tempVec;
    """
    from isa import Instruction
    for instrList in self.abi.callInstr:
        routineStatesInit += 'tempVec.clear();\n'
        if not instrList:
            routineStatesInit += 'tempVec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            routineStatesInit += 'tempVec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                routineStatesInit += 'tempVec.push_back("' + instr.name + '");\n'
        routineStatesInit += 'this->routineEntrySequence.push_back(tempVec);\n'
    for instrList in self.abi.returnCallInstr:
        routineStatesInit += 'tempVec.clear();\n'
        if not instrList:
            routineStatesInit += 'tempVec.push_back("");\n'
        elif isinstance(instrList, Instruction):
            routineStatesInit += 'tempVec.push_back("' + instrList.name + '");\n'
        else:
            for instr in instrList:
                routineStatesInit += 'tempVec.push_back("' + instr.name + '");\n'
        routineStatesInit += 'this->routineExitSequence.push_back(tempVec);\n'
    instructionBaseType = cxx_writer.writer_code.Type('InstructionBase', 'instructionBase.hpp')
    baseInstrParam = cxx_writer.writer_code.Parameter('instr', instructionBaseType.makePointer().makeConst())
    isRoutineEntryBody = """std::vector<std::string> nextNames = this->routineEntrySequence[this->routineEntryState];
    std::vector<std::string>::const_iterator namesIter, namesEnd;
    std::string curName = instr->getInstructionName();
    for(namesIter = nextNames.begin(), namesEnd = nextNames.end(); namesIter != namesEnd; namesIter++){
        if(curName == *namesIter || *namesIter == ""){
            if(this->routineEntryState == """ + str(len(self.abi.callInstr) -1) + """){
                this->routineEntryState = 0;
                return true;
            }
            this->routineEntryState++;
            return false;
        }
    }
    this->routineEntryState = 0;
    return false;
    """
    isRoutineEntryCode = cxx_writer.writer_code.Code(isRoutineEntryBody)
    isRoutineEntryMethod = cxx_writer.writer_code.Method('isRoutineEntry', isRoutineEntryCode, cxx_writer.writer_code.boolType, 'pu', [baseInstrParam], noException = True)
    ifClassElements.append(isRoutineEntryMethod)
    isRoutineExitBody = """std::vector<std::string> nextNames = this->routineExitSequence[this->routineExitState];
    std::vector<std::string>::const_iterator namesIter, namesEnd;
    std::string curName = instr->getInstructionName();
    for(namesIter = nextNames.begin(), namesEnd = nextNames.end(); namesIter != namesEnd; namesIter++){
        if(curName == *namesIter || *namesIter == ""){
            if(this->routineExitState == """ + str(len(self.abi.returnCallInstr) -1) + """){
                this->routineExitState = 0;
                return true;
            }
            this->routineExitState++;
            return false;
        }
    }
    this->routineExitState = 0;
    return false;
    """
    isRoutineExitCode = cxx_writer.writer_code.Code(isRoutineExitBody)
    isRoutineExitMethod = cxx_writer.writer_code.Method('isRoutineExit', isRoutineExitCode, cxx_writer.writer_code.boolType, 'pu', [baseInstrParam], noException = True)
    ifClassElements.append(isRoutineExitMethod)

    # Here I add the methods mecessary to save and restore the complete
    # processor status (useful, for example, to implement hardware context-switches,
    # or simulation chepointing)
    totalStateSize = 0
    for reg in self.regs:
        totalStateSize += reg.bitWidth/self.byteSize
    for regB in self.regBanks:
        totalStateSize += (regB.bitWidth*regB.numRegs)/self.byteSize
    getStateBody = 'unsigned char * curState = new unsigned char[' + str(totalStateSize) + '];\n'
    getStateBody += 'unsigned char * curStateTemp = curState;\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) + '>')
            getStateBody += '*((' + str(regWType.makePointer()) + ')curStateTemp) = this->' + reg.name + regReadCode + ';\ncurStateTemp += ' + 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):
                getStateBody += '*((' + str(regWType.makePointer()) + ')curStateTemp) = this->' + regB.name + '[' + str(i) + ']' + regReadCode + ';\ncurStateTemp += ' + str(regB.bitWidth/self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    getStateBody += '*((' + str(regWType.makePointer()) + ')curStateTemp) = this->' + regB.name + '[' + str(i) + ']' + regReadCode + ';\ncurStateTemp += ' + str(regB.bitWidth/self.byteSize) + ';\n'
    getStateBody += 'return curState;'
    getStateCode = cxx_writer.writer_code.Code(getStateBody)
    getStateMethod = cxx_writer.writer_code.Method('getState', getStateCode, cxx_writer.writer_code.ucharPtrType, 'pu', noException = True, const = True)
    ifClassElements.append(getStateMethod)
    setStateBody = 'unsigned char * curStateTemp = state;\n'
    for reg in self.regs:
        if not reg.name in self.abi.stateIgnoreRegs:
            regWType = resolveBitType('BIT<' + str(reg.bitWidth) + '>')
            setStateBody += 'this->' + reg.name + regWriteCode + '(*((' + str(regWType.makePointer()) + ')curStateTemp));\ncurStateTemp += ' + 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):
                setStateBody += 'this->' + regB.name + '[' + str(i) + ']' + regWriteCode + '(*((' + str(regWType.makePointer()) + ')curStateTemp));\ncurStateTemp += ' + str(regB.bitWidth/self.byteSize) + ';\n'
        else:
            for i in range(0, regB.numRegs):
                if i not in stateIgnoreRegs[regB.name]:
                    setStateBody += 'this->' + regB.name + '[' + str(i) + ']' + regWriteCode + '(*((' + str(regWType.makePointer()) + ')curStateTemp));\ncurStateTemp += ' + str(regB.bitWidth/self.byteSize) + ';\n'
    setStateCode = cxx_writer.writer_code.Code(setStateBody)
    stateParam = cxx_writer.writer_code.Parameter('state', cxx_writer.writer_code.ucharPtrType)
    setStateMethod = cxx_writer.writer_code.Method('setState', setStateCode, cxx_writer.writer_code.voidType, 'pu', [stateParam], noException = True)
    ifClassElements.append(setStateMethod)

    codeLimitCode = cxx_writer.writer_code.Code('return this->PROGRAM_LIMIT;')
    codeLimitMethod = cxx_writer.writer_code.Method('getCodeLimit', codeLimitCode, wordType, 'pu')
    ifClassElements.append(codeLimitMethod)
    for elem in [self.abi.LR, self.abi.PC, self.abi.SP, self.abi.FP, self.abi.retVal]:
        if not elem:
            continue
        readElemBody = 'return this->' + elem
        if self.abi.offset.has_key(elem):
            readElemBody += ' + ' + str(self.abi.offset[elem])
        readElemBody += ';'
        readElemCode = cxx_writer.writer_code.Code(readElemBody)
        readElemCode.addInclude(includes)
        readElemMethod = cxx_writer.writer_code.Method('read' + self.abi.name[elem], readElemCode, wordType, 'pu', noException = True, const = True)
        ifClassElements.append(readElemMethod)
        setElemBody = 'this->' + elem + regWriteCode + '(newValue);'
        setElemCode = cxx_writer.writer_code.Code(setElemBody)
        setElemCode.addInclude(includes)
        setElemParam = cxx_writer.writer_code.Parameter('newValue', wordType.makeRef().makeConst())
        setElemMethod = cxx_writer.writer_code.Method('set' + self.abi.name[elem], setElemCode, cxx_writer.writer_code.voidType, 'pu', [setElemParam], noException = True)
        ifClassElements.append(setElemMethod)
    vectorType = cxx_writer.writer_code.TemplateType('std::vector', [wordType], 'vector')
    readArgsBody = str(vectorType) + ' args;\n'
    for arg in self.abi.args:
        readArgsBody += 'args.push_back(this->' + arg
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            readArgsBody += ' + ' + str(self.abi.offset[arg])
        readArgsBody += ');\n'
    readArgsBody += 'return args;\n'
    readArgsCode = cxx_writer.writer_code.Code(readArgsBody)
    readArgsCode.addInclude(includes)
    readArgsMethod = cxx_writer.writer_code.Method('readArgs', readArgsCode, vectorType, 'pu', noException = True, const = True)
    ifClassElements.append(readArgsMethod)
    setArgsBody = 'if(args.size() > ' + str(len(self.abi.args)) + '){\nTHROW_EXCEPTION(\"ABI of processor supports up to ' + str(len(self.abi.args)) + ' arguments: \" << args.size() << \" given\");\n}\n'
    setArgsBody += str(vectorType) + '::const_iterator argIter = args.begin(), argEnd = args.end();\n'
    for arg in self.abi.args:
        setArgsBody += 'if(argIter != argEnd){\n'
        setArgsBody += 'this->' + arg + regWriteCode + '(*argIter'
        if self.abi.offset.has_key(arg) and not model.startswith('acc'):
            setArgsBody += ' - ' + str(self.abi.offset[arg])
        setArgsBody += ');\nargIter++;\n}\n'
    setArgsCode = cxx_writer.writer_code.Code(setArgsBody)
    setArgsParam = cxx_writer.writer_code.Parameter('args', vectorType.makeRef().makeConst())
    setArgsMethod = cxx_writer.writer_code.Method('setArgs', setArgsCode, cxx_writer.writer_code.voidType, 'pu', [setArgsParam], noException = True)
    ifClassElements.append(setArgsMethod)
    maxGDBId = 0
    readGDBRegBody = 'switch(gdbId){\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
        readGDBRegBody += 'case ' + str(gdbId) + ':{\n'
        readGDBRegBody += 'return ' + reg
        if self.abi.offset.has_key(reg) and not model.startswith('acc'):
            readGDBRegBody += ' + ' + str(self.abi.offset[reg])
        readGDBRegBody += ';\nbreak;}\n'
    readGDBRegBody += 'default:{\nreturn 0;\n}\n}\n'
    readGDBRegCode = cxx_writer.writer_code.Code(readGDBRegBody)
    readGDBRegCode.addInclude(includes)
    readGDBRegParam = cxx_writer.writer_code.Parameter('gdbId', cxx_writer.writer_code.uintType.makeRef().makeConst())
    readGDBRegMethod = cxx_writer.writer_code.Method('readGDBReg', readGDBRegCode, wordType, 'pu', [readGDBRegParam], noException = True, const = True)
    ifClassElements.append(readGDBRegMethod)
    nGDBRegsCode = cxx_writer.writer_code.Code('return ' + str(maxGDBId + 1) + ';')
    nGDBRegsMethod = cxx_writer.writer_code.Method('nGDBRegs', nGDBRegsCode, cxx_writer.writer_code.uintType, 'pu', noException = True, const = True)
    ifClassElements.append(nGDBRegsMethod)
    setGDBRegBody = 'switch(gdbId){\n'
    for reg, gdbId in sortedGDBRegs:
        setGDBRegBody += 'case ' + str(gdbId) + ':{\n'
        setGDBRegBody += reg + regWriteCode + '(newValue'
        setGDBRegBody += ');\nbreak;}\n'
    setGDBRegBody += 'default:{\nTHROW_EXCEPTION(\"No register corresponding to GDB id \" << gdbId);\n}\n}\n'
    setGDBRegCode = cxx_writer.writer_code.Code(setGDBRegBody)
    setGDBRegCode.addInclude(includes)
    setGDBRegParam1 = cxx_writer.writer_code.Parameter('newValue', wordType.makeRef().makeConst())
    setGDBRegParam2 = cxx_writer.writer_code.Parameter('gdbId', cxx_writer.writer_code.uintType.makeRef().makeConst())
    setGDBRegMethod = cxx_writer.writer_code.Method('setGDBReg', setGDBRegCode, cxx_writer.writer_code.voidType, 'pu', [setGDBRegParam1, setGDBRegParam2], noException = True)
    ifClassElements.append(setGDBRegMethod)
    readMemBody = ''
    if not self.abi.memories:
        readMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            readMemBody += 'return this->' + self.abi.memories.keys()[0] + '.read_word_dbg(address);'
        else:
            for memName, mem_range in self.abi.memories.items():
                readMemBody += 'if(address >= ' + hex(mem_range[0]) + ' && address <= ' + hex(mem_range[1]) + '){\n'
                readMemBody += 'return this->' + self.abi.memories.keys()[0] + '.read_word_dbg(address);\n}\nelse '
            readMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    readMemCode = cxx_writer.writer_code.Code(readMemBody)
    readMemParam1 = cxx_writer.writer_code.Parameter('address', wordType.makeRef().makeConst())
    readMemMethod = cxx_writer.writer_code.Method('readMem', readMemCode, wordType, 'pu', [readMemParam1])
    ifClassElements.append(readMemMethod)

    readByteMemBody = ''
    if not self.abi.memories:
        readByteMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            readByteMemBody += 'return this->' + self.abi.memories.keys()[0] + '.read_byte_dbg(address);'
        else:
            for memName, mem_range in self.abi.memories.items():
                readByteMemBody += 'if(address >= ' + hex(mem_range[0]) + ' && address <= ' + hex(mem_range[1]) + '){\n'
                readByteMemBody += 'return this->' + self.abi.memories.keys()[0] + '.read_byte_dbg(address);\n}\nelse '
            readByteMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    readByteMemCode = cxx_writer.writer_code.Code(readByteMemBody)
    readByteMemParam = cxx_writer.writer_code.Parameter('address', wordType.makeRef().makeConst())
    readByteMemMethod = cxx_writer.writer_code.Method('readCharMem', readByteMemCode, cxx_writer.writer_code.ucharType, 'pu', [readByteMemParam])
    ifClassElements.append(readByteMemMethod)

    writeMemBody = ''
    if not self.abi.memories:
        writeMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            writeMemBody += 'this->' + self.abi.memories.keys()[0] + '.write_word_dbg(address, datum);'
        else:
            for memName, mem_range in self.abi.memories.items():
                writeMemBody += 'if(address >= ' + hex(mem_range[0]) + ' && address <= ' + hex(mem_range[1]) + '){\n'
                writeMemBody += 'this->' + self.abi.memories.keys()[0] + '.write_word_dbg(address, datum);\n}\nelse '
            writeMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    writeMemCode = cxx_writer.writer_code.Code(writeMemBody)
    writeMemCode.addInclude('trap_utils.hpp')
    writeMemParam1 = cxx_writer.writer_code.Parameter('address', wordType.makeRef().makeConst())
    writeMemParam2 = cxx_writer.writer_code.Parameter('datum', wordType)
    writeMemMethod = cxx_writer.writer_code.Method('writeMem', writeMemCode, cxx_writer.writer_code.voidType, 'pu', [writeMemParam1, writeMemParam2])
    ifClassElements.append(writeMemMethod)
    writeMemBody = ''
    if not self.abi.memories:
        writeMemBody += 'THROW_EXCEPTION(\"No memory accessible from the ABI or processor ' + self.name + '\");'
    else:
        if len(self.abi.memories) == 1:
            writeMemBody += 'this->' + self.abi.memories.keys()[0] + '.write_byte_dbg(address, datum);'
        else:
            for memName, mem_range in self.abi.memories.items():
                writeMemBody += 'if(address >= ' + hex(mem_range[0]) + ' && address <= ' + hex(mem_range[1]) + '){\n'
                writeMemBody += 'this->' + self.abi.memories.keys()[0] + '.write_byte_dbg(address, datum);\n}\nelse '
            writeMemBody += '{\nTHROW_EXCEPTION(\"Address \" << std::hex << address << \" out of range\");\n}'
    writeMemCode = cxx_writer.writer_code.Code(writeMemBody)
    writeMemParam1 = cxx_writer.writer_code.Parameter('address', wordType.makeRef().makeConst())
    writeMemParam2 = cxx_writer.writer_code.Parameter('datum', cxx_writer.writer_code.ucharType)
    writeMemMethod = cxx_writer.writer_code.Method('writeCharMem', writeMemCode, cxx_writer.writer_code.voidType, 'pu', [writeMemParam1, writeMemParam2])
    ifClassElements.append(writeMemMethod)

    getInstructionHistoryCode = cxx_writer.writer_code.Code('return this->instHistoryQueue;')
    getInstructionHistoryMethod = cxx_writer.writer_code.Method('getInstructionHistory', getInstructionHistoryCode, histQueueType.makeRef(), 'pu')
    ifClassElements.append(getInstructionHistoryMethod)

    ABIIfType = cxx_writer.writer_code.TemplateType('ABIIf', [wordType], 'ABIIf.hpp')
    ifClassDecl = cxx_writer.writer_code.ClassDeclaration(self.name + '_ABIIf', ifClassElements, [ABIIfType], namespaces = [namespace])
    publicIfConstr = cxx_writer.writer_code.Constructor(cxx_writer.writer_code.Code(routineStatesInit), 'pu', baseInstrConstrParams, initElements)
    emptyBody = cxx_writer.writer_code.Code('')
    opDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True)
    ifClassDecl.addDestructor(opDestr)
    ifClassDecl.addConstructor(publicIfConstr)
    return ifClassDecl