Exemplo n.º 1
0
class HdlToVerilogParamMapper():
    def __init__(self, chipName, partName, lineNo, toPort : VerilogPort, fromPort : VerilogPort):
        self.chipName       = chipName
        self.partName       = partName 
        self.lineNo         = lineNo
        self.toPort         = toPort
        self.fromPort       = fromPort
        self.logger         = Logger()
        self.hdlConnections = [] #type: list[HdlConnection]
        self.mappedParams   = H2VMappedParamsList()
        return

    ##########################################################################
    def AddHdlConnection(self, connection : HdlConnection):
        self.hdlConnections.append(connection)
        return

    ##########################################################################
    def DoMapping(self):
        pin1, pin2   = self.hdlConnections[0].GetPins()
        pin1BitWidth = pin1.GetPinBitWidth()

        self.logger.Info("Start: Chip: %s, part: %s (line %d), pin: %s" % (self.chipName, self.partName, self.lineNo, pin1.pinName))
        for connection in self.hdlConnections:
            pin1, pin2 = connection.GetPins() # type: HdlPin, HdlPin

            self.logger.Info("Mapping: %s" % (connection.GetPinStr()))

            # Note: Cases todo..
            # all bits   <-- input all bits (different bit length)

            pin1BitIndex, pin1StartBitOfBus, pin1EndBitOfBus, pin1ConnectionWidth, pin1ConnectionType = connection.GetPin1Params()
            pin2BitIndex, pin2StartBitOfBus, pin2EndBitOfBus, pin2ConnectionWidth, pin2ConnectionType = connection.GetPin2Params()

            paramFullName = self._MakeParamFullName(pin2.pinName,
                                                    pin2BitIndex,
                                                    pin2StartBitOfBus,
                                                    pin2EndBitOfBus,
                                                    pin2ConnectionWidth,
                                                    True if pin1.pinType == HdlPinTypes.Input else False)

            # Cases:
            # all bits   <-- input all bits (same bit length)
            # all bits   <-- input single bit
            # all bits   <-- input bit range
            # all bits   <-- internal all bits
            if pin1ConnectionType == HdlConnectionTypes.AllBits:
                if pin1BitWidth != pin2ConnectionWidth:
                    self.logger.Error("Mapping all input bits of '%s' to '%s' but bit sizes differ. (Pin size: %d, connection size: %d)" %
                                        (pin1.pinName, pin2.pinName, pin1BitWidth, pin2ConnectionWidth))
                self.mappedParams.AddItem(0, pin1BitWidth - 1, pin1BitWidth, paramFullName)

            # Cases:
            # bit range  <-- input single bit
            elif (pin1ConnectionType == HdlConnectionTypes.BitRange and 
                  pin2ConnectionType == HdlConnectionTypes.SingleBit):
                for hdlBitNumber in range(connection.pin1StartBitOfBus, connection.pin1EndBitOfBus):
                    self.mappedParams.AddItem(hdlBitNumber, hdlBitNumber, pin1BitWidth, paramFullName)

            # Cases:
            # bit range  <-- input all bits
            # bit range  <-- internal all bits
            elif (pin1ConnectionType == HdlConnectionTypes.BitRange and 
                  pin2ConnectionType == HdlConnectionTypes.AllBits):
                self.mappedParams.AddItem(pin1StartBitOfBus, pin1EndBitOfBus, pin1BitWidth, paramFullName)

            # Cases:
            # bit range  <-- input bit range
            elif (pin1ConnectionType == HdlConnectionTypes.BitRange and 
                  pin2ConnectionType == HdlConnectionTypes.BitRange):
                self.mappedParams.AddItem(pin1StartBitOfBus, pin1EndBitOfBus, pin1BitWidth, paramFullName)

            # Cases:
            # single bit <-- input all bits     
            # single bit <-- input single bit 
            # single bit <-- internal all bits
            else:
                self.mappedParams.AddItem(connection.pin1BitIndex, connection.pin1BitIndex, pin1BitWidth, paramFullName)

        self.mappedParams.CompleteMapping(pin1, pin2, pin1BitWidth)
        
        self.logger.Info("End: Mapping chip: %s, part:%s (line %d), pin: %s" % (self.chipName, self.partName, self.lineNo, pin1.pinName))
        return

    ##########################################################################
    def GetMappedParams(self):
        return self.mappedParams
    
    ##########################################################################
    def _MakeParamFullName(self, pinName, pinBitIndex, pinStartBitOfBus, pinEndBitOfBus, pinConnectionWidth, isInputPin):
        paramName  = pinName
        paramExtra = ""

        # If the pin is an Input then swap false to 1'b0
        if isInputPin and pinName == 'false':
            paramName = ("%d'b%s" % (pinConnectionWidth, '0'.join(['0' * pinConnectionWidth])))

        # If the pin is an Input then swap true to 1'b1
        if isInputPin and pinName == 'true':
            paramName = ("%d'b%s" % (pinConnectionWidth, '1'.join(['1' * pinConnectionWidth])))

        if pinBitIndex != commonDefs.NO_BIT_VALUE:
            paramExtra += "[" + str(pinBitIndex) + "]"
        elif pinStartBitOfBus != commonDefs.NO_BIT_VALUE:
            paramExtra += "[" + str(pinEndBitOfBus) + ":"  + str(pinStartBitOfBus) +  "]"

        return ("%s%s" % (paramName, paramExtra))
Exemplo n.º 2
0
class Hdl2verilogMain():
    def __init__(self):
        self.logger = Logger()
        self.fileActions = FileActions()
        self.mapper = HdlToVerilogMapper()
        return

    ##########################################################################
    def Run(self, inputFolder, builtInChipFolder, outputFolder):
        verilogModuleList = VerilogModuleList(builtInChipFolder)
        # Read in the built-in Verilog modules
        verilogFilenames = [
            join(builtInChipFolder, x)
            for x in self.fileActions.GetFilesWithExtInFolder(
                builtInChipFolder, '.v')
        ]
        for verilogFilename in verilogFilenames:
            self.logger.Info("Reading %s .." % (verilogFilename))
            verilogFile = VerilogFile(verilogFilename)
            verilogModule = verilogFile.ParseFile()
            verilogModuleList.AddBuiltInModule(verilogModule)

        hdlChipList = HdlChipList()
        # Read in the built-in HDL chips
        hdlFilenames = [
            join(builtInChipFolder, x)
            for x in self.fileActions.GetFilesWithExtInFolder(
                builtInChipFolder, '.hdl')
        ]
        for hdlFilename in hdlFilenames:
            self.logger.Info("Reading %s .." % (hdlFilename))
            hdlFile = HdlFile(hdlFilename)
            hdlChip = hdlFile.ParseFile()
            hdlChipList.AddBuiltInChip(hdlChip)

        # Read in the input HDL chips to be converted
        hdlFilenames = [
            join(inputFolder, x)
            for x in self.fileActions.GetFilesWithExtInFolder(
                inputFolder, '.hdl')
        ]
        for hdlFilename in hdlFilenames:
            self.logger.Info("Reading %s .." % (hdlFilename))
            hdlFile = HdlFile(hdlFilename)
            hdlChip = hdlFile.ParseFile()
            hdlChipList.AddChip(hdlChip)

        result, builtInChipsUsedList = self.CheckChipDependencies(
            hdlChipList, verilogModuleList)
        if not result:
            return

        hdlChipList.CheckAndAddClockInputs()
        hdlChipList.UpdateAllPinBitWidths()
        hdlChipList.UpdateAllPartConnections()

        # Create the Verilog Modules from input HDL chips
        for hdlChip in hdlChipList.chipList:
            self.mapper.CreateVerilogModule(hdlChip, hdlChipList,
                                            verilogModuleList)

        # Read-in the Tst files and create the Verilog Testbench Modules
        tstsToRun = []
        tstFilenames = self.fileActions.GetFilesWithExtInFolder(
            inputFolder, '.tst')
        for tstFilename in tstFilenames:
            testName, ext = self.fileActions.GetFileNameAndExt(tstFilename)
            self.logger.Info("Reading %s .." % (tstFilename))
            tstFile = TstFile(join(inputFolder, tstFilename))
            tstScript = tstFile.ParseFile(testName)

            tstScript.testChip = hdlChipList.GetChip(tstScript.testHdlModule)
            self.mapper.CreateVerilogModuleTB(tstScript, outputFolder)
            tstsToRun.append(tstScript)

        verilogModuleList.WriteModules(outputFolder)
        verilogModuleList.CopyInternalModules(outputFolder,
                                              builtInChipsUsedList)

        ivlScriptGen = IVerilogScriptGenerator(outputFolder)
        ivlScriptGen.CreateScript(inputFolder, tstsToRun, hdlChipList,
                                  verilogModuleList)
        return

    ##########################################################################
    def CheckChipDependencies(self, hdlChipList, verilogModuleList):
        passed = True
        missingChipList, builtInChipsUsedList, noimplementationChipList = hdlChipList.CheckChipDependencies(
        )

        if len(missingChipList) > 0:
            self.logger.Error(
                "Missing chips detected! Following dependencies were not found in the input folder or built-in chip folder: %s"
                % (missingChipList))
            passed = False

        if len(builtInChipsUsedList) > 0:
            missingBuiltInModuleList = verilogModuleList.CheckModulesInBuiltInList(
                builtInChipsUsedList)

            if len(missingBuiltInModuleList) > 0:
                self.logger.Error(
                    "Missing built-in verilog modules detected! Following expected built-in modules were not found in the built-in chip folder: %s"
                    % (missingBuiltInModuleList))
                passed = False

        if len(noimplementationChipList) > 0:
            self.logger.Error(
                "Some HDL chips are missing implementation! Please check the following HDL chips run and pass tests using the nand2tetris HardwareSimulator : %s"
                % (noimplementationChipList))
            passed = False

        return passed, builtInChipsUsedList
class HdlChipList():
    def __init__(self):
        self.logger = Logger()
        self.chipList = []  # type: list[HdlChip]
        self.builtInChipList = []  # type: list[HdlChip]
        return

    ##########################################################################
    def AddChip(self, chip):
        self.chipList.append(chip)
        return

    ##########################################################################
    def AddBuiltInChip(self, chip):
        self.builtInChipList.append(chip)
        return

    ##########################################################################
    def GetChip(self, chipName):
        result = None
        for hdlChip in self.chipList:
            if hdlChip.chipName == chipName:
                result = hdlChip
                break

        if not result:
            for hdlChip in self.builtInChipList:
                if hdlChip.chipName == chipName:
                    result = hdlChip
                    break

        return result

    ##########################################################################
    def UpdateAllPinBitWidths(self):
        self.logger.Info("Started: UpdateAllPinBitWidths")
        for hdlChip in self.chipList:
            for part in hdlChip.partList:  # type: HdlChipPart
                for connection in part.connections:  # type: HdlConnection
                    pin1, pin2 = connection.GetPins()
                    pinFromChip = self.GetPinFromChip(
                        part.partName, pin1.pinName)  # type: HdlPin
                    hdlChip.UpdatePin1Width(part.partName, pin1.pinName,
                                            pinFromChip.GetPinBitWidth())
                    hdlChip.UpdatePin1Type(pin1.pinName, pinFromChip.pinType)
                    hdlChip.UpdatePin2Width(pin2.pinName,
                                            pinFromChip.GetPinBitWidth())

        self.logger.Info("Completed: UpdateAllPinBitWidths")
        return

    ##########################################################################
    def CheckAndAddClockInputs(self):
        self.logger.Info("Started: CheckAndAddClockInputs")
        for hdlChip in self.chipList:
            clkPin = None
            partsNeedingClkCon = []
            for part in hdlChip.partList:  # type: HdlChipPart
                partChip = self.GetChip(part.partName)
                tmpClkPin = self._GetClkPinInDependencies(partChip)
                if tmpClkPin:
                    partsNeedingClkCon.append(part)
                    clkPin = tmpClkPin

            # If one of the parts contains a chip with a clk input, then add the input
            # to it an create a connection in the part.
            if clkPin:
                if not hdlChip.GetClkPin():
                    hdlChip.AddInputPins([clkPin])

                for part in partsNeedingClkCon:
                    part.AddConnection(HdlConnection(clkPin, clkPin))

        self.logger.Info("Completed: CheckAndAddClockInputs")
        return

    ##########################################################################
    def UpdateAllPartConnections(self):
        self.logger.Info("Started: UpdateAllPartConnections")
        for hdlChip in self.chipList:
            for part in hdlChip.partList:  # type: HdlChipPart
                for connection in part.connections:  # type: HdlConnection
                    connection.UpdateConnectionBitWidths()

        self.logger.Info("Completed: UpdateAllPartConnections")
        return

    ##########################################################################
    def GetPinFromChip(self, chipName, pinName):
        pin = None
        hdlChip = self.GetChip(chipName)

        if hdlChip:  # type: HdlChip
            pin = hdlChip.GetPin(pinName)

        return pin

    ##########################################################################
    def GetBitWidthForPin(self, chipName, pinName):
        bitWidth = None
        hdlChip = self.GetChip(chipName)

        if hdlChip:  # type: HdlChip
            bitWidth = hdlChip.GetBitWidthForPin(pinName)

        #self.logger.Debug("Chip %s, pin \"%s\" bitwidth = %s" % (chipName, pinName, bitWidth))
        return bitWidth

    ##########################################################################
    def GetChipDependencyList(self, hdlChip: HdlChip):
        # Get the direct dependencies of the chip being tested
        moduleList = hdlChip.GetChipDependencyList()

        indirectModules = ['Nand']
        moduleLength = len(indirectModules)
        runLoop = True
        inModuleList = moduleList
        while runLoop == True:
            # Get the indirect dependencies
            for module in inModuleList:  #type: list[string]
                for chip in self.chipList:  #type: HdlChip
                    if module == chip.chipName:
                        newDependencies = chip.GetChipDependencyList()
                        for newDependency in newDependencies:
                            if newDependency not in indirectModules:
                                indirectModules.append(newDependency)
            if moduleLength == len(indirectModules):
                runLoop = False
            else:
                moduleLength = len(indirectModules)
                inModuleList = indirectModules

        for indirectModule in indirectModules:
            if indirectModule not in moduleList:
                moduleList.append(indirectModule)

        moduleList.append(hdlChip.chipName)
        return moduleList

    ##########################################################################
    def CheckChipDependencies(self):
        missingChipList = []
        builtInChipsUsedList = []
        noimplementationChipList = []

        for chip in self.chipList:
            if len(chip.partList) == 0:
                noimplementationChipList.append(chip.filename)

            dependencyList = self.GetChipDependencyList(chip)
            for dependentChip in dependencyList:
                chipFoundList = [
                    x.chipName for x in self.chipList
                    if x.chipName == dependentChip
                ]
                builtInChipFoundList = [
                    x.chipName for x in self.builtInChipList
                    if x.chipName == dependentChip
                ]

                if len(chipFoundList) == 0 and len(
                        builtInChipFoundList
                ) == 0 and dependentChip not in missingChipList:
                    missingChipList.append(dependentChip)

                for chipName in builtInChipFoundList:
                    if chipName not in builtInChipsUsedList:
                        builtInChipsUsedList.append(chipName)

        return missingChipList, builtInChipsUsedList, noimplementationChipList

    ##########################################################################
    def _GetChipsFromNameList(self, chipNameList):
        chipList = []
        for chipName in chipNameList:
            chipList.append(self.GetChip(chipName))
        return chipList

    ##########################################################################
    def _GetClkPinInDependencies(self, hdlChip: HdlChip):
        chipDependencyList = self.GetChipDependencyList(hdlChip)
        chipList = self._GetChipsFromNameList(chipDependencyList)

        clkPin = None
        for chip in chipList:
            clkPin = chip.GetClkPin()
            if clkPin:
                break

        return clkPin
class VerilogModuleTB():
    def __init__(self, moduleName, testModuleName, dumpFilename, outFilename,
                 clkPortName):
        self.logger = Logger()
        self.moduleName = moduleName
        self.testModuleName = testModuleName
        self.dumpFilename = dumpFilename
        self.outFilename = outFilename
        self.clkPortName = clkPortName
        self.inputPorts = []
        self.outputPorts = []
        self.outputFormats = []
        self.testSequences = []
        return

    ##########################################################################
    def AddInputPorts(self, inputs):
        self.logger.Debug("AddInputPorts: %d" % (len(inputs)))
        for inputPort in inputs:
            self.inputPorts.append(inputPort)
        return

    ##########################################################################
    def AddOutputPorts(self, outputs):
        self.logger.Debug("AddOutputPorts: %d" % (len(outputs)))
        for outputPort in outputs:
            self.outputPorts.append(outputPort)
        return

    ##########################################################################
    def AddOutputFormatList(self, outputFormatList):
        self.logger.Debug("AddOutputFormatList: %d" % (len(outputFormatList)))
        self.outputFormatList = outputFormatList
        return

    ##########################################################################
    def AddTestSequence(self, testSequence: TstSetSequence):
        self.testSequences.append(testSequence)
        return

    ##########################################################################
    def GetInputNameList(self):
        return [str(x.portName) for x in self.inputPorts]

    ##########################################################################
    def GetOutputNameList(self):
        return [str(x.portName) for x in self.outputPorts]

    ##########################################################################
    def GetInputPortList(self):
        return self.inputPorts

    ##########################################################################
    def GetOutputPortList(self):
        return self.outputPorts

    ##########################################################################
    def GetOutputFormatList(self):
        return self.outputFormatList

    ##########################################################################
    def GetOutputParamList(self):
        return [x for x in self.outputFormatList if x.GetParamName() != "time"]

    ##########################################################################
    def GetClkPortName(self):
        return self.clkPortName

    ##########################################################################
    def GetPortSignedStr(self, portName):
        signedStr = "signed"
        # HDL HardwareSimulator.sh treats certain params as unsigned if they
        # are specified as decimal. This is a hack to replicate that behaviour.
        if portName == "address" or portName == "sel":
            signedStr = "unsigned"

        return signedStr

    ##########################################################################
    def DumpModuleDetails(self):
        self.logger.Info("***** START: %s Verilog TestBench Module *****" %
                         (self.moduleName))
        self.logger.Info("Interface:")
        self.logger.Info("  Inputs:  %s" %
                         (', '.join(self.GetInputNameList())))
        self.logger.Info("  Outputs: %s" %
                         (', '.join(self.GetOutputNameList())))

        sequenceNumber = 1
        self.logger.Info("Test Steps:")
        for setSequence in self.testSequences:  #type: TstSetSequence
            self.logger.Info("  Test Step: %d" % (sequenceNumber))
            if setSequence.setOperations:
                for setOperation in setSequence.setOperations:  #type: TstSetOperation
                    self.logger.Info(
                        "    Operation: %s = %s" %
                        (setOperation.pinName, setOperation.pinValue))
            sequenceNumber += 1
        self.logger.Info("***** END: %s Verilog TestBench Module *****" %
                         (self.moduleName))
        return
class VerilogModule():
    def __init__(self, moduleName):
        self.logger = Logger()
        self.moduleName = moduleName
        self.inputPorts = []
        self.outputPorts = []
        self.submoduleCalls = []
        self.wireAssignments = []

        if self.moduleName:
            self.SetModuleFilename(self.moduleName + ".v")
        return

    ##########################################################################
    def SetModuleName(self, moduleName):
        self.moduleName = moduleName

    ##########################################################################
    def SetModuleFilename(self, moduleFilename):
        self.moduleFilename = moduleFilename

    ##########################################################################
    def AddInputPorts(self, inputs):
        #self.logger.Debug("AddInputPorts: %d" % (len(inputs)))
        for inputPort in inputs:
            self.inputPorts.append(inputPort)
        return

    ##########################################################################
    def AddOutputPorts(self, outputs):
        #self.logger.Debug("AddOutputPorts: %d" % (len(outputs)))
        for outputPort in outputs:
            self.outputPorts.append(outputPort)
        return

    ##########################################################################
    def AddSubmoduleCall(self, submoduleCall):
        self.submoduleCalls.append(submoduleCall)
        return

    ##########################################################################
    def AddWireAssignment(self, wireAssignment):
        self.wireAssignments.append(wireAssignment)
        return

    ##########################################################################
    def GetInputPortList(self):
        return self.inputPorts

    ##########################################################################
    def GetOutputPortList(self):
        return self.outputPorts

    ##########################################################################
    def GetPortFromName(self, portName):
        port = None

        for inputPort in self.inputPorts:  # type: VerilogPort
            if portName == inputPort.portName:
                port = inputPort

        for outputPort in self.outputPorts:  # type: VerilogPort
            if portName == outputPort.portName:
                port = outputPort

        return port

    ##########################################################################
    def GetSubmoduleCalls(self):
        return self.submoduleCalls

    ##########################################################################
    def GetWireAssignments(self):
        return self.wireAssignments

    ##########################################################################
    def DumpModuleDetails(self):
        self.logger.Info("***** START: %s Verilog Module *****" %
                         (self.moduleName))
        self.logger.Info("Interface:")
        self.logger.Info(
            "  Inputs:  %s" %
            (', '.join([str(x.GetPortStr()) for x in self.inputPorts])))
        self.logger.Info(
            "  Outputs: %s" %
            (', '.join([str(x.GetPortStr()) for x in self.outputPorts])))

        self.logger.Info("Implementation:")
        for submoduleCall in self.GetSubmoduleCalls():
            self.logger.Info("  Submodule %s: %s" %
                             (submoduleCall.GetModuleName(),
                              submoduleCall.GetCallParamsStr()))
        self.logger.Info("***** END: %s Verilog Module *****" %
                         (self.moduleName))
        return