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))
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