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
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
def getCPPIRQInstr(self, model, trace, namespace): from procWriter import instrCtorParams, instrCtorValues instructionType = cxx_writer.Type('Instruction', '#include \"instructions.hpp\"') from registerWriter import registerType IRQInstrClasses = [] emptyBody = cxx_writer.Code('') for irq in self.irqs: IRQInstrMembers = [] # Methods: get_id() getIdBody = cxx_writer.Code('return (unsigned)-1;') getIdMethod = cxx_writer.Method('get_id', getIdBody, cxx_writer.uintType, 'public', noException=True, const=True) IRQInstrMembers.append(getIdMethod) # Methods: get_name() getNameBody = cxx_writer.Code('return \"' + irq.name + 'IntrInstruction\";') getNameMethod = cxx_writer.Method('get_name', getNameBody, cxx_writer.stringType, 'public', noException=True, const=True) IRQInstrMembers.append(getNameMethod) # Methods: get_mnemonic() getMnemonicBody = cxx_writer.Code('return \"' + irq.name + '\";') getMnemonicMethod = cxx_writer.Method('get_mnemonic', getMnemonicBody, cxx_writer.stringType, 'public', noException=True, const=True) IRQInstrMembers.append(getMnemonicMethod) # Methods: replicate() replicateBody = cxx_writer.Code('return new ' + irq.name + 'IntrInstruction(' + instrCtorValues + ', this->' + irq.name + ');') replicateMethod = cxx_writer.Method( 'replicate', replicateBody, instructionType.makePointer(), 'public', parameters=[ cxx_writer.Parameter('instr', instructionType.makePointer(), initValue='NULL') ], noException=True, const=True) IRQInstrMembers.append(replicateMethod) # Methods: behavior() for pipeStage in self.pipes: behaviorUserCode = '' if irq.operation.has_key(pipeStage.name): behaviorUserCode += '{\nunsigned num_cycles = 0;\n' behaviorUserCode += str(irq.operation[pipeStage.name]) behaviorUserCode += 'this->' if model.startswith('acc'): behaviorUserCode += 'num_stage_cycles' else: behaviorUserCode += 'num_instr_cycles' behaviorUserCode += ' += num_cycles;\n}\n' if model.startswith('acc'): behaviorCode = 'this->num_stage_cycles = 0;\n' if behaviorUserCode: # Set the pipeline stage so that the usage of the registers # is transparent to the user. behaviorCode += '\nR.set_stage(' + str( self.pipes.index(pipeStage)) + ');\n' behaviorCode += behaviorUserCode behaviorCode += '\nR.unset_stage();\n' behaviorCode += 'return this->num_stage_cycles;\n' behaviorBody = cxx_writer.Code(behaviorCode) behaviorMethod = cxx_writer.Method( 'behavior_' + pipeStage.name, behaviorBody, cxx_writer.uintType, 'public') IRQInstrMembers.append(behaviorMethod) if not model.startswith('acc'): behaviorCode = 'this->num_instr_cycles = 0;\n' behaviorCode += behaviorUserCode behaviorCode += 'return this->num_instr_cycles;\n' behaviorBody = cxx_writer.Code(behaviorCode) behaviorMethod = cxx_writer.Method('behavior', behaviorBody, cxx_writer.uintType, 'public') IRQInstrMembers.append(behaviorMethod) # Methods: set_interrupt_value() # Sets the value of the received interrupt and the related attribute. from isa import resolveBitType irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>') IRQAttr = cxx_writer.Attribute(irq.name, irqWidthType.makeRef(), 'public') IRQInstrMembers.append(IRQAttr) IRQInstrCtorParams = [ cxx_writer.Parameter(irq.name, irqWidthType.makeRef()) ] IRQInstrCtorInit = [irq.name + '(' + irq.name + ')'] InterruptValueParam = cxx_writer.Parameter( 'interrupt_value', irqWidthType.makeRef().makeConst()) setInterruptValueBody = cxx_writer.Code('this->' + irq.name + ' = interrupt_value;') setInterruptValueMethod = cxx_writer.Method('set_interrupt_value', setInterruptValueBody, cxx_writer.voidType, 'public', [InterruptValueParam], noException=True, inline=True) IRQInstrMembers.append(setInterruptValueMethod) # Attributes for var in irq.variables: IRQInstrMembers.append( cxx_writer.Attribute(var.name, var.varType, 'protected', var.static)) # Constructors and Destructors IRQInstrCtor = cxx_writer.Constructor( emptyBody, 'public', parameters=instrCtorParams + IRQInstrCtorParams, initList=['Instruction(' + instrCtorValues + ')'] + IRQInstrCtorInit) IRQInstrDtor = cxx_writer.Destructor(emptyBody, 'public', True) # Class IRQInstrClass = cxx_writer.ClassDeclaration( irq.name + 'IntrInstruction', IRQInstrMembers, [instructionType], namespaces=[namespace]) IRQInstrClass.addDocString( brief='IRQ Instruction Class', detail= 'Wraps IRQ exception handling behavior as a dummy instruction.') IRQInstrClass.addConstructor(IRQInstrCtor) IRQInstrClass.addDestructor(IRQInstrDtor) IRQInstrClasses.append(IRQInstrClass) return IRQInstrClasses
def getGetIRQInstr(self, model, trace, namespace): from pipelineWriter import hasCheckHazard instructionType = cxx_writer.writer_code.Type('Instruction', 'instructions.hpp') emptyBody = cxx_writer.writer_code.Code('') IRQInstrClasses = [] for irq in self.irqs: IRQInstrElements = [] # now I have to go over the behavior of this interrupt and create, like for the instructions, # the behavior for the different pipeline stages if not model.startswith('acc'): behaviorCode = 'this->totalInstrCycles = 0;\n' userDefineBehavior = '' for pipeStage in self.pipes: userDefineBehavior = '' if model.startswith('acc'): behaviorCode = 'this->stageCycles = 0;\n' if irq.operation.has_key(pipeStage.name): userDefineBehavior += str(irq.operation[pipeStage.name]) if model.startswith('acc'): # now I have to take all the resources and create a define which # renames such resources so that their usage can be transparent # to the developer for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks: behaviorCode += '#define ' + reg.name + ' ' + reg.name + '_' + pipeStage.name + '\n' behaviorCode += '\n' behaviorCode += userDefineBehavior if model.startswith('acc'): for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks: behaviorCode += '#undef ' + reg.name + '\n' if model.startswith('acc'): behaviorCode += 'return this->stageCycles;\n\n' registerType = cxx_writer.writer_code.Type('Register') unlockQueueType = cxx_writer.writer_code.TemplateType( 'std::map', [ 'unsigned int', cxx_writer.writer_code.TemplateType( 'std::vector', [registerType.makePointer()], 'vector') ], 'map') unlockQueueParam = cxx_writer.writer_code.Parameter( 'unlockQueue', unlockQueueType.makeRef()) behaviorBody = cxx_writer.writer_code.Code(behaviorCode) behaviorDecl = cxx_writer.writer_code.Method( 'behavior_' + pipeStage.name, behaviorBody, cxx_writer.writer_code.uintType, 'pu', [unlockQueueParam]) IRQInstrElements.append(behaviorDecl) if not model.startswith('acc'): behaviorCode += 'return this->totalInstrCycles;' behaviorBody = cxx_writer.writer_code.Code(behaviorCode) behaviorDecl = cxx_writer.writer_code.Method( 'behavior', behaviorBody, cxx_writer.writer_code.uintType, 'pu') IRQInstrElements.append(behaviorDecl) # Standard Instruction methods, there is not much to do since the IRQ instruction does nothing special from procWriter import baseInstrInitElement replicateBody = cxx_writer.writer_code.Code('return new IRQ_' + irq.name + '_Instruction(' + baseInstrInitElement + ', this->' + irq.name + ');') replicateDecl = cxx_writer.writer_code.Method( 'replicate', replicateBody, instructionType.makePointer(), 'pu', noException=True, const=True) IRQInstrElements.append(replicateDecl) setparamsParam = cxx_writer.writer_code.Parameter( 'bitString', self.bitSizes[1].makeRef().makeConst()) setparamsDecl = cxx_writer.writer_code.Method( 'setParams', emptyBody, cxx_writer.writer_code.voidType, 'pu', [setparamsParam], noException=True) IRQInstrElements.append(setparamsDecl) getIstructionNameBody = cxx_writer.writer_code.Code('return \"IRQ_' + irq.name + '_Instruction\";') getIstructionNameDecl = cxx_writer.writer_code.Method( 'getInstructionName', getIstructionNameBody, cxx_writer.writer_code.stringType, 'pu', noException=True, const=True) IRQInstrElements.append(getIstructionNameDecl) getMnemonicBody = cxx_writer.writer_code.Code('return \"irq_' + irq.name + '\";') getMnemonicDecl = cxx_writer.writer_code.Method( 'getMnemonic', getMnemonicBody, cxx_writer.writer_code.stringType, 'pu', noException=True, const=True) IRQInstrElements.append(getMnemonicDecl) getIdBody = cxx_writer.writer_code.Code('return (unsigned int)-1;') getIdDecl = cxx_writer.writer_code.Method( 'getId', getIdBody, cxx_writer.writer_code.uintType, 'pu', noException=True, const=True) IRQInstrElements.append(getIdDecl) # Now we have all the methods related to data hazards detection and management: # TODO: is an implementation needed for the IRQ instruction? if model.startswith('acc'): if hasCheckHazard: for pipeStage in self.pipes: checkHazardDecl = cxx_writer.writer_code.Method( 'checkHazard_' + pipeStage.name, emptyBody, cxx_writer.writer_code.boolType, 'pu') IRQInstrElements.append(checkHazardDecl) lockDecl = cxx_writer.writer_code.Method( 'lockRegs_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu') IRQInstrElements.append(lockDecl) unlockHazard = False for pipeStage in self.pipes: if pipeStage.checkHazard: unlockHazard = True if unlockHazard: getUnlockDecl = cxx_writer.writer_code.Method( 'getUnlock_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu', [unlockQueueParam]) IRQInstrElements.append(getUnlockDecl) printBusyRegsDecl = cxx_writer.writer_code.Method( 'printBusyRegs', cxx_writer.writer_code.Code('return "";'), cxx_writer.writer_code.stringType, 'pu') IRQInstrElements.append(printBusyRegsDecl) # Here I add a method to specify the value of the received interrupt and the related attribute from isa import resolveBitType irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>') IRQAttribute = cxx_writer.writer_code.Attribute( irq.name, irqWidthType.makeRef(), 'pu') IRQInstrElements.append(IRQAttribute) irqParams = [ cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef()) ] irqInit = [irq.name + '(' + irq.name + ')'] InterruptValueParam = cxx_writer.writer_code.Parameter( 'interruptValue', irqWidthType.makeRef().makeConst()) setInterruptValueBody = cxx_writer.writer_code.Code( 'this->' + irq.name + ' = interruptValue;') setInterruptValueDecl = cxx_writer.writer_code.Method( 'setInterruptValue', setInterruptValueBody, cxx_writer.writer_code.voidType, 'pu', [InterruptValueParam], noException=True, inline=True) IRQInstrElements.append(setInterruptValueDecl) # Now I declare the instruction variables for this IRQ instruction for var in irq.variables: IRQInstrElements.append( cxx_writer.writer_code.Attribute(var.name, var.varType, 'pro', var.static)) # Finally I can declare the IRQ class for this specific IRQ from procWriter import baseInstrInitElement from isaWriter import baseInstrConstrParams publicConstr = cxx_writer.writer_code.Constructor( emptyBody, 'pu', baseInstrConstrParams + irqParams, ['Instruction(' + baseInstrInitElement + ')'] + irqInit) IRQInstrClass = cxx_writer.writer_code.ClassDeclaration( 'IRQ_' + irq.name + '_Instruction', IRQInstrElements, [instructionType], namespaces=[namespace]) IRQInstrClass.addConstructor(publicConstr) publicDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True) IRQInstrClass.addDestructor(publicDestr) IRQInstrClasses.append(IRQInstrClass) return IRQInstrClasses
def getCPPIRQInstr(self, model, trace, namespace): from procWriter import instrCtorParams, instrCtorValues instructionType = cxx_writer.Type("Instruction", '#include "instructions.hpp"') from registerWriter import registerType IRQInstrClasses = [] emptyBody = cxx_writer.Code("") for irq in self.irqs: IRQInstrMembers = [] # Methods: get_id() getIdBody = cxx_writer.Code("return (unsigned)-1;") getIdMethod = cxx_writer.Method( "get_id", getIdBody, cxx_writer.uintType, "public", noException=True, const=True ) IRQInstrMembers.append(getIdMethod) # Methods: get_name() getNameBody = cxx_writer.Code('return "' + irq.name + 'IntrInstruction";') getNameMethod = cxx_writer.Method( "get_name", getNameBody, cxx_writer.stringType, "public", noException=True, const=True ) IRQInstrMembers.append(getNameMethod) # Methods: get_mnemonic() getMnemonicBody = cxx_writer.Code('return "' + irq.name + '";') getMnemonicMethod = cxx_writer.Method( "get_mnemonic", getMnemonicBody, cxx_writer.stringType, "public", noException=True, const=True ) IRQInstrMembers.append(getMnemonicMethod) # Methods: replicate() replicateBody = cxx_writer.Code( "return new " + irq.name + "IntrInstruction(" + instrCtorValues + ", this->" + irq.name + ");" ) replicateMethod = cxx_writer.Method( "replicate", replicateBody, instructionType.makePointer(), "public", parameters=[cxx_writer.Parameter("instr", instructionType.makePointer(), initValue="NULL")], noException=True, const=True, ) IRQInstrMembers.append(replicateMethod) # Methods: behavior() for pipeStage in self.pipes: behaviorUserCode = "" if irq.operation.has_key(pipeStage.name): behaviorUserCode += "{\nunsigned num_cycles = 0;\n" behaviorUserCode += str(irq.operation[pipeStage.name]) behaviorUserCode += "this->" if model.startswith("acc"): behaviorUserCode += "num_stage_cycles" else: behaviorUserCode += "num_instr_cycles" behaviorUserCode += " += num_cycles;\n}\n" if model.startswith("acc"): behaviorCode = "this->num_stage_cycles = 0;\n" if behaviorUserCode: # Set the pipeline stage so that the usage of the registers # is transparent to the user. behaviorCode += "\nR.set_stage(" + str(self.pipes.index(pipeStage)) + ");\n" behaviorCode += behaviorUserCode behaviorCode += "\nR.unset_stage();\n" behaviorCode += "return this->num_stage_cycles;\n" behaviorBody = cxx_writer.Code(behaviorCode) behaviorMethod = cxx_writer.Method( "behavior_" + pipeStage.name, behaviorBody, cxx_writer.uintType, "public" ) IRQInstrMembers.append(behaviorMethod) if not model.startswith("acc"): behaviorCode = "this->num_instr_cycles = 0;\n" behaviorCode += behaviorUserCode behaviorCode += "return this->num_instr_cycles;\n" behaviorBody = cxx_writer.Code(behaviorCode) behaviorMethod = cxx_writer.Method("behavior", behaviorBody, cxx_writer.uintType, "public") IRQInstrMembers.append(behaviorMethod) # Methods: set_interrupt_value() # Sets the value of the received interrupt and the related attribute. from isa import resolveBitType irqWidthType = resolveBitType("BIT<" + str(irq.portWidth) + ">") IRQAttr = cxx_writer.Attribute(irq.name, irqWidthType.makeRef(), "public") IRQInstrMembers.append(IRQAttr) IRQInstrCtorParams = [cxx_writer.Parameter(irq.name, irqWidthType.makeRef())] IRQInstrCtorInit = [irq.name + "(" + irq.name + ")"] InterruptValueParam = cxx_writer.Parameter("interrupt_value", irqWidthType.makeRef().makeConst()) setInterruptValueBody = cxx_writer.Code("this->" + irq.name + " = interrupt_value;") setInterruptValueMethod = cxx_writer.Method( "set_interrupt_value", setInterruptValueBody, cxx_writer.voidType, "public", [InterruptValueParam], noException=True, inline=True, ) IRQInstrMembers.append(setInterruptValueMethod) # Attributes for var in irq.variables: IRQInstrMembers.append(cxx_writer.Attribute(var.name, var.varType, "protected", var.static)) # Constructors and Destructors IRQInstrCtor = cxx_writer.Constructor( emptyBody, "public", parameters=instrCtorParams + IRQInstrCtorParams, initList=["Instruction(" + instrCtorValues + ")"] + IRQInstrCtorInit, ) IRQInstrDtor = cxx_writer.Destructor(emptyBody, "public", True) # Class IRQInstrClass = cxx_writer.ClassDeclaration( irq.name + "IntrInstruction", IRQInstrMembers, [instructionType], namespaces=[namespace] ) IRQInstrClass.addDocString( brief="IRQ Instruction Class", detail="Wraps IRQ exception handling behavior as a dummy instruction." ) IRQInstrClass.addConstructor(IRQInstrCtor) IRQInstrClass.addDestructor(IRQInstrDtor) IRQInstrClasses.append(IRQInstrClass) return IRQInstrClasses
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
def getGetIRQInstr(self, model, trace, namespace): from pipelineWriter import hasCheckHazard instructionType = cxx_writer.writer_code.Type('Instruction', 'instructions.hpp') emptyBody = cxx_writer.writer_code.Code('') IRQInstrClasses = [] for irq in self.irqs: IRQInstrElements = [] # now I have to go over the behavior of this interrupt and create, like for the instructions, # the behavior for the different pipeline stages if not model.startswith('acc'): behaviorCode = 'this->totalInstrCycles = 0;\n' userDefineBehavior = '' for pipeStage in self.pipes: userDefineBehavior = '' if model.startswith('acc'): behaviorCode = 'this->stageCycles = 0;\n' if irq.operation.has_key(pipeStage.name): userDefineBehavior += str(irq.operation[pipeStage.name]) if model.startswith('acc'): # now I have to take all the resources and create a define which # renames such resources so that their usage can be transparent # to the developer for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks: behaviorCode += '#define ' + reg.name + ' ' + reg.name + '_' + pipeStage.name + '\n' behaviorCode += '\n' behaviorCode += userDefineBehavior if model.startswith('acc'): for reg in self.regs + self.regBanks + self.aliasRegs + self.aliasRegBanks: behaviorCode += '#undef ' + reg.name + '\n' if model.startswith('acc'): behaviorCode += 'return this->stageCycles;\n\n' registerType = cxx_writer.writer_code.Type('Register') unlockQueueType = cxx_writer.writer_code.TemplateType('std::map', ['unsigned int', cxx_writer.writer_code.TemplateType('std::vector', [registerType.makePointer()], 'vector')], 'map') unlockQueueParam = cxx_writer.writer_code.Parameter('unlockQueue', unlockQueueType.makeRef()) behaviorBody = cxx_writer.writer_code.Code(behaviorCode) behaviorDecl = cxx_writer.writer_code.Method('behavior_' + pipeStage.name, behaviorBody, cxx_writer.writer_code.uintType, 'pu', [unlockQueueParam]) IRQInstrElements.append(behaviorDecl) if not model.startswith('acc'): behaviorCode += 'return this->totalInstrCycles;' behaviorBody = cxx_writer.writer_code.Code(behaviorCode) behaviorDecl = cxx_writer.writer_code.Method('behavior', behaviorBody, cxx_writer.writer_code.uintType, 'pu') IRQInstrElements.append(behaviorDecl) # Standard Instruction methods, there is not much to do since the IRQ instruction does nothing special from procWriter import baseInstrInitElement replicateBody = cxx_writer.writer_code.Code('return new IRQ_' + irq.name + '_Instruction(' + baseInstrInitElement + ', this->' + irq.name + ');') replicateDecl = cxx_writer.writer_code.Method('replicate', replicateBody, instructionType.makePointer(), 'pu', noException = True, const = True) IRQInstrElements.append(replicateDecl) setparamsParam = cxx_writer.writer_code.Parameter('bitString', self.bitSizes[1].makeRef().makeConst()) setparamsDecl = cxx_writer.writer_code.Method('setParams', emptyBody, cxx_writer.writer_code.voidType, 'pu', [setparamsParam], noException = True) IRQInstrElements.append(setparamsDecl) getIstructionNameBody = cxx_writer.writer_code.Code('return \"IRQ_' + irq.name + '_Instruction\";') getIstructionNameDecl = cxx_writer.writer_code.Method('getInstructionName', getIstructionNameBody, cxx_writer.writer_code.stringType, 'pu', noException = True, const = True) IRQInstrElements.append(getIstructionNameDecl) getMnemonicBody = cxx_writer.writer_code.Code('return \"irq_' + irq.name + '\";') getMnemonicDecl = cxx_writer.writer_code.Method('getMnemonic', getMnemonicBody, cxx_writer.writer_code.stringType, 'pu', noException = True, const = True) IRQInstrElements.append(getMnemonicDecl) getIdBody = cxx_writer.writer_code.Code('return (unsigned int)-1;') getIdDecl = cxx_writer.writer_code.Method('getId', getIdBody, cxx_writer.writer_code.uintType, 'pu', noException = True, const = True) IRQInstrElements.append(getIdDecl) # Now we have all the methods related to data hazards detection and management: # TODO: is an implementation needed for the IRQ instruction? if model.startswith('acc'): if hasCheckHazard: for pipeStage in self.pipes: checkHazardDecl = cxx_writer.writer_code.Method('checkHazard_' + pipeStage.name, emptyBody, cxx_writer.writer_code.boolType, 'pu') IRQInstrElements.append(checkHazardDecl) lockDecl = cxx_writer.writer_code.Method('lockRegs_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu') IRQInstrElements.append(lockDecl) unlockHazard = False for pipeStage in self.pipes: if pipeStage.checkHazard: unlockHazard = True if unlockHazard: getUnlockDecl = cxx_writer.writer_code.Method('getUnlock_' + pipeStage.name, emptyBody, cxx_writer.writer_code.voidType, 'pu', [unlockQueueParam]) IRQInstrElements.append(getUnlockDecl) printBusyRegsDecl = cxx_writer.writer_code.Method('printBusyRegs', cxx_writer.writer_code.Code('return "";'), cxx_writer.writer_code.stringType, 'pu') IRQInstrElements.append(printBusyRegsDecl) # Here I add a method to specify the value of the received interrupt and the related attribute from isa import resolveBitType irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>') IRQAttribute = cxx_writer.writer_code.Attribute(irq.name, irqWidthType.makeRef(), 'pu') IRQInstrElements.append(IRQAttribute) irqParams = [cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef())] irqInit = [irq.name + '(' + irq.name + ')'] InterruptValueParam = cxx_writer.writer_code.Parameter('interruptValue', irqWidthType.makeRef().makeConst()) setInterruptValueBody = cxx_writer.writer_code.Code('this->' + irq.name + ' = interruptValue;') setInterruptValueDecl = cxx_writer.writer_code.Method('setInterruptValue', setInterruptValueBody, cxx_writer.writer_code.voidType, 'pu', [InterruptValueParam], noException = True, inline = True) IRQInstrElements.append(setInterruptValueDecl) # Now I declare the instruction variables for this IRQ instruction for var in irq.variables: IRQInstrElements.append(cxx_writer.writer_code.Attribute(var.name, var.varType, 'pro', var.static)) # Finally I can declare the IRQ class for this specific IRQ from procWriter import baseInstrInitElement from isaWriter import baseInstrConstrParams publicConstr = cxx_writer.writer_code.Constructor(emptyBody, 'pu', baseInstrConstrParams + irqParams, ['Instruction(' + baseInstrInitElement + ')'] + irqInit) IRQInstrClass = cxx_writer.writer_code.ClassDeclaration('IRQ_' + irq.name + '_Instruction', IRQInstrElements, [instructionType], namespaces = [namespace]) IRQInstrClass.addConstructor(publicConstr) publicDestr = cxx_writer.writer_code.Destructor(emptyBody, 'pu', True) IRQInstrClass.addDestructor(publicDestr) IRQInstrClasses.append(IRQInstrClass) return IRQInstrClasses
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
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
def getGetPipelineStages(self, trace, combinedTrace, model, namespace): global hasCheckHazard global wbStage global chStage from procWriter import resourceType # Returns the code implementing the class representing a pipeline stage pipeCodeElements = [] pipelineElements = [] constructorCode = '' constructorParamsBase = [] constructorInit = [] baseConstructorInit = '' pipeType = cxx_writer.writer_code.Type('BasePipeStage') IntructionType = cxx_writer.writer_code.Type('Instruction', includes = ['instructions.hpp']) registerType = cxx_writer.writer_code.Type('Register', includes = ['registers.hpp']) stageEndedFlag = cxx_writer.writer_code.Attribute('stageEnded', cxx_writer.writer_code.boolType, 'pu') pipelineElements.append(stageEndedFlag) constructorCode += 'this->chStalled = false;\n' constructorCode += 'this->stalled = false;\n' constructorCode += 'this->stageEnded = false;\n' stageBeginningFlag = cxx_writer.writer_code.Attribute('stageBeginning', cxx_writer.writer_code.boolType, 'pu') pipelineElements.append(stageBeginningFlag) constructorCode += 'this->stageBeginning = false;\n' hasToFlush = cxx_writer.writer_code.Attribute('hasToFlush', cxx_writer.writer_code.boolType, 'pu') pipelineElements.append(hasToFlush) constructorCode += 'this->hasToFlush = false;\n' stageEndedEvent = cxx_writer.writer_code.Attribute('stageEndedEv', cxx_writer.writer_code.sc_eventType, 'pu') pipelineElements.append(stageEndedEvent) stageBeginningEvent = cxx_writer.writer_code.Attribute('stageBeginningEv', cxx_writer.writer_code.sc_eventType, 'pu') pipelineElements.append(stageBeginningEvent) NOPIntructionType = cxx_writer.writer_code.Type('NOPInstruction', 'instructions.hpp') NOPinstructionsAttribute = cxx_writer.writer_code.Attribute('NOPInstrInstance', NOPIntructionType.makePointer(), 'pu') pipelineElements.append(NOPinstructionsAttribute) constructorCode += 'this->NOPInstrInstance = NULL;\n' # Lets declare the interrupt instructions in case we have any and we also declare the signal attribute for irq in self.irqs: IRQIntructionType = cxx_writer.writer_code.Type('IRQ_' + irq.name + '_Instruction', 'instructions.hpp') IRQinstructionAttribute = cxx_writer.writer_code.Attribute(irq.name + '_irqInstr', IRQIntructionType.makePointer(), 'pu') pipelineElements.append(IRQinstructionAttribute) constructorCode += 'this->' + irq.name + '_irqInstr = NULL;\n' latencyAttribute = cxx_writer.writer_code.Attribute('latency', cxx_writer.writer_code.sc_timeType, 'pro') pipelineElements.append(latencyAttribute) latencyParam = cxx_writer.writer_code.Parameter('latency', cxx_writer.writer_code.sc_timeType.makeRef()) constructorParamsBase.append(latencyParam) constructorInit.append('latency(latency)') baseConstructorInit += 'latency, ' curInstrAttr = cxx_writer.writer_code.Attribute('curInstruction', IntructionType.makePointer(), 'pu') pipelineElements.append(curInstrAttr) constructorCode += 'this->curInstruction = NULL;\n' nextInstrAttr = cxx_writer.writer_code.Attribute('nextInstruction', IntructionType.makePointer(), 'pu') pipelineElements.append(nextInstrAttr) constructorCode += 'this->nextInstruction = NULL;\n' flushCode = """this->hasToFlush = true; if(this->prevStage != NULL){ this->prevStage->flush(); } """ flushBody = cxx_writer.writer_code.Code(flushCode) flushDecl = cxx_writer.writer_code.Method('flush', flushBody, cxx_writer.writer_code.voidType, 'pu', noException = True) pipelineElements.append(flushDecl) for pipe in self.pipes: otherStageAttr = cxx_writer.writer_code.Attribute('stage_' + pipe.name, pipeType.makePointer(), 'pro') pipelineElements.append(otherStageAttr) otherStageParam = cxx_writer.writer_code.Parameter('stage_' + pipe.name, pipeType.makePointer()) constructorParamsBase.append(otherStageParam) constructorInit.append('stage_' + pipe.name + '(stage_' + pipe.name + ')') baseConstructorInit += 'stage_' + pipe.name + ', ' chStalledAttr = cxx_writer.writer_code.Attribute('chStalled', cxx_writer.writer_code.boolType, 'pu') pipelineElements.append(chStalledAttr) stalledAttr = cxx_writer.writer_code.Attribute('stalled', cxx_writer.writer_code.boolType, 'pu') pipelineElements.append(stalledAttr) stageAttr = cxx_writer.writer_code.Attribute('prevStage', pipeType.makePointer(), 'pu') pipelineElements.append(stageAttr) stageAttr = cxx_writer.writer_code.Attribute('succStage', pipeType.makePointer(), 'pu') pipelineElements.append(stageAttr) unlockQueueType = cxx_writer.writer_code.TemplateType('std::map', ['unsigned int', cxx_writer.writer_code.TemplateType('std::vector', [registerType.makePointer()], 'vector')], 'map') unlockQueueAttr = cxx_writer.writer_code.Attribute('unlockQueue', unlockQueueType, 'pro', static = True) pipelineElements.append(unlockQueueAttr) prevStageParam = cxx_writer.writer_code.Parameter('prevStage', pipeType.makePointer(), initValue = 'NULL') succStageParam = cxx_writer.writer_code.Parameter('succStage', pipeType.makePointer(), initValue = 'NULL') constructorParamsBase.append(prevStageParam) constructorParamsBase.append(succStageParam) constructorInit.append('prevStage(prevStage)') constructorInit.append('succStage(succStage)') baseConstructorInit += 'prevStage, ' baseConstructorInit += 'succStage, ' pipelineDecl = cxx_writer.writer_code.ClassDeclaration('BasePipeStage', pipelineElements, namespaces = [namespace]) constructorBody = cxx_writer.writer_code.Code(constructorCode) publicPipelineConstr = cxx_writer.writer_code.Constructor(constructorBody, 'pu', constructorParamsBase, constructorInit) pipelineDecl.addConstructor(publicPipelineConstr) pipeCodeElements.append(pipelineDecl) hasCheckHazard = False hasWb = False for pipeStage in self.pipes: if pipeStage.checkHazard: if self.pipes.index(pipeStage) + 1 < len(self.pipes): if not self.pipes[self.pipes.index(pipeStage) + 1].endHazard: hasCheckHazard = True if pipeStage.endHazard: if self.pipes.index(pipeStage) - 1 >= 0: if not self.pipes[self.pipes.index(pipeStage) - 1].checkHazard: hasWb = True # Now lets determine the stages which need a call to check hazard #checkHazadsStagesDecl = [] #if hasCheckHazard: #for instr in self.isa.instructions.values(): #for stageName in instr.specialInRegs.keys(): #if not stageName in checkHazadsStagesDecl: #checkHazadsStagesDecl.append(stageName) # Remember that all the stages preceding the the last one where we check for # hazards have to check if the following stages are stalled. # Now I have to actually declare the different pipeline stages, all of them being equal a part from # the fecth stage which have to fetch instructions and check interrupts before calling # the appropriate behavior method checkHazardsMet = False wbStage = self.pipes[-1] chStage = self.pipes[0] seenStages = 0 for pipeStage in self.pipes: seenStages += 1 if pipeStage.wb: wbStage = pipeStage if pipeStage.checkHazard: chStage = pipeStage pipeNameParam = cxx_writer.writer_code.Parameter('pipeName', cxx_writer.writer_code.sc_module_nameType) curPipeElements = [] constructorCode = '' constructorInit = [] constructorParams = [pipeNameParam] + constructorParamsBase codeString = """this->curInstruction = this->NOPInstrInstance; this->nextInstruction = this->NOPInstrInstance; """ if pipeStage == self.pipes[0]: # This is the fetch pipeline stage, I have to fetch instructions codeString += 'unsigned int numNOPS = 0;\n' codeString += 'bool startMet = false;\n' if self.instructionCache: codeString += 'template_map< ' + str(self.bitSizes[1]) + ', CacheElem >::iterator instrCacheEnd = this->instrCache.end();\n\n' codeString += 'while(true){\n' # Here is the code to notify start of the instruction execution codeString += 'this->instrExecuting = true;\n' codeString += 'unsigned int numCycles = 0;\n' if hasCheckHazard: codeString += 'if(!this->chStalled){\n' codeString += '\n// HERE WAIT FOR BEGIN OF ALL STAGES\nthis->waitPipeBegin();\n' # Here is the code to deal with interrupts; note one problem: if an interrupt is raised, we need to # deal with it in the correct stage, i.e. we need to create a special instruction reaching the correct # stage and dealing with it properly. codeString += getInterruptCode(self, trace, pipeStage) # computes the correct memory and/or memory port from which fetching the instruction stream fetchCode = computeFetchCode(self) # computes the address from which the next instruction shall be fetched fetchAddress = computeCurrentPC(self, model) codeString += str(self.bitSizes[1]) + ' curPC = ' + fetchAddress + ';\n' # Here is the code for updating cycle counts codeString += """if(!startMet && curPC == this->profStartAddr){ this->profTimeStart = sc_time_stamp(); } if(startMet && curPC == this->profEndAddr){ this->profTimeEnd = sc_time_stamp(); } """ # Now lets start with the code necessary to check the tools, to see if they need # the pipeline to be empty before being able to procede with execution codeString += """ #ifndef DISABLE_TOOLS // code necessary to check the tools, to see if they need // the pipeline to be empty before being able to procede with execution if(this->toolManager.emptyPipeline(curPC)){ numNOPS++; } else{ numNOPS = 0; } if(numNOPS > 0 && numNOPS < """ + str(len(self.pipes)) + """){ this->curInstruction = this->NOPInstrInstance; """ if trace and not combinedTrace: codeString += 'std::cerr << \"PC: \" << std::hex << std::showbase << curPC << " propagating NOP because tools need it" << std::endl;\n' codeString += """} else{ numNOPS = 0; #endif wait(this->latency); //Ok, either the pipeline is empty or there is not tool which needs the pipeline //to be empty: I can procede with the execution """ # Lets start with the code for the instruction queue codeString += """#ifdef ENABLE_HISTORY HistoryInstrType instrQueueElem; if(this->historyEnabled){ instrQueueElem.cycle = (unsigned int)(sc_time_stamp()/this->latency); instrQueueElem.address = curPC; } #endif """ # We need to fetch the instruction ... only if the cache is not used or if # the index of the cache is the current instruction if not (self.instructionCache and self.fastFetch): codeString += fetchCode if trace and not combinedTrace: codeString += 'std::cerr << \"Fetching PC: \" << std::hex << std::showbase << curPC << std::endl;\n' # Now lets starts the real instruction fetch: two paths are possible: the instruction buffer # and the normal instruction stream. if self.instructionCache: codeString += fetchWithCacheCode(self, fetchCode, trace, combinedTrace, getInstrIssueCodePipe, hasCheckHazard, pipeStage) else: codeString += standardInstrFetch(self, trace, combinedTrace, getInstrIssueCodePipe, hasCheckHazard, pipeStage) # Lets finish with the code for the instruction queue: I just still have to # check if it is time to save to file the instruction queue codeString += """#ifdef ENABLE_HISTORY if(this->historyEnabled){ // First I add the new element to the queue this->instHistoryQueue.push_back(instrQueueElem); //Now, in case the queue dump file has been specified, I have to check if I need to save it if(this->histFile){ this->undumpedHistElems++; if(undumpedHistElems == this->instHistoryQueue.capacity()){ boost::circular_buffer<HistoryInstrType>::const_iterator beg, end; for(beg = this->instHistoryQueue.begin(), end = this->instHistoryQueue.end(); beg != end; beg++){ this->histFile << beg->toStr() << std::endl; } this->undumpedHistElems = 0; } } } #endif """ # Finally we have completed waiting for the other cycles in order to be able to go on # with this cycle. codeString += """this->numInstructions++; #ifndef DISABLE_TOOLS } #endif """ if self.irqs: codeString += '}\n' codeString += """wait(numCycles*this->latency); // HERE WAIT FOR END OF ALL STAGES this->waitPipeEnd(); """ codeString += """ // Now I have to propagate the instruction to the next cycle if // the next stage has completed elaboration if(this->hasToFlush){ if(this->curInstruction->toDestroy){ delete this->curInstruction; } else{ this->curInstruction->inPipeline = false; } this->curInstruction = this->NOPInstrInstance; this->nextInstruction = this->NOPInstrInstance; this->hasToFlush = false; } """ codeString += 'this->succStage->nextInstruction = this->curInstruction;\n' if hasCheckHazard: codeString += """} else{ //The current stage is not doing anything since one of the following stages //is blocked to a data hazard. this->waitPipeBegin(); //Note that I need to return controll to the scheduler, otherwise //I will be impossible to procede, this thread will always execute wait(this->latency); this->waitPipeEnd(); if(this->hasToFlush){ if(this->curInstruction->toDestroy){ delete this->curInstruction; } else{ this->curInstruction->inPipeline = false; } this->curInstruction = this->NOPInstrInstance; this->nextInstruction = this->NOPInstrInstance; this->hasToFlush = false; } } """ # Here is the code to notify start of the instruction execution codeString += """this->refreshRegisters(); this->instrExecuting = false; this->instrEndEvent.notify(); """ # Now I have to insert the code for checking the presence of hazards; # in particular I have to see if the instruction to be executed next in # the checkHazardsStage will lock if hasCheckHazard: codeString += 'Instruction * succToCheck = this->' for pipeStageTemp in self.pipes: if pipeStageTemp.checkHazard: break else: codeString += 'succStage->' codeString += 'nextInstruction;\n' codeString += 'if(!succToCheck->checkHazard_' + pipeStageTemp.name + '()){\n' codeTemp = 'this->' for pipeStageTemp in self.pipes: codeString += codeTemp + 'chStalled = true;\n' codeTemp += 'succStage->' if pipeStageTemp.checkHazard: break codeString += '}\nelse{\n' codeTemp = 'this->' for pipeStageTemp in self.pipes: codeString += codeTemp + 'chStalled = false;\n' codeTemp += 'succStage->' if pipeStageTemp.checkHazard: break codeString += '}\n' if trace and not combinedTrace: codeString += 'std::cerr << \"---------------------------------------------------------------\" << std::endl << std::endl;\n' codeString += '}\n' else: # This is a normal pipeline stage # First of all I have to wait for the completion of the other pipeline stages before being able # to go on. if hasCheckHazard and not checkHazardsMet: codeString += 'Instruction * nextStageInstruction;\n' codeString += """while(true){ unsigned int numCycles = 0; bool flushAnnulled = false; // HERE WAIT FOR BEGIN OF ALL STAGES this->waitPipeBegin(); this->curInstruction = this->nextInstruction; """ if hasCheckHazard and not checkHazardsMet: codeString += 'if(!this->chStalled){\n' codeString += 'wait((' + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n' if trace and not combinedTrace: codeString += 'std::cerr << \"Stage ' + pipeStage.name + ' instruction at PC = \" << std::hex << std::showbase << this->curInstruction->fetchPC << std::endl;\n' #if hasCheckHazard and pipeStage.name in checkHazadsStagesDecl: if hasCheckHazard and pipeStage.checkHazard: codeString += 'this->curInstruction->lockRegs_' + pipeStage.name + '();\n' if trace and combinedTrace and pipeStage == self.pipes[-1]: codeString += 'if(this->curInstruction != this->NOPInstrInstance){\n' codeString += 'std::cerr << \"Current PC: \" << std::hex << std::showbase << this->curInstruction->fetchPC << std::endl;\n' codeString += '}\n' # Now we issue the instruction, i.e. we execute its behavior related to this pipeline stage codeString += getInstrIssueCodePipe(self, trace, combinedTrace, 'this->curInstruction', hasCheckHazard, pipeStage) # Finally I finalize the pipeline stage by synchrnonizing with the others codeString += 'wait((numCycles + ' + str(float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n' codeString += """// flushing current stage if(this->curInstruction->flushPipeline || flushAnnulled){ this->curInstruction->flushPipeline = false; //Now I have to flush the preceding pipeline stages this->prevStage->flush(); } """ if not hasCheckHazard or checkHazardsMet: codeString += """// HERE WAIT FOR END OF ALL STAGES this->waitPipeEnd(); """ if pipeStage != self.pipes[-1]: codeString += """if(this->hasToFlush){ if(this->curInstruction->toDestroy){ delete this->curInstruction; } else{ this->curInstruction->inPipeline = false; } // First of all I have to free any used resource in case there are any this->curInstruction = this->NOPInstrInstance; this->nextInstruction = this->NOPInstrInstance; this->hasToFlush = false; } """ if hasCheckHazard and not checkHazardsMet: codeString += 'nextStageInstruction = this->curInstruction;\n' if pipeStage == self.pipes[-1]: # Here I have to check if it is the case of destroying the instruction codeString += 'if(this->curInstruction->toDestroy){\n' codeString += 'delete this->curInstruction;\n' codeString += '}\n' codeString += 'else{\n' codeString += 'this->curInstruction->inPipeline = false;\n' codeString += '}\n' if hasCheckHazard and not checkHazardsMet: codeString += """} else{ //The current stage is not doing anything since one of the following stages //is blocked to a data hazard. //Note that I need to return controll to the scheduler, otherwise //I will be impossible to procede, this thread will always execute wait(this->latency); """ if trace and hasCheckHazard and pipeStage.checkHazard and not combinedTrace: codeString += """std::cerr << "Stage: """ + pipeStage.name + """ - Instruction " << this->curInstruction->getInstructionName() << " Mnemonic = " << this->curInstruction->getMnemonic() << " at PC = " << std::hex << std::showbase << this->curInstruction->fetchPC << " stalled on a data hazard" << std::endl; std::cerr << "Stalled registers: " << this->curInstruction->printBusyRegs() << std::endl << std::endl; """ codeString += """if(this->hasToFlush){ if(this->curInstruction->toDestroy){ delete this->curInstruction; } else{ this->curInstruction->inPipeline = false; } // First of all I have to free any used resource in case there are any this->curInstruction = this->NOPInstrInstance; this->nextInstruction = this->NOPInstrInstance; this->hasToFlush = false; } nextStageInstruction = this->NOPInstrInstance; } """ if hasCheckHazard and not checkHazardsMet: codeString += """// HERE WAIT FOR END OF ALL STAGES this->waitPipeEnd(); """ if pipeStage != self.pipes[-1]: if checkHazardsMet: codeString += 'this->succStage->nextInstruction = this->curInstruction;\n' else: codeString += 'this->succStage->nextInstruction = nextStageInstruction;\n' codeString += '}\n' if pipeStage.checkHazard: checkHazardsMet = True behaviorMethodBody = cxx_writer.writer_code.Code(codeString) behaviorMethodDecl = cxx_writer.writer_code.Method('behavior', behaviorMethodBody, cxx_writer.writer_code.voidType, 'pu') curPipeElements.append(behaviorMethodDecl) constructorCode += 'SC_THREAD(behavior);\n' waitPipeBeginCode = """this->stageBeginning = true; this->stageBeginningEv.notify(); """ for pipeStageInner in self.pipes: if pipeStageInner != pipeStage: waitPipeBeginCode += """if(!this->stage_""" + pipeStageInner.name + """->stageBeginning){ wait(this->stage_""" + pipeStageInner.name + """->stageBeginningEv); } """ waitPipeBeginCode += 'this->stageEnded = false;' waitPipeBeginBody = cxx_writer.writer_code.Code(waitPipeBeginCode) waitPipeBeginDecl = cxx_writer.writer_code.Method('waitPipeBegin', waitPipeBeginBody, cxx_writer.writer_code.voidType, 'pri', noException = True) curPipeElements.append(waitPipeBeginDecl) waitPipeEndCode = """this->stageBeginning = false; this->stageEnded = true; this->stageEndedEv.notify(); """ for pipeStageInner in self.pipes: if pipeStageInner != pipeStage: waitPipeEndCode += """if(!this->stage_""" + pipeStageInner.name + """->stageEnded){ wait(this->stage_""" + pipeStageInner.name + """->stageEndedEv); } """ waitPipeEndBody = cxx_writer.writer_code.Code(waitPipeEndCode) waitPipeEndDecl = cxx_writer.writer_code.Method('waitPipeEnd', waitPipeEndBody, cxx_writer.writer_code.voidType, 'pri', noException = True) curPipeElements.append(waitPipeEndDecl) IntructionType = cxx_writer.writer_code.Type('Instruction', 'instructions.hpp') IntructionTypePtr = IntructionType.makePointer() pipelineStageMap = {} notCheckStages = [] checkHazardsStageMet = False for curPipeMap in self.pipes: pipelineStageMap[curPipeMap.name] = curPipeMap if checkHazardsStageMet: notCheckStages.append(curPipeMap.name) if curPipeMap.checkHazard: checkHazardsStageMet = True if pipeStage == self.pipes[0]: # I create the refreshRegisters method; note that in order to update the registers # i simply have to call the "propagate" method; I also have to deal with the update of the alias # by manually moving the pointer to the pipeline register from one stage alias to # the other to update the alias codeString = '// Now we update the registers to propagate the values in the pipeline\n' for reg in self.regs: codeString += 'if(this->' + reg.name + '.hasToPropagate){\n' ######## if trace and not combinedTrace: codeString += 'std::cerr << "Propagating register ' + reg.name + '" << std::endl;\n' ######## codeString += 'this->' + reg.name + '.propagate();\n' codeString += '}\n' for regB in self.regBanks: codeString += 'for(int i = 0; i < ' + str(regB.numRegs) + '; i++){\n' codeString += 'if(this->' + regB.name + '[i].hasToPropagate){\n' ######## if trace and not combinedTrace: codeString += 'std::cerr << "Propagating register ' + regB.name + '[" << std::dec << i << "]" << std::endl;\n' ######## codeString += 'this->' + regB.name + '[i].propagate();\n' codeString += '}\n}\n' # Now lets procede to the update of the alias: for each stage alias I have to copy the reference # of the general pipeline register from one stage to the other codeString += '\n//Here we update the aliases, so that what they point to is updated in the pipeline\n' for i in reversed(range(0, len(self.pipes) -1)): for alias in self.aliasRegs: if not alias.isFixed: codeString += 'if(this->' + alias.name + '_' + self.pipes[i + 1].name + '.getPipeReg() != this->' + alias.name + '_' + self.pipes[i].name + '.getPipeReg()){\n' if trace and not combinedTrace: codeString += 'std::cerr << "Updating alias ' + alias.name + '_' + self.pipes[i + 1].name + '" << std::endl;\n' codeString += 'this->' + alias.name + '_' + self.pipes[i + 1].name + '.propagateAlias(*(this->' + alias.name + '_' + self.pipes[i].name + '.getPipeReg()));\n' codeString += '}\n' for aliasB in self.aliasRegBanks: checkContiguous = True for j in range(0, len(aliasB.fixedIndices) - 1): if aliasB.fixedIndices[j] + 1 != aliasB.fixedIndices[j + 1]: checkContiguous = False break if checkContiguous: if aliasB.fixedIndices[0] > 0: if aliasB.checkGroup: codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[0].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[0].getPipeReg()){\n' codeString += 'for(int i = 0; i < ' + str(aliasB.fixedIndices[-1]) + '; i++){\n' if not aliasB.checkGroup: codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()){\n' if trace and not combinedTrace: codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << i << "]" << std::endl;\n' codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()));\n' codeString += '}\n' codeString += '}\n' if aliasB.fixedIndices[-1] + 1 < aliasB.numRegs: if aliasB.checkGroup: codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(aliasB.fixedIndices[-1] + 1) + '].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(aliasB.fixedIndices[-1] + 1) + '].getPipeReg()){\n' codeString += 'for(int i = ' + str(aliasB.fixedIndices[-1] + 1) + '; i < ' + str(aliasB.numRegs) + '; i++){\n' if not aliasB.checkGroup: codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()){\n' if trace and not combinedTrace: codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << i << "]" << std::endl;\n' codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[i].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[i].getPipeReg()));\n' codeString += '}\n' codeString += '}\n' else: for j in range(0, aliasB.numRegs): if not j in aliasB.fixedIndices: codeString += 'if(this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(j) + '].getPipeReg() != this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(j) + '].getPipeReg()){\n' if trace and not combinedTrace: codeString += 'std::cerr << "Updating alias ' + aliasB.name + '_' + self.pipes[i + 1].name + '[" << ' + str(i) + ' << "]" << std::endl;\n' codeString += 'this->' + aliasB.name + '_' + self.pipes[i + 1].name + '[' + str(j) + '].propagateAlias(*(this->' + aliasB.name + '_' + self.pipes[i].name + '[' + str(j) + '].getPipeReg()));\n' codeString += '}\n' # Now I have to produce the code for unlocking the registers in the unlockQueue codeString += """ // Finally registers are unlocked, so that stalls due to data hazards can be resolved std::map<unsigned int, std::vector<Register *> >::iterator unlockQueueIter, unlockQueueEnd; for(unlockQueueIter = BasePipeStage::unlockQueue.begin(), unlockQueueEnd = BasePipeStage::unlockQueue.end(); unlockQueueIter != unlockQueueEnd; unlockQueueIter++){ std::vector<Register *>::iterator regToUnlockIter, regToUnlockEnd; if(unlockQueueIter->first == 0){ for(regToUnlockIter = unlockQueueIter->second.begin(), regToUnlockEnd = unlockQueueIter->second.end(); regToUnlockIter != regToUnlockEnd; regToUnlockIter++){ (*regToUnlockIter)->unlock(); } } else{ for(regToUnlockIter = unlockQueueIter->second.begin(), regToUnlockEnd = unlockQueueIter->second.end(); regToUnlockIter != regToUnlockEnd; regToUnlockIter++){ (*regToUnlockIter)->unlock(unlockQueueIter->first); } } unlockQueueIter->second.clear(); } """ refreshRegistersBody = cxx_writer.writer_code.Code(codeString) refreshRegistersDecl = cxx_writer.writer_code.Method('refreshRegisters', refreshRegistersBody, cxx_writer.writer_code.voidType, 'pri', noException = True) curPipeElements.append(refreshRegistersDecl) # Here I declare the references to the pipeline registers and to the alias pipeRegisterType = cxx_writer.writer_code.Type('PipelineRegister', 'registers.hpp') for reg in self.regs: if self.fetchReg[0] != reg.name: attribute = cxx_writer.writer_code.Attribute(reg.name, pipeRegisterType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(reg.name, pipeRegisterType.makeRef())] + constructorParams constructorInit.append(reg.name + '(' + reg.name + ')') curPipeElements.append(attribute) for regB in self.regBanks: attribute = cxx_writer.writer_code.Attribute(regB.name, pipeRegisterType.makePointer(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(regB.name, pipeRegisterType.makePointer())] + constructorParams constructorInit.append(regB.name + '(' + regB.name + ')') curPipeElements.append(attribute) aliasType = cxx_writer.writer_code.Type('Alias', 'alias.hpp') for pipeStageInner in self.pipes: for alias in self.aliasRegs: attribute = cxx_writer.writer_code.Attribute(alias.name + '_' + pipeStageInner.name, aliasType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(alias.name + '_' + pipeStageInner.name, aliasType.makeRef())] + constructorParams constructorInit.append(alias.name + '_' + pipeStageInner.name + '(' + alias.name + '_' + pipeStageInner.name + ')') curPipeElements.append(attribute) for aliasB in self.aliasRegBanks: attribute = cxx_writer.writer_code.Attribute(aliasB.name + '_' + pipeStageInner.name, aliasType.makePointer(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(aliasB.name + '_' + pipeStageInner.name, aliasType.makePointer())] + constructorParams constructorInit.append(aliasB.name + '_' + pipeStageInner.name + '(' + aliasB.name + '_' + pipeStageInner.name + ')') curPipeElements.append(attribute) # I have to also instantiate the reference to the memories, in order to be able to # fetch instructions if self.memory: # I perform the fetch from the local memory memName = self.memory[0] memType = cxx_writer.writer_code.Type('LocalMemory', 'memory.hpp').makeRef() else: for name, isFetch in self.tlmPorts.items(): if isFetch: memName = name memType = cxx_writer.writer_code.Type('TLMMemory', 'externalPorts.hpp').makeRef() constructorParams = [cxx_writer.writer_code.Parameter(memName, memType)] + constructorParams constructorInit.append(memName + '(' + memName + ')') memRefAttr = cxx_writer.writer_code.Attribute(memName, memType, 'pri') curPipeElements.append(memRefAttr) decoderAttribute = cxx_writer.writer_code.Attribute('decoder', cxx_writer.writer_code.Type('Decoder', 'decoder.hpp'), 'pu') curPipeElements.append(decoderAttribute) # I also have to add the map containig the ISA instructions to this stage instructionsAttribute = cxx_writer.writer_code.Attribute('INSTRUCTIONS', IntructionTypePtr.makePointer().makeRef(), 'pri') curPipeElements.append(instructionsAttribute) constructorParams = [cxx_writer.writer_code.Parameter('INSTRUCTIONS', IntructionTypePtr.makePointer().makeRef())] + constructorParams constructorInit.append('INSTRUCTIONS(INSTRUCTIONS)') # fetch register; regsNames = [i.name for i in self.regBanks + self.regs] fetchRegType = resourceType[self.fetchReg[0]] if self.fetchReg[0] in regsNames: fetchRegType = pipeRegisterType fetchAttr = cxx_writer.writer_code.Attribute(self.fetchReg[0], fetchRegType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(self.fetchReg[0], fetchRegType.makeRef())] + constructorParams constructorInit.append(self.fetchReg[0] + '(' + self.fetchReg[0] + ')') curPipeElements.append(fetchAttr) numInstructions = cxx_writer.writer_code.Attribute('numInstructions', cxx_writer.writer_code.uintType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter('numInstructions', cxx_writer.writer_code.uintType.makeRef())] + constructorParams constructorInit.append('numInstructions(numInstructions)') curPipeElements.append(numInstructions) attribute = cxx_writer.writer_code.Attribute('instrExecuting', cxx_writer.writer_code.boolType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter('instrExecuting', cxx_writer.writer_code.boolType.makeRef())] + constructorParams constructorInit.append('instrExecuting(instrExecuting)') curPipeElements.append(attribute) attribute = cxx_writer.writer_code.Attribute('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter('instrEndEvent', cxx_writer.writer_code.sc_eventType.makeRef())] + constructorParams constructorInit.append('instrEndEvent(instrEndEvent)') curPipeElements.append(attribute) for irq in self.irqs: from isa import resolveBitType irqWidthType = resolveBitType('BIT<' + str(irq.portWidth) + '>') IRQAttribute = cxx_writer.writer_code.Attribute(irq.name, irqWidthType.makeRef(), 'pri') constructorParams = [cxx_writer.writer_code.Parameter(irq.name, irqWidthType.makeRef())] + constructorParams constructorInit.append(irq.name + '(' + irq.name + ')') curPipeElements.append(IRQAttribute) if self.instructionCache: CacheElemType = cxx_writer.writer_code.Type('CacheElem') template_mapType = cxx_writer.writer_code.TemplateType('template_map', [self.bitSizes[1], CacheElemType], hash_map_include) cacheAttribute = cxx_writer.writer_code.Attribute('instrCache', template_mapType, 'pri') curPipeElements.append(cacheAttribute) # The fetch stage also contains the tools manager ToolsManagerType = cxx_writer.writer_code.TemplateType('ToolsManager', [self.bitSizes[1]], 'ToolsIf.hpp') toolManagerAttribute = cxx_writer.writer_code.Attribute('toolManager', ToolsManagerType.makeRef(), 'pri') curPipeElements.append(toolManagerAttribute) constructorParams = [cxx_writer.writer_code.Parameter('toolManager', ToolsManagerType.makeRef())] + constructorParams constructorInit.append('toolManager(toolManager)') # Lets finally declare the attributes and constructor parameters for counting the cycles in a specified time # frame profilingTimeStartAttribute = cxx_writer.writer_code.Attribute('profTimeStart', cxx_writer.writer_code.sc_timeRefType, 'pu') curPipeElements.append(profilingTimeStartAttribute) constructorParams = [cxx_writer.writer_code.Parameter('profTimeStart', cxx_writer.writer_code.sc_timeRefType)] + constructorParams constructorInit.append('profTimeStart(profTimeStart)') profilingTimeEndAttribute = cxx_writer.writer_code.Attribute('profTimeEnd', cxx_writer.writer_code.sc_timeRefType, 'pu') curPipeElements.append(profilingTimeEndAttribute) constructorParams = [cxx_writer.writer_code.Parameter('profTimeEnd', cxx_writer.writer_code.sc_timeRefType)] + constructorParams constructorInit.append('profTimeEnd(profTimeEnd)') profilingAddrStartAttribute = cxx_writer.writer_code.Attribute('profStartAddr', self.bitSizes[1], 'pu') curPipeElements.append(profilingAddrStartAttribute) constructorCode += 'this->profStartAddr = (' + str(self.bitSizes[1]) + ')-1;\n' profilingAddrEndAttribute = cxx_writer.writer_code.Attribute('profEndAddr', self.bitSizes[1], 'pu') constructorCode += 'this->profEndAddr = (' + str(self.bitSizes[1]) + ')-1;\n' curPipeElements.append(profilingAddrEndAttribute) # Here are the attributes for the instruction history queue instrQueueFileAttribute = cxx_writer.writer_code.Attribute('histFile', cxx_writer.writer_code.ofstreamType, 'pu') curPipeElements.append(instrQueueFileAttribute) historyEnabledAttribute = cxx_writer.writer_code.Attribute('historyEnabled', cxx_writer.writer_code.boolType, 'pu') curPipeElements.append(historyEnabledAttribute) constructorCode += 'this->historyEnabled = false;\n' instrHistType = cxx_writer.writer_code.Type('HistoryInstrType', 'instructionBase.hpp') histQueueType = cxx_writer.writer_code.TemplateType('boost::circular_buffer', [instrHistType], 'boost/circular_buffer.hpp') instHistoryQueueAttribute = cxx_writer.writer_code.Attribute('instHistoryQueue', histQueueType, 'pu') curPipeElements.append(instHistoryQueueAttribute) constructorCode += 'this->instHistoryQueue.set_capacity(1000);\n' undumpedHistElemsAttribute = cxx_writer.writer_code.Attribute('undumpedHistElems', cxx_writer.writer_code.uintType, 'pu') curPipeElements.append(undumpedHistElemsAttribute) constructorCode += 'this->undumpedHistElems = 0;\n' # Now, before the processor elements is destructed I have to make sure that the history dump file is correctly closed destrCode = """#ifdef ENABLE_HISTORY if(this->historyEnabled){ //Now, in case the queue dump file has been specified, I have to check if I need to save it if(this->histFile){ if(this->undumpedHistElems > 0){ std::vector<std::string> histVec; boost::circular_buffer<HistoryInstrType>::const_reverse_iterator beg, end; unsigned int histRead = 0; for(histRead = 0, beg = this->instHistoryQueue.rbegin(), end = this->instHistoryQueue.rend(); beg != end && histRead < this->undumpedHistElems; beg++, histRead++){ histVec.push_back(beg->toStr()); } std::vector<std::string>::const_reverse_iterator histVecBeg, histVecEnd; for(histVecBeg = histVec.rbegin(), histVecEnd = histVec.rend(); histVecBeg != histVecEnd; histVecBeg++){ this->histFile << *histVecBeg << std::endl; } } this->histFile.flush(); this->histFile.close(); } } #endif """ destructorBody = cxx_writer.writer_code.Code(destrCode) publicDestr = cxx_writer.writer_code.Destructor(destructorBody, 'pu') constructorInit = ['sc_module(pipeName)', 'BasePipeStage(' + baseConstructorInit[:-2] + ')'] + constructorInit curPipeDecl = cxx_writer.writer_code.SCModule(pipeStage.name.upper() + '_PipeStage', curPipeElements, [pipeType], namespaces = [namespace]) constructorBody = cxx_writer.writer_code.Code(constructorCode + 'end_module();') publicCurPipeConstr = cxx_writer.writer_code.Constructor(constructorBody, 'pu', constructorParams, constructorInit) if pipeStage == self.pipes[0]: curPipeDecl.addDestructor(publicDestr) curPipeDecl.addConstructor(publicCurPipeConstr) pipeCodeElements.append(curPipeDecl) return pipeCodeElements
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