diff options
author | Rahul P | 2023-06-13 18:24:33 +0530 |
---|---|---|
committer | GitHub | 2023-06-13 18:24:33 +0530 |
commit | 4a276b252d84a0b7dd24588e56dc7e214ea2d7c6 (patch) | |
tree | e9cf9d33ed2c137f3ac463c7b272e27fe23be75d /src | |
parent | 9a5f3dabc357277b384c51ccf047f5580772f454 (diff) | |
parent | 3436aa4615dcc1310db8dc8a85f36418db641fb4 (diff) | |
download | eSim-4a276b252d84a0b7dd24588e56dc7e214ea2d7c6.tar.gz eSim-4a276b252d84a0b7dd24588e56dc7e214ea2d7c6.tar.bz2 eSim-4a276b252d84a0b7dd24588e56dc7e214ea2d7c6.zip |
Merge pull request #251 from FOSSEE/sky130-dev
Merge Sky130 PDK development
Diffstat (limited to 'src')
-rw-r--r-- | src/browser/UserManual.py | 2 | ||||
-rw-r--r-- | src/configuration/Appconfig.py | 4 | ||||
-rw-r--r-- | src/frontEnd/Application.py | 17 | ||||
-rwxr-xr-x | src/frontEnd/ProjectExplorer.py | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | src/kicadtoNgspice/Convert.py | 63 | ||||
-rwxr-xr-x[-rw-r--r--] | src/kicadtoNgspice/DeviceModel.py | 396 | ||||
-rw-r--r-- | src/kicadtoNgspice/KicadtoNgspice.py | 24 | ||||
-rw-r--r-- | src/kicadtoNgspice/Model.py | 19 | ||||
-rwxr-xr-x | src/maker/Maker.py | 2 | ||||
-rwxr-xr-x | src/maker/ModelGeneration.py | 204 | ||||
-rwxr-xr-x | src/maker/NgVeri.py | 46 | ||||
-rwxr-xr-x | src/ngspicetoModelica/NgspicetoModelica.py | 2 |
12 files changed, 622 insertions, 159 deletions
diff --git a/src/browser/UserManual.py b/src/browser/UserManual.py index bf9c4b2b..5f12bdc0 100644 --- a/src/browser/UserManual.py +++ b/src/browser/UserManual.py @@ -14,7 +14,7 @@ class UserManual(QtWidgets.QWidget): self.vlayout = QtWidgets.QVBoxLayout() - manual = 'library/browser/User-Manual/eSim_Manual_2.2.pdf' + manual = 'library/browser/User-Manual/eSim_Manual_2.3.pdf' if os.name == 'nt': os.startfile(os.path.realpath(manual)) diff --git a/src/configuration/Appconfig.py b/src/configuration/Appconfig.py index ab19ada5..00977ca0 100644 --- a/src/configuration/Appconfig.py +++ b/src/configuration/Appconfig.py @@ -13,7 +13,7 @@ # MODIFIED: Rahul Paknikar, rahulp@iitb.ac.in # ORGANIZATION: eSim Team at FOSSEE, IIT Bombay # CREATED: Tuesday 24 February 2015 -# REVISION: Sunday 02 August 2020 +# REVISION: Tuesday 13 September 2022 # ========================================================================= from PyQt5 import QtWidgets @@ -105,7 +105,7 @@ class Appconfig(QtWidgets.QWidget): # Application Details self._APPLICATION = 'eSim' - self._VERSION = '2.2' + self._VERSION = '2.3' self._AUTHOR = 'Fahim' self._REVISION = 'Rahul, Sumanto' diff --git a/src/frontEnd/Application.py b/src/frontEnd/Application.py index 790bf779..96be7ca4 100644 --- a/src/frontEnd/Application.py +++ b/src/frontEnd/Application.py @@ -163,6 +163,23 @@ class Application(QtWidgets.QMainWindow): self.topToolbar.addAction(self.switchmode) self.topToolbar.addAction(self.helpfile) + # ## This part is meant for SoC Generation which is currently ## + # ## under development and will be will be required in future. ## + # self.soc = QtWidgets.QToolButton(self) + # self.soc.setText('Generate SoC') + # self.soc.setToolTip( + # '<b>SPICE to Verilog Conversion</b><br>' + \ + # '<br>The feature is under development.' + \ + # '<br>It will be released soon.' + \ + # '<br><br>Thank you for your patience!!!' + # ) + # self.soc.setStyleSheet(" \ + # QWidget { border-radius: 15px; border: 1px \ + # solid gray; padding: 10px; margin-left: 20px; } \ + # ") + # self.soc.clicked.connect(self.showSoCRelease) + # self.topToolbar.addWidget(self.soc) + # This part is setting fossee logo to the right # corner in the application window. self.spacer = QtWidgets.QWidget() diff --git a/src/frontEnd/ProjectExplorer.py b/src/frontEnd/ProjectExplorer.py index 77c9352e..99772378 100755 --- a/src/frontEnd/ProjectExplorer.py +++ b/src/frontEnd/ProjectExplorer.py @@ -78,7 +78,7 @@ class ProjectExplorer(QtWidgets.QWidget): def refreshInstant(self): for i in range(self.treewidget.topLevelItemCount()): - if(self.treewidget.topLevelItem(i).isExpanded()): + if self.treewidget.topLevelItem(i).isExpanded(): index = self.treewidget.indexFromItem( self.treewidget.topLevelItem(i)) self.refreshProject(indexItem=index) diff --git a/src/kicadtoNgspice/Convert.py b/src/kicadtoNgspice/Convert.py index a5b34cee..66f8a7c0 100644..100755 --- a/src/kicadtoNgspice/Convert.py +++ b/src/kicadtoNgspice/Convert.py @@ -645,38 +645,71 @@ class Convert: # print("Library Path :", libpath) # Copying library from devicemodelLibrary to Project Path # Special case for MOSFET + tempStr = libname.split(':') + libname = tempStr[0] + libAbsPath = os.path.join(libpath, libname) + if eachline[0] == 'm': # For mosfet library name come along with MOSFET # dimension information - tempStr = libname.split(':') - libname = tempStr[0] dimension = tempStr[1] # Replace last word with library name # words[-1] = libname.split('.')[0] - words[-1] = self.getRefrenceName(libname, libpath) + words[-1] = self.getReferenceName(libname, libpath) # Appending Dimension of MOSFET words.append(dimension) deviceLine[index] = words includeLine.append(".include " + libname) - # src = completeLibPath.split(':')[0] # <----- Not - # working in Windows + shutil.copy2(libAbsPath, projpath) + + elif eachline[0:6] == 'scmode': + (filepath, filemname) = os.path.split(self.clarg1) + self.Fileopen = os.path.join(filepath, ".spiceinit") + print("==============================================") + print("Writing to the .spiceinit file to " + + "make ngspice SKY130 compatible") + self.writefile = open(self.Fileopen, "w") + self.writefile.write(''' +set ngbehavior=hsa ; set compatibility for reading PDK libs +set ng_nomodcheck ; don't check the model parameters +set num_threads=8 ; CPU hardware threads available +option noinit ; don't print operating point data +optran 0 0 0 100p 2n 0 ; don't use dc operating point, but transient op) +''') + print("==============================================") + + libs = ''' +sky130_fd_pr__model__diode_pd2nw_11v0.model.spice +sky130_fd_pr__model__diode_pw2nd_11v0.model.spice +sky130_fd_pr__model__inductors.model.spice +sky130_fd_pr__model__linear.model.spice +sky130_fd_pr__model__pnp.model.spice +sky130_fd_pr__model__r+c.model.spice +''' + includeLine.append( + ".lib \"" + libAbsPath + "\" " + tempStr[1]) + for i in libs.split(): + includeLine.append( + ".include \"" + libAbsPath.replace( + "sky130.lib.spice", i) + "\"") + deviceLine[index] = "*scmode" + # words.append(completeLibPath) + # deviceLine[index] = words + + elif eachline[0:2] == 'sc' and eachline[0:6] != 'scmode': + words[0] = words[0].replace('sc', 'xsc') + words.append(completeLibPath) + deviceLine[index] = words - (src_path, src_lib) = os.path.split(completeLibPath) - src_lib = src_lib.split(':')[0] - src = os.path.join(src_path, src_lib) - dst = projpath - shutil.copy2(src, dst) else: # Replace last word with library name # words[-1] = libname.split('.')[0] - words[-1] = self.getRefrenceName(libname, libpath) + words[-1] = self.getReferenceName(libname, libpath) deviceLine[index] = words includeLine.append(".include " + libname) - src = completeLibPath - dst = projpath - shutil.copy2(src, dst) + shutil.copy2(completeLibPath, projpath) # Adding device line to schematicInfo for index, value in deviceLine.items(): @@ -750,7 +783,7 @@ class Convert: return schematicInfo - def getRefrenceName(self, libname, libpath): + def getReferenceName(self, libname, libpath): libname = libname.replace('.lib', '.xml') library = os.path.join(libpath, libname) diff --git a/src/kicadtoNgspice/DeviceModel.py b/src/kicadtoNgspice/DeviceModel.py index d2cd0e73..ccbe8986 100644..100755 --- a/src/kicadtoNgspice/DeviceModel.py +++ b/src/kicadtoNgspice/DeviceModel.py @@ -28,7 +28,7 @@ class DeviceModel(QtWidgets.QWidget): kicadFile = self.clarg1 (projpath, filename) = os.path.split(kicadFile) project_name = os.path.basename(projpath) - + self.root = [] try: f = open( os.path.join( @@ -37,10 +37,10 @@ class DeviceModel(QtWidgets.QWidget): "_Previous_Values.xml"), 'r') tree = ET.parse(f) - parent_root = tree.getroot() - for child in parent_root: + parent_self = tree.getroot() + for child in parent_self: if child.tag == "devicemodel": - root = child + self.root = child except BaseException: print("Device Model Previous XML is Empty") @@ -57,6 +57,7 @@ class DeviceModel(QtWidgets.QWidget): # For MOSFET self.widthLabel = {} self.lengthLabel = {} + self.parameterLabel = {} self.multifactorLable = {} self.devicemodel_dict_beg = {} self.devicemodel_dict_end = {} @@ -67,11 +68,189 @@ class DeviceModel(QtWidgets.QWidget): self.grid = QtWidgets.QGridLayout() self.setLayout(self.grid) # print("Reading Device model details from Schematic") + if "sky130" in " ".join(schematicInfo): + self.eSim_sky130(schematicInfo) + else: + self.eSim_general_libs(schematicInfo) + + def eSim_sky130(self, schematicInfo): + sky130box = QtWidgets.QGroupBox() + sky130grid = QtWidgets.QGridLayout() + self.count = self.count+1 + self.row = self.row + 1 + self.devicemodel_dict_beg["scmode1"] = self.count + beg = self.count + self.deviceDetail[self.count] = "scmode1" + sky130box.setTitle("Add parameters of SKY130 library ") + # + + # " : " + + # words[6]) + self.parameterLabel[self.count] = QtWidgets.QLabel("Enter the path ") + self.row = self.row + 1 + sky130grid.addWidget(self.parameterLabel[self.count], self.row, 0) + self.entry_var[self.count] = QtWidgets.QLineEdit() + self.entry_var[self.count].setReadOnly(True) + + for child in self.root: + if child.tag == "scmode1": + if child[0].text \ + and os.path.exists(child[0].text): + self.entry_var[self.count] \ + .setText(child[0].text) + path_name = child[0].text + else: + if os.name == 'nt': + path_name = os.path.abspath( + "library/" + + "sky130_fd_pr/models/sky130.lib.spice" + ) + else: + path_name = os.path.abspath( + "/usr/share/local/" + + "sky130_fd_pr/models/sky130.lib.spice" + ) + self.entry_var[self.count].setText(path_name) + # self.trackLibraryWithoutButton(self.count, path_name) + + sky130grid.addWidget(self.entry_var[self.count], self.row, 1) + self.addbtn = QtWidgets.QPushButton("Add") + self.addbtn.setObjectName("%d" % beg) + self.addbtn.clicked.connect(self.trackLibrary) + sky130grid.addWidget(self.addbtn, self.row, 2) + # self.count = self.count + 1 + self.adddefaultbtn = QtWidgets.QPushButton("Add Default") + self.adddefaultbtn.setObjectName("%d" % beg) + self.adddefaultbtn.clicked.connect(self.trackDefaultLib) + sky130grid.addWidget(self.adddefaultbtn, self.row, 3) + self.count = self.count + 1 + self.parameterLabel[self.count] = QtWidgets.QLabel( + "Enter the corner e.g. tt") + self.row = self.row + 1 + sky130grid.addWidget(self.parameterLabel[self.count], self.row, 0) + self.entry_var[self.count] = QtWidgets.QLineEdit() + self.entry_var[self.count].setText("") + self.entry_var[self.count].setMaximumWidth(150) + self.entry_var[self.count].setObjectName("%d" % beg) + path_name = '' + for child in self.root: + if child.tag == "scmode1": + if child[1].text: + self.entry_var[self.count] \ + .setText(child[1].text) + path_name = child[0].text + else: + self.entry_var[self.count].setText("") + + sky130grid.addWidget(self.entry_var[self.count], self.row, 1) + self.entry_var[self.count].textChanged.connect(self.textChange) + self.trackLibraryWithoutButton(beg, path_name) + + sky130box.setLayout(sky130grid) + sky130box.setStyleSheet(" \ + QGroupBox { border: 1px solid gray; border-radius:\ + 9px; margin-top: 0.5em; } \ + QGroupBox::title { subcontrol-origin: margin; left:\ + 10px; padding: 0 3px 0 3px; } \ + ") + self.grid.addWidget(sky130box) + # if self.entry_var[self.count-3].text() == "": + # pass + # else: + # self.trackLibraryWithoutButton(self.count-3, path_name) + + self.row = self.row + 1 + self.devicemodel_dict_end["scmode1"] = self.count + self.count = self.count + 1 for eachline in schematicInfo: print("=========================================") print(eachline) words = eachline.split() + # supporteddesignator = ['sc', 'u', 'x', 'v', 'i', 'a'] + if eachline[0:2] != 'sc' and eachline[0] != 'u' \ + and eachline[0] != 'x' and eachline[0] != '*'\ + and eachline[0] != 'v' and eachline[0] != 'i'\ + and eachline[0] != 'a': + print("Only components with designators 'sc', 'u', \ +'x', 'v', 'i', 'a'\ + can be used with SKY130 mode") + print("Please remove other components") + self.msg = QtWidgets.QErrorMessage() + self.msg.setModal(True) + self.msg.setWindowTitle("Invalid components") + self.content = "Only components with designators " + \ + "'sc', 'u' and 'x' can be used \ + with SKY130 mode. " + \ + "Please edit the schematic and \ + generate netlist again" + self.msg.showMessage(self.content) + self.msg.exec_() + return + + elif eachline[0:2] == 'sc' and eachline[0:6] != 'scmode': + self.devicemodel_dict_beg[words[0]] = self.count + self.deviceDetail[self.count] = words[0] + sky130box = QtWidgets.QGroupBox() + sky130grid = QtWidgets.QGridLayout() + beg = self.count + sky130box.setTitle( + "Add parameters for " + + words[0] + " : " + words[-1]) + path_name = '' + + # Adding to get SKY130 dimension + self.parameterLabel[self.count] = QtWidgets.QLabel( + "Enter the parameters of SKY130 component " + words[0]) + sky130grid.addWidget( + self.parameterLabel[self.count], self.row, 0) + self.entry_var[self.count] = QtWidgets.QLineEdit() + self.entry_var[self.count].setText("") + self.entry_var[self.count].setMaximumWidth(1000) + self.entry_var[self.count].setObjectName("%d" % beg) + sky130grid.addWidget(self.entry_var[self.count], self.row, 1) + self.entry_var[self.count].textChanged.connect(self.textChange) + sky130box.setLayout(sky130grid) + sky130box.setStyleSheet(" \ + QGroupBox { border: 1px solid gray; border-radius: \ + 9px; margin-top: 0.5em; } \ + QGroupBox::title { subcontrol-origin: margin; left:\ + 10px; padding: 0 3px 0 3px; } \ + ") + try: + for child in self.root: + if child.tag == words[0]: + # print("DEVICE MODEL MATCHING---", \ + # child.tag, words[0]) + try: + if child[0].text: + self.entry_var[self.count] \ + .setText(child[0].text) + path_name = child[0].text + else: + self.entry_var[self.count].setText("") + path_name = "" + except BaseException as e: + print("Error when set text of Device " + + "SKY130 Component :", str(e)) + except BaseException: + pass + self.trackLibraryWithoutButton(self.count, path_name) + self.grid.addWidget(sky130box) + + # Adding Device Details # + + # Increment row and widget count + self.row = self.row + 1 + self.devicemodel_dict_end[words[0]] = self.count + self.count = self.count + 1 + + self.show() + + def eSim_general_libs(self, schematicInfo): + for eachline in schematicInfo: + print("=========================================") + print(eachline) + words = eachline.split() if eachline[0] == 'q': # print("Device Model Transistor: ", words[0]) self.devicemodel_dict_beg[words[0]] = self.count @@ -88,7 +267,7 @@ class DeviceModel(QtWidgets.QWidget): global path_name try: - for child in root: + for child in self.root: if child.tag == words[0]: # print("DEVICE MODEL MATCHING---", \ # child.tag, words[0]) @@ -152,7 +331,7 @@ class DeviceModel(QtWidgets.QWidget): self.entry_var[self.count].setReadOnly(True) # global path_name try: - for child in root: + for child in self.root: if child.tag == words[0]: # print("DEVICE MODEL MATCHING---", \ # child.tag, words[0]) @@ -216,7 +395,7 @@ class DeviceModel(QtWidgets.QWidget): self.entry_var[self.count].setReadOnly(True) # global path_name try: - for child in root: + for child in self.root: if child.tag == words[0]: # print("DEVICE MODEL MATCHING---", \ # child.tag, words[0]) @@ -456,7 +635,7 @@ class DeviceModel(QtWidgets.QWidget): # global path_name try: - for child in root: + for child in self.root: if child.tag == words[0]: # print("DEVICE MODEL MATCHING---", \ # child.tag, words[0]) @@ -488,6 +667,55 @@ class DeviceModel(QtWidgets.QWidget): self.show() + def trackDefaultLib(self): + sending_btn = self.sender() + self.widgetObjCount = int(sending_btn.objectName()) + if os.name == 'nt': + path_name = os.path.abspath( + "library/" + + "sky130_fd_pr/models/sky130.lib.spice" + ) + else: + path_name = os.path.abspath( + "/usr/share/local/" + + "sky130_fd_pr/models/sky130.lib.spice" + ) + self.entry_var[self.widgetObjCount].setText(path_name) + self.trackLibraryWithoutButton(self.widgetObjCount, path_name) + + def textChange(self): + sending_btn = self.sender() + self.widgetObjCount = int(sending_btn.objectName()) + self.deviceName = self.deviceDetail[self.widgetObjCount] + # self.widgetObjCount = self.count_beg + # if self.deviceName[0] == 'm': + # width = str(self.entry_var[self.widgetObjCount + 1].text()) + # length = str(self.entry_var[self.widgetObjCount + 2].text()) + # multifactor = str(self.entry_var[self.widgetObjCount + 3].text()) + # if width == "": + # width = "100u" + # if length == "": + # length = "100u" + # if multifactor == "": + # multifactor = "1" + + # self.obj_trac.deviceModelTrack[self.deviceName] =\ + # str(self.entry_var[self.widgetObjCount].text()) + \ + # ":" + "W=" + width + " L=" + length + " M=" + multifactor + + if self.deviceName[0:6] == 'scmode': + self.obj_trac.deviceModelTrack[self.deviceName] = \ + self.entry_var[self.widgetObjCount].text() + \ + ":" + str(self.entry_var[self.widgetObjCount + 1].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + elif self.deviceName[0:2] == 'sc': + self.obj_trac.deviceModelTrack[self.deviceName] = str( + self.entry_var[self.widgetObjCount].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + + else: + self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + def trackLibrary(self): """ This function is use to keep track of all Device Model widget @@ -529,6 +757,16 @@ class DeviceModel(QtWidgets.QWidget): self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + \ ":" + "W=" + width + " L=" + length + " M=" + multifactor + elif self.deviceName[0:6] == 'scmode': + self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + \ + ":" + str(self.entry_var[self.widgetObjCount + 1].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + + elif self.deviceName[0:2] == 'sc': + self.obj_trac.deviceModelTrack[self.deviceName] = str( + self.entry_var[self.widgetObjCount].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + else: self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile @@ -559,5 +797,147 @@ class DeviceModel(QtWidgets.QWidget): multifactor = "1" self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + \ ":" + "W=" + width + " L=" + length + " M=" + multifactor + + elif self.deviceName[0:6] == 'scmode': + self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + \ + ":" + str(self.entry_var[self.widgetObjCount + 1].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + + elif self.deviceName[0:2] == 'sc': + self.obj_trac.deviceModelTrack[self.deviceName] = str( + self.entry_var[self.widgetObjCount].text()) + print(self.obj_trac.deviceModelTrack[self.deviceName]) + else: self.obj_trac.deviceModelTrack[self.deviceName] = self.libfile + + def GenerateSOCbutton(self): + ############################################################# + # ***************** SPICE to Verilog Converter ************** + + # The development is under progress and may not be accurate + + # Developed by: + # Sumanto Kar, sumantokar@iitb.ac.in + # Nagesh Karmali, nags@cse.iitb.ac.in + # Firuza Karmali, firuza@cse.iitb.ac.in + # Rahul Paknikar, rahulp@iitb.ac.in + # GUIDED BY: + # Kunal Ghosh, VLSI System Design Corp.Pvt.Ltd + # Anagha Ghosh, VLSI System Design Corp.Pvt.Ltd + # Philipp Gühring + + # *********************************************************** + + kicadFile = self.clarg1 + (projpath, filename) = os.path.split(kicadFile) + analysisfile = open(os.path.join(projpath, filename)) + # analysisfile = open(os.path.join(projpath, 'analysis')) + content = analysisfile.read() + contentlines = content.split("\n") + parsedfile = open(os.path.join(projpath, filename+'.parsed.v'), 'w') + parsedfile.write("") + # print("module "+filename) + i = 1 + inputlist = [] + realinputlist = [] + outputlist = [] + realoutputlist = [] + wirelist = [] + realwirelist = [] + uutlist = [] + filelist = [] + parsedcontent = [] + for contentlist in contentlines: + if "IPDD" in contentlist or "IPAD" in contentlist: + # if len(contentlist)>1 and ( contentlist[0:1]=='U'\ + # or contentlist[0:1]=='X') and not 'plot_' in contentlist : + # print(contentlist) + netnames = contentlist.split() + net = ' '.join(map(str, netnames[1:-1])) + netnames[-1] = netnames[-1].replace("IPAD", '') + netnames[-1] = netnames[-1].replace("IPDD", '') + # net=net.replace(netnames[-1],'') + # net=net.replace('BI_','') + # net=net.replace('BO_','') + net2 = [] + + for j in net.split(): + # print(j) + secondpart = j + if '_' in j: + secondpart = j.split('_')[1] + if secondpart in net2: + continue + if net.count(secondpart)-1 > 0: + k = "["+str(net.count(secondpart)-1) + \ + ":0"+"] "+secondpart + else: + k = secondpart + + net2.append(secondpart) + if '_I_' in str(j): + inputlist.append(k) + if '_IR_' in str(j): + inputlist.append(k) + if '_O_' in str(j): + outputlist.append(k) + if '_OR_' in str(j): + realoutputlist.append(k) + if '_W_' in str(j) and not (k in wirelist): + wirelist.append(k) + if '_WR_' in str(j) and not (k in realwirelist): + realwirelist.append(k) + + netnames[-1] = netnames[-1].replace("IPAD", '') + netnames[-1] = netnames[-1].replace("IPDD", '') + uutlist.append(netnames[-1]+" uut" + + str(i)+" ("+', '.join(net2)+');') + filelist.append(netnames[-1]) + i = i+1 + # print(inputlist) + # print(outputlist) + # print(wirelist) + parsedcontent.append( + "\\\\Generated from SPICE to Verilog. \ +Converter developed at FOSSEE, IIT Bombay\n") + parsedcontent.append( + "\\\\The development is under progress and may not be accurate.\n") + + for j in filelist: + parsedcontent.append('''`include "'''+j+'''.v"''') + parsedcontent.append( + "module "+filename+"("+', '.join(inputlist # noqa + + realinputlist + outputlist + realoutputlist)+");") # noqa + if inputlist: + parsedcontent.append("input "+', '.join(inputlist)+";") + if realinputlist: + parsedcontent.append("input real "+', '.join(inputlist)+";") + if outputlist: + parsedcontent.append("output "+', '.join(outputlist)+";") + if realoutputlist: + parsedcontent.append("output real "+', '.join(realoutputlist)+";") + if wirelist: + parsedcontent.append("wire "+', '.join(wirelist)+";") + if realwirelist: + parsedcontent.append("wire real"+', '.join(realwirelist)+";") + for j in uutlist: + parsedcontent.append(j) + parsedcontent.append("endmodule;") + + print('\n**************Generated Verilog File: ' + + filename + '.parsed.v***************\n') + for j in parsedcontent: + print(j) + parsedfile.write(j+"\n") + print( + '\n*************************************\ +************************************\n') + self.msg = QtWidgets.QErrorMessage() + self.msg.setModal(True) + self.msg.setWindowTitle("Verilog File Generated") + self.content = "The Verilog file has been successfully \ + generated from the SPICE netlist" + self.msg.showMessage(self.content) + self.msg.exec_() + return diff --git a/src/kicadtoNgspice/KicadtoNgspice.py b/src/kicadtoNgspice/KicadtoNgspice.py index f549c5c6..e018143f 100644 --- a/src/kicadtoNgspice/KicadtoNgspice.py +++ b/src/kicadtoNgspice/KicadtoNgspice.py @@ -578,8 +578,8 @@ class MainWindow(QtWidgets.QWidget): attr_ui.text = line[2] for key, value in line[7].items(): if ( - hasattr(value, '__iter__') and - i <= end and not isinstance(value, str) + hasattr(value, '__iter__') and + i <= end and not isinstance(value, str) ): for item in value: ET.SubElement( @@ -934,16 +934,16 @@ class MainWindow(QtWidgets.QWidget): subcktInfo += words[i] + " " continue if ( - words[0] == ".end" or - words[0] == ".ac" or - words[0] == ".dc" or - words[0] == ".tran" or - words[0] == '.disto' or - words[0] == '.noise' or - words[0] == '.op' or - words[0] == '.pz' or - words[0] == '.sens' or - words[0] == '.tf' + words[0] == ".end" or + words[0] == ".ac" or + words[0] == ".dc" or + words[0] == ".tran" or + words[0] == '.disto' or + words[0] == '.noise' or + words[0] == '.op' or + words[0] == '.pz' or + words[0] == '.sens' or + words[0] == '.tf' ): continue elif words[0] == ".control": diff --git a/src/kicadtoNgspice/Model.py b/src/kicadtoNgspice/Model.py index 22fa02b5..55a988c0 100644 --- a/src/kicadtoNgspice/Model.py +++ b/src/kicadtoNgspice/Model.py @@ -1,10 +1,8 @@ #!/usr/bin/python # -*- coding: utf-8 -*- import os -from configparser import ConfigParser from xml.etree import ElementTree as ET - -from PyQt5 import QtWidgets, QtCore +from PyQt5 import QtWidgets from . import TrackWidget @@ -14,7 +12,6 @@ class Model(QtWidgets.QWidget): - This class creates Model Tab of KicadtoNgspice window. The widgets are created dynamically in the Model Tab. """ - def __init__( self, schematicInfo, @@ -25,7 +22,6 @@ class Model(QtWidgets.QWidget): QtWidgets.QWidget.__init__(self) # Processing for getting previous values - kicadFile = clarg1 (projpath, filename) = os.path.split(kicadFile) project_name = os.path.basename(projpath) @@ -44,16 +40,13 @@ class Model(QtWidgets.QWidget): check = 0 # Creating track widget object - self.obj_trac = TrackWidget.TrackWidget() # for increasing row and counting/tracking line edit widget - self.nextrow = 0 self.nextcount = 0 # for storing line edit details position details - self.start = 0 self.end = 0 self.entry_var = [] @@ -61,7 +54,6 @@ class Model(QtWidgets.QWidget): self.text = "" # Creating GUI dynamically for Model tab - self.grid = QtWidgets.QGridLayout() self.setLayout(self.grid) @@ -78,17 +70,14 @@ class Model(QtWidgets.QWidget): self.model_name = line[2] # line[7] is parameter dictionary holding parameter tags. - i = 0 for (key, value) in line[7].items(): print(value) print(key) - # Check if value is iterable + # Check if value is iterable if not isinstance(value, str) and hasattr(value, "__iter__"): - # For tag having vector value - temp_tag = [] for item in value: @@ -131,7 +120,6 @@ class Model(QtWidgets.QWidget): tag_dict[key] = temp_tag else: - paramLabel = QtWidgets.QLabel(value) modelgrid.addWidget(paramLabel, self.nextrow, 0) self.obj_trac.model_entry_var[ @@ -180,7 +168,6 @@ class Model(QtWidgets.QWidget): modelbox.setLayout(modelgrid) # CSS - modelbox.setStyleSheet( " \ QGroupBox { border: 1px solid gray; border-radius: \ @@ -193,7 +180,6 @@ class Model(QtWidgets.QWidget): self.grid.addWidget(modelbox) # This keeps the track of Model Tab Widget - lst = [ line[0], line[1], @@ -223,7 +209,6 @@ class Model(QtWidgets.QWidget): modelbox.setLayout(modelgrid) # CSS - modelbox.setStyleSheet( " \ QGroupBox { border: 1px solid gray; border-radius:\ diff --git a/src/maker/Maker.py b/src/maker/Maker.py index e5d11988..b9895f21 100755 --- a/src/maker/Maker.py +++ b/src/maker/Maker.py @@ -472,7 +472,7 @@ class Handler(watchdog.events.PatternMatchingEventHandler): # self.obj_Appconfig.print_info("NgVeri File:\ # "+self.verilogfile+" modified. Please click on Refresh") global toggle_flag - if not(self.refreshoption in toggle_flag): + if self.refreshoption not in toggle_flag: toggle_flag.append(self.refreshoption) # i.rm_watch() self.observer.stop() diff --git a/src/maker/ModelGeneration.py b/src/maker/ModelGeneration.py index 49d5da0b..42ebd285 100755 --- a/src/maker/ModelGeneration.py +++ b/src/maker/ModelGeneration.py @@ -27,20 +27,20 @@ # ========================================================================= -# importing the files and libraries import re import os from PyQt5 import QtCore, QtWidgets from configparser import ConfigParser from configuration import Appconfig + from . import createkicad import hdlparse.verilog_parser as vlog -# Class is used to generate the Ngspice Model class ModelGeneration(QtWidgets.QWidget): - - # initialising the variables + ''' + Class is used to generate the Ngspice Model + ''' def __init__(self, file, termedit): QtWidgets.QWidget.__init__(self) super().__init__() @@ -72,11 +72,12 @@ class ModelGeneration(QtWidgets.QWidget): self.licensefile = self.parser.get('SRC', 'LICENSE') self.digital_home = self.parser.get( 'NGHDL', 'DIGITAL_MODEL') + "/Ngveri" - # # #### Creating connection_info.txt file from verilog file #### # - # Reading the file and performing operations and - # copying it in the Ngspice folder def verilogfile(self): + ''' + Reading the file and performing operations and + copying it in the Ngspice folder + ''' Text = "<span style=\" font-size:25pt;\ font-weight:1000; color:#008000;\" >" Text += ".................Running NgVeri..................." @@ -107,8 +108,10 @@ class ModelGeneration(QtWidgets.QWidget): f.write("\n") f.close() - # This function calls the sandpiper to convert .tlv file to .sv file def sandpiper(self): + ''' + This function calls the sandpiper to convert .tlv file to .sv file + ''' init_path = '../../' if os.name == 'nt': init_path = '' @@ -153,12 +156,12 @@ class ModelGeneration(QtWidgets.QWidget): os.chdir(self.cur_dir) self.fname = self.fname.split('.')[0] + ".sv" - # This function parses the module name and \ - # input/output ports of verilog code using HDL parse - # and writes to the connection_info.txt - def verilogParse(self): - + ''' + This function parses the module name and + input/output ports of verilog code using HDL parse + and writes to the "connection_info.txt". + ''' with open(self.modelpath + self.fname, 'rt') as fh: code = fh.read() @@ -218,9 +221,11 @@ class ModelGeneration(QtWidgets.QWidget): return "Error" return "No Error" - # This function is used to get the Port Information from - # connection_info.txt def getPortInfo(self): + ''' + This function is used to get the port information + from "connection_info.txt" + ''' readfile = open(self.modelpath + 'connection_info.txt', 'r') data = readfile.readlines() self.input_list = [] @@ -254,10 +259,11 @@ class ModelGeneration(QtWidgets.QWidget): for output in self.output_list: self.output_port.append(output[0] + ":" + output[2]) - # This function is used to create the cfunc.mod file in Ngspice folder - # automatically - def cfuncmod(self): + ''' + This function is used to create the "cfunc.mod" file + in Ngspice folder automatically. + ''' # ############# Creating content for cfunc.mod file ############## # @@ -397,12 +403,17 @@ and set the load for input ports */ }\n\n\ if(ANALYSIS == DC)\n\ {\n\ - OUTPUT_STATE(" + item.split(':')[0] + "[Ii]) = _op_" + item.split(':')[0] + "[Ii];\n\ + OUTPUT_STATE(" + item.split(':')[0] + + "[Ii]) = _op_" + item.split(':')[0] + "[Ii];\n\ }\n\ - else if(_op_" + item.split(':')[0] + "[Ii] != _op_" + item.split(':')[0] + "_old[Ii])\n\ + else if(_op_" + item.split(':')[0] + + "[Ii] != _op_" + item.split(':')[0] + "_old[Ii])\n\ {\n\ - OUTPUT_STATE(" + item.split(':')[0] + "[Ii]) = _op_" + item.split(':')[0] + "[Ii];\n\ - OUTPUT_DELAY(" + item.split(':')[0] + "[Ii]) = ((_op_" + item.split(':')[0] + "[Ii] == ZERO) ? PARAM(fall_delay) : PARAM(rise_delay));\n\ + OUTPUT_STATE(" + item.split(':')[0] + "[Ii]) = _op_" + + item.split(':')[0] + "[Ii];\n\ + OUTPUT_DELAY(" + item.split(':')[0] + "[Ii]) = ((_op_" + + item.split(':')[0] + + "[Ii] == ZERO) ? PARAM(fall_delay) : PARAM(rise_delay));\n\ }\n\ else\n\ {\n\ @@ -497,9 +508,11 @@ and set the load for input ports */ cfunc.write("\n}") cfunc.close() - # This function creates the ifspec file automatically in Ngspice folder - def ifspecwrite(self): + ''' + This function creates the ifspec file + automatically in Ngspice folder. + ''' print("Starting with ifspec.ifs file") ifspec = open(self.modelpath + 'ifspec.ifs', 'w') @@ -607,10 +620,11 @@ and set the load for input ports */ ifspec.write("\n") ifspec.close() - # This function creates the header file of sim_main file automatically in - # Ngspice folder - def sim_main_header(self): + ''' + This function creates the header file of + "sim_main" file automatically in Ngspice folder. + ''' print("Starting With sim_main_" + self.fname.split('.')[0] + ".h file") simh = open( self.modelpath + @@ -632,9 +646,11 @@ and set the load for input ports */ simh.write(item) simh.close() - # This function creates the sim_main file needed by verilator - # automatically in Ngspice folder def sim_main(self): + ''' + This function creates the "sim_main" file needed by verilator + automatically in Ngspice folder. + ''' print( "Starting With sim_main_" + self.fname.split('.')[0] + @@ -650,7 +666,8 @@ and set the load for input ports */ self.fname.split('.')[0] + ".cpp file") - comment = '''/* This is cfunc.mod file auto generated by gen_con_info.py + comment = \ + '''/* This is cfunc.mod file auto generated by gen_con_info.py Developed by Sumanto Kar at IIT Bombay */\n ''' @@ -680,7 +697,8 @@ and set the load for input ports */ extern "C" int foo_''' + self.fname.split('.')[0] + '''(int,int); ''') convert_func = ''' - void int2arr''' + self.fname.split('.')[0] + '''(int num, int array[], int n) + void int2arr''' + self.fname.split('.')[0] + \ + '''(int num, int array[], int n) { for (int i = 0; i < n && num>=0; i++) { @@ -700,17 +718,20 @@ and set the load for input ports */ int foo_''' + self.fname.split('.')[0] + '''(int init,int count) { static VerilatedContext* contextp = new VerilatedContext; - static V''' + self.fname.split('.')[0] + "* " + self.fname.split('.')[0] + '''[1024]; + static V''' + self.fname.split('.')[0] + "* " + \ + self.fname.split('.')[0] + '''[1024]; count--; if (init==0) { - ''' + self.fname.split('.')[0] + '''[count]=new V''' + self.fname.split('.')[0] + '''{contextp}; + ''' + self.fname.split('.')[0] + '''[count]=new V''' + \ + self.fname.split('.')[0] + '''{contextp}; contextp->traceEverOn(true); } else { contextp->timeInc(1); - printf("=============''' + self.fname.split('.')[0] + ''' : New Iteration==========="); + printf("=============''' + self.fname.split('.')[0] + \ + ''' : New Iteration==========="); printf("\\nInstance : %d\\n",count); printf("\\nInside foo before eval.....\\n"); ''' @@ -788,8 +809,10 @@ and set the load for input ports */ csim.write(item) csim.close() - # This function creates modpathlst in Ngspice folder def modpathlst(self): + ''' + This function creates modpathlst in Ngspice folder. + ''' print("Editing modpath.lst file") mod = open(self.digital_home + '/modpath.lst', 'r') text = mod.read() @@ -799,8 +822,11 @@ and set the load for input ports */ mod.write(self.fname.split('.')[0] + "\n") mod.close() - # This function is used to run the Verilator using the verilator commands def run_verilator(self): + ''' + This function is used to run the Verilator + using the verilator commands. + ''' init_path = '../../' if os.name == 'nt': init_path = '' @@ -841,8 +867,10 @@ and set the load for input ports */ print("Verilator Executed") os.chdir(self.cur_dir) - # Running make verilator using this function def make_verilator(self): + ''' + Running make verilator using this function + ''' self.cur_dir = os.getcwd() print("Make Verilator.............") os.chdir(self.modelpath) @@ -876,9 +904,11 @@ and set the load for input ports */ print("Make Verilator Executed") os.chdir(self.cur_dir) - # This function copies the verilator files/object files from - # src/xspice/icm/Ngveri/ to release/src/xspice/icm/Ngveri/ def copy_verilator(self): + ''' + This function copies the verilator files/object files from + "src/xspice/icm/Ngveri/ to release/src/xspice/icm/Ngveri/" + ''' self.cur_dir = os.getcwd() print("Copying the required files to Release Folder.............") os.chdir(self.modelpath) @@ -934,8 +964,10 @@ and set the load for input ports */ except BaseException: print("There is error in Copying Files ") - # Running the make command for Ngspice def runMake(self): + ''' + Running the make command for Ngspice + ''' print("run Make Called") self.release_home = self.parser.get('NGHDL', 'RELEASE') path_icm = os.path.join(self.release_home, "src/xspice/icm") @@ -965,10 +997,11 @@ and set the load for input ports */ os.chdir(self.cur_dir) except BaseException: print("There is error in 'make' ") - # sys.exit() - # Running the make install command for Ngspice def runMakeInstall(self): + ''' + Running the make install command for Ngspice + ''' self.cur_dir = os.getcwd() print("run Make Install Called") self.release_home = self.parser.get('NGHDL', 'RELEASE') @@ -1005,11 +1038,12 @@ and set the load for input ports */ except BaseException as e: print(e) print("There is error in 'make install' ") - # sys.exit() - # This function is used to add additional files required by the verilog - # top module def addfile(self): + ''' + This function is used to add additional files + required by the verilog top module. + ''' print("Adding the files required by the top level module file") init_path = '../../' @@ -1120,9 +1154,11 @@ and set the load for input ports */ print("Added the folder") # os.chdir(self.cur_dir) - # This function is used to print the titles in the terminal of Ngveri tab def termtitle(self, textin): - + ''' + This function is used to print the titles + in the terminal of Ngveri tab. + ''' Text = "<span style=\" font-size:20pt; \ font-weight:1000; color:#0000FF;\" >" Text += "<br>================================<br>" @@ -1131,20 +1167,23 @@ and set the load for input ports */ Text += "</span>" self.termedit.append(Text) - # This function is used to print the text/commands in the terminal of - # Ngveri tab def termtext(self, textin): - + ''' + This function is used to print the text/commands + in the terminal of Ngveri tab. + ''' Text = "<span style=\" font-size:12pt;\ font-weight:500; color:#000000;\" >" Text += textin Text += "</span>" self.termedit.append(Text) - # This function reads all the Standard output data and the errors from the - # process that aree being run @QtCore.pyqtSlot() def readAllStandard(self): + ''' + This function reads all the standard output data and + the errors from the process that are being run. + ''' # self.termedit = termedit # self.termedit.append(str(self.process.readAll().data(),\ # encoding='utf-8')) @@ -1166,11 +1205,12 @@ and set the load for input ports */ TextErr += "<br>" + line TextErr += "</span>" self.termedit.append(TextErr) + # @QtCore.pyqtSlot() # def readAllStandard(self): # #self.termedit = termedit # self.termedit.append(str(self.process.\ - # readAll().data(), encoding='utf-8')) + # readAll().data(), encoding='utf-8')) # print(str(self.process.readAll().data(), encoding='utf-8')) # stderror = self.process.readAllStandardError() @@ -1183,32 +1223,32 @@ and set the load for input ports */ # Text += "</span>" # self.termedit.append(Text+"\n") - # init_path = '../../' - # if os.name == 'nt': - # init_path = '' - # includefile = QtCore.QDir.toNativeSeparators(\ - # QtWidgets.QFileDialog.getOpenFileName( - # self, "Open adding other necessary files to be included", - # init_path + "home" - # )[0] - # ) - # if includefile=="": - # reply=QtWidgets.QMessageBox.critical( - # None, "Error Message", - # "<b>Error: No File Chosen. Please chose a file</b>", - # QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel - # ) - # if reply == QtWidgets.QMessageBox.Ok: - # self.addfile() - # self.obj_Appconfig.print_info('Add Other Files Called') - - # elif reply == QtWidgets.QMessageBox.Cancel: - # self.obj_Appconfig.print_info('No File Chosen') - # filename = os.path.basename(includefile) - # self.modelpath=self.digital_home+"/"+self.fname.split('.')[0]+"/" - - # if not os.path.isdir(self.modelpath): - # os.mkdir(self.modelpath) - # text = open(includefile).read() - # open(self.modelpath+filename,'w').write(text) - # includefile.close() + # init_path = '../../' + # if os.name == 'nt': + # init_path = '' + # includefile = QtCore.QDir.toNativeSeparators(\ + # QtWidgets.QFileDialog.getOpenFileName( + # self, "Open adding other necessary files to be included", + # init_path + "home" + # )[0] + # ) + # if includefile=="": + # reply=QtWidgets.QMessageBox.critical( + # None, "Error Message", + # "<b>Error: No File Chosen. Please chose a file</b>", + # QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel + # ) + # if reply == QtWidgets.QMessageBox.Ok: + # self.addfile() + # self.obj_Appconfig.print_info('Add Other Files Called') + + # elif reply == QtWidgets.QMessageBox.Cancel: + # self.obj_Appconfig.print_info('No File Chosen') + # filename = os.path.basename(includefile) + # self.modelpath=self.digital_home+"/"+self.fname.split('.')[0]+"/" + + # if not os.path.isdir(self.modelpath): + # os.mkdir(self.modelpath) + # text = open(includefile).read() + # open(self.modelpath+filename,'w').write(text) + # includefile.close() diff --git a/src/maker/NgVeri.py b/src/maker/NgVeri.py index 4a221964..c5756e7d 100755 --- a/src/maker/NgVeri.py +++ b/src/maker/NgVeri.py @@ -37,10 +37,10 @@ from configuration.Appconfig import Appconfig from configparser import ConfigParser -# beginning class NgVeri. This class create the NgVeri Tab class NgVeri(QtWidgets.QWidget): - - # initialising the variables + ''' + This class create the NgVeri Tab + ''' def __init__(self, filecount): QtWidgets.QWidget.__init__(self) # Maker.addverilog(self) @@ -67,10 +67,10 @@ class NgVeri(QtWidgets.QWidget): self.fname = "" self.filecount = filecount - # Creating the various components of the Widget(Ngveri Tab) - def createNgveriWidget(self): - + ''' + Creating the various components of the Widget(Ngveri Tab) + ''' self.grid = QtWidgets.QGridLayout() self.setLayout(self.grid) @@ -79,8 +79,10 @@ class NgVeri(QtWidgets.QWidget): self.show() - # Adding the verilog file in Maker tab to Ngveri Tab automatically def addverilog(self): + ''' + Adding the verilog file in Maker tab to Ngveri Tab automatically + ''' # b=Maker.Maker(self) print(Maker.verilogFile) if Maker.verilogFile[self.filecount] == "": @@ -194,9 +196,11 @@ class NgVeri(QtWidgets.QWidget): # model.verilogfile() model.addfile() - # This function is used to add additional folder required by the verilog - # top module def addfolder(self): + ''' + This function is used to add additional folder required + by the verilog top module. + ''' if len(Maker.verilogFile) < (self.filecount + 1): reply = QtWidgets.QMessageBox.critical( None, @@ -214,14 +218,16 @@ class NgVeri(QtWidgets.QWidget): # model.verilogfile() model.addfolder() - # This function is used to clear the terminal - def clearTerminal(self): + ''' + This function is used to clear the terminal + ''' self.entry_var[0].setText("") - # This function is used to create buttons/options def createoptionsBox(self): - + ''' + This function is used to create buttons/options + ''' self.optionsbox = QtWidgets.QGroupBox() self.optionsbox.setTitle("Select Options") self.optionsgrid = QtWidgets.QGridLayout() @@ -263,9 +269,11 @@ class NgVeri(QtWidgets.QWidget): return self.optionsbox - # This function is used to remove models in modlst of Ngspice folder if - # the user wants to remove a model. Note: files do not get removed def edit_modlst(self, text): + ''' + This is used to remove models in modlst of Ngspice folder if + the user wants to remove a model. Note: files do not get removed. + ''' if text == "Remove Verilog Models": return index = self.entry_var[1].findText(text) @@ -357,11 +365,11 @@ class NgVeri(QtWidgets.QWidget): file.close() self.entry_var[3].setText("") - # creating various other groups like terminal, remove modlst, remove lint_off - # and add lint_off - def creategroup(self): - + ''' + Creates various other groups like terminal, remove modlst, + remove lint_off and add lint_off + ''' self.trbox = QtWidgets.QGroupBox() self.trbox.setTitle("Terminal") # self.trbox.setDisabled(True) diff --git a/src/ngspicetoModelica/NgspicetoModelica.py b/src/ngspicetoModelica/NgspicetoModelica.py index 6951e3c8..9a3d504f 100755 --- a/src/ngspicetoModelica/NgspicetoModelica.py +++ b/src/ngspicetoModelica/NgspicetoModelica.py @@ -998,7 +998,7 @@ class NgMoConverter: for i in range(0, len(words), 1): words[i] = words[i].replace("-", "") - if( + if ( eachline[0] == 'r' or eachline[0] == 'R' or eachline[0] == 'c' or |