Exemplo n.º 1
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
Exemplo n.º 2
0
def getCPPMemoryIf(self, model, namespace):
    """Creates the necessary structures for communicating with the memory: An
    array in case of an internal memory or a TLM port for TLM memories."""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return memoryClasses
Exemplo n.º 3
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
Exemplo n.º 4
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
Exemplo n.º 5
0
def getCPPMemoryIf(self, model, namespace):
    """Creates the necessary structures for communicating with the memory: An
    array in case of an internal memory or a TLM port for TLM memories."""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return memoryClasses
Exemplo n.º 6
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
Exemplo n.º 7
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
Exemplo n.º 8
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