def getCPPMemoryIf(self, model, namespace): """Creates the necessary structures for communicating with the memory: An array in case of an internal memory or a TLM port for TLM memories.""" archDWordType = self.bitSizes[0] archWordType = self.bitSizes[1] archHWordType = self.bitSizes[2] archByteType = self.bitSizes[3] global methodTypes, methodTypeLen methodTypes = { 'read_dword': archDWordType, 'read_word': archWordType, 'read_half': archHWordType, 'read_byte': archByteType, 'read_instr': archWordType, 'read_dword_dbg': archDWordType, 'read_word_dbg': archWordType, 'read_half_dbg': archHWordType, 'read_byte_dbg': archByteType, 'write_dword': archDWordType, 'write_word': archWordType, 'write_half': archHWordType, 'write_byte': archByteType, 'write_dword_dbg': archDWordType, 'write_word_dbg': archWordType, 'write_half_dbg': archHWordType, 'write_byte_dbg': archByteType } methodTypeLen = { 'read_dword': self.wordSize * 2, 'read_word': self.wordSize, 'read_half': self.wordSize / 2, 'read_byte': 1, 'read_instr': self.wordSize, 'read_dword_dbg': self.wordSize * 2, 'read_word_dbg': self.wordSize, 'read_half_dbg': self.wordSize / 2, 'read_byte_dbg': 1, 'write_dword': self.wordSize * 2, 'write_word': self.wordSize, 'write_half': self.wordSize / 2, 'write_byte': 1, 'write_dword_dbg': self.wordSize * 2, 'write_word_dbg': self.wordSize, 'write_half_dbg': self.wordSize / 2, 'write_byte_dbg': 1 } #--------------------------------------------------------------------------- ## @name Memory Interface Class # @{ memoryClasses = [] memoryIfMembers = [] emptyBody = cxx_writer.Code('') # Methods: read(), write() methodsCode = {} methodsAttrs = {} for methName in readMethodNames + writeMethodNames: methodsAttrs[methName] = ['pure', 'noexc'] methodsCode[methName] = emptyBody for methName in readMethodNames_dbg: methodsAttrs[methName] = ['virtual'] methodsCode[methName] = cxx_writer.Code('return this->' + methName[:-4] + '(address);') for methName in writeMethodNames_dbg: methodsAttrs[methName] = ['virtual'] methodsCode[methName] = cxx_writer.Code('this->' + methName[:-4] + '(address, datum);') for methName in genericMethodNames: methodsAttrs[methName] = ['pure'] methodsCode[methName] = emptyBody addMemoryMethods(self, memoryIfMembers, methodsCode, methodsAttrs) # Methods: swap_endianess() for cur_type in [archWordType, archHWordType]: swapEndianessCode = str(archByteType) + """ helper_byte = 0; for (unsigned i = 0; i < sizeof(""" + str(cur_type) + """)/2; i++) { helper_byte = ((""" + str(archByteType) + """ *)&datum)[i]; ((""" + str(archByteType) + """ *)&datum)[i] = ((""" + str( archByteType) + """ *)&datum)[sizeof(""" + str( cur_type) + """) -1 -i]; ((""" + str(archByteType) + """ *)&datum)[sizeof(""" + str( cur_type) + """) -1 -i] = helper_byte; } """ swapEndianessBody = cxx_writer.Code(swapEndianessCode) swapEndianessParam = cxx_writer.Parameter('datum', cur_type.makeRef()) swapEndianessMethod = cxx_writer.Method('swap_endianess', swapEndianessBody, cxx_writer.voidType, 'public', [swapEndianessParam], inline=True, noException=True, const=True) memoryIfMembers.append(swapEndianessMethod) # Constructors and Destructors memoryIfDtor = cxx_writer.Destructor(emptyBody, 'public', True) # Class memoryIfClass = cxx_writer.ClassDeclaration('MemoryInterface', memoryIfMembers, namespaces=[namespace]) memoryIfClass.addDestructor(memoryIfDtor) memoryClasses.append(memoryIfClass) ## @} Memory Interface Class #--------------------------------------------------------------------------- ## @name Local Memory Class # @{ from registerWriter import registerType, aliasType, registerContainerType MemoryToolsIfType = cxx_writer.TemplateType('MemoryToolsIf', [str(archWordType)], 'common/tools_if.hpp') localMemoryMembers = [] aliasAttrs = [] aliasParams = [] aliasInit = [] # Attributes and Initialization if self.memAlias: aliasAttrs.append( cxx_writer.Attribute('R', registerContainerType.makeRef(), 'private')) aliasParams.append( cxx_writer.Parameter('R', registerContainerType.makeRef())) aliasInit.append('R(R)') localMemoryMembers.append( cxx_writer.Attribute('debugger', MemoryToolsIfType.makePointer(), 'private')) # Methods: set_debugger() Code = 'this->debugger = debugger;' localMemoryMembers.append( cxx_writer.Method('set_debugger', cxx_writer.Code(Code), cxx_writer.voidType, 'public', [ cxx_writer.Parameter( 'debugger', MemoryToolsIfType.makePointer()) ])) # Methods: Building Blocks checkAddressCode = 'if (address >= this->size) {\nTHROW_ERROR("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n' checkAddressCodeException = 'if (address >= this->size) {\nTHROW_EXCEPTION("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n' checkWatchPointCode = """if (this->debugger != NULL) { this->debugger->notify_address(address, sizeof(datum)); } """ swapEndianessCode = '// Endianess conversion: The processor is always modeled with the host endianess. In case they are different, the endianess is swapped.\n' if self.isBigEndian: swapEndianessDefine = '#ifdef LITTLE_ENDIAN_BO\n' else: swapEndianessDefine = '#ifdef BIG_ENDIAN_BO\n' swapEndianessCode += swapEndianessDefine + 'this->swap_endianess(datum);\n#endif\n' if self.isBigEndian: swapDEndianessCode = '#ifdef LITTLE_ENDIAN_BO\n' else: swapDEndianessCode = '#ifdef BIG_ENDIAN_BO\n' swapDEndianessCode += str(archWordType) + ' datum1 = (' + str( archWordType) + ')(datum);\nthis->swap_endianess(datum1);\n' swapDEndianessCode += str(archWordType) + ' datum2 = (' + str( archWordType) + ')(datum >> ' + str( self.wordSize * self.byteSize) + ');\nthis->swap_endianess(datum2);\n' swapDEndianessCode += 'datum = datum1 | (((' + str( archDWordType) + ')datum2) << ' + str( self.wordSize * self.byteSize) + ');\n#endif\n' endianessCode = { 'read_dword': swapDEndianessCode, 'read_word': swapEndianessCode, 'read_half': swapEndianessCode, 'read_byte': '', 'read_instr': swapEndianessCode, 'read_dword_dbg': swapDEndianessCode, 'read_word_dbg': swapEndianessCode, 'read_half_dbg': swapEndianessCode, 'read_byte_dbg': '', 'write_dword': swapDEndianessCode, 'write_word': swapEndianessCode, 'write_half': swapEndianessCode, 'write_byte': '', 'write_dword_dbg': swapDEndianessCode, 'write_word_dbg': swapEndianessCode, 'write_half_dbg': swapEndianessCode, 'write_byte_dbg': '' } readAliasCode = {} readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex(long( alias.address)) + ') {\nreturn this->' + alias.alias + ';\n}\n' readAliasCode['read_dword'] = readMemAliasCode readAliasCode['read_word'] = readMemAliasCode readAliasCode['read_dword_dbg'] = readMemAliasCode readAliasCode['read_word_dbg'] = readMemAliasCode readAliasCode['read_instr'] = readMemAliasCode readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str( archHWordType) + ')' + alias.alias + '_temp;\n}\n' readMemAliasCode += 'if (address == ' + hex( long(alias.address) + self.wordSize / 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str( archHWordType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n' readAliasCode['read_half_dbg'] = readMemAliasCode readAliasCode['read_half'] = readMemAliasCode readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str( archByteType) + ')' + alias.alias + '_temp;\n}\n' readMemAliasCode += 'if (address == ' + hex( long(alias.address) + 1 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str( archByteType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n' readMemAliasCode += 'if (address == ' + hex( long(alias.address) + 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str( archByteType) + ' *)&(' + alias.alias + '_temp)) + 2);\n}\n' readMemAliasCode += 'if (address == ' + hex( long(alias.address) + 3 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str( archByteType) + ' *)&(' + alias.alias + '_temp)) + 3);\n}\n' readAliasCode['read_byte_dbg'] = readMemAliasCode readAliasCode['read_byte'] = readMemAliasCode writeAliasCode = {} writeMemAliasCode = '' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex( long(alias.address )) + ') {\n this->' + alias.alias + ' = datum;\nreturn;\n}\n' writeAliasCode['write_dword'] = writeMemAliasCode writeAliasCode['write_word'] = writeMemAliasCode writeAliasCode['write_dword_dbg'] = writeMemAliasCode writeAliasCode['write_word_dbg'] = writeMemAliasCode writeMemAliasCode = swapEndianessDefine for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + self.wordSize / 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str( archHWordType ) + ' *)&' + alias.alias + '_temp) = (' + str( archHWordType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archHWordType ) + ' *)&' + alias.alias + '_temp) + 1) = (' + str( archHWordType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#else\n' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str( archHWordType ) + ' *)&' + alias.alias + '_temp) = (' + str( archHWordType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + self.wordSize / 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archHWordType ) + ' *)&' + alias.alias + '_temp) + 1) = (' + str( archHWordType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#endif\n' writeAliasCode['write_half'] = writeMemAliasCode writeAliasCode['write_half_dbg'] = writeMemAliasCode writeMemAliasCode = swapEndianessDefine for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 3 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str( archByteType) + '*)&' + alias.alias + '_temp) = (' + str( archByteType) + ')datum;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 1) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 1 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 2) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 3) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#else\n' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex( long(alias.address) ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str( archByteType) + '*)&' + alias.alias + '_temp) = (' + str( archByteType) + ')datum;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 1 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 1) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 2 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 2) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex( long(alias.address) + 3 ) + ') {\n' + str( archWordType ) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str( archByteType ) + '*)&' + alias.alias + '_temp) + 3) = (' + str( archByteType ) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#endif\n' writeAliasCode['write_byte'] = writeMemAliasCode writeAliasCode['write_byte_dbg'] = writeMemAliasCode # If there is no memory or debugging is disabled. if not self.memories or not any(memAttr[1] == True for memAttr in self.memories.values()): # Methods: read(), write(), lock(), unlock() methodsCode = {} methodsAttrs = {} for methName in readMethodNames + readMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): readBody = cxx_writer.Code( readAliasCode[methName] + checkAddressCodeException + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') else: methodsAttrs[methName].append('noexc') readBody = cxx_writer.Code( readAliasCode[methName] + checkAddressCode + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') if methName == 'read_word': methodsAttrs[methName].append('inline') readBody.addInclude('common/report.hpp') methodsCode[methName] = readBody for methName in writeMethodNames + writeMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): methodsCode[methName] = cxx_writer.Code( writeAliasCode[methName] + checkAddressCodeException + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;') else: methodsAttrs[methName].append('noexc') methodsCode[methName] = cxx_writer.Code( writeAliasCode[methName] + checkAddressCode + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;') if methName == 'write_word': methodsAttrs[methName].append('inline') for methName in genericMethodNames: methodsAttrs[methName] = [] methodsCode[methName] = emptyBody addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs) # Attributes and Initialization arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType, 'private') localMemoryMembers.append(arrayAttr) sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private') localMemoryMembers.append(sizeAttr) # Constructors and Destructors localMemoryCtorParams = [ cxx_writer.Parameter('size', cxx_writer.uintType) ] localMemoryCtorBody = cxx_writer.Code( 'this->memory = new char[size];\nthis->debugger = NULL;') localMemoryCtor = cxx_writer.Constructor( localMemoryCtorBody, 'public', localMemoryCtorParams + aliasParams, ['size(size)'] + aliasInit) localMemoryDtorBody = cxx_writer.Code('delete [] this->memory;') localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public', True) # Class localMemoryClass = cxx_writer.ClassDeclaration( 'LocalMemory', localMemoryMembers + aliasAttrs, [memoryIfClass.getType()], namespaces=[namespace]) localMemoryClass.addDocString( brief='Memory Interface Class', detail= 'Interface used by the core to communicate with memory. Defines the required TLM ports.' ) localMemoryClass.addConstructor(localMemoryCtor) localMemoryClass.addDestructor(localMemoryDtor) memoryClasses.append(localMemoryClass) # Debugging is enabled. else: # Methods: read(), write(), lock() dumpCode1 = '\n\nMemAccessType dump_info;\n' if not self.systemc and not model.startswith( 'acc') and not model.endswith('AT'): dumpCode1 += 'dump_info.simulation_time = cur_cycle;\n' else: dumpCode1 += 'dump_info.simulation_time = sc_time_stamp().to_double();\n' if [ memName for memName, memAttr in self.memories.items() if memAttr[2] != '' ]: dumpCode1 += 'dump_info.program_counter = this->' + self.memories[ memName][2] + ';\n' else: dumpCode1 += 'dump_info.program_counter = 0;\n' dumpCode1 += 'for (unsigned i = 0; i < ' dumpCode2 = """; i++) { dump_info.address = address + i; dump_info.val = (char)((datum & (0xFF << i*8)) >> i*8); this->dump_file.write((char*)&dump_info, sizeof(MemAccessType)); } """ methodsCode = {} methodsAttrs = {} for methName in readMethodNames + readMethodNames_dbg: methodsAttrs[methName] = ['noexc'] if methName.endswith('_gdb'): readBody = cxx_writer.Code( readAliasCode[methName] + checkAddressCodeException + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') else: readBody = cxx_writer.Code( readAliasCode[methName] + checkAddressCode + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') if methName == 'read_word': methodsAttrs[methName].append('inline') readBody.addInclude('common/report.hpp') methodsCode[methName] = readBody for methName in writeMethodNames + writeMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): methodsCode[methName] = cxx_writer.Code( writeAliasCode[methName] + checkAddressCodeException + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;' + dumpCode1 + str(methodTypeLen[methName]) + dumpCode2) else: methodsAttrs[methName].append('noexc') methodsCode[methName] = cxx_writer.Code( writeAliasCode[methName] + checkAddressCode + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;' + dumpCode1 + str(methodTypeLen[methName]) + dumpCode2) if methName == 'write_word': methodsAttrs[methName].append('inline') for methName in genericMethodNames: methodsAttrs[methName] = [] methodsCode[methName] = emptyBody addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs) # Methods: end_of_simulation() endOfSimBody = cxx_writer.Code("""if (this->dump_file) { this->dump_file.flush(); this->dump_file.close(); } """) endOfSimMethod = cxx_writer.Method('end_of_simulation', endOfSimBody, cxx_writer.voidType, 'public') localMemoryMembers.append(endOfSimMethod) # Attributes and Initialization arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType, 'private') localMemoryMembers.append(arrayAttr) sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private') localMemoryMembers.append(sizeAttr) dumpFileAttr = cxx_writer.Attribute('dump_file', cxx_writer.ofstreamType, 'private') localMemoryMembers.append(dumpFileAttr) if not self.systemc and not model.startswith( 'acc') and not model.endswith('AT'): cycleAttr = cxx_writer.Attribute('cur_cycle', cxx_writer.uintType.makeRef(), 'private') localMemoryCtorParams.append( cxx_writer.Parameter('cur_cycle', cxx_writer.uintType.makeRef())) localMemoryCtorInit.append('cur_cycle(cur_cycle)') localMemoryMembers.append(cycleAttr) if [ memName for memName, memAttr in self.memories.items() if memAttr[2] != '' ]: # Find out type of fetch register. from processor import extractRegInterval fetchReg = self.memories[memName][2] fetchIndex = extractRegInterval(fetchReg) if fetchIndex: fetchReg = fetchReg[0:fetchReg.index('[')] fetchType = None if fetchReg in [i.name for i in self.regs + self.regBanks]: fetchType = registerType if fetchType == None and fetchReg in [ i.name for i in self.aliasRegs + self.aliasRegBanks ]: fetchType = aliasType localMemoryMembers.append( cxx_writer.Attribute(self.memories[memName][2], fetchType.makeRef(), 'private')) pcRegParam = [ cxx_writer.Parameter(self.memories[memName][2], fetchType.makeRef()) ] pcRegInit = [ self.memories[memName][2] + '(' + self.memories[memName][2] + ')' ] # Constructors and Destructors localMemoryCtorParams = [ cxx_writer.Parameter('size', cxx_writer.uintType) ] localMemoryCtorInit = ['size(size)'] localMemoryCtorBody = cxx_writer.Code("""this->memory = new char[size]; this->debugger = NULL; this->dump_file.open("memoryDump.dmp", ios::out | ios::binary | ios::ate); if (!this->dump_file) { THROW_EXCEPTION("Cannot open file memoryDump.dmp for writing."); } """) localMemoryCtor = cxx_writer.Constructor( localMemoryCtorBody, 'public', localMemoryCtorParams + aliasParams + pcRegParam, localMemoryCtorInit + aliasInit + pcRegInit) localMemoryDtorBody = cxx_writer.Code("""delete [] this->memory; if (this->dump_file) { this->dump_file.flush(); this->dump_file.close(); } """) localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public', True) # Class localMemoryClass = cxx_writer.ClassDeclaration( 'LocalMemory', localMemoryMembers + aliasAttrs, [memoryIfClass.getType()], namespaces=[namespace]) localMemoryClass.addDocString( brief='Memory Interface Class', detail= 'Interface used by the core to communicate with memory. Defines the required TLM ports.' ) localMemoryClass.addConstructor(localMemoryCtor) localMemoryClass.addDestructor(localMemoryDtor) memoryClasses.append(localMemoryClass) ## @} Local Memory Class #--------------------------------------------------------------------------- return memoryClasses
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 getCPPMemoryIf(self, model, namespace): """Creates the necessary structures for communicating with the memory: An array in case of an internal memory or a TLM port for TLM memories.""" archDWordType = self.bitSizes[0] archWordType = self.bitSizes[1] archHWordType = self.bitSizes[2] archByteType = self.bitSizes[3] global methodTypes, methodTypeLen methodTypes = {'read_dword': archDWordType, 'read_word': archWordType, 'read_half': archHWordType, 'read_byte': archByteType, 'read_instr': archWordType, 'read_dword_dbg': archDWordType, 'read_word_dbg': archWordType, 'read_half_dbg': archHWordType, 'read_byte_dbg': archByteType, 'write_dword': archDWordType, 'write_word': archWordType, 'write_half': archHWordType, 'write_byte': archByteType, 'write_dword_dbg': archDWordType, 'write_word_dbg': archWordType, 'write_half_dbg': archHWordType, 'write_byte_dbg': archByteType} methodTypeLen = {'read_dword': self.wordSize*2, 'read_word': self.wordSize, 'read_half': self.wordSize/2, 'read_byte': 1, 'read_instr': self.wordSize, 'read_dword_dbg': self.wordSize*2, 'read_word_dbg': self.wordSize, 'read_half_dbg': self.wordSize/2, 'read_byte_dbg': 1, 'write_dword': self.wordSize*2, 'write_word': self.wordSize, 'write_half': self.wordSize/2, 'write_byte': 1, 'write_dword_dbg': self.wordSize*2, 'write_word_dbg': self.wordSize, 'write_half_dbg': self.wordSize/2, 'write_byte_dbg': 1} #--------------------------------------------------------------------------- ## @name Memory Interface Class # @{ memoryClasses = [] memoryIfMembers = [] emptyBody = cxx_writer.Code('') # Methods: read(), write() methodsCode = {} methodsAttrs = {} for methName in readMethodNames + writeMethodNames: methodsAttrs[methName] = ['pure', 'noexc'] methodsCode[methName] = emptyBody for methName in readMethodNames_dbg: methodsAttrs[methName] = ['virtual'] methodsCode[methName] = cxx_writer.Code('return this->' + methName[:-4] + '(address);') for methName in writeMethodNames_dbg: methodsAttrs[methName] = ['virtual'] methodsCode[methName] = cxx_writer.Code('this->' + methName[:-4] + '(address, datum);') for methName in genericMethodNames: methodsAttrs[methName] = ['pure'] methodsCode[methName] = emptyBody addMemoryMethods(self, memoryIfMembers, methodsCode, methodsAttrs) # Methods: swap_endianess() for cur_type in [archWordType, archHWordType]: swapEndianessCode = str(archByteType) + """ helper_byte = 0; for (unsigned i = 0; i < sizeof(""" + str(cur_type) + """)/2; i++) { helper_byte = ((""" + str(archByteType) + """ *)&datum)[i]; ((""" + str(archByteType) + """ *)&datum)[i] = ((""" + str(archByteType) + """ *)&datum)[sizeof(""" + str(cur_type) + """) -1 -i]; ((""" + str(archByteType) + """ *)&datum)[sizeof(""" + str(cur_type) + """) -1 -i] = helper_byte; } """ swapEndianessBody = cxx_writer.Code(swapEndianessCode) swapEndianessParam = cxx_writer.Parameter('datum', cur_type.makeRef()) swapEndianessMethod = cxx_writer.Method('swap_endianess', swapEndianessBody, cxx_writer.voidType, 'public', [swapEndianessParam], inline = True, noException = True, const = True) memoryIfMembers.append(swapEndianessMethod) # Constructors and Destructors memoryIfDtor = cxx_writer.Destructor(emptyBody, 'public', True) # Class memoryIfClass = cxx_writer.ClassDeclaration('MemoryInterface', memoryIfMembers, namespaces = [namespace]) memoryIfClass.addDestructor(memoryIfDtor) memoryClasses.append(memoryIfClass) ## @} Memory Interface Class #--------------------------------------------------------------------------- ## @name Local Memory Class # @{ from registerWriter import registerType, aliasType, registerContainerType MemoryToolsIfType = cxx_writer.TemplateType('MemoryToolsIf', [str(archWordType)], 'common/tools_if.hpp') localMemoryMembers = [] aliasAttrs = [] aliasParams = [] aliasInit = [] # Attributes and Initialization if self.memAlias: aliasAttrs.append(cxx_writer.Attribute('R', registerContainerType.makeRef(), 'private')) aliasParams.append(cxx_writer.Parameter('R', registerContainerType.makeRef())) aliasInit.append('R(R)') localMemoryMembers.append(cxx_writer.Attribute('debugger', MemoryToolsIfType.makePointer(), 'private')) # Methods: set_debugger() Code = 'this->debugger = debugger;' localMemoryMembers.append(cxx_writer.Method('set_debugger', cxx_writer.Code(Code), cxx_writer.voidType, 'public', [cxx_writer.Parameter('debugger', MemoryToolsIfType.makePointer())])) # Methods: Building Blocks checkAddressCode = 'if (address >= this->size) {\nTHROW_ERROR("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n' checkAddressCodeException = 'if (address >= this->size) {\nTHROW_EXCEPTION("Address " << std::hex << std::showbase << address << " out of memory.");\n}\n' checkWatchPointCode = """if (this->debugger != NULL) { this->debugger->notify_address(address, sizeof(datum)); } """ swapEndianessCode = '// Endianess conversion: The processor is always modeled with the host endianess. In case they are different, the endianess is swapped.\n' if self.isBigEndian: swapEndianessDefine = '#ifdef LITTLE_ENDIAN_BO\n' else: swapEndianessDefine = '#ifdef BIG_ENDIAN_BO\n' swapEndianessCode += swapEndianessDefine + 'this->swap_endianess(datum);\n#endif\n' if self.isBigEndian: swapDEndianessCode = '#ifdef LITTLE_ENDIAN_BO\n' else: swapDEndianessCode = '#ifdef BIG_ENDIAN_BO\n' swapDEndianessCode += str(archWordType) + ' datum1 = (' + str(archWordType) + ')(datum);\nthis->swap_endianess(datum1);\n' swapDEndianessCode += str(archWordType) + ' datum2 = (' + str(archWordType) + ')(datum >> ' + str(self.wordSize*self.byteSize) + ');\nthis->swap_endianess(datum2);\n' swapDEndianessCode += 'datum = datum1 | (((' + str(archDWordType) + ')datum2) << ' + str(self.wordSize*self.byteSize) + ');\n#endif\n' endianessCode = {'read_dword': swapDEndianessCode, 'read_word': swapEndianessCode, 'read_half': swapEndianessCode, 'read_byte': '', 'read_instr': swapEndianessCode, 'read_dword_dbg': swapDEndianessCode, 'read_word_dbg': swapEndianessCode, 'read_half_dbg': swapEndianessCode, 'read_byte_dbg': '', 'write_dword': swapDEndianessCode, 'write_word': swapEndianessCode, 'write_half': swapEndianessCode, 'write_byte': '', 'write_dword_dbg': swapDEndianessCode, 'write_word_dbg': swapEndianessCode, 'write_half_dbg': swapEndianessCode, 'write_byte_dbg': ''} readAliasCode = {} readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\nreturn this->' + alias.alias + ';\n}\n' readAliasCode['read_dword'] = readMemAliasCode readAliasCode['read_word'] = readMemAliasCode readAliasCode['read_dword_dbg'] = readMemAliasCode readAliasCode['read_word_dbg'] = readMemAliasCode readAliasCode['read_instr'] = readMemAliasCode readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str(archHWordType) + ')' + alias.alias + '_temp;\n}\n' readMemAliasCode += 'if (address == ' + hex(long(alias.address) + self.wordSize/2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(archHWordType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n' readAliasCode['read_half_dbg'] = readMemAliasCode readAliasCode['read_half'] = readMemAliasCode readMemAliasCode = '' for alias in self.memAlias: readMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn (' + str(archByteType) + ')' + alias.alias + '_temp;\n}\n' readMemAliasCode += 'if (address == ' + hex(long(alias.address) + 1) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(archByteType) + ' *)&(' + alias.alias + '_temp)) + 1);\n}\n' readMemAliasCode += 'if (address == ' + hex(long(alias.address) + 2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(archByteType) + ' *)&(' + alias.alias + '_temp)) + 2);\n}\n' readMemAliasCode += 'if (address == ' + hex(long(alias.address) + 3) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n' + swapEndianessDefine + 'this->swap_endianess(' + alias.alias + '_temp);\n#endif\nreturn *(((' + str(archByteType) + ' *)&(' + alias.alias + '_temp)) + 3);\n}\n' readAliasCode['read_byte_dbg'] = readMemAliasCode readAliasCode['read_byte'] = readMemAliasCode writeAliasCode = {} writeMemAliasCode = '' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n this->' + alias.alias + ' = datum;\nreturn;\n}\n' writeAliasCode['write_dword'] = writeMemAliasCode writeAliasCode['write_word'] = writeMemAliasCode writeAliasCode['write_dword_dbg'] = writeMemAliasCode writeAliasCode['write_word_dbg'] = writeMemAliasCode writeMemAliasCode = swapEndianessDefine for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + self.wordSize/2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(archHWordType) + ' *)&' + alias.alias + '_temp) = (' + str(archHWordType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archHWordType) + ' *)&' + alias.alias + '_temp) + 1) = (' + str(archHWordType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#else\n' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(archHWordType) + ' *)&' + alias.alias + '_temp) = (' + str(archHWordType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + self.wordSize/2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archHWordType) + ' *)&' + alias.alias + '_temp) + 1) = (' + str(archHWordType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#endif\n' writeAliasCode['write_half'] = writeMemAliasCode writeAliasCode['write_half_dbg'] = writeMemAliasCode writeMemAliasCode = swapEndianessDefine for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 3) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(archByteType) + '*)&' + alias.alias + '_temp) = (' + str(archByteType) + ')datum;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 1) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 1) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 2) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 3) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#else\n' for alias in self.memAlias: writeMemAliasCode += 'if (address == ' + hex(long(alias.address)) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*((' + str(archByteType) + '*)&' + alias.alias + '_temp) = (' + str(archByteType) + ')datum;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 1) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 1) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 2) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 2) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += 'if (address == ' + hex(long(alias.address) + 3) + ') {\n' + str(archWordType) + ' ' + alias.alias + '_temp = this->' + alias.alias + ';\n*(((' + str(archByteType) + '*)&' + alias.alias + '_temp) + 3) = (' + str(archByteType) + ')datum;\nthis->' + alias.alias + '= ' + alias.alias + '_temp;\nreturn;\n}\n' writeMemAliasCode += '#endif\n' writeAliasCode['write_byte'] = writeMemAliasCode writeAliasCode['write_byte_dbg'] = writeMemAliasCode # If there is no memory or debugging is disabled. if not self.memories or not any(memAttr[1] == True for memAttr in self.memories.values()): # Methods: read(), write(), lock(), unlock() methodsCode = {} methodsAttrs = {} for methName in readMethodNames + readMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): readBody = cxx_writer.Code(readAliasCode[methName] + checkAddressCodeException + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') else: methodsAttrs[methName].append('noexc') readBody = cxx_writer.Code(readAliasCode[methName] + checkAddressCode + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') if methName == 'read_word': methodsAttrs[methName].append('inline') readBody.addInclude('common/report.hpp') methodsCode[methName] = readBody for methName in writeMethodNames + writeMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): methodsCode[methName] = cxx_writer.Code(writeAliasCode[methName] + checkAddressCodeException + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;') else: methodsAttrs[methName].append('noexc') methodsCode[methName] = cxx_writer.Code(writeAliasCode[methName] + checkAddressCode + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;') if methName == 'write_word': methodsAttrs[methName].append('inline') for methName in genericMethodNames: methodsAttrs[methName] = [] methodsCode[methName] = emptyBody addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs) # Attributes and Initialization arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType, 'private') localMemoryMembers.append(arrayAttr) sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private') localMemoryMembers.append(sizeAttr) # Constructors and Destructors localMemoryCtorParams = [cxx_writer.Parameter('size', cxx_writer.uintType)] localMemoryCtorBody = cxx_writer.Code('this->memory = new char[size];\nthis->debugger = NULL;') localMemoryCtor = cxx_writer.Constructor(localMemoryCtorBody, 'public', localMemoryCtorParams + aliasParams, ['size(size)'] + aliasInit) localMemoryDtorBody = cxx_writer.Code('delete [] this->memory;') localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public', True) # Class localMemoryClass = cxx_writer.ClassDeclaration('LocalMemory', localMemoryMembers + aliasAttrs, [memoryIfClass.getType()], namespaces = [namespace]) localMemoryClass.addDocString(brief = 'Memory Interface Class', detail = 'Interface used by the core to communicate with memory. Defines the required TLM ports.') localMemoryClass.addConstructor(localMemoryCtor) localMemoryClass.addDestructor(localMemoryDtor) memoryClasses.append(localMemoryClass) # Debugging is enabled. else: # Methods: read(), write(), lock() dumpCode1 = '\n\nMemAccessType dump_info;\n' if not self.systemc and not model.startswith('acc') and not model.endswith('AT'): dumpCode1 += 'dump_info.simulation_time = cur_cycle;\n' else: dumpCode1 += 'dump_info.simulation_time = sc_time_stamp().to_double();\n' if [memName for memName, memAttr in self.memories.items() if memAttr[2] != '']: dumpCode1 += 'dump_info.program_counter = this->' + self.memories[memName][2] + ';\n' else: dumpCode1 += 'dump_info.program_counter = 0;\n' dumpCode1 += 'for (unsigned i = 0; i < ' dumpCode2 = """; i++) { dump_info.address = address + i; dump_info.val = (char)((datum & (0xFF << i*8)) >> i*8); this->dump_file.write((char*)&dump_info, sizeof(MemAccessType)); } """ methodsCode = {} methodsAttrs = {} for methName in readMethodNames + readMethodNames_dbg: methodsAttrs[methName] = ['noexc'] if methName.endswith('_gdb'): readBody = cxx_writer.Code(readAliasCode[methName] + checkAddressCodeException + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') else: readBody = cxx_writer.Code(readAliasCode[methName] + checkAddressCode + '\n' + str(methodTypes[methName]) + ' datum = *(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address);\n' + endianessCode[methName] + '\nreturn datum;') if methName == 'read_word': methodsAttrs[methName].append('inline') readBody.addInclude('common/report.hpp') methodsCode[methName] = readBody for methName in writeMethodNames + writeMethodNames_dbg: methodsAttrs[methName] = [] if methName.endswith('_gdb'): methodsCode[methName] = cxx_writer.Code(writeAliasCode[methName] + checkAddressCodeException + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;' + dumpCode1 + str(methodTypeLen[methName]) + dumpCode2) else: methodsAttrs[methName].append('noexc') methodsCode[methName] = cxx_writer.Code(writeAliasCode[methName] + checkAddressCode + checkWatchPointCode + '\n' + endianessCode[methName] + '\n*(' + str(methodTypes[methName].makePointer()) + ')(this->memory + (unsigned long)address) = datum;' + dumpCode1 + str(methodTypeLen[methName]) + dumpCode2) if methName == 'write_word': methodsAttrs[methName].append('inline') for methName in genericMethodNames: methodsAttrs[methName] = [] methodsCode[methName] = emptyBody addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs) # Methods: end_of_simulation() endOfSimBody = cxx_writer.Code("""if (this->dump_file) { this->dump_file.flush(); this->dump_file.close(); } """) endOfSimMethod = cxx_writer.Method('end_of_simulation', endOfSimBody, cxx_writer.voidType, 'public') localMemoryMembers.append(endOfSimMethod) # Attributes and Initialization arrayAttr = cxx_writer.Attribute('memory', cxx_writer.charPtrType, 'private') localMemoryMembers.append(arrayAttr) sizeAttr = cxx_writer.Attribute('size', cxx_writer.uintType, 'private') localMemoryMembers.append(sizeAttr) dumpFileAttr = cxx_writer.Attribute('dump_file', cxx_writer.ofstreamType, 'private') localMemoryMembers.append(dumpFileAttr) if not self.systemc and not model.startswith('acc') and not model.endswith('AT'): cycleAttr = cxx_writer.Attribute('cur_cycle', cxx_writer.uintType.makeRef(), 'private') localMemoryCtorParams.append(cxx_writer.Parameter('cur_cycle', cxx_writer.uintType.makeRef())) localMemoryCtorInit.append('cur_cycle(cur_cycle)') localMemoryMembers.append(cycleAttr) if [memName for memName, memAttr in self.memories.items() if memAttr[2] != '']: # Find out type of fetch register. from processor import extractRegInterval fetchReg = self.memories[memName][2] fetchIndex = extractRegInterval(fetchReg) if fetchIndex: fetchReg = fetchReg[0:fetchReg.index('[')] fetchType = None if fetchReg in [i.name for i in self.regs + self.regBanks]: fetchType = registerType if fetchType == None and fetchReg in [i.name for i in self.aliasRegs + self.aliasRegBanks]: fetchType = aliasType localMemoryMembers.append(cxx_writer.Attribute(self.memories[memName][2], fetchType.makeRef(), 'private')) pcRegParam = [cxx_writer.Parameter(self.memories[memName][2], fetchType.makeRef())] pcRegInit = [self.memories[memName][2] + '(' + self.memories[memName][2] + ')'] # Constructors and Destructors localMemoryCtorParams = [cxx_writer.Parameter('size', cxx_writer.uintType)] localMemoryCtorInit = ['size(size)'] localMemoryCtorBody = cxx_writer.Code("""this->memory = new char[size]; this->debugger = NULL; this->dump_file.open("memoryDump.dmp", ios::out | ios::binary | ios::ate); if (!this->dump_file) { THROW_EXCEPTION("Cannot open file memoryDump.dmp for writing."); } """) localMemoryCtor = cxx_writer.Constructor(localMemoryCtorBody, 'public', localMemoryCtorParams + aliasParams + pcRegParam, localMemoryCtorInit + aliasInit + pcRegInit) localMemoryDtorBody = cxx_writer.Code("""delete [] this->memory; if (this->dump_file) { this->dump_file.flush(); this->dump_file.close(); } """) localMemoryDtor = cxx_writer.Destructor(localMemoryDtorBody, 'public', True) # Class localMemoryClass = cxx_writer.ClassDeclaration('LocalMemory', localMemoryMembers + aliasAttrs, [memoryIfClass.getType()], namespaces = [namespace]) localMemoryClass.addDocString(brief = 'Memory Interface Class', detail = 'Interface used by the core to communicate with memory. Defines the required TLM ports.') localMemoryClass.addConstructor(localMemoryCtor) localMemoryClass.addDestructor(localMemoryDtor) memoryClasses.append(localMemoryClass) ## @} Local Memory Class #--------------------------------------------------------------------------- return memoryClasses