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 testSimpleFunction(self): code = cxx_writer.Code('printf(\"Wow\");') function = cxx_writer.Function('dummy_func', code) function.writeImplementation(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'void dummy_func() {\n') self.assertEqual(lines[1], ' printf(\"Wow\");\n') self.assertEqual(lines[2], '} // dummy_func()\n')
def testTemplateFunctionsImpl(self): tempType = cxx_writer.TemplateType('std::map', [cxx_writer.intType, cxx_writer.stringType], 'map') tempVar = cxx_writer.Function('pippo', cxx_writer.Code('std::map<int, std::string> myMap;\nmyMap[5] = \"ccc\";\nreturn myMap;'), tempType, [], False, ['T']) dumper = cxx_writer.FileDumper('prova.cpp', False, indentSize = 4, lineWidth = 80) dumper.addMember(tempVar) dumper.write() testFile = open('prova.cpp', 'rt') lines = testFile.readlines() testFile.close() os.remove('prova.cpp') self.assertEqual(len(lines), 2 + 14) self.assertEqual(lines[11], '#include <map>\n') self.assertEqual(lines[12], '#include <string>\n')
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 testTemplateFunctionsHeader(self): tempType = cxx_writer.TemplateType('std::map', [cxx_writer.intType, cxx_writer.stringType], 'map') tempVar = cxx_writer.Function('pippo', cxx_writer.Code('std::map<int, std::string> myMap;\nmyMap[5] = \"ccc\";\nreturn myMap;'), tempType, [], False, False, ['T']) dumper = cxx_writer.FileDumper('prova.cpp', True, indentSize = 4, lineWidth = 80) dumper.addMember(tempVar) dumper.write() testFile = open('prova.cpp', 'rt') lines = testFile.readlines() testFile.close() os.remove('prova.cpp') self.assertEqual(len(lines), 7 + 18) self.assertEqual(lines[13], '#include <map>\n') self.assertEqual(lines[14], '#include <string>\n') self.assertEqual(lines[17], 'template <typename T> std::map<int, std::string> pippo() {\n') self.assertEqual(lines[18], ' std::map<int, std::string> myMap;\n') self.assertEqual(lines[19], ' myMap[5] = \"ccc\";\n') self.assertEqual(lines[20], ' return myMap;\n') self.assertEqual(lines[21], '} // pippo()\n')
def testReturnFunction(self): code = cxx_writer.Code( 'if (works) {\nprintf(\"hummm\\n\");\nreturn 1;\n} else {\nreturn 0;\n}' ) retType = cxx_writer.intType function = cxx_writer.Function('dummy_func', code, retType) function.writeImplementation(self.writer) self.writer.flush() testFile = open('prova.cpp', 'r') lines = testFile.readlines() testFile.close() self.assertEqual(len(lines), 8) self.assertEqual(lines[0], 'int dummy_func() {\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 getCPPDecoderTests(self, namespace = ''): """Returns the decoder tests. All the instruction patterns, including invalid patterns, are fed to the decoder and the decoding output checked. Random values are chosen for don't-care bits.""" import cxx_writer import random, math ranGen = random.SystemRandom() allTests = [] testCount = 0 for instrId, instruction in self.instrId.items(): code = namespace + '::Decoder dec;\n' pattern = instruction[0] try: pattern[0][0] pattern = pattern[0] except: pass for i in range(0, len(pattern)): if pattern[i] == None: if ranGen.random() > 0.5: pattern[i] = '1' else: pattern[i] = '0' else: pattern[i] = str(pattern[i]) if instrId == -1: expectedId = self.instrNum else: # Check for the presence of sub-instructions and possibly # adapt the expected test outcome. expectedId = None for instr in self.instrSub[instrId]: found = True revInstrPattern = instr.bitstring revInstrPattern.reverse() for i in range(0, len(pattern)): if revInstrPattern[i] != None and int(pattern[i]) != revInstrPattern[i]: found = False if found: expectedId = instr.id break if expectedId == None: expectedId = instrId pattern.reverse() if instrId != -1: code += '// Checking Instruction ' + self.instrName[instrId] + '.\n' else: code += '// Checking Invalid Instruction.\n' code += 'BOOST_CHECK_EQUAL(dec.decode(' + hex(int(''.join(pattern), 2)) + '), ' + str(expectedId) + ');\n' curTest = cxx_writer.Code(code) curTest.addInclude(['boost/test/test_tools.hpp', 'decoder.hpp']) if instrId != -1: testName = self.instrName[instrId] + '_' + str(testCount) + '_decode' else: testName = 'Invalid_' + str(testCount) + '_decode' curTestFunction = cxx_writer.Function(testName, curTest, cxx_writer.voidType) from procWriter import testNames testNames.append(testName) allTests.append(curTestFunction) testCount += 1 return allTests
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
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