# ========================================================================= # FILE: Maker.py # # USAGE: --- # # DESCRIPTION: This define all components of the Makerchip Tab. # # OPTIONS: --- # REQUIREMENTS: --- # BUGS: --- # NOTES: --- # AUTHOR: Sumanto Kar, jeetsumanto123@gmail.com, FOSSEE, IIT Bombay # ACKNOWLEDGEMENTS: Rahul Paknikar, rahulp@iitb.ac.in, FOSSEE, IIT Bombay # Digvjay Singh, digvijay.singh@iitb.ac.in, FOSSEE, IIT Bombay # Prof. Maheswari R., VIT Chennai # GUIDED BY: Steve Hoover, Founder Redwood EDA # ORGANIZATION: eSim Team at FOSSEE, IIT Bombay # CREATED: Monday 29, November 2021 # REVISION: Monday 29, November 2021 # ========================================================================= # importing the files and libraries from xml.etree import ElementTree as ET import hdlparse.verilog_parser as vlog import time from PyQt5 import QtCore, QtWidgets from PyQt5.QtCore import QThread, Qt from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout from configuration.Appconfig import Appconfig import os import subprocess import watchdog.events import watchdog.observers from os.path import expanduser home = expanduser("~") # import inotify.adapters # declaring the global variables # verilogfile stores the name of the file # toggle flag stores the object of the toggling button verilogFile = [] toggle_flag = [] # beginning class Maker. This class create the Maker Tab class Maker(QtWidgets.QWidget): # initailising the varaibles def __init__(self, filecount): print(self) QtWidgets.QWidget.__init__(self) self.count = 0 self.text = "" self.filecount = filecount self.entry_var = {} self.createMakerWidget() self.obj_Appconfig = Appconfig() verilogFile.append("") # Creating the various components of the Widget(Maker Tab) def createMakerWidget(self): self.grid = QtWidgets.QGridLayout() self.setLayout(self.grid) self.grid.addWidget(self.createoptionsBox(), 0, 0, QtCore.Qt.AlignTop) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.show() # This function is to Add new verilog file def addverilog(self): init_path = '../../../' if os.name == 'nt': init_path = '' self.verilogfile = QtCore.QDir.toNativeSeparators( QtWidgets.QFileDialog.getOpenFileName( self, "Open verilog Directory", init_path + "home", "*v" )[0] ) if self.verilogfile == "": self.verilogfile = self.entry_var[0].text() if self.verilogfile == "": reply = QtWidgets.QMessageBox.critical( None, "Error Message", "Error: No Verilog File Chosen.\ Please chose a Verilog file", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) if reply == QtWidgets.QMessageBox.Ok: self.addverilog() self.obj_Appconfig.print_info('Add Verilog File Called') elif reply == QtWidgets.QMessageBox.Cancel: self.obj_Appconfig.print_info('No Verilog File Chosen') return self.text = open(self.verilogfile).read() self.entry_var[0].setText(self.verilogfile) self.entry_var[1].setText(self.text) global verilogFile verilogFile[self.filecount] = self.verilogfile if self.refreshoption in toggle_flag: toggle_flag.remove(self.refreshoption) self.observer = watchdog.observers.Observer() self.event_handler = Handler( self.verilogfile, self.refreshoption, self.observer) self.observer.schedule( self.event_handler, path=self.verilogfile, recursive=True) self.observer.start() # self.notify=notify(self.verilogfile,self.refreshoption) # self.notify.start() # open("filepath.txt","w").write(self.verilogfile) # This function is used to call refresh while # running Ngspice to Verilog Converter # (as the original one gets destroyed) def refresh_change(self): if self.refreshoption in toggle_flag: self.toggle = toggle(self.refreshoption) self.toggle.start() # It is used to refresh the file in eSim if its edited anywhere else def refresh(self): if not hasattr(self, 'verilogfile'): return self.text = open(self.verilogfile).read() self.entry_var[1].setText(self.text) print("NgVeri File: " + self.verilogfile + " Refreshed") self.obj_Appconfig.print_info( "NgVeri File: " + self.verilogfile + " Refreshed") self.observer = watchdog.observers.Observer() self.event_handler = Handler( self.verilogfile, self.refreshoption, self.observer) self.observer.schedule( self.event_handler, path=self.verilogfile, recursive=True) self.observer.start() # self.notify.start() global toggle_flag if self.refreshoption in toggle_flag: toggle_flag.remove(self.refreshoption) # This function is used to save the edited file in eSim def save(self): wr = self.entry_var[1].toPlainText() open(self.verilogfile, "w+").write(wr) # This is used to run the makerchip-app def runmakerchip(self): init_path = '../../' if os.name == 'nt': init_path = '' try: if not os.path.isfile(home + "/.makerchip_accepted"): reply = QtWidgets.QMessageBox.warning( None, "Terms of Services", "Please review the makerchip\ Terms of Service \ (\ https://www.makerchip.com/terms/ ).\ Have you read and do you accept \ these Terms of Service? [y/N]:", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No ) if reply == QtWidgets.QMessageBox.Yes: f = open(home + "/.makerchip_accepted", "w") f.close() else: return print("Running Makerchip..............................") # self.file = open(self.verilogfile,"w") # self.file.write(self.entry_var[1].toPlainText()) # self.file.close() filename = self.verilogfile if self.verilogfile.split('.')[1] != "tlv": reply = QtWidgets.QMessageBox.warning( None, "Do you want to automate top module?", "Click on YES if you want top module \ to be automatically added. \ NOTE: a .tlv file will be created \ in the directory of current verilog file\ and the makerchip will be running on \ this file. Otherwise click on NO.", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: code = open(self.verilogfile).read() text = code filename = self.verilogfile.split('.')[0] + ".tlv" file = os.path.basename(self.verilogfile.split('.')[0]) f = open(filename, 'w') flag = 1 ports = "" code = code.replace("wire", " ") code = code.replace("reg", " ") vlog_ex = vlog.VerilogExtractor() vlog_mods = vlog_ex.extract_objects_from_source(code) lint_off = open("../maker/lint_off.txt").readlines() string = '''\\TLV_version 1d: tl-x.org\n\\SV\n''' for item in lint_off: string += "/* verilator lint_off " + \ item.strip("\n") + "*/ " string += '''\n\n//Your Verilog/System \ Verilog Code Starts Here:\n''' + \ text + '''\n\n//Top Module Code \ Starts here:\n\tmodule top(input \ logic clk, input logic reset, input logic [31:0] cyc_cnt, \ output logic passed, output logic failed);\n''' print(file) for m in vlog_mods: if m.name.lower() == file.lower(): for p in m.ports: if str( p.name) != "clk" and str( p.name) != "reset" and str( p.name) != "cyc_cnt" and str( p.name) != "passed" and str( p.name) != "failed": string += '\t\tlogic ' + p.data_type\ + " " + p.name + ";//" + p.mode + "\n" string += "//The $random() can be replaced \ if user wants to assign values\n" for m in vlog_mods: if m.name.lower() == file.lower(): for p in m.ports: if str( p.mode) == "input" or str( p.mode) == "inout": if str( p.name) != "clk" and str( p.name) != "reset" and str( p.name) != "cyc_cnt" and str( p.name) != "passed" and str( p.name) != "failed": string += '\t\tassign ' + p.name\ + " = " + "$random();\n" for m in vlog_mods: if m.name.lower() == file.lower(): string += '\t\t' + m.name + " " + m.name + '(' i = 0 for p in m.ports: i = i + 1 string += p.name if i == len(m.ports): string += ");\n\t\n\\TLV\n//\ Add \\TLV here if desired\ \n\\SV\nendmodule\n\n" else: string += ", " f.write(string) self.process = QtCore.QProcess(self) cmd = 'makerchip ' + filename print("File: " + filename) self.process.start(cmd) print( "Makerchip command process pid ---------- >", self.process.pid()) except BaseException: self.msg = QtWidgets.QErrorMessage(self) self.msg.setModal(True) self.msg.setWindowTitle("Error Message") self.msg.showMessage( "Error in running Makerchip. \ Please check if Verilog File Chosen.") self.msg.exec_() print("Error in running Makerchip. \ Please check if Verilog File Chosen.") # initial = self.read_file() # while True: # current = self.read_file() # if initial != current: # for line in current: # if line not in initial: # print(line) # initial = current # self.processfile = QtCore.QProcess(self) # self.processfile.start("python3 notify.py") # print(self.processfile.readChannel()) # This creates the buttons/options def createoptionsBox(self): self.optionsbox = QtWidgets.QGroupBox() self.optionsbox.setTitle("Select Options") self.optionsgrid = QtWidgets.QGridLayout() # self.optionsbox2 = QtWidgets.QGroupBox() # self.optionsbox2.setTitle("Note: Please save the file once edited") # self.optionsgrid2 = QtWidgets.QGridLayout() self.optionsgroupbtn = QtWidgets.QButtonGroup() self.addoptions = QtWidgets.QPushButton("Add Top Level Verilog file") self.optionsgroupbtn.addButton(self.addoptions) self.addoptions.clicked.connect(self.addverilog) self.optionsgrid.addWidget(self.addoptions, 0, 1) self.optionsbox.setLayout(self.optionsgrid) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.refreshoption = QtWidgets.QPushButton("Refresh") self.optionsgroupbtn.addButton(self.refreshoption) self.refreshoption.clicked.connect(self.refresh) self.optionsgrid.addWidget(self.refreshoption, 0, 2) self.optionsbox.setLayout(self.optionsgrid) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.saveoption = QtWidgets.QPushButton("Save") self.optionsgroupbtn.addButton(self.saveoption) self.saveoption.clicked.connect(self.save) self.optionsgrid.addWidget(self.saveoption, 0, 3) self.optionsbox.setLayout(self.optionsgrid) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.runoptions = QtWidgets.QPushButton("Edit in Makerchip") self.optionsgroupbtn.addButton(self.runoptions) self.runoptions.clicked.connect(self.runmakerchip) self.optionsgrid.addWidget(self.runoptions, 0, 4) self.optionsbox.setLayout(self.optionsgrid) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) self.acceptTOS = QtWidgets.QPushButton("Accept Makerchip TOS") self.optionsgroupbtn.addButton(self.acceptTOS) self.acceptTOS.clicked.connect(self.makerchipaccepted) self.optionsgrid.addWidget(self.acceptTOS, 0, 5) self.optionsbox.setLayout(self.optionsgrid) self.grid.addWidget(self.creategroup(), 1, 0, 5, 0) return self.optionsbox # This function is called to accept TOS of makerchip def makerchipaccepted(self): reply = QtWidgets.QMessageBox.warning( None, "Terms of Services", "Please review the makerchip\ Terms of Service \ (\ https://www.makerchip.com/terms/ ).\ Have you read and do you \ accept these Terms of Service? [y/N]:", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No ) if reply == QtWidgets.QMessageBox.Yes: f = open(home + "/.makerchip_accepted", "w") f.close() else: return # This function adds the other parts of widget like text box def creategroup(self): self.trbox = QtWidgets.QGroupBox() self.trbox.setTitle(".tlv file") # self.trbox.setDisabled(True) # self.trbox.setVisible(False) self.trgrid = QtWidgets.QGridLayout() self.trbox.setLayout(self.trgrid) self.start = QtWidgets.QLabel("Path to .tlv file") self.trgrid.addWidget(self.start, 1, 0) self.count = 0 self.entry_var[self.count] = QtWidgets.QLineEdit(self) self.trgrid.addWidget(self.entry_var[self.count], 1, 1) self.entry_var[self.count].setMaximumWidth(1000) self.count += 1 # CSS self.trbox.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.start = QtWidgets.QLabel(".tlv code") # self.start2 = QtWidgets.QLabel("Note: \ # Please save the file once edited") # self.start2.setStyleSheet("background-color: red") self.trgrid.addWidget(self.start, 2, 0) # self.trgrid.addWidget(self.start2, 3,0) self.entry_var[self.count] = QtWidgets.QTextEdit() self.trgrid.addWidget(self.entry_var[self.count], 2, 1) self.entry_var[self.count].setMaximumWidth(1000) self.entry_var[self.count].setMaximumHeight(1000) # self.entry_var[self.count].textChanged.connect(self.save) self.count += 1 # CSS self.trbox.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; } \ ") return self.trbox # The Handler class is used to create a watch on the files using WatchDog class Handler(watchdog.events.PatternMatchingEventHandler): # this function initialisses the variable and the objects of watchdog def __init__(self, verilogfile, refreshoption, observer): # Set the patterns for PatternMatchingEventHandler watchdog.events.PatternMatchingEventHandler.__init__( self, ignore_directories=True, case_sensitive=False) self.verilogfile = verilogfile self.refreshoption = refreshoption self.obj_Appconfig = Appconfig() self.observer = observer self.toggle = toggle(self.refreshoption) # if a file is modified, toggle starts to toggle the refresh button def on_modified(self, event): print("Watchdog received modified event - % s." % event.src_path) msg = QtWidgets.QErrorMessage() msg.setWindowTitle("eSim Message") msg.showMessage( "NgVeri File: " + self.verilogfile + " modified. Please click on Refresh") msg.exec_() print("NgVeri File: " + self.verilogfile + " modified. Please click on Refresh") # self.obj_Appconfig.print_info("NgVeri File:\ # "+self.verilogfile+" modified. Please click on Refresh") global toggle_flag if not(self.refreshoption in toggle_flag): toggle_flag.append(self.refreshoption) # i.rm_watch() self.observer.stop() self.toggle.start() # class notify(QThread): # def __init__(self,verilogfile,refreshoption):#,obj_Appconfig): # QThread.__init__(self) # self.verilogfile=verilogfile # self.refreshoption=refreshoption # self.obj_Appconfig = Appconfig() # self.toggle=toggle(self.refreshoption) # def __del__(self): # self.wait() # def run(self): # i = inotify.adapters.Inotify() # i.add_watch(self.verilogfile) # for event in i.event_gen(): # if not self.refreshoption.isVisible(): # break # if event!=None: # print(event) # if "IN_CLOSE_WRITE" in event[1] : # msg = QtWidgets.QErrorMessage() # msg.setModal(True) # msg.setWindowTitle("eSim Message") # msg.showMessage( # "NgVeri File: "+self.verilogfile+"\ # modified. Please click on Refresh") # msg.exec_() # print("NgVeri File: "+self.verilogfile+"\ # modified. Please click on Refresh") # # self.obj_Appconfig.print_info("NgVeri File: \ # "+self.verilogfile+" modified. Please click on Refresh") # global toggle_flag # toggle_flag.append(self.refreshoption) # #i.rm_watch() # self.toggle.start() # break # This class is used to toggle a button(change colour by toggling) class toggle(QThread): # initialising the threads def __init__(self, option): QThread.__init__(self) self.option = option def __del__(self): self.wait() # running the thread to toggle def run(self): while True: self.option.setStyleSheet("background-color: red") self.sleep(1) self.option.setStyleSheet("background-color: none") self.sleep(1) print(toggle_flag) if not self.option.isVisible(): break if self.option not in toggle_flag: break