class TstScript(): def __init__(self): self.logger = Logger() self.testName = None self.testHdlModule = None self.outputFile = None self.compareFile = None self.testChip = None self.outputFormatList = [] self.setSequences = [] return ########################################################################## def AddSetSequence(self, setSequence): self.setSequences.append(setSequence) return ########################################################################## def SetOutputFormatList(self, outputFormatList): self.outputFormatList = outputFormatList return ########################################################################## def GetOutputFormatList(self): return self.outputFormatList ########################################################################## def DumpTestDetails(self): self.logger.Debug("***** START: %s Test Script *****" % (self.testName)) self.logger.Debug("Test module: %s" % (self.testHdlModule)) self.logger.Debug("Output file: %s" % (self.outputFile)) self.logger.Debug("Compare file: %s" % (self.compareFile)) self.logger.Debug( "Output format: %s" % (', '.join([x.GetParamName() for x in self.outputFormatList]))) sequenceNumber = 1 for setSequence in self.setSequences: #Type: TstSetSequence self.logger.Debug(" Sequence: %d" % (sequenceNumber)) if setSequence.setOperation: self.logger.Debug(" Operation: %s = %s" % (setSequence.setOperation.pinName, setSequence.setOperation.pinValue)) sequenceNumber += 1 self.logger.Debug("***** END: %s Test Script *****" % (self.testName)) return
class H2VParamMappingList: def __init__(self): self.logger = Logger() self.verilogCallParams = VerilogCallParams() self.paramMappingList = [] #type: list[H2VParamMappingItem] return ########################################################################## def AddItem(self, hdlStartBit, hdlEndBit, pinBitWdith, verilogParam): itemAdded = False overlapDetected = False for item in self.paramMappingList: if hdlStartBit >= item.hdlStartBit and hdlEndBit <= item.hdlEndBit: overlapDetected = True break if not overlapDetected: self.paramMappingList.append(H2VParamMappingItem(hdlStartBit, hdlEndBit, pinBitWdith, verilogParam)) itemAdded = True return itemAdded ########################################################################## def CompleteMapping(self, pin1, pin2, pin1BitWidth): numMappedBits = self._CountMappedBits(self.paramMappingList) if numMappedBits < pin1BitWidth: self.logger.Debug("Not enough bits mapped: %s to %s: Bit Width: %d, Mapped Bits: %d. Will add padding." % (pin1.pinName, pin2.pinName, pin1BitWidth, numMappedBits)) self._PadMissingBits(pin1.pinName, pin2.pinName, pin1BitWidth, self.paramMappingList, True if pin1.pinType == HdlPinTypes.Output else False) newlist = sorted(self.paramMappingList, key=lambda x: x.vStartBit) for item in newlist: self.verilogCallParams.AddParam(item.verilogParam) #print(len(newlist)) #self.verilogCallParams.DumpInfo() return ########################################################################## def GetVerilogParams(self): return self.verilogCallParams ########################################################################## def _PadMissingBits(self, pin1Name, pin2Name, pinBitWidth, paramMappingList, isOutputPin): bitMapList = [0] * pinBitWidth for item in paramMappingList: for i in range(item.hdlStartBit, item.hdlEndBit + 1): bitMapList[i] = 1 if isOutputPin: for i in range(0, pinBitWidth): if bitMapList[i] == 0: paramMappingList.append(H2VParamMappingItem(i, i, pinBitWidth, "false")) else: startPos = -1 endPos = -1 for i in range(0, pinBitWidth): if startPos == -1 and bitMapList[i] == 0: startPos = i if startPos != -1 and bitMapList[i] == 1: endPos = i width = endPos - startPos paramMappingList.append(H2VParamMappingItem(startPos, endPos, pinBitWidth, str(width) + "'b0")) startPos = -1 endPos = -1 if startPos != -1 and endPos == -1: width = pinBitWidth - startPos paramMappingList.append(H2VParamMappingItem(startPos, pinBitWidth - 1, pinBitWidth, str(width) + "'b0")) #print("%s --> %s: %s" % (pin1Name, pin2Name, bitMapList)) return ########################################################################## def _CountMappedBits(self, paramMappingList): totalBits = 0 for item in paramMappingList: totalBits += item.GetNumBits() return totalBits
class HdlToVerilogMapper(): def __init__(self): self.logger = Logger() return ########################################################################## def CreateVerilogModuleTB(self, tstScript : TstScript, outputFolder): hdlChip = tstScript.testChip # type: HDLChip verilogModGen = VerilogTestBenchGenerator(outputFolder) clkPinName = None clkPin = hdlChip.GetClkPin() if clkPin: clkPinName = clkPin.pinName verilogModuleTB = VerilogModuleTB(tstScript.testName + "_tb", tstScript.testHdlModule, tstScript.testName + ".vcd", tstScript.outputFile, clkPinName) portList = [] for inputPin in hdlChip.GetInputPinList(): #type: HdlPin portList.append(self._HdlPinToVerilogPort(inputPin, inputPin.GetPinBitWidth())) verilogModuleTB.AddInputPorts(portList) portList = [] for outputPin in hdlChip.GetOutputPinList(): #type: HdlPin portList.append(self._HdlPinToVerilogPort(outputPin, outputPin.GetPinBitWidth())) verilogModuleTB.AddOutputPorts(portList) verilogModuleTB.AddOutputFormatList(tstScript.GetOutputFormatList()) for setSequence in tstScript.setSequences: #type: TstSetSequence setOperation = None if setSequence.setOperation: setOperation = TstSetOperation(setSequence.setOperation.pinName, self._HdlFormatToVerilogFormatLiteral(setSequence.setOperation.pinValue)) verilogModuleTB.AddTestSequence(TstSetSequence(setSequence.sequenceType, setOperation)) #verilogModuleTB.DumpModuleDetails() verilogModGen.CreateModule(verilogModuleTB) return ########################################################################## def CreateVerilogModule(self, hdlChip : HdlChip, hdlChipList : HdlChipList, verilogModuleList : VerilogModuleList): partList = hdlChip.GetChipPartList() #type: list[HdlChipPart] verilogMainModule = VerilogModule(hdlChip.chipName) portList = [] for inputPin in hdlChip.GetInputPinList(): #type: HdlPin portList.append(self._HdlPinToVerilogPort(inputPin, inputPin.GetPinBitWidth())) verilogMainModule.AddInputPorts(portList) portList = [] for outputPin in hdlChip.GetOutputPinList(): #type: HdlPin portList.append(self._HdlPinToVerilogPort(outputPin, outputPin.GetPinBitWidth())) verilogMainModule.AddOutputPorts(portList) tmpVarCounter = 0 verilogSubmoduleDict = {} for part in partList: self.logger.Debug("Mapping: Chip %s, Part %s (line %d)" % (hdlChip.chipName, part.partName, part.lineNo)) connections = part.GetConnections() #type: list[HdlConnection] paramMapperDict = {} for connection in connections: pin1, pin2 = connection.GetPins() # type: HdlPin, HdlPin toPort = self._HdlPinToVerilogPort(pin1, pin1.GetPinBitWidth()) fromPort = self._HdlPinToVerilogPort(pin2, connection.pin2ConnectionWidth) keyName = pin1.pinName if keyName not in paramMapperDict: paramMapperDict[keyName] = HdlToVerilogParamMapper(hdlChip.chipName, part.partName, part.lineNo, toPort, fromPort) paramMapperDict[keyName].AddHdlConnection(connection) if part.partName not in verilogSubmoduleDict: verilogSubmoduleDict[part.partName] = 0 else: verilogSubmoduleDict[part.partName] += 1 verilogSubmoduleCall = VerilogSubmoduleCall(part.partName, verilogSubmoduleDict[part.partName]) for paramMapper in paramMapperDict: paramMapperDict[paramMapper].DoMapping() toPort = paramMapperDict[paramMapper].toPort fromPort = paramMapperDict[paramMapper].fromPort mappedParams = paramMapperDict[paramMapper].GetMappedParams() numParamsForCall = mappedParams.GetNumParamsForCall() # Normal case: All parameters can be mapped onto a single input or output port if numParamsForCall == 1: verilogSubmoduleCallParam = VerilogSubmoduleCallParam(toPort, fromPort, mappedParams.GetVerilogParams(0)) verilogSubmoduleCall.AddCallParam(verilogSubmoduleCallParam) # Multiple param case: # We can duplicate outputs in HDL mode calls, which isn't support in verilog. Therefore to map this case to verilog # we will have to assign the output pin to a new internal parameter and the use assign calls to set the correct ports. # e.g. # HDL: Nand(a=a, b=b, out=out1, out=out2) # would map to.. # Verilog: Nand nand_1(.a (a), .b(b), .out(outTemp)) # assign out1 = outTemp; # assign out2 = outTemp; else: # Create the mapping to a new temporary internal parameter, which is the same width as the toPort tmpPinName = ("tempOutput_%d" % (tmpVarCounter)) tmpPin = HdlPin(tmpPinName, HdlPinTypes.Internal, None) tmpPort = self._HdlPinToVerilogPort(tmpPin, toPort.portBitWidth) verilogSubmoduleCallParam = VerilogSubmoduleCallParam(toPort, tmpPort, VerilogCallParams(paramList=[tmpPort.portName])) verilogSubmoduleCall.AddCallParam(verilogSubmoduleCallParam) tmpVarCounter += 1 for i in range(0, numParamsForCall): verilogMainModule.AddWireAssignment(VerilogWireAssignment(mappedParams.GetVerilogParams(i).GetCallStr(), tmpPinName)) verilogMainModule.AddSubmoduleCall(verilogSubmoduleCall) verilogMainModule.DumpModuleDetails() verilogModuleList.AddModule(verilogMainModule) return ########################################################################## def _HdlFormatToVerilogFormatLiteral(self, hdlLiteral): verilogLiteral = hdlLiteral.replace("%B", "'b").replace("%X", "'h") return verilogLiteral ########################################################################## def _HdlPinToVerilogPort(self, hdlPin : HdlPin, bitWidth): portDirection = VerilogPortDirectionTypes.unknown if hdlPin.pinType == HdlPinTypes.Input or hdlPin.pinType == HdlPinTypes.Clk: portDirection = VerilogPortDirectionTypes.input elif hdlPin.pinType == HdlPinTypes.Output: portDirection = VerilogPortDirectionTypes.output return VerilogPort(hdlPin.pinName, portDirection, "", bitWidth, hdlPin.IsInternal())
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