def addMemoryMethods(self, localMemoryMembers, methodsCode, methodsAttrs): archDWordType = self.bitSizes[0] archWordType = self.bitSizes[1] archHWordType = self.bitSizes[2] archByteType = self.bitSizes[3] addressParam = cxx_writer.Parameter('address', archWordType.makeRef().makeConst()) userParams = [ cxx_writer.Parameter(paramName, paramAttr[0], initValue=paramAttr[2]) for paramName, paramAttr in self.memoryParams.items() ] for methName in readMethodNames + readMethodNames_dbg: if methName in methodsCode.keys() and methName in methodsAttrs.keys(): readMethod = cxx_writer.Method( methName, methodsCode[methName], methodTypes[methName], 'public', [addressParam] + userParams, inline='inline' in methodsAttrs[methName], pure='pure' in methodsAttrs[methName], virtual='virtual' in methodsAttrs[methName], const=len(self.tlmPorts) == 0, noException='noexc' in methodsAttrs[methName]) localMemoryMembers.append(readMethod) for methName in writeMethodNames + writeMethodNames_dbg: if methName in methodsCode.keys() and methName in methodsAttrs.keys(): datumParam = cxx_writer.Parameter('datum', methodTypes[methName]) writeMethod = cxx_writer.Method( methName, methodsCode[methName], cxx_writer.voidType, 'public', [addressParam, datumParam] + userParams, inline='inline' in methodsAttrs[methName], pure='pure' in methodsAttrs[methName], virtual='virtual' in methodsAttrs[methName], noException='noexc' in methodsAttrs[methName]) localMemoryMembers.append(writeMethod) for methName in genericMethodNames: if methName in methodsCode.keys() and methName in methodsAttrs.keys(): lockMethod = cxx_writer.Method(methName, methodsCode[methName], cxx_writer.voidType, 'public', inline='inline' in methodsAttrs[methName], pure='pure' in methodsAttrs[methName], virtual='virtual' in methodsAttrs[methName], noException='noexc' in methodsAttrs[methName]) localMemoryMembers.append(lockMethod)
def testInlineFunction(self): code = cxx_writer.Code( 'if (works) {\nprintf(\"hummm\\n\");\nreturn 1;\n} else {\nreturn 0;\n}' ) intType = cxx_writer.intType parameters = [cxx_writer.Parameter('param1', intType)] function = cxx_writer.Function('dummy_func', code, intType, parameters, inline=True) function.writeDeclaration(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 8) self.assertEqual(lines[0], 'inline int dummy_func(int param1) {\n') self.assertEqual(lines[1], ' if (works) {\n') self.assertEqual(lines[2], ' printf(\"hummm\\n\");\n') self.assertEqual(lines[3], ' return 1;\n') self.assertEqual(lines[4], ' } else {\n') self.assertEqual(lines[5], ' return 0;\n') self.assertEqual(lines[6], ' }\n') self.assertEqual(lines[7], '} // dummy_func()\n')
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 testFunctionDoc(self): intType = cxx_writer.intType code = cxx_writer.Code('') parameters = [cxx_writer.Parameter('param1', intType)] function = cxx_writer.Function('dummy_func', code, intType, parameters) function.addDocString('Documentation test\nanother line\n') function.writeImplementation(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 5) self.assertEqual(lines[0], '/// Documentation test\n') self.assertEqual(lines[1], '/// another line\n') self.assertEqual(lines[2], 'int dummy_func(int param1) {\n') self.assertEqual(lines[3], '\n') self.assertEqual(lines[4], '} // dummy_func()\n')
def testSCModuleImpl(self): intDecl = cxx_writer.intType stringDecl = cxx_writer.stringType module_nameDecl = cxx_writer.sc_module_nameType privateVar = cxx_writer.Attribute('pippo', intDecl, 'private') emptyBody = cxx_writer.Code('end_module();') publicConstr = cxx_writer.Constructor(emptyBody, 'public', [cxx_writer.Parameter('name', module_nameDecl)], ['std::string()', 'sc_module(name)']) classDecl = cxx_writer.SCModule('MyClass', [privateVar], [stringDecl]) classDecl.addConstructor(publicConstr) classDecl.writeImplementation(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 6) self.assertEqual(lines[0], 'MyClass::MyClass(sc_module_name name) :\n') self.assertEqual(lines[1], ' std::string(),\n') self.assertEqual(lines[2], ' sc_module(name) {\n') self.assertEqual(lines[3], ' end_module();\n') self.assertEqual(lines[4], '} // MyClass()\n')
def testSCModuleDecl(self): intDecl = cxx_writer.intType stringDecl = cxx_writer.stringType module_nameDecl = cxx_writer.sc_module_nameType privateVar = cxx_writer.Attribute('pippo', intDecl, 'private') emptyBody = cxx_writer.Code('end_module();') publicConstr = cxx_writer.Constructor(emptyBody, 'public', [cxx_writer.Parameter('name', module_nameDecl)], ['std::string()']) classDecl = cxx_writer.SCModule('MyClass', [privateVar], [stringDecl]) classDecl.addConstructor(publicConstr) classDecl.writeDeclaration(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 10) self.assertEqual(lines[0], 'class MyClass : public std::string, public sc_module {\n') self.assertEqual(lines[1], ' public:\n') self.assertEqual(lines[2], ' SC_HAS_PROCESS(MyClass);\n') self.assertEqual(lines[3], ' MyClass(sc_module_name name);\n') self.assertEqual(lines[4], '\n') self.assertEqual(lines[5], ' private:\n') self.assertEqual(lines[6], ' int pippo;\n') self.assertEqual(lines[7], '\n') self.assertEqual(lines[8], '}; // class MyClass\n')
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 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
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 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 only for consistency, since registers should obviously neither be read nor written before regsStage (first read). c. Regular step-wise forward propagation: Each register from regsStage to wbStage propagates one stage forward every cycle. A stalled pipeline is split into three sections: The stalled stages (ideally [0..regsStage]) retain their values, the following stages containing bubbles (NOPs) either retain their stale values or explicitly reset them (they will be overwritten anyway), the non-stalled stages propagate normally. 2. Common feedback loops via <processor>Arch.py:<pipe>.setWbStageOrder(): Aside from the default behavior in (1), TRAP interprets <pipe>. setWbStageOrder() as a backward path from each stage in the list back to <pipe> for all registers. Hence, the default behavior still executes but the pipe forwarding paths take precedence in case of contention. If the forwarding stage is stalled, the bypass is deactivated. 3. Register-specific feedback loops via <reg>.setWbStageOrder(): the common pipe behavior in (1) and (2) does not run except for the step- wise forward propagation, in which case all stages propagate, not just [regsStage..wbStage] If <reg>.setWbStageOrder() is used, care should therefore be taken to re-define all feedback loops as required. If the forwarding stage is stalled, the bypass is deactivated. This function generates the callback function containing default propagation logic (1) as well as any forwarding specified by <pipe>.setWbStageOrder( ['pipe_x', ... 'pipe_0']) as described in (2). The list of stages is interpreted in order of decreasing precedence. The calling sequence is: pipeline.cpp: <fetchStage>::behavior() -> registers.cpp: clock_cycle() -> register_abstraction.hpp:clock_cycle() -> registers.cpp: regs_clock_cycle() The fetch stage calls a clock_cycle function which iterates through all registers and calls their clock_cycle() method defined in register_abstraction.hpp. This, in turn, calls the callback function regs_clock_cycle, generated by TRAP in the registers.cpp file.""" if not self.pipes: return regsStage = 0 wbStage = len(self.pipes) - 1 pipeNumbers = {} i = 0 for pipeStage in self.pipes: if pipeStage.regsStage: regsStage = self.pipes.index(pipeStage) if pipeStage.wbStage: wbStage = self.pipes.index(pipeStage) pipeNumbers[pipeStage.name] = i i += 1 Code = """bool has_changes = false; // Copy over old values, just in case stalls should prevent propagation. for (unsigned i = 0; i < """ + str(len(self.pipes)) + """; ++i) { temp_values[i] = values[i]; temp_time_stamps[i] = time_stamps[i]; } """ # 1a. Default behavior: Propagation to stages after wb. if wbStage == len(self.pipes) - 2: Code += """ // Feed stable value to all stages after write-back. This is only for consistency. if (!(nop_stages & """ + hex(1 << wbStage) + """)) { if (time_stamps[""" + str(wbStage) + """] >= time_stamps[""" + str( wbStage + 1) + """]) { temp_values[""" + str(wbStage + 1) + """] = values[""" + str(wbStage) + """]; temp_time_stamps[""" + str(wbStage + 1) + """] = time_stamps[""" + str( wbStage) + """]; has_changes = true; } } """ elif wbStage < len(self.pipes) - 2: Code += """ // Feed stable value to all stages after write-back. This is only for consistency. if (!(nop_stages & """ + hex(1 << wbStage) + """)) { for (unsigned i = """ + str(wbStage + 1) + """; i < this->m_num_stages; ++i) { if (time_stamps[""" + str(wbStage) + """] >= time_stamps[i]) { temp_values[i] = values[""" + str(wbStage) + """]; temp_time_stamps[i] = time_stamps[""" + str(wbStage) + """]; has_changes = true; } } } """ # 1b. Default behavior: Propagation to stages before and up to regsStage. if regsStage == 0: Code += """ // Feed stable value back to first-read. if (!(cur_nop_stages & """ + hex(1 << wbStage) + """)) { if (time_stamps[""" + str(wbStage) + """] >= time_stamps[0]) { temp_values[0] = values[""" + str(wbStage) + """]; temp_time_stamps[0] = time_stamps[""" + str(wbStage) + """]; has_changes = true; } } """ elif regsStage > 1: Code += """ // Feed stable value to first-read and all stages before. The latter is only for consistency. if (!(cur_nop_stages & """ + hex(1 << wbStage) + """)) { for (unsigned i = 0; i <= """ + str(regsStage) + """; ++i) { if (time_stamps[""" + str(wbStage) + """] >= time_stamps[i]) { temp_values[i] = values[""" + str(wbStage) + """]; temp_time_stamps[i] = time_stamps[""" + str(wbStage) + """]; has_changes = true; } } } """ # 1c. Default Behavior: Regular step-wise forward propagation. Code += """ // Regular step-wise forward propagation. for (int i = """ + str(regsStage + 1) + """; i <= """ + str(wbStage) + """; ++i) { // The stage will contain a bubble. if (next_nop_stages & (1 << i)) { temp_values[i] = 0; temp_time_stamps[i] = 0; } else if ((i > stall_stage) && (time_stamps[i-1] >= time_stamps[i])) { temp_values[i] = values[i-1]; temp_time_stamps[i] = time_stamps[i-1]; has_changes = true; } } """ # 2. Common feedback loops via <processor>Arch.py:<pipe>.setWbStageOrder(). for toStage in self.pipes: if toStage.wbStageOrder: for fromStage in reversed(toStage.wbStageOrder): Code += """ // Feedback path """ + fromStage + """ -> """ + toStage.name + """ if (!(cur_nop_stages & """ + hex( 1 << pipeNumbers[fromStage]) + """)) { if (time_stamps[""" + str( pipeNumbers[fromStage] ) + """] >= temp_time_stamps[""" + str( pipeNumbers[toStage.name]) + """]) { temp_values[""" + str(pipeNumbers[ toStage.name]) + """] = values[""" + str( pipeNumbers[fromStage]) + """]; temp_time_stamps[""" + str( pipeNumbers[toStage.name] ) + """] = time_stamps[""" + str( pipeNumbers[fromStage]) + """]; has_changes = true; } } """ Code += '\nreturn has_changes;\n' pipeClockCycleValueParam = cxx_writer.Parameter( 'values', registerMaxBitwidth.makePointer()) pipeClockCycleTempValueParam = cxx_writer.Parameter( 'temp_values', registerMaxBitwidth.makePointer()) pipeClockCycleTimeStampParam = cxx_writer.Parameter( 'time_stamps', cxx_writer.ulonglongPtrType) pipeClockCycleTempTimeStampParam = cxx_writer.Parameter( 'temp_time_stamps', cxx_writer.ulonglongPtrType) pipeClockCycleStallStageParam = cxx_writer.Parameter( 'stall_stage', cxx_writer.intType) pipeClockCycleCurNopStagesParam = cxx_writer.Parameter( 'cur_nop_stages', cxx_writer.uintType) pipeClockCycleNextNopStagesParam = cxx_writer.Parameter( 'next_nop_stages', cxx_writer.uintType) pipeClockCycleFunction = cxx_writer.Function( 'regs_clock_cycle', cxx_writer.Code(Code), cxx_writer.boolType, [ pipeClockCycleValueParam, pipeClockCycleTempValueParam, pipeClockCycleTimeStampParam, pipeClockCycleTempTimeStampParam, pipeClockCycleStallStageParam, pipeClockCycleCurNopStagesParam, pipeClockCycleNextNopStagesParam ]) return pipeClockCycleFunction
# ******* opCode = cxx_writer.Code(""" shifted = toShift >> shift_amm; //Controlling the sign extensions if((toShift & 0x80000000) != 0){ shifted |= (((unsigned)0xFFFFFFFF) << (32 - shift_amm)); } else{ shifted &= (((unsigned)0xFFFFFFFF) >> shift_amm); } return shifted; """) AShiftRight_method = trap.HelperMethod('ArithmeticShiftRight', opCode, 'execute') AShiftRight_method.setSignature(('BIT<32>'), [ cxx_writer.Parameter('shift_amm', cxx_writer.uintType), ('toShift', 'BIT<32>') ]) AShiftRight_method.addVariable(('shifted', 'BIT<32>')) opCode = cxx_writer.Code(""" if((bitSeq & (1 << (bitSeq_length - 1))) != 0) bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length); return bitSeq; """) SignExtend_method = trap.HelperMethod('SignExtend', opCode, 'execute') SignExtend_method.setSignature( ('BIT<32>'), [('bitSeq', 'BIT<32>'), cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)]) opCode = cxx_writer.Code("""
def getRegisterClockCycleFunction(self, regName, wbStageOrder, registerMaxBitwidth): """Generates the callback function set by <reg>.setWbStageOrder({'pipe_n': ['pipe_x', ... 'pipe_0']})) as described in @see getPipeClockCycleFunction (3). The list of stages is interpreted in order of decreasing precedence. Note that step-wise forward propagation (1c) still takes place, but the feed-forward/-back from wb is not implicitly assumed. The user therefore needs to explicitly define all stage connections. The calling sequence is: pipeline.cpp: <fetchStage>::behavior() -> registers.cpp: clock_cycle() -> register_abstraction.hpp:clock_cycle() -> registers.cpp: <reg>_clock_cycle() The fetch stage calls a clock_cycle function which iterates through all registers and calls their clock_cycle() method defined in register_abstraction.hpp. This, in turn, calls the register-specific callback function <reg>_clock_cycle, generated by TRAP in the registers.cpp file.""" if not wbStageOrder: return pipeNumbers = {} i = 0 for pipeStage in self.pipes: pipeNumbers[pipeStage.name] = i i += 1 Code = """bool has_changes = false; // Copy over old values, just in case stalls should prevent propagation. for (unsigned i = 0; i < """ + str(len(self.pipes)) + """; ++i) { temp_values[i] = values[i]; temp_time_stamps[i] = time_stamps[i]; } """ # 1c. Default Behavior: Regular step-wise forward propagation. # Note that in this case, all stages propagate, not just [regsStage.. # wbStage] Code += """ // Regular step-wise forward propagation. for (int i = 1; i <= """ + str(len(self.pipes) - 1) + """; ++i) { // The stage will contain a bubble. if (next_nop_stages & (1 << i)) { temp_values[i] = 0; temp_time_stamps[i] = 0; } else if ((i > stall_stage) && (time_stamps[i-1] >= time_stamps[i])) { temp_values[i] = values[i-1]; temp_time_stamps[i] = time_stamps[i-1]; has_changes = true; } } """ # 3. Register-specific feedback loops via <reg>.setWbStageOrder(): #for fromStage in sorted(wbStageOrder, key=lambda x: [pipe.name for pipe in self.pipes].index(x), reverse = True): for toStage, fromStages in wbStageOrder.items(): for fromStage in reversed(fromStages): Code += """ // """ + fromStage + """ -> """ + toStage + """ if (!(cur_nop_stages & """ + hex( 1 << pipeNumbers[fromStage]) + """)) { if (time_stamps[""" + str( pipeNumbers[fromStage] ) + """] >= temp_time_stamps[""" + str( pipeNumbers[toStage]) + """]) { temp_values[""" + str( pipeNumbers[toStage] ) + """] = values[""" + str(pipeNumbers[fromStage]) + """]; temp_time_stamps[""" + str( pipeNumbers[toStage]) + """] = time_stamps[""" + str( pipeNumbers[fromStage]) + """]; has_changes = true; } } """ Code += '\nreturn has_changes;\n' registerClockCycleValueParam = cxx_writer.Parameter( 'values', registerMaxBitwidth.makePointer()) registerClockCycleTempValueParam = cxx_writer.Parameter( 'temp_values', registerMaxBitwidth.makePointer()) registerClockCycleTimeStampParam = cxx_writer.Parameter( 'time_stamps', cxx_writer.ulonglongPtrType) registerClockCycleTempTimeStampParam = cxx_writer.Parameter( 'temp_time_stamps', cxx_writer.ulonglongPtrType) registerClockCycleStallStageParam = cxx_writer.Parameter( 'stall_stage', cxx_writer.intType) registerClockCycleCurNopStagesParam = cxx_writer.Parameter( 'cur_nop_stages', cxx_writer.uintType) registerClockCycleNextNopStagesParam = cxx_writer.Parameter( 'next_nop_stages', cxx_writer.uintType) registerClockCycleFunction = cxx_writer.Function( regName.lower() + '_clock_cycle', cxx_writer.Code(Code), cxx_writer.boolType, [ registerClockCycleValueParam, registerClockCycleTempValueParam, registerClockCycleTimeStampParam, registerClockCycleTempTimeStampParam, registerClockCycleStallStageParam, registerClockCycleCurNopStagesParam, registerClockCycleNextNopStagesParam ]) return registerClockCycleFunction
# accessed by any instruction #------------------------------------------------------- # ******* # Here we define some helper methods, which are not directly part of the # instructions, but which can be called by the instruction body # ******* opCode = cxx_writer.Code(""" if((bitSeq & (1 << (bitSeq_length - 1))) != 0) bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length); return bitSeq; """) SignExtend_method = trap.HelperMethod('SignExtend', opCode, 'execute') SignExtend_method.setSignature( ('BIT<32>'), [('bitSeq', 'BIT<32>'), cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)]) # PC increment opCode = cxx_writer.Code(""" if (TARGET == 0xffffffff) { PC = PC + 4; DSFLAG = 0x0; } else { PC = TARGET; TARGET = 0xffffffff; DSFLAG = 0x1; } """) IncrementPC = trap.HelperOperation('IncrementPC', opCode, inline=False) opCode = cxx_writer.Code("""
def getCPPRegisters(self, trace, combinedTrace, model, namespace): """Creates a container register bank for all registers, register banks, aliases and alias register banks of a processor. This encapsulates the register instantiation details (defining fields, etc) away from the processor. It also eases passes the registers to instructions, since only the container class needs to be passed. @see trap/runtime/modules/register/register_bank.hpp for a discussion.""" #--------------------------------------------------------------------------- ## @name Preprocessing # @{ # Abstraction Level abstractionType = cxx_writer.Type( 'trap::amba_layer_ids', 'register_abstraction.hpp') #'amba_parameters.h') abstraction = '' if model.startswith('acc'): abstraction = 'trap::amba_CT' elif model.startswith('func'): if model.endswith('AT'): abstraction = 'trap::amba_AT' else: abstraction = 'trap::amba_LT' # Register Types regLen = 0 # Determine the register with the largest bitwidth. for reg in self.regs + self.regBanks: if reg.bitWidth > regLen: regLen = reg.bitWidth from isa import resolveBitType global registerInterfaceType, registerType, aliasType registerMaxBitwidth = resolveBitType('BIT<' + str(regLen) + '>') registerFieldType = cxx_writer.TemplateType('trap::RegisterField', [registerMaxBitwidth], 'modules/register.hpp') registerInterfaceType = cxx_writer.TemplateType( 'trap::RegisterInterface', [registerMaxBitwidth, registerFieldType], 'modules/register.hpp') registerType = cxx_writer.TemplateType('trap::Register', [registerMaxBitwidth], 'modules/register.hpp') aliasType = cxx_writer.TemplateType('trap::RegisterAlias', [registerMaxBitwidth], 'modules/register.hpp') # Alias Register and Alias Register Bank Initialization Order # Aliases that depend on each other need to be initialized in order. We # therefore create a dependency graph for both alias registers and alias # register banks. if nxVersion < 0.99: aliasUnsortedGraph = NX.XDiGraph() else: aliasUnsortedGraph = NX.DiGraph() for alias in self.aliasRegs + self.aliasRegBanks: aliasUnsortedGraph.add_node(alias) for alias in self.aliasRegs + self.aliasRegBanks: aliasPredecessors = [] if isinstance(alias.initAlias, str): bracketIdx = alias.initAlias.find('[') if bracketIdx > 0: aliasPredecessors.append(alias.initAlias[:bracketIdx]) else: aliasPredecessors.append(alias.initAlias) else: for aliasPredecessor in alias.initAlias: bracketIdx = aliasPredecessor.find('[') if bracketIdx > 0: aliasPredecessors.append(aliasPredecessor[:bracketIdx]) else: aliasPredecessors.append(aliasPredecessor) for aliasPredecessor in aliasPredecessors: for aliasTarget in self.aliasRegs + self.aliasRegBanks: if aliasPredecessor == aliasTarget.name: aliasUnsortedGraph.add_edge(aliasTarget, alias) # Check for circular dependencies. # NOTE: We might have some false positives here. We discarded indices for # banks, so a perfectly valid REGS1[x1]->REGS2[y1]; REGS2[y2]->REGS1[x2] # with ((x1 != x2) || (y1 != y2)) will be stored as REG1->REGS2; # REGS2->REGS1 and raise an error. # In reality, this will probably never happen anyway, since the visibility # of banks as a whole tends to be hierarchical. if not NX.is_directed_acyclic_graph(aliasUnsortedGraph): raise Exception( 'Detected circular dependence in alias initializations.') # Sort dependency graph. global aliasGraph aliasGraph = NX.topological_sort(aliasUnsortedGraph) registerElements = [] # reg_clock_cycle() # @see getPipeClockCycleFunction. pipeClockCycleFunction = getPipeClockCycleFunction(self, registerMaxBitwidth) if model.startswith('acc'): registerElements.append(pipeClockCycleFunction) ## @} Preprocessing #--------------------------------------------------------------------------- ## @name Attributes and Initialization # @{ from processor import extractRegInterval registerMembers = [] registerCtorParams = [] registerCtorInit = [] registerCtorCode = '' # Registers registerCtorCode += '// Initialize registers.\n' for reg in self.regs: # Attribute Declaration registerMembers.append( cxx_writer.Attribute(reg.name.lower(), registerType, 'public')) # Constructor Parameters if isinstance(reg.constValue, str): if reg.constValue not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(reg.constValue, registerMaxBitwidth)) # Iterable element, i.e. initialization with a constant and an offset. # TODO: Some of the default values are processor variables such as # ENTRY_POINT and MPROC_ID. These are sadly globals and set by the # loader at some point. The current solution passes uninitialized # values. There are several options: # 1. Force program loading before processor construction. Easy but # limits the user. # 2. Keep the current proc if, but pass a reference instead of a value. # Create a stub bool = 0 for all other registers. Minimal impact but # ugly. # 3. Create processor.load(), which sets both the processor vars and # resets the registers. Works for the PC, but not for others. Also # still ugly, as the register should do its own resetting. # 4. Create a processor.load(), which calls a register. # set_reset_value(). 1) Clean processor if, 2) keeps the reset value # in the register and 3) works for both const and non-const reset # values. if isinstance(reg.defValue, tuple): if reg.defValue[0] not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(str(reg.defValue[0]), registerMaxBitwidth)) elif isinstance(reg.defValue, str): if reg.defValue not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(str(reg.defValue), registerMaxBitwidth)) # Constructor Initialization List # name, abstraction Code = '("' + reg.name.lower() + '", ' + abstraction + ', ' # is_const if reg.constValue: Code += 'true, ' else: Code += 'false, ' # offset if reg.offset: Code += str(reg.offset) + ', ' else: Code += '0, ' # delay if reg.delay: Code += str(reg.delay) + ', ' else: Code += '0, ' # reset_val if reg.constValue != None: try: Code += hex(reg.constValue) except TypeError: Code += str(reg.constValue) elif reg.defValue != None: # Iterable element, i.e. initialization with a constant and an # offset. if isinstance(reg.defValue, tuple): Code += str(reg.defValue[0]) + ' + ' try: Code += hex(reg.defValue[1]) except TypeError: Code += str(reg.defValue[1]) else: try: Code += hex(reg.defValue) except TypeError: Code += str(reg.defValue) else: Code += '0' Code += ', ' # num_pipe_stages if self.pipes: Code += str(len(self.pipes)) else: Code += '1' if model.startswith('acc'): if reg.isGlobal: Code += ', NULL, true' elif reg.wbStageOrder: registerClockCycleFunction = getRegisterClockCycleFunction( self, reg.name, reg.wbStageOrder, registerMaxBitwidth) registerElements.append(registerClockCycleFunction) Code += ', ' + registerClockCycleFunction.name elif pipeClockCycleFunction: Code += ', ' + pipeClockCycleFunction.name Code += ')' registerCtorInit.append(reg.name.lower() + Code) # Constructor Body: Add fields if reg.bitMask: for registerFieldMaskName, registerFieldMaskPos in reg.bitMask.items( ): registerCtorCode += reg.name.lower( ) + '.add_field("' + registerFieldMaskName + '", ' + str( registerFieldMaskPos[1]) + ', ' + str( registerFieldMaskPos[0]) + ');\n' registerCtorCode += '\n' # Register Banks registerCtorCode += '// Initialize register banks.\n' for regBank in self.regBanks: # Attribute Declaration registerMembers.append( cxx_writer.Attribute( regBank.name.lower() + '[' + str(regBank.numRegs) + ']', registerType, 'public')) # Constructor Parameters for regConstValue in regBank.constValue.values(): if isinstance(regConstValue, str): if regConstValue not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(regConstValue, registerMaxBitwidth)) for regDefaultValue in regBank.defValues: # Iterable element, i.e. initialization with a constant and an # offset. if isinstance(regDefaultValue, tuple): if regDefaultValue[0] not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(str(regDefaultValue[0]), registerMaxBitwidth)) elif isinstance(regDefaultValue, str): if regDefaultValue not in [ param.name for param in registerCtorParams ]: registerCtorParams.append( cxx_writer.Parameter(str(regDefaultValue), registerMaxBitwidth)) # Constructor Initialization List Code = '' for reg in range(0, regBank.numRegs): # name, abstraction Code += '{"' + regBank.name.lower() + '[' + str( reg) + ']", ' + abstraction + ', ' # is_const if regBank.constValue.has_key(reg): Code += 'true, ' else: Code += 'false, ' # offset if regBank.offset: Code += str(regBank.offset) + ', ' else: Code += '0, ' # delay if regBank.delay.has_key(reg): Code += str(regBank.delay[reg]) + ', ' else: Code += '0, ' # reset_val if regBank.constValue.has_key(reg): try: Code += hex(regBank.constValue[reg]) except TypeError: Code += str(regBank.constValue[reg]) elif regBank.defValues[reg] != None: # Iterable element, i.e. initialization with a constant and an # offset. if isinstance(regBank.defValues[reg], tuple): Code += str(regBank.defValues[reg][0]) + ' + ' try: Code += hex(regBank.defValues[reg][1]) except TypeError: Code += str(regBank.defValues[reg][1]) else: try: Code += hex(regBank.defValues[reg]) except TypeError: Code += str(regBank.defValues[reg]) else: Code += '0' Code += ', ' # num_pipe_stages if self.pipes: Code += str(len(self.pipes)) else: Code += '1' if model.startswith('acc'): if regBank.isGlobal: Code += ', NULL, true' elif regBank.wbStageOrder.has_key(reg): registerClockCycleFunction = getRegisterClockCycleFunction( self, regBank.name + str(reg), regBank.wbStageOrder[reg], registerMaxBitwidth) registerElements.append(registerClockCycleFunction) Code += ', ' + registerClockCycleFunction.name elif pipeClockCycleFunction: Code += ', ' + pipeClockCycleFunction.name Code += '},\n' registerCtorInit.append(regBank.name.lower() + ' {' + Code[:-2] + '}') # Constructor Body: Add fields. if regBank.bitMask: registerCtorCode += 'for (unsigned i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' for registerFieldMaskName, registerFieldMaskPos in regBank.bitMask.items( ): registerCtorCode += regBank.name.lower( ) + '[i].add_field("' + registerFieldMaskName + '", ' + str( registerFieldMaskPos[1]) + ', ' + str( registerFieldMaskPos[0]) + ');\n' registerCtorCode += '}\n\n' # Alias Registers for alias in self.aliasRegs: # Attribute Declaration #aliasType = cxx_writer.TemplateType('std::reference_wrapper', [registerType], 'functional') #aliasBankType = cxx_writer.TemplateType('std::vector', [aliasType], 'vector') registerMembers.append( cxx_writer.Attribute(alias.name.lower(), aliasType, 'public')) # Constructor Initialization List registerCtorInit.append(alias.name.lower() + '("' + alias.name.lower() + '")') # Alias Register Banks for aliasBank in self.aliasRegBanks: # Attribute Declaration registerMembers.append( cxx_writer.Attribute( aliasBank.name.lower() + '[' + str(aliasBank.numRegs) + ']', aliasType, 'public')) # Constructor Initialization List Code = '' for aliasIdx in range(0, aliasBank.numRegs): Code += '{"' + aliasBank.name.lower() + '[' + str( aliasIdx) + ']"},' registerCtorInit.append(aliasBank.name.lower() + ' {' + Code[:-1] + '}') # Alias Registers and Alias Register Banks # Constructor Body: Update alias targets. registerCtorCode += '// Initialize alias registers and alias register banks.\n' for alias in aliasGraph: if isinstance(alias.initAlias, str): regName = alias.initAlias[:alias.initAlias.find('[')] regRange = extractRegInterval(alias.initAlias) # REGBANK[n], REGBANK[n:m], REGBANK if regRange or regName in self.regBanks + self.aliasRegBanks: aliasIdx = 0 if regRange: regStart = regRange[0] regEnd = regRange[1] + 1 else: regStart = 0 regEnd = reg.numRegs for regIdx in range(regStart, regEnd): registerCtorCode += 'this->' + alias.name.lower() if alias in self.aliasRegBanks: registerCtorCode += '[' + str(aliasIdx) + ']' registerCtorCode += '.update_alias(this->' + regName.lower( ) + '[' + str(regIdx) + ']' if alias in self.aliasRegs: registerCtorCode += ', ' + str(alias.offset) elif alias.offsets.has_key(aliasIdx): registerCtorCode += ', ' + str(alias.offsets[aliasIdx]) else: registerCtorCode += ', 0' registerCtorCode += ');\n' aliasIdx = aliasIdx + 1 # REG else: registerCtorCode += 'this->' + alias.name.lower( ) + '.update_alias(this->' + regName.lower() if alias in self.aliasRegs: registerCtorCode += ', ' + str(alias.offset) elif alias.offsets.has_key(aliasIdx): registerCtorCode += ', ' + str(alias.offsets[aliasIdx]) else: registerCtorCode += ', 0' registerCtorCode += ');\n' else: aliasIdx = 0 for reg in alias.initAlias: regName = reg[:reg.find('[')] regRange = extractRegInterval(reg) # REGBANK[n], REGBANK[n:m], REGBANK if regRange or regName in self.regBanks + self.aliasRegBanks: if regRange: regStart = regRange[0] regEnd = regRange[1] + 1 else: regStart = 0 regEnd = reg.numRegs for regIdx in range(regStart, regEnd): registerCtorCode += 'this->' + alias.name.lower( ) + '[' + str( aliasIdx ) + '].update_alias(this->' + regName.lower( ) + '[' + str(regIdx) + ']' if alias.offsets.has_key(aliasIdx): registerCtorCode += ', ' + str( alias.offsets[aliasIdx]) else: registerCtorCode += ', 0' registerCtorCode += ');\n' aliasIdx = aliasIdx + 1 # REG else: registerCtorCode += 'this->' + alias.name.lower( ) + '[' + str( aliasIdx) + '].update_alias(this->' + regName.lower() if alias.offsets.has_key(aliasIdx): registerCtorCode += ', ' + str(alias.offsets[aliasIdx]) else: registerCtorCode += ', 0' registerCtorCode += ');\n' aliasIdx = aliasIdx + 1 # Constructor registerCtor = cxx_writer.Constructor(cxx_writer.Code(registerCtorCode), 'public', parameters=registerCtorParams, initList=registerCtorInit) ## @} Attributes and Initialization #--------------------------------------------------------------------------- ## @name Methods # Access and Modification: reset(), write(), write_dbg(), write_force() # Observer: execute_callbacks(), set_stage(), unset_stage(), clock_cycle() # Information and Helper: operator<<() # @{ # TODO: Consider a visitor pattern, where the function visiting the # registers is passed as a parameter. # Method Bodies: Registers registerResetCode = '// Reset registers.\n' registerWriteCode = 'bool ret = true;\n\n// Write registers.\n' registerWriteDbgCode = 'bool ret = true;\n\n// Write registers.\n' registerWriteForceCode = 'bool ret = true;\n\n// Write registers.\n' registerExecuteCallbacksCode = '// Execute callbacks on registers.\n' registerSetStageCode = '// Set pipeline stage for registers.\n' registerUnsetStageCode = '// Unset pipeline stage for registers.\n' registerClockCycleCode = '// Propagate pipeline stage for registers.\n' registerStallCode = '// Stall pipeline for registers.\n' registerAdvanceCode = '// Advance pipeline for registers.\n' registerFlushCode = '// Flush registers.\n' registerPrintCode = 'os << std::hex << std::showbase;\n\n// Print registers.\n' for reg in self.regs: if reg.constValue == None: registerResetCode += reg.name.lower() + '.reset();\n' registerWriteCode += 'ret = ret && ' + reg.name.lower( ) + '.write(data);\n' registerWriteDbgCode += 'ret = ret && ' + reg.name.lower( ) + '.write_dbg(data);\n' registerWriteForceCode += 'ret = ret && ' + reg.name.lower( ) + '.write_force(data);\n' registerExecuteCallbacksCode += reg.name.lower( ) + '.execute_callbacks(type, 0, sizeof(' + registerMaxBitwidth.name.lower( ) + '));\n' registerSetStageCode += reg.name.lower( ) + '.get_strategy()->set_stage(stage);\n' registerUnsetStageCode += reg.name.lower( ) + '.get_strategy()->unset_stage();\n' registerClockCycleCode += reg.name.lower() + '.clock_cycle();\n' registerStallCode += reg.name.lower() + '.stall(stage);\n' registerAdvanceCode += reg.name.lower() + '.advance();\n' registerFlushCode += reg.name.lower() + '.flush(stage);\n' registerPrintCode += 'os << ' + reg.name.lower( ) + '.name() << ": " << ' + reg.name.lower( ) + '.read_dbg() << \'\\n\';\n' # Method Bodies: Register Banks registerResetCode += '\n// Reset register banks.\n' registerWriteCode += '\n// Write register banks.\n' registerWriteDbgCode += '\n// Write register banks.\n' registerWriteForceCode += '\n// Write register banks.\n' registerExecuteCallbacksCode += '\n// Execute callbacks on register banks.\n' registerSetStageCode += '\n// Set pipeline stage for register banks.\n' registerUnsetStageCode += '\n// Unset pipeline stage for register banks.\n' registerClockCycleCode += '// Propagate pipeline stage for register banks.\n' registerStallCode += '// Stall pipeline for register banks.\n' registerAdvanceCode += '// Advance pipeline for register banks.\n' registerFlushCode += '// Flush register banks.\n' registerPrintCode += '\n// Print register banks.\n' for regBank in self.regBanks: registerResetCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerResetCode += regBank.name.lower() + '[i].reset();\n' registerResetCode += '}\n\n' registerWriteCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerWriteCode += 'ret = ret && ' + regBank.name.lower( ) + '[i].write(data);\n' registerWriteCode += '}\n\n' registerWriteDbgCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerWriteDbgCode += 'ret = ret && ' + regBank.name.lower( ) + '[i].write_dbg(data);\n' registerWriteDbgCode += '}\n\n' registerWriteForceCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerWriteForceCode += 'ret = ret && ' + regBank.name.lower( ) + '[i].write_force(data);\n' registerWriteForceCode += '}\n\n' registerExecuteCallbacksCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerExecuteCallbacksCode += regBank.name.lower( ) + '[i].execute_callbacks(type, 0, sizeof(' + registerMaxBitwidth.name.lower( ) + '));\n' registerExecuteCallbacksCode += '}\n\n' registerSetStageCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerSetStageCode += regBank.name.lower( ) + '[i].set_stage(stage);\n' registerSetStageCode += '}\n\n' registerUnsetStageCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerUnsetStageCode += regBank.name.lower() + '[i].unset_stage();\n' registerUnsetStageCode += '}\n\n' registerClockCycleCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerClockCycleCode += regBank.name.lower() + '[i].clock_cycle();\n' registerClockCycleCode += '}\n\n' registerStallCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerStallCode += regBank.name.lower() + '[i].stall(stage);\n' registerStallCode += '}\n\n' registerAdvanceCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerAdvanceCode += regBank.name.lower() + '[i].advance();\n' registerAdvanceCode += '}\n\n' registerFlushCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerFlushCode += regBank.name.lower() + '[i].flush(stage);\n' registerFlushCode += '}\n\n' registerPrintCode += 'for (int i = 0; i < ' + str( regBank.numRegs) + '; ++i) {\n' registerPrintCode += 'os << ' + regBank.name.lower( ) + '[i].name() << ": " << ' + regBank.name.lower( ) + '[i].read_dbg() << \'\\n\';\n' registerPrintCode += '}\n\n' registerWriteCode += 'return ret;\n' registerWriteDbgCode += 'return ret;\n' registerWriteForceCode += 'return ret;\n' registerPrintCode += 'os << std::dec;\nreturn os;\n' # Method Declarations registerResetMethod = cxx_writer.Method('reset', cxx_writer.Code(registerResetCode), cxx_writer.voidType, 'public') registerMembers.append(registerResetMethod) registerWriteDataParam = cxx_writer.Parameter( 'data', registerMaxBitwidth.makeConst().makeRef()) registerWriteMethod = cxx_writer.Method('write', cxx_writer.Code(registerWriteCode), cxx_writer.boolType, 'public', [registerWriteDataParam]) registerMembers.append(registerWriteMethod) registerWriteDbgMethod = cxx_writer.Method( 'write_dbg', cxx_writer.Code(registerWriteDbgCode), cxx_writer.boolType, 'public', [registerWriteDataParam]) registerMembers.append(registerWriteDbgMethod) registerWriteForceMethod = cxx_writer.Method( 'write_force', cxx_writer.Code(registerWriteForceCode), cxx_writer.boolType, 'public', [registerWriteDataParam]) registerMembers.append(registerWriteForceMethod) registerExecuteCallbacksUint32RefType = cxx_writer.Type( 'uint32_t', const=True).makeRef() registerExecuteCallbacksMethod = cxx_writer.Method( 'execute_callbacks', cxx_writer.Code(registerExecuteCallbacksCode), cxx_writer.voidType, 'public', [ cxx_writer.Parameter( 'type', cxx_writer.Type('scireg_ns::scireg_callback_type', const=True).makeRef()), cxx_writer.Parameter('offset', registerExecuteCallbacksUint32RefType, initValue='0'), cxx_writer.Parameter('size', cxx_writer.Type('uint32_t', const=True).makeRef(), initValue='0') ]) registerMembers.append(registerExecuteCallbacksMethod) registerSetStageMethod = cxx_writer.Method( 'set_stage', cxx_writer.Code(registerSetStageCode), cxx_writer.voidType, 'public', [cxx_writer.Parameter('stage', cxx_writer.uintType)]) registerMembers.append(registerSetStageMethod) registerUnsetStageMethod = cxx_writer.Method( 'unset_stage', cxx_writer.Code(registerUnsetStageCode), cxx_writer.voidType, 'public') registerMembers.append(registerUnsetStageMethod) registerClockCycleMethod = cxx_writer.Method( 'clock_cycle', cxx_writer.Code(registerClockCycleCode), cxx_writer.voidType, 'public') registerMembers.append(registerClockCycleMethod) registerStallMethod = cxx_writer.Method( 'stall', cxx_writer.Code(registerStallCode), cxx_writer.voidType, 'public', [cxx_writer.Parameter('stage', cxx_writer.uintType)]) registerMembers.append(registerStallMethod) registerAdvanceMethod = cxx_writer.Method( 'advance', cxx_writer.Code(registerAdvanceCode), cxx_writer.voidType, 'public') registerMembers.append(registerAdvanceMethod) registerFlushMethod = cxx_writer.Method( 'flush', cxx_writer.Code(registerFlushCode), cxx_writer.voidType, 'public', [cxx_writer.Parameter('stage', cxx_writer.uintType)]) registerMembers.append(registerFlushMethod) registerPrintOstreamRefType = cxx_writer.Type('std::ostream', 'iostream').makeRef() registerPrintMethod = cxx_writer.MemberOperator( '<<', cxx_writer.Code(registerPrintCode), registerPrintOstreamRefType, 'public', [cxx_writer.Parameter('os', registerPrintOstreamRefType)], const=True) registerMembers.append(registerPrintMethod) ## @} Methods #--------------------------------------------------------------------------- registerClass = cxx_writer.ClassDeclaration('Registers', registerMembers, namespaces=[namespace]) registerClass.addDocString( brief='Register Container Class', detail= 'Contains all registers and register banks of the processor as member variables. It serves for encapsulating the instantiation details (defining fields, etc) away from the processor. It also simplifies passing the registers to the instructions, instead of passing each register individually.' ) registerClass.addConstructor(registerCtor) return [registerClass] + registerElements
def 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
# Sign extends the input bitstring opCode = cxx_writer.Code(""" if((bitSeq & (1 << (bitSeq_length - 1))) != 0) bitSeq |= (((unsigned)0xFFFFFFFF) << bitSeq_length); return bitSeq; """) SignExtend_method = trap.HelperMethod('SignExtend', opCode, 'execute', exception=False, const=True) SignExtend_method.setSignature( cxx_writer.intType, [('bitSeq', 'BIT<32>'), cxx_writer.Parameter('bitSeq_length', cxx_writer.uintType)]) # Normal PC increment, used when not in a branch instruction; in a branch instruction # I will directly modify both PC and nPC in case we are in a the cycle accurate model, # while just nPC in case we are in the functional one; if the branch has the annuling bit # set, then also in the functional model both the PC and nPC will be modified raiseExcCode = """ if(PSR[PSR_ET] == 0){ if(exceptionId < IRQ_LEV_15){ // I print a core dump and then I signal an error: an exception happened while // exceptions were disabled in the processor core THROW_EXCEPTION("Exception " << exceptionId << " happened while the PSR[ET] = 0; PC = " << std::hex << std::showbase << PC << std::endl << "Instruction " << get_mnemonic()); } } else{ unsigned curPSR = PSR;