# =========================================================================
# 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