def __init__(self, name, code, stage, exception=True, const=False, inline=False): """Code must be an instance of cxx_writer.CustomCode.""" self.name = name self.code = code self.stage = stage self.exception = exception self.const = const self.inline = inline self.localvars = [] self.parameters = [] self.retType = cxx_writer.Type('void')
def getCPPDecoder(self, fetchSizeType, instructionCache, namespace = ''): """Returns the class representing the decoder.""" import cxx_writer # Go over the decoding tree. if self.rootNode.splitFunction.pattern: codeString = self.createPatternDecoder(self.rootNode) else: codeString = self.createTableDecoder(self.rootNode) codeString += '// Invalid pattern\nreturn ' if self.invalid_instr: codeString += str(self.invalid_instr.id) else: codeString += str(self.instrNum) codeString += ';\n' code = cxx_writer.Code(codeString) parameters = [cxx_writer.Parameter('instr_code', fetchSizeType)] decodeMethod = cxx_writer.Method('decode', code, cxx_writer.intType, 'public', parameters, const = True, noException = True) decodeClass = cxx_writer.ClassDeclaration('Decoder', [decodeMethod], namespaces = [namespace]) decodeClass.addDocString(brief = 'Decoder Class', detail = 'Implements the state-machine that decodes an instruction string and returns an ID specifying the instruction.') # Declare the type which shall be contained in the cache. if instructionCache: emptyBody = cxx_writer.Code('') InstructionTypePtr = cxx_writer.Type('Instruction', '#include \"instructions.hpp\"').makePointer() instrAttr = cxx_writer.Attribute('instr', InstructionTypePtr, 'public') countAttr = cxx_writer.Attribute('count', cxx_writer.uintType, 'public') cacheTypeElements = [instrAttr, countAttr] cacheType = cxx_writer.ClassDeclaration('CacheElem', cacheTypeElements, namespaces = [namespace]) instrParam = cxx_writer.Parameter('instr', InstructionTypePtr) countParam = cxx_writer.Parameter('count', cxx_writer.uintType) cacheTypeConstr = cxx_writer.Constructor(emptyBody, 'public', [instrParam, countParam], ['instr(instr)', 'count(count)']) cacheType.addConstructor(cacheTypeConstr) emptyCacheTypeConstr = cxx_writer.Constructor(emptyBody, 'public', [], ['instr(NULL)', 'count(1)']) cacheType.addConstructor(emptyCacheTypeConstr) if instructionCache: return [cacheType, decodeClass] else: return [decodeClass]
def setSignature(self, retType=cxx_writer.Type('void'), parameters=[]): """Sets the function signature. The return type has to be an instance of cxx_writer.Type or a string representing a bit type. The parameters can either be cxx_writer.Parameter or a string representing a bit type.""" if isinstance(retType, str): self.retType = resolveBitType(retType) else: self.retType = retType for param in parameters: if isinstance(param, type(())): param = cxx_writer.Parameter(param[0], resolveBitType(param[1])) for instrVar in self.localvars: if param.name == instrVar.name: raise Exception('Cannot add parameter ' + param.name + ' to operation ' + self.name + '. Variable already exists in operation.') for lparam in self.parameters: if param.name == lparam.name: raise Exception('Cannot add parameter ' + param.name + ' to operation ' + self.name + '. Parameter already exists in operation.') self.parameters.append(param)
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 getCPPPipeline(self, trace, combinedTrace, model, namespace): # Returns the class representing a pipeline stage. from registerWriter import registerType, aliasType, registerContainerType InstructionType = cxx_writer.Type('Instruction', includes = ['#include \"instructions.hpp\"', 'iomanip']) pipeType = cxx_writer.Type('BasePipeStage') #--------------------------------------------------------------------------- ## @name Pipeline Base Class # @{ pipeClasses = [] pipeBaseMembers = [] pipeBaseCtorParams = [] pipeBaseCtorValues = '' pipeBaseCtorInit = [] pipeBaseCtorCode = '' # Attributes and Initialization for pipe in self.pipes: otherStageAttr = cxx_writer.Attribute('stage_' + pipe.name, pipeType.makePointer(), 'protected') pipeBaseMembers.append(otherStageAttr) otherStageParam = cxx_writer.Parameter('stage_' + pipe.name, pipeType.makePointer()) pipeBaseCtorParams.append(otherStageParam) pipeBaseCtorValues += 'stage_' + pipe.name + ', ' pipeBaseCtorInit.append('stage_' + pipe.name + '(stage_' + pipe.name + ')') stageAttr = cxx_writer.Attribute('prev_stage', pipeType.makePointer(), 'public') pipeBaseMembers.append(stageAttr) stageParam = cxx_writer.Parameter('prev_stage', pipeType.makePointer())#, initValue = 'NULL') pipeBaseCtorParams.append(stageParam) pipeBaseCtorValues += 'prev_stage, ' pipeBaseCtorInit.append('prev_stage(prev_stage)') stageAttr = cxx_writer.Attribute('succ_stage', pipeType.makePointer(), 'public') pipeBaseMembers.append(stageAttr) stageParam = cxx_writer.Parameter('succ_stage', pipeType.makePointer())#, initValue = 'NULL') pipeBaseCtorParams.append(stageParam) pipeBaseCtorValues += 'succ_stage, ' pipeBaseCtorInit.append('succ_stage(succ_stage)') stageBeginEventAttr = cxx_writer.Attribute('stage_begin_event', cxx_writer.sc_eventType, 'public') pipeBaseMembers.append(stageBeginEventAttr) stageEndedEventAttr = cxx_writer.Attribute('stage_end_event', cxx_writer.sc_eventType, 'public') pipeBaseMembers.append(stageEndedEventAttr) stageBeginningAttr = cxx_writer.Attribute('stage_beginning', cxx_writer.boolType, 'public') pipeBaseMembers.append(stageBeginningAttr) pipeBaseCtorCode += 'this->stage_beginning = false;\n' stageEndedAttrFlag = cxx_writer.Attribute('stage_ended', cxx_writer.boolType, 'public') pipeBaseMembers.append(stageEndedAttrFlag) pipeBaseCtorCode += 'this->stage_ended = false;\n' hasToFlushAttr = cxx_writer.Attribute('has_to_flush', cxx_writer.boolType, 'public') pipeBaseMembers.append(hasToFlushAttr) pipeBaseCtorCode += 'this->has_to_flush = false;\n' stalledAttr = cxx_writer.Attribute('stalled', cxx_writer.boolType, 'public') pipeBaseMembers.append(stalledAttr) pipeBaseCtorCode += 'this->stalled = false;\n' latencyAttr = cxx_writer.Attribute('latency', cxx_writer.sc_timeType, 'protected') pipeBaseMembers.append(latencyAttr) latencyParam = cxx_writer.Parameter('latency', cxx_writer.sc_timeType.makeRef()) pipeBaseCtorParams.append(latencyParam) pipeBaseCtorValues += 'latency, ' pipeBaseCtorInit.append('latency(latency)') registerAttr = cxx_writer.Attribute('R', registerContainerType.makeRef(), 'protected') pipeBaseMembers.append(registerAttr) registerParam = cxx_writer.Parameter('R', registerContainerType.makeRef()) pipeBaseCtorParams.append(registerParam) pipeBaseCtorValues += 'R, ' pipeBaseCtorInit.append('R(R)') NOPInstrType = cxx_writer.Type('NOPInstruction', '#include \"instructions.hpp\"') NOPInstrAttr = cxx_writer.Attribute('NOP_instr', NOPInstrType.makePointer(), 'public') pipeBaseMembers.append(NOPInstrAttr) pipeBaseCtorCode += 'this->NOP_instr = NULL;\n' # Declare the interrupt instructions if any and the corresponding signal # attribute. for irq in self.irqs: IRQInstrType = cxx_writer.Type(irq.name + 'IntrInstruction', '#include \"instructions.hpp\"') IRQInstrAttr = cxx_writer.Attribute(irq.name + '_instr', IRQInstrType.makePointer(), 'public') pipeBaseMembers.append(IRQInstrAttr) pipeBaseCtorCode += 'this->' + irq.name + '_instr = NULL;\n' curInstrAttr = cxx_writer.Attribute('cur_instr', InstructionType.makePointer(), 'public') pipeBaseMembers.append(curInstrAttr) pipeBaseCtorCode += 'cur_instr = NULL;\n' nextInstrAttr = cxx_writer.Attribute('next_instr', InstructionType.makePointer(), 'public') pipeBaseMembers.append(nextInstrAttr) pipeBaseCtorCode += 'this->next_instr = NULL;\n' # Constructors and Destructors pipeBaseCtor = cxx_writer.Constructor(cxx_writer.Code(pipeBaseCtorCode), 'public', pipeBaseCtorParams, pipeBaseCtorInit) # Methods: flush() flushCode = """this->has_to_flush = true; if (this->prev_stage != NULL) { this->prev_stage->flush(); } """ flushMethod = cxx_writer.Method('flush', cxx_writer.Code(flushCode), cxx_writer.voidType, 'public', noException = True) pipeBaseMembers.append(flushMethod) # Class pipeBaseClass = cxx_writer.ClassDeclaration('BasePipeStage', pipeBaseMembers, namespaces = [namespace]) pipeBaseClass.addConstructor(pipeBaseCtor) pipeClasses.append(pipeBaseClass) ## @} Pipeline Base Class #--------------------------------------------------------------------------- ## @name Pipeline Stage Classes # @{ from procWriter import pipeFetchAttrs, pipeCtorParams, pipeFetchCtorParams hasHazard = False hazardStarted = False seenStages = 0 for pipeStage in self.pipes: if pipeStage.regsStage: if self.pipes.index(pipeStage) + 1 < len(self.pipes): # There exist stages between the beginning and the end of the hazard. if not self.pipes[self.pipes.index(pipeStage) + 1].wbStage: hasHazard = True for pipeStage in self.pipes: seenStages += 1 pipeMembers = [] pipeCtorInit = [] if pipeStage.fetchStage: for attr in pipeFetchAttrs: pipeMembers.append(attr) pipeCtorInit.append(attr.name + '(' + attr.name + ')') pipeCtorCode = '' # Methods: behavior() Code = """cur_instr = this->NOP_instr; this->next_instr = this->NOP_instr; // Wait for SystemC infrastructure, otherwise register callbacks will crash. wait(SC_ZERO_TIME); """ if pipeStage.fetchStage: Code += 'unsigned num_NOPs = 0;\n' if self.instructionCache: Code += 'template_map< ' + str(self.bitSizes[1]) + ', CacheElem>::iterator icache_end = this->instr_cache.end();\n\n' Code += """while(true) { // Wait for other pipeline stages to begin. this->wait_pipe_begin(); unsigned num_cycles = 0; """ if pipeStage.fetchStage: Code +='this->instr_executing = true;\n' # Tool-induced Stall Detection Code += 'bool will_stall = false;\n' else: Code += """cur_instr = this->next_instr; bool instr_annulled = false; """ # Hazard Detection if hasHazard and pipeStage.decodeStage: Code += """ // Hazard Detection bool was_stalled = this->stalled, will_stall = false; // Check read registers. if (cur_instr->check_regs() > 0) { will_stall = true; // Lock write registers: Only if read registers are available, otherwise do not lock yet. } else if (!cur_instr->lock_regs()) { will_stall = true; } // Just discovered stall: Stall registers: if (!was_stalled && will_stall) { R.stall(""" + str(self.pipes.index(pipeStage)) + """); // Just discovered end of stall: Advance registers. } else if (was_stalled && !will_stall) { R.advance(); } // Stall this pipeline stage. this->stalled = will_stall; """ if hasHazard: Code += 'if (!this->stalled) {\n' if pipeStage.fetchStage: # Interrupts # If an interrupt is raised, we need to deal with it in the correct # stage, i.e. we need to create a special instruction that reaches # the correct stage and deals with the interrupt properly. Code += getInterruptCode(self, trace, pipeStage) if self.irqs: Code += 'else /* !IRQ */ {\n' # Instruction Fetch Address Code += getFetchAddressCode(self, model) # Logging and Tracing: Update cycle count. Code += """// Logging and Tracing: Update cycle count. if (cur_PC == this->profiler_start_addr) { this->profiler_time_start = sc_time_stamp(); } if (cur_PC == this->profiler_end_addr) { this->profiler_time_end = sc_time_stamp(); } """ # Tools: Check whether the tools require the pipeline to be empty # before proceeding with execution. Code += """ #ifndef DISABLE_TOOLS // Check whether the tools require the pipeline to be empty before proceeding with execution. if (this->tool_manager.is_pipeline_empty(cur_PC)) { // Pipeline is already emptying. if (num_NOPs) { num_NOPs--; will_stall = true; // Just discovered end of stall: Advance registers. if (!num_NOPs) { will_stall = false; // Do not advance registers if stall was initiated in a succeeding stage. if (!this->stalled) { R.advance(); } } } // Pipeline has to be emptied. else { num_NOPs = """ + str(len(self.pipes)-self.pipes.index(pipeStage)-1)+ """; // Stall might be shorter if pipeline already contains a bubble for some other reason. BasePipeStage* stage = this->succ_stage; while (stage) { if (stage->cur_instr != this->NOP_instr) break; num_NOPs--; stage = stage->succ_stage; } if (num_NOPs) { // Stall this pipeline stage. will_stall = true; // Just discovered stall: Stall registers: R.stall(""" + str(self.pipes.index(pipeStage)) + """); } } } else { num_NOPs = 0; } if (num_NOPs > 0 && num_NOPs < """ + str(len(self.pipes)) + """) { std::cerr << std::setw(15) << std::left << \"Stage=""" + pipeStage.name + """\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_PC << \", Instruction=NOP , Mnemonic=NOP: Propagating NOP as required by tools.\" << std::endl; wait(this->latency); """ Code += """} else { num_NOPs = 0; #endif // Either the pipeline is actually empty or no tool requires it to be so. Proceed with execution. wait((""" + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + """)*this->latency); """ # Tools: Instruction History Code += """ // Tools: Instruction History #ifdef ENABLE_HISTORY HistoryInstrType instr_queue_elem; if (this->history_en) { instr_queue_elem.cycle = (unsigned)(sc_time_stamp()/this->latency); instr_queue_elem.address = cur_PC; } #endif """ # Instruction Fetch and Issue # Computes the correct memory and/or memory port from which to # perform the fetch. doFetchCode = getDoFetchCode(self) # Perform the fetch only if the cache is not used or if the index of # the cache is the current instruction. if not (self.instructionCache and self.fastFetch): Code += doFetchCode # Two fetch paths are possible: the instruction buffer or the normal # instruction stream. # getPipeInstrIssueCode() executes this stage's instruction behavior. if self.instructionCache: Code += getCacheInstrFetchCode(self, doFetchCode, trace, combinedTrace, getPipeInstrIssueCode, hasHazard, pipeStage) else: Code += getDoDecodeCode(self, trace, combinedTrace, getPipeInstrIssueCode, hasHazard, pipeStage) if trace: if combinedTrace: Code += 'if (cur_instr != this->NOP_instr) {\n' Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \'.\' << std::endl;\n' Code += 'cur_instr->print_trace();\n' if combinedTrace: Code += '}\n' else: Code += 'wait((' + str(1 - float(seenStages - 1)/(len(self.pipes) - 1)) + ')*this->latency);\n' if trace: if not combinedTrace: Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_instr->fetch_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \'.\' << std::endl;\n' # Instruction Issue: Execute this stage's instruction behavior. Code += getPipeInstrIssueCode(self, trace, combinedTrace, hasHazard, pipeStage) # User-defined Operations if pipeStage.operation: Code += '\n// User-defined Operations\n' Code += 'this->R.set_stage(' + str(self.pipes.index(pipeStage)) + ');\n' Code += pipeStage.operation Code += 'this->R.unset_stage();\n' if pipeStage.fetchStage: # Tools: Instruction History # Check if it is time to save the instruction queue to file. Code += """ // Tools: Instruction History #ifdef ENABLE_HISTORY if (this->history_en) { // Add current instruction to history queue. this->history_instr_queue.push_back(instr_queue_elem); // In case a queue dump file has been specified, check if it needs to be saved. if (this->history_file) { this->history_undumped_elements++; if (history_undumped_elements == this->history_instr_queue.capacity()) { boost::circular_buffer<HistoryInstrType>::const_iterator history_it, history_end; for (history_it = this->history_instr_queue.begin(), history_end = this->history_instr_queue.end(); history_it != history_end; history_it++) { this->history_file << history_it->get_mnemonic() << std::endl; } this->history_undumped_elements = 0; } } } #endif """ # Synchronize with other stages. Code += """// Instruction-induced Latency wait((num_cycles + """ + str(float(seenStages - 1)/(len(self.pipes) - 1)) + """)*this->latency); """ if pipeStage.fetchStage: Code += """this->num_instructions++; #ifndef DISABLE_TOOLS } // Pipeline is empty or no tools require it to be so. #endif """ # Interrupts if self.irqs: Code += '} // if (!IRQ)\n' if pipeStage.fetchStage or (hasHazard and pipeStage.decodeStage): Code += """ // Stall pipeline stages. BasePipeStage* stage = this; while (stage) { stage->stalled = this->stalled || will_stall; stage = stage->prev_stage; } """ Code += """ // Wait for other pipeline stages to end. this->wait_pipe_end(); """ if not pipeStage.fetchStage: Code += """ // Flush pipeline. if (instr_annulled) { cur_instr->flush_pipeline = false; // Flush preceding pipeline stages. this->prev_stage->flush(); // Flush registers from this stage downwards. R.flush(""" + str(self.pipes.index(pipeStage)) + """); } else if (cur_instr->flush_pipeline) { cur_instr->flush_pipeline = false; // Flush preceding pipeline stages. this->prev_stage->flush(); // Flush registers from the preceding stage downwards. R.flush(""" + str(self.pipes.index(pipeStage)-1) + """); } """ # Stalled Due to Hazard if hasHazard: Code += """} else { // One of the following stages is blocked due to a data hazard, so the current stage is not doing anything. wait(this->latency); """ if trace: if combinedTrace and pipeStage.fetchStage: Code += 'if (cur_instr != this->NOP_instr) {\n' if not combinedTrace or pipeStage.decodeStage: Code += 'std::cerr << std::setw(15) << std::left << \"Stage=' + pipeStage.name + '\" << \", PC=\" << std::hex << std::showbase << std::setw(10) << cur_instr->fetch_PC << \", Instruction=\" << std::setw(10) << std::left << cur_instr->get_name() << \", Mnemonic=\" << cur_instr->get_mnemonic() << \": Stalled on a data hazard.\" << std::endl;\n' if pipeStage.decodeStage: Code += 'std::cerr << " Stalled registers: " << cur_instr->print_busy_regs() << std::endl;' if pipeStage.fetchStage: Code += 'cur_instr->print_trace();\n' if combinedTrace and pipeStage.fetchStage: Code += '}\n' if pipeStage.fetchStage or pipeStage.decodeStage: Code += """ // Stall pipeline stages. BasePipeStage* stage = this; while (stage) { stage->stalled = this->stalled || will_stall; stage = stage->prev_stage; } """ Code += """ // Wait for other pipeline stages to end. this->wait_pipe_end(); } // if (this->stalled) """ Code += """ // Instruction Propagation if (this->has_to_flush) { if (cur_instr->to_destroy) { delete cur_instr; } else { cur_instr->in_pipeline = false; } this->has_to_flush = false; cur_instr = this->NOP_instr; this->next_instr = this->NOP_instr; this->succ_stage->next_instr = this->NOP_instr; }""" if pipeStage.fetchStage or (hasHazard and pipeStage.decodeStage): Code += """ else if (will_stall) { // Propagate NOP because the stall is caused by the instruction in this stage. this->succ_stage->next_instr = this->NOP_instr; }""" if hasHazard and not pipeStage.decodeStage and pipeStage != self.pipes[-1]: Code += """ else if (this->stalled) { // Retain next_instr = cur_instr in the following stage. this->succ_stage->next_instr = this->succ_stage->cur_instr; }""" if pipeStage != self.pipes[-1]: Code += """ else { this->succ_stage->next_instr = cur_instr; } """ #if hasHazard and pipeStage.decodeStage: # Code += """ else if (will_stall) { # // Propagate NOP because the stall is caused by the instruction in this stage. # this->succ_stage->next_instr = this->NOP_instr; # } else { # this->succ_stage->next_instr = cur_instr; # } # """ #elif hasHazard and pipeStage != self.pipes[-1]: # Code += """ else if (this->stalled) { # // Retain next_instr = cur_instr in the following stage. # this->succ_stage->next_instr = this->succ_stage->cur_instr; # } else { # this->succ_stage->next_instr = cur_instr; # } # """ #elif pipeStage != self.pipes[-1]: # Code += '\nthis->succ_stage->next_instr = cur_instr;\n' if pipeStage.fetchStage: # Register Propagation and Instruction Execution State Code += """ // Register Propagation this->refresh_registers(); this->instr_executing = false; this->instr_end_event.notify(); """ if pipeStage.fetchStage and trace and not combinedTrace: Code += 'std::cerr << \"------------------------------------------------------------------------\" << std::endl << std::endl;\n' Code += '} // while (true)\n' if pipeStage.regsStage: hazardStarted = True behaviorMethod = cxx_writer.Method('behavior', cxx_writer.Code(Code), cxx_writer.voidType, 'public') pipeMembers.append(behaviorMethod) pipeCtorCode += 'SC_THREAD(behavior);\n' # Methods: wait_pipe_begin() Code = """this->stage_beginning = true; this->stage_begin_event.notify(); """ for pipeStageInner in self.pipes: if pipeStageInner != pipeStage: Code += """if (!this->stage_""" + pipeStageInner.name + """->stage_beginning) { wait(this->stage_""" + pipeStageInner.name + """->stage_begin_event); } """ Code += 'this->stage_ended = false;' waitPipeBeginMethod = cxx_writer.Method('wait_pipe_begin', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True) pipeMembers.append(waitPipeBeginMethod) # Methods: wait_pipe_end() Code = """this->stage_beginning = false; this->stage_ended = true; this->stage_end_event.notify(); """ for pipeStageInner in self.pipes: if pipeStageInner != pipeStage: Code += """if (!this->stage_""" + pipeStageInner.name + """->stage_ended) { wait(this->stage_""" + pipeStageInner.name + """->stage_end_event); } """ waitPipeEndMethod = cxx_writer.Method('wait_pipe_end', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True) pipeMembers.append(waitPipeEndMethod) # Methods: refresh_registers() for fetch stage # Propagates the register latches forward. Honors bypasses. if pipeStage.fetchStage: Code = """// Update the registers to propagate the values in the pipeline. R.clock_cycle(); """ refreshRegistersMethod = cxx_writer.Method('refresh_registers', cxx_writer.Code(Code), cxx_writer.voidType, 'private', noException = True) pipeMembers.append(refreshRegistersMethod) # Fetch Stage Attributes, Constructors and Destructors decoderAttr = cxx_writer.Attribute('decoder', cxx_writer.Type('Decoder', '#include \"decoder.hpp\"'), 'public') pipeMembers.append(decoderAttr) if self.instructionCache: CacheElemType = cxx_writer.Type('CacheElem') template_mapType = cxx_writer.TemplateType('template_map', [self.bitSizes[1], CacheElemType], hash_map_include) cacheAttr = cxx_writer.Attribute('instr_cache', template_mapType, 'private') pipeMembers.append(cacheAttr) profilerStartAddrAttr = cxx_writer.Attribute('profiler_start_addr', self.bitSizes[1], 'public') pipeMembers.append(profilerStartAddrAttr) pipeCtorCode += 'this->profiler_start_addr = (' + str(self.bitSizes[1]) + ')-1;\n' profilerEndAddrAttr = cxx_writer.Attribute('profiler_end_addr', self.bitSizes[1], 'public') pipeCtorCode += 'this->profiler_end_addr = (' + str(self.bitSizes[1]) + ')-1;\n' pipeMembers.append(profilerEndAddrAttr) # Here are the attributes for the instruction history queue historyFileAttr = cxx_writer.Attribute('history_file', cxx_writer.ofstreamType, 'public') pipeMembers.append(historyFileAttr) historyEnabledAttr = cxx_writer.Attribute('history_en', cxx_writer.boolType, 'public') pipeMembers.append(historyEnabledAttr) pipeCtorCode += 'this->history_en = false;\n' historyQueueType = cxx_writer.Type('HistoryInstrType', 'modules/instruction.hpp') histQueueType = cxx_writer.TemplateType('boost::circular_buffer', [historyQueueType], 'boost/circular_buffer.hpp') historyQueueAttr = cxx_writer.Attribute('history_instr_queue', histQueueType, 'public') pipeMembers.append(historyQueueAttr) pipeCtorCode += 'this->history_instr_queue.set_capacity(1000);\n' historyUndumpedElementsAttr = cxx_writer.Attribute('history_undumped_elements', cxx_writer.uintType, 'public') pipeMembers.append(historyUndumpedElementsAttr) pipeCtorCode += 'this->history_undumped_elements = 0;\n' # Close history dump file before destruction. pipeDtorCode = """#ifdef ENABLE_HISTORY if (this->history_en) { // In case a queue dump file has been specified, check if it needs to be saved. if (this->history_file) { if (this->history_undumped_elements > 0) { std::vector<std::string> history_vector; boost::circular_buffer<HistoryInstrType>::const_reverse_iterator history_it, history_end; unsigned history_read = 0; for (history_read = 0, history_it = this->history_instr_queue.rbegin(), history_end = this->history_instr_queue.rend(); history_it != history_end && history_read < this->history_undumped_elements; history_it++, history_read++) { history_vector.push_back(history_it->get_mnemonic()); } std::vector<std::string>::const_reverse_iterator history_vector_it, history_vector_end; for (history_vector_it = history_vector.rbegin(), history_vector_end = history_vector.rend(); history_vector_it != history_vector_end; history_vector_it++) { this->history_file << *history_vector_it << std::endl; } } this->history_file.flush(); this->history_file.close(); } } #endif """ # Constructors and Destructors pipeCtorInit = ['sc_module(pipe_name)', 'BasePipeStage(' + pipeBaseCtorValues[:-2] + ')'] + pipeCtorInit pipeCtorBody = cxx_writer.Code(pipeCtorCode + 'end_module();') pipeCtor = cxx_writer.Constructor(pipeCtorBody, 'public', pipeCtorParams + pipeFetchCtorParams, pipeCtorInit) pipeDtor = cxx_writer.Destructor(cxx_writer.Code(pipeDtorCode), 'public') else: # Constructors and Destructors pipeCtorInit = ['sc_module(pipe_name)', 'BasePipeStage(' + pipeBaseCtorValues[:-2] + ')'] + pipeCtorInit pipeCtorBody = cxx_writer.Code(pipeCtorCode + 'end_module();') pipeCtor = cxx_writer.Constructor(pipeCtorBody, 'public', pipeCtorParams, pipeCtorInit) # Class pipeClass = cxx_writer.SCModule(pipeStage.name + 'PipeStage', pipeMembers, [pipeType], namespaces = [namespace]) pipeClass.addDocString(brief = 'Pipeline Class', detail = 'Implements a pipeline stage. Addresses hazards.') pipeClass.addConstructor(pipeCtor) if pipeStage.fetchStage: pipeClass.addDestructor(pipeDtor) pipeClasses.append(pipeClass) ## @} Pipeline Stage Classes #--------------------------------------------------------------------------- return pipeClasses
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
nxVersion = p.sub('', NX.__version__) if nxVersion.count('.') > 1: nxVersion = '.'.join(nxVersion.split('.')[:2]) nxVersion = float(nxVersion) except: import traceback traceback.print_exc() raise Exception( 'Cannot determine networkx version. Try changing versions >= 0.36.') ################################################################################ # Globals and Helpers ################################################################################ aliasGraph = None registerType = None registerContainerType = cxx_writer.Type('Registers', '#include "registers.hpp"') aliasType = None def getPipeClockCycleFunction(self, registerMaxBitwidth): """In the accurate (pipelined) model, register values are propagated every cycle according to the three following specifications: 1. Default behavior: a. Propagation to stages after wb: wbStage is considered the stable value and fed forward to all stages from [wbStage+1..lastStage]. This is only for consistency, since registers should obviously neither be read nor written after wbStage (last write). b. Propagation to stages before and up to regsStage: wbStage is also fed back to all stages from [0..regsStage]. This is