示例#1
0
 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')
示例#2
0
 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')
示例#3
0
 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')
示例#4
0
 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')
示例#5
0
 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')
示例#6
0
 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')
示例#7
0
    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
示例#8
0
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
示例#9
0
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