diff options
author | Rahul P | 2020-08-08 18:07:20 +0530 |
---|---|---|
committer | GitHub | 2020-08-08 18:07:20 +0530 |
commit | 5e61158c70425c61fd1af76e69e2fe8b8f7e5105 (patch) | |
tree | 7777265338f455a0e0eccccf59f2e541bc869b7f | |
parent | a28522ac35da6f275f6ca73c47006b39c8a6725f (diff) | |
parent | f9c63c4941b20543f5d7a99240ceee2a3fe38df5 (diff) | |
download | nghdl-5e61158c70425c61fd1af76e69e2fe8b8f7e5105.tar.gz nghdl-5e61158c70425c61fd1af76e69e2fe8b8f7e5105.tar.bz2 nghdl-5e61158c70425c61fd1af76e69e2fe8b8f7e5105.zip |
Merge pull request #58 from rahulp13/master
unified linux and windows code; ported GUI to PyQt5
-rw-r--r-- | README.md (renamed from readme.md) | 38 | ||||
-rw-r--r-- | ngspice-nghdl.tar.xz | bin | 4493772 -> 4053164 bytes | |||
-rw-r--r-- | src/createKicadLibrary.py | 545 | ||||
-rw-r--r-- | src/ghdlserver/ghdlserver.c | 654 | ||||
-rw-r--r-- | src/ghdlserver/ghdlserver.h | 20 | ||||
-rwxr-xr-x | src/ghdlserver/start_server.sh | 10 | ||||
-rw-r--r-- | src/model_generation.py | 147 | ||||
-rwxr-xr-x | src/ngspice_ghdl.py | 128 | ||||
-rw-r--r-- | src/outitf.c | 237 |
9 files changed, 955 insertions, 824 deletions
@@ -1,9 +1,7 @@ Ngspice Ghdl Interfacing Documentation ==== -It contains all the documenation for Ngspice and Ghdl related work. - -> Note: This project is in beta version and has been tested for rings, counters and PWM controllers. +It contains all the documentation for Ngspice and GHDL related work. ## How is Ngspice interfaced with GHDL? @@ -18,33 +16,33 @@ So the idea of interfacing is just to write VHDL code for a model and use it as GHDL's foreign language interface is used for this inter-process communication. -## Pre-requisites -1. Ubuntu 16.04-18.04 (You can try it on other version and let us know) -2. GHDL (LLVM)-0.36 -3. Ngspice-31 +## Releases +* Ubuntu 16.04 OS and above LTS versions. +* Microsoft Windows 7, 8 and 10. +> Note: Refer [`installers`](https://github.com/fossee/nghdl/tree/installers) branch for documentation on packaging for above mentioned platforms. -## How to install? -This module is made available with eSim (Electronic Circuit Simulation). -Refer https://esim.fossee.in/ for more information. + +## Features +* Support for 500 digital models. +* Support for digital models upto 64 output ports/pins. +* Multiple instances of same digital model. -## Installed Code Structure -1. Ngspice will be installed in home directory $HOME. -2. Source code for all other file will be present in ~/.esim-nghdl -3. symlink "nghdl" is stored in /usr/local/bin +## Pre-requisites +* GHDL (LLVM)-v0.37 +* Ngspice-v31 -## Features -1. Support for 512 digital models. -2. Support for digital models upto 64 output ports/pins. -3. Multiple instances of same digital model. +## How to install? +This module is made available with eSim (Electronic Circuit Simulation). +Refer https://esim.fossee.in/ for more information. ## How to use the Examples provided with NGHDL? -1. Launch eSim --> Click on "NGHDL" icon from the left toolbar --> Click on "Browse" button --> Go to ../nghdl/Example/ +1. Launch eSim --> Click on "NGHDL" icon from the left toolbar --> Click on "Browse" button --> Go to `nghdl/Example/` 2. Locate the example you wish to simulate, find the VHDL file within that example and click on "Open" button at the bottom of "Open File" window. 3. Click on "Upload" button in the NGHDL window. File will be processed in the backend for few seconds. Now exit the NGHDL window. -4. Open the desired example under eSim/Examples/NGHDL_Examples/ using the "Open Project" button, double click on the project when the project is loaded in the "Projects" window. +4. Open the desired example under `eSim/Examples/Mixed_Signal/` using the "Open Project" button, double click on the project when the project is loaded in the "Projects" window. 5. Click on the "Simulation" button on eSim Main window. diff --git a/ngspice-nghdl.tar.xz b/ngspice-nghdl.tar.xz Binary files differindex f32a0a8..c9dc8ca 100644 --- a/ngspice-nghdl.tar.xz +++ b/ngspice-nghdl.tar.xz diff --git a/src/createKicadLibrary.py b/src/createKicadLibrary.py index 966c9d6..e98d0d0 100644 --- a/src/createKicadLibrary.py +++ b/src/createKicadLibrary.py @@ -1,269 +1,276 @@ -from Appconfig import Appconfig -import re -import os -import xml.etree.cElementTree as ET -from PyQt4 import QtGui - - -class AutoSchematic(QtGui.QWidget): - - def __init__(self, modelname): - QtGui.QWidget.__init__(self) - self.modelname = modelname.split('.')[0] - self.template = Appconfig.kicad_lib_template.copy() - self.xml_loc = Appconfig.xml_loc - self.lib_loc = Appconfig.lib_loc - self.kicad_nghdl_lib = '/usr/share/kicad/library/eSim_Nghdl.lib' - self.parser = Appconfig.parser_nghdl - - def createKicadLibrary(self): - xmlFound = None - for root, dirs, files in os.walk(self.xml_loc): - if (str(self.modelname) + '.xml') in files: - xmlFound = root - print(xmlFound) - if xmlFound is None: - self.getPortInformation() - self.createXML() - self.createLib() - elif (xmlFound == self.xml_loc + '/Nghdl'): - print('Library already exists...') - ret = QtGui.QMessageBox.warning( - self, "Warning", '''<b>Library files for this model ''' + - '''already exist. Do you want to overwrite it?</b><br/> - If yes press ok, else cancel it and ''' + - '''change the name of your vhdl file.''', - QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel - ) - if ret == QtGui.QMessageBox.Ok: - print("Overwriting existing libraries") - self.getPortInformation() - self.createXML() - self.removeOldLibrary() # Removes the exisitng library - self.createLib() - else: - print("Exiting Nghdl") - quit() - else: - print('Pre existing library...') - ret = QtGui.QMessageBox.critical( - self, "Error", '''<b>A standard library already exists ''' + - '''with this name.</b><br/><b>Please change the name ''' + - '''of your vhdl file and upload it again</b>''', - QtGui.QMessageBox.Ok - ) - - # quit() - - def getPortInformation(self): - portInformation = PortInfo(self) - portInformation.getPortInfo() - self.portInfo = portInformation.bit_list - self.input_length = portInformation.input_len - - def createXML(self): - cwd = os.getcwd() - xmlDestination = os.path.join(self.xml_loc, 'Nghdl') - self.splitText = "" - for bit in self.portInfo[:-1]: - self.splitText += bit + "-V:" - self.splitText += self.portInfo[-1] + "-V" - - print("changing directory to ", xmlDestination) - os.chdir(xmlDestination) - - root = ET.Element("model") - ET.SubElement(root, "name").text = self.modelname - ET.SubElement(root, "type").text = "Nghdl" - ET.SubElement(root, "node_number").text = str(len(self.portInfo)) - ET.SubElement(root, "title").text = ( - "Add parameters for " + str(self.modelname)) - ET.SubElement(root, "split").text = self.splitText - param = ET.SubElement(root, "param") - ET.SubElement(param, "rise_delay", default="1.0e-9").text = ( - "Enter Rise Delay (default=1.0e-9)") - ET.SubElement(param, "fall_delay", default="1.0e-9").text = ( - "Enter Fall Delay (default=1.0e-9)") - ET.SubElement(param, "input_load", default="1.0e-12").text = ( - "Enter Input Load (default=1.0e-12)") - ET.SubElement(param, "instance_id", default="1").text = ( - "Enter Instance ID (Between 0-99)") - tree = ET.ElementTree(root) - tree.write(str(self.modelname) + '.xml') - print("Leaving the directory ", xmlDestination) - os.chdir(cwd) - - # Calculates the maximum between input and output ports - def findBlockSize(self): - ind = self.input_length - return max( - self.char_sum(self.portInfo[:ind]), - self.char_sum(self.portInfo[ind:]) - ) - - def char_sum(self, ls): - return sum([int(x) for x in ls]) - - def removeOldLibrary(self): - cwd = os.getcwd() - os.chdir(self.lib_loc) - print("Changing directory to ", self.lib_loc) - f = open(self.kicad_nghdl_lib) - lines = f.readlines() - f.close() - - output = [] - line_reading_flag = False - - for line in lines: - if line.startswith("DEF"): - if line.split()[1] == self.modelname: - line_reading_flag = True - if not line_reading_flag: - output.append(line) - if line.startswith("ENDDEF"): - line_reading_flag = False - - f = open(self.kicad_nghdl_lib, 'w') - for line in output: - f.write(line) - - os.chdir(cwd) - print("Leaving directory, ", self.lib_loc) - - def createLib(self): - self.dist_port = 100 # Distance between two ports - self.inc_size = 100 # Increment size of a block - cwd = os.getcwd() - os.chdir(self.lib_loc) - print("Changing directory to ", self.lib_loc) - - lib_file = open(self.kicad_nghdl_lib, "a") - line1 = self.template["start_def"] - line1 = line1.split() - line1 = [w.replace('comp_name', self.modelname) for w in line1] - self.template["start_def"] = ' '.join(line1) - if os.stat(self.kicad_nghdl_lib).st_size == 0: - lib_file.write("EESchema-LIBRARY Version 2.3" + "\n\n") - # lib_file.write("#encoding utf-8"+ "\n"+ "#"+ "\n" + - # "#test_compo" + "\n"+ "#"+ "\n") - lib_file.write( - self.template["start_def"] + "\n" + self.template["U_field"]+"\n" - ) - - line3 = self.template["comp_name_field"] - line3 = line3.split() - line3 = [w.replace('comp_name', self.modelname) for w in line3] - self.template["comp_name_field"] = ' '.join(line3) - - lib_file.write(self.template["comp_name_field"] + "\n") - - line4 = self.template["blank_field"] - line4_1 = line4[0] - line4_2 = line4[1] - line4_1 = line4_1.split() - line4_1 = [w.replace('blank_quotes', '""') for w in line4_1] - line4_2 = line4_2.split() - line4_2 = [w.replace('blank_quotes', '""') for w in line4_2] - line4[0] = ' '.join(line4_1) - line4[1] = ' '.join(line4_2) - self.template["blank_qoutes"] = line4 - - lib_file.write( - line4[0] + "\n" + line4[1] + "\n" + - self.template["start_draw"] + "\n" - ) - - draw_pos = self.template["draw_pos"] - draw_pos = draw_pos.split() - draw_pos[4] = str( - int(draw_pos[4]) - self.findBlockSize() * self.inc_size) - self.template["draw_pos"] = ' '.join(draw_pos) - - lib_file.write(self.template["draw_pos"]+"\n") - - input_port = self.template["input_port"] - input_port = input_port.split() - output_port = self.template["output_port"] - output_port = output_port.split() - inputs = self.portInfo[0: self.input_length] - outputs = self.portInfo[self.input_length:] - - print("INPUTS AND OUTPUTS ") - print(inputs) - print(outputs) - - inputs = self.char_sum(inputs) - outputs = self.char_sum(outputs) - - total = inputs+outputs - - port_list = [] - - for i in range(total): - if (i < inputs): - input_port[1] = "in" + str(i + 1) - input_port[2] = str(i + 1) - input_port[4] = str(int(input_port[4]) - self.dist_port) - input_list = ' '.join(input_port) - port_list.append(input_list) - - else: - output_port[1] = "out" + str(i - inputs + 1) - output_port[2] = str(i + 1) - output_port[4] = str(int(output_port[4]) - self.dist_port) - output_list = ' '.join(output_port) - port_list.append(output_list) - - for ports in port_list: - lib_file.write(ports+"\n") - lib_file.write( - self.template["end_draw"] + "\n" + - self.template["end_def"] + "\n\n\n" - ) - - os.chdir(cwd) - print('Leaving directory, ', self.lib_loc) - QtGui.QMessageBox.information( - self, "Library added", - '''Library details for this model is added to the ''' + - '''<b>eSim_Nghdl.lib</b> in the KiCad shared directory''', - QtGui.QMessageBox.Ok - ) - - -class PortInfo: - def __init__(self, model): - self.modelname = model.modelname - self.model_loc = model.parser.get('NGSPICE', 'DIGITAL_MODEL') - self.bit_list = [] - self.input_len = 0 - - def getPortInfo(self): - info_loc = os.path.join(self.model_loc, self.modelname+'/DUTghdl/') - input_list = [] - output_list = [] - read_file = open(info_loc + 'connection_info.txt', 'r') - data = read_file.readlines() - read_file.close() - - for line in data: - if re.match(r'^\s*$', line): - pass - else: - in_items = re.findall( - "IN", line, re.MULTILINE | re.IGNORECASE - ) - out_items = re.findall( - "OUT", line, re.MULTILINE | re.IGNORECASE - ) - if in_items: - input_list.append(line.split()) - if out_items: - output_list.append(line.split()) - - for in_list in input_list: - self.bit_list.append(in_list[2]) - self.input_len = len(self.bit_list) - for out_list in output_list: - self.bit_list.append(out_list[2]) +from Appconfig import Appconfig
+import re
+import os
+import xml.etree.cElementTree as ET
+from PyQt5 import QtWidgets
+
+
+class AutoSchematic(QtWidgets.QWidget):
+
+ def __init__(self, parent, modelname):
+ QtWidgets.QWidget.__init__(self)
+ self.parent = parent
+ self.modelname = modelname.split('.')[0]
+ self.template = Appconfig.kicad_lib_template.copy()
+ self.xml_loc = Appconfig.xml_loc
+ self.lib_loc = Appconfig.lib_loc
+ if os.name == 'nt':
+ eSim_src = Appconfig.src_home
+ inst_dir = eSim_src.replace('\eSim', '')
+ self.kicad_nghdl_lib = \
+ inst_dir + '/KiCad/share/kicad/library/eSim_Nghdl.lib'
+ else:
+ self.kicad_nghdl_lib = '/usr/share/kicad/library/eSim_Nghdl.lib'
+ self.parser = Appconfig.parser_nghdl
+
+ def createKicadLibrary(self):
+ xmlFound = None
+ for root, dirs, files in os.walk(self.xml_loc):
+ if (str(self.modelname) + '.xml') in files:
+ xmlFound = root
+ print(xmlFound)
+ if xmlFound is None:
+ self.getPortInformation()
+ self.createXML()
+ self.createLib()
+ elif (xmlFound == os.path.join(self.xml_loc, 'Nghdl')):
+ print('Library already exists...')
+ ret = QtWidgets.QMessageBox.warning(
+ self.parent, "Warning", '''<b>Library files for this model ''' +
+ '''already exist. Do you want to overwrite it?</b><br/>
+ If yes press ok, else cancel it and ''' +
+ '''change the name of your vhdl file.''',
+ QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel
+ )
+ if ret == QtWidgets.QMessageBox.Ok:
+ print("Overwriting existing libraries")
+ self.getPortInformation()
+ self.createXML()
+ self.removeOldLibrary() # Removes the exisitng library
+ self.createLib()
+ else:
+ print("Exiting Nghdl")
+ quit()
+ else:
+ print('Pre existing library...')
+ ret = QtWidgets.QMessageBox.critical(
+ self.parent, "Error", '''<b>A standard library already exists ''' +
+ '''with this name.</b><br/><b>Please change the name ''' +
+ '''of your vhdl file and upload it again</b>''',
+ QtWidgets.QMessageBox.Ok
+ )
+
+ # quit()
+
+ def getPortInformation(self):
+ portInformation = PortInfo(self)
+ portInformation.getPortInfo()
+ self.portInfo = portInformation.bit_list
+ self.input_length = portInformation.input_len
+
+ def createXML(self):
+ cwd = os.getcwd()
+ xmlDestination = os.path.join(self.xml_loc, 'Nghdl')
+ self.splitText = ""
+ for bit in self.portInfo[:-1]:
+ self.splitText += bit + "-V:"
+ self.splitText += self.portInfo[-1] + "-V"
+
+ print("changing directory to ", xmlDestination)
+ os.chdir(xmlDestination)
+
+ root = ET.Element("model")
+ ET.SubElement(root, "name").text = self.modelname
+ ET.SubElement(root, "type").text = "Nghdl"
+ ET.SubElement(root, "node_number").text = str(len(self.portInfo))
+ ET.SubElement(root, "title").text = (
+ "Add parameters for " + str(self.modelname))
+ ET.SubElement(root, "split").text = self.splitText
+ param = ET.SubElement(root, "param")
+ ET.SubElement(param, "rise_delay", default="1.0e-9").text = (
+ "Enter Rise Delay (default=1.0e-9)")
+ ET.SubElement(param, "fall_delay", default="1.0e-9").text = (
+ "Enter Fall Delay (default=1.0e-9)")
+ ET.SubElement(param, "input_load", default="1.0e-12").text = (
+ "Enter Input Load (default=1.0e-12)")
+ ET.SubElement(param, "instance_id", default="1").text = (
+ "Enter Instance ID (Between 0-99)")
+ tree = ET.ElementTree(root)
+ tree.write(str(self.modelname) + '.xml')
+ print("Leaving the directory ", xmlDestination)
+ os.chdir(cwd)
+
+ # Calculates the maximum between input and output ports
+ def findBlockSize(self):
+ ind = self.input_length
+ return max(
+ self.char_sum(self.portInfo[:ind]),
+ self.char_sum(self.portInfo[ind:])
+ )
+
+ def char_sum(self, ls):
+ return sum([int(x) for x in ls])
+
+ def removeOldLibrary(self):
+ cwd = os.getcwd()
+ os.chdir(self.lib_loc)
+ print("Changing directory to ", self.lib_loc)
+ f = open(self.kicad_nghdl_lib)
+ lines = f.readlines()
+ f.close()
+
+ output = []
+ line_reading_flag = False
+
+ for line in lines:
+ if line.startswith("DEF"):
+ if line.split()[1] == self.modelname:
+ line_reading_flag = True
+ if not line_reading_flag:
+ output.append(line)
+ if line.startswith("ENDDEF"):
+ line_reading_flag = False
+
+ f = open(self.kicad_nghdl_lib, 'w')
+ for line in output:
+ f.write(line)
+
+ os.chdir(cwd)
+ print("Leaving directory, ", self.lib_loc)
+
+ def createLib(self):
+ self.dist_port = 100 # Distance between two ports
+ self.inc_size = 100 # Increment size of a block
+ cwd = os.getcwd()
+ os.chdir(self.lib_loc)
+ print("Changing directory to ", self.lib_loc)
+
+ lib_file = open(self.kicad_nghdl_lib, "a")
+ line1 = self.template["start_def"]
+ line1 = line1.split()
+ line1 = [w.replace('comp_name', self.modelname) for w in line1]
+ self.template["start_def"] = ' '.join(line1)
+ if os.stat(self.kicad_nghdl_lib).st_size == 0:
+ lib_file.write("EESchema-LIBRARY Version 2.3" + "\n\n")
+ # lib_file.write("#encoding utf-8"+ "\n"+ "#"+ "\n" +
+ # "#test_compo" + "\n"+ "#"+ "\n")
+ lib_file.write(
+ self.template["start_def"] + "\n" + self.template["U_field"]+"\n"
+ )
+
+ line3 = self.template["comp_name_field"]
+ line3 = line3.split()
+ line3 = [w.replace('comp_name', self.modelname) for w in line3]
+ self.template["comp_name_field"] = ' '.join(line3)
+
+ lib_file.write(self.template["comp_name_field"] + "\n")
+
+ line4 = self.template["blank_field"]
+ line4_1 = line4[0]
+ line4_2 = line4[1]
+ line4_1 = line4_1.split()
+ line4_1 = [w.replace('blank_quotes', '""') for w in line4_1]
+ line4_2 = line4_2.split()
+ line4_2 = [w.replace('blank_quotes', '""') for w in line4_2]
+ line4[0] = ' '.join(line4_1)
+ line4[1] = ' '.join(line4_2)
+ self.template["blank_qoutes"] = line4
+
+ lib_file.write(
+ line4[0] + "\n" + line4[1] + "\n" +
+ self.template["start_draw"] + "\n"
+ )
+
+ draw_pos = self.template["draw_pos"]
+ draw_pos = draw_pos.split()
+ draw_pos[4] = str(
+ int(draw_pos[4]) - self.findBlockSize() * self.inc_size)
+ self.template["draw_pos"] = ' '.join(draw_pos)
+
+ lib_file.write(self.template["draw_pos"]+"\n")
+
+ input_port = self.template["input_port"]
+ input_port = input_port.split()
+ output_port = self.template["output_port"]
+ output_port = output_port.split()
+ inputs = self.portInfo[0: self.input_length]
+ outputs = self.portInfo[self.input_length:]
+
+ print("INPUTS AND OUTPUTS ")
+ print(inputs)
+ print(outputs)
+
+ inputs = self.char_sum(inputs)
+ outputs = self.char_sum(outputs)
+
+ total = inputs+outputs
+
+ port_list = []
+
+ for i in range(total):
+ if (i < inputs):
+ input_port[1] = "in" + str(i + 1)
+ input_port[2] = str(i + 1)
+ input_port[4] = str(int(input_port[4]) - self.dist_port)
+ input_list = ' '.join(input_port)
+ port_list.append(input_list)
+
+ else:
+ output_port[1] = "out" + str(i - inputs + 1)
+ output_port[2] = str(i + 1)
+ output_port[4] = str(int(output_port[4]) - self.dist_port)
+ output_list = ' '.join(output_port)
+ port_list.append(output_list)
+
+ for ports in port_list:
+ lib_file.write(ports+"\n")
+ lib_file.write(
+ self.template["end_draw"] + "\n" +
+ self.template["end_def"] + "\n\n\n"
+ )
+
+ os.chdir(cwd)
+ print('Leaving directory, ', self.lib_loc)
+ QtWidgets.QMessageBox.information(
+ self.parent, "Library added",
+ '''Library details for this model is added to the ''' +
+ '''<b>eSim_Nghdl.lib</b> in the KiCad shared directory''',
+ QtWidgets.QMessageBox.Ok
+ )
+
+
+class PortInfo:
+ def __init__(self, model):
+ self.modelname = model.modelname
+ self.model_loc = model.parser.get('NGSPICE', 'DIGITAL_MODEL')
+ self.bit_list = []
+ self.input_len = 0
+
+ def getPortInfo(self):
+ info_loc = os.path.join(self.model_loc, self.modelname+'/DUTghdl/')
+ input_list = []
+ output_list = []
+ read_file = open(info_loc + 'connection_info.txt', 'r')
+ data = read_file.readlines()
+ read_file.close()
+
+ for line in data:
+ if re.match(r'^\s*$', line):
+ pass
+ else:
+ in_items = re.findall(
+ "IN", line, re.MULTILINE | re.IGNORECASE
+ )
+ out_items = re.findall(
+ "OUT", line, re.MULTILINE | re.IGNORECASE
+ )
+ if in_items:
+ input_list.append(line.split())
+ if out_items:
+ output_list.append(line.split())
+
+ for in_list in input_list:
+ self.bit_list.append(in_list[2])
+ self.input_len = len(self.bit_list)
+ for out_list in output_list:
+ self.bit_list.append(out_list[2])
diff --git a/src/ghdlserver/ghdlserver.c b/src/ghdlserver/ghdlserver.c index 60e1a20..f2b632d 100644 --- a/src/ghdlserver/ghdlserver.c +++ b/src/ghdlserver/ghdlserver.c @@ -1,38 +1,24 @@ -/********************************************************************************** - * <ghdlserver.c> FOSSEE, IIT-Bombay - ********************************************************************************** +/************************************************************************************ + * <ghdlserver.c> eSim Team, FOSSEE, IIT-Bombay + ************************************************************************************ + * 8.June.2020 - Bladen Martin - Added OS (Windows and Linux) dependent + * - Rahul Paknikar preprocessors for ease of maintenance + * + * 28.May.2020 - Bladen Martin - Termination of testbench: Replaced Process ID + * - Rahul Paknikar mechanism with socket connection from client + * receiving the special close message + ************************************************************************************ + ************************************************************************************ * 08.Nov.2019 - Rahul Paknikar - Switched to blocking sockets from non-blocking * - Close previous used socket to prevent from * generating too many socket descriptors * - Enabled SO_REUSEPORT, SO_DONTROUTE socket options - * 26.Sept.2019 - Rahul Paknikar - Added reading of IP from a file to - * support multiple digital models - * - On exit, the test bench removes the - * NGHDL_COMMON_IP_<ngspice_pid> file, shared by all - * nghdl digital models and is stored in /tmp - * directory. It tracks the used IPs for existing - * digital models in current simulation. - * - Writes PID file in append mode. * 5.July.2019 - Rahul Paknikar - Added loop to send all port values for * a given event. - * - Removed bug to terminate multiple testbench - * instances in ngpsice windows. - ********************************************************************************** - ********************************************************************************** - * 24.Mar.2017 - Raj Mohan - Added signal handler for SIGUSR1, to handle an - * orphan test bench process. - * The test bench will now create a PID file in - * /tmp directory with the name - * NGHDL_<ngspice pid>_<test bench>_<instance_id> - * This file contains the PID of the test bench . - * On exit, the test bench removes this file. - * The SIGUSR1 signal serves the same purpose as the - * "End" signal. - * - Added syslog interface for logging. + ************************************************************************************ + ************************************************************************************ + * 24.Mar.2017 - Raj Mohan - Added syslog interface for logging. * - Enabled SO_REUSEADDR socket option. - * - Added the following functions: - * o create_pid_file() - * o get_ngspice_pid() * 22.Feb.2017 - Raj Mohan - Implemented a kludge to fix a problem in the * test bench VHDL code. * - Changed sleep() to nanosleep(). @@ -40,43 +26,52 @@ * Added the following functions: * o curtim() * o print_hash_table() - *********************************************************************************/ + ***********************************************************************************/ #include <string.h> #include "ghdlserver.h" #include "uthash.h" #include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <signal.h> #include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <netdb.h> +#include <sys/types.h> +#include <sys/time.h> #include <limits.h> #include <time.h> #include <errno.h> -#include <dirent.h> -#include <syslog.h> + +#ifdef __linux__ + #include <sys/socket.h> + #include <arpa/inet.h> + #include <netinet/in.h> + #include <netdb.h> + #include <syslog.h> +#elif _WIN32 + #include <ws2tcpip.h> + #include <winsock2.h> + #include <eventsys.h> + #include <windows.h> +#endif #define _XOPEN_SOURCE 500 #define MAX_NUMBER_PORT 100 #define NGSPICE "ngspice" // 17.Mar.2017 - RM -static FILE* pid_file; +static FILE *pid_file; static char pid_filename[80]; -static char* Out_Port_Array[MAX_NUMBER_PORT]; -static int out_port_num = 0; +static char *Out_Port_Array[MAX_NUMBER_PORT]; +static int out_port_num = 0; static int server_socket_id = -1; static int sendto_sock; // 22.Feb.2017 - RM - Kludge static int prev_sendto_sock; // 22.Feb.2017 - RM - Kludge -static int pid_file_created; // 10.Mar.2017 - RM +static int pid_file_created; // 10.Mar.2017 - RM -extern char* __progname; // 26.Feb.2017 May not be portable to non-GNU systems. +#ifdef __linux__ + extern char* __progname; // 26.Feb.2017 May not be portable to non-GNU systems. +#endif void Vhpi_Exit(int sig); @@ -89,95 +84,12 @@ struct my_struct { static struct my_struct *s, *users, *tmp = NULL; -/* 17.Mar.2017 - RM - Get the process id of ngspice program.*/ -static int get_ngspice_pid(void) -{ - DIR* dirp; - FILE* fp = NULL; - struct dirent* dir_entry; - char path[1024], rd_buff[1024]; - pid_t pid = -1; - - if ((dirp = opendir("/proc/")) == NULL) - { - perror("get_ngspice_pid() - opendir /proc failed "); - exit(-1); - } - - while ((dir_entry = readdir(dirp)) != NULL) - { - char* nptr; - int valid_num = 0; - - int tmp = strtol(dir_entry->d_name, &nptr, 10); - if ((errno == ERANGE) && (tmp == LONG_MAX || tmp == LONG_MIN)) - { - perror("get_ngspice_pid() - strtol"); // Number out of range. - return(-1); - } - if (dir_entry->d_name == nptr) - { - continue; // No digits found. - } - if (tmp) - { - sprintf(path, "/proc/%s/comm", dir_entry->d_name); - if ((fp = fopen(path, "r")) != NULL) - { - fscanf(fp, "%s", rd_buff); - if (strcmp(rd_buff, NGSPICE) == 0) - { - pid = (pid_t)tmp; // 5.July.2019 - RP - Kludge - } - } - } - } - - if (fp) fclose(fp); - - return(pid); -} - - -/* 23.Mar.2017 - RM - Pass the sock_port argument. We need this if a netlist - * uses more than one instance of the same test bench, so that we can uniquely - * identify the PID files. - */ -/* 10.Mar.2017 - RM - Create PID file for the test bench in /tmp. */ -static void create_pid_file(int sock_port) -{ - pid_t my_pid = getpid(); - pid_t ngspice_pid = get_ngspice_pid(); - - if (ngspice_pid == -1) - { - fprintf(stderr, "create_pid_file() Failed to get ngspice PID"); - syslog(LOG_ERR, "create_pid_file() Failed to get ngspice PID"); - exit(1); - } - - sprintf(pid_filename, "/tmp/NGHDL_%d_%s_%d", ngspice_pid, __progname, sock_port); - pid_file = fopen(pid_filename, "a"); // 26.Sept.2019 - RP - Open file in append mode - - if (pid_file) - { - pid_file_created = 1; - fprintf(pid_file,"%d\n", my_pid); - fclose(pid_file); - } else { - perror("create_pid_file() - cannot open PID file "); - syslog(LOG_ERR, "create_pid_file(): Unable to open PID file in /tmp"); - exit(1); - } -} - - #ifdef DEBUG static char* curtim(void) { static char ct[50]; struct timeval tv; - struct tm* ptm; + struct tm *ptm; long milliseconds; char time_string[40]; @@ -192,48 +104,52 @@ static char* curtim(void) #ifdef DEBUG -static void print_hash_table(void) +static void print_hash_table(void) { struct my_struct *sptr; - - for(sptr=users; sptr != NULL; sptr=sptr->hh.next) - syslog(LOG_INFO, "Hash table:val:%s: key: %s", sptr->val, sptr->key); + + #ifdef __linux__ + for(sptr = users; sptr != NULL; sptr = sptr->hh.next) + syslog(LOG_INFO, "Hash table:val:%s: key: %s", sptr->val, sptr->key); + #endif } #endif -static void parse_buffer(int sock_id, char* receive_buffer) +static void parse_buffer(int sock_id, char *receive_buffer) { static int rcvnum; + + #ifdef __linux__ + syslog(LOG_INFO, "RCVD RCVN:%d from CLT:%d buffer : %s", + rcvnum++, sock_id, receive_buffer); + #endif - syslog(LOG_INFO,"RCVD RCVN:%d from CLT:%d buffer : %s", - rcvnum++, sock_id,receive_buffer); - - /*Parsing buffer to store in hash table */ + /*Parsing buffer to store in hash table */ char *rest; char *token; - char *ptr1=receive_buffer; + char *ptr1 = receive_buffer; char *var; char *value; - // Processing tokens. - while(token = strtok_r(ptr1, ",", &rest)) - { - ptr1 = rest; - while(var=strtok_r(token, ":", &value)) - { - s = (struct my_struct*)malloc(sizeof(struct my_struct)); - strncpy(s->key, var, 64); - strncpy(s->val, value, 64); - HASH_ADD_STR(users, key, s ); - break; - } - } - - s = (struct my_struct*)malloc(sizeof(struct my_struct)); - strncpy(s->key, "sock_id", 64); - snprintf(s->val,64, "%d", sock_id); - HASH_ADD_STR(users, key, s); + // Processing tokens. + while (token = strtok_r(ptr1, ",", &rest)) + { + ptr1 = rest; + while (var = strtok_r(token, ":", &value)) + { + s = (struct my_struct *) malloc(sizeof(struct my_struct)); + strncpy(s->key, var, 64); + strncpy(s->val, value, 64); + HASH_ADD_STR(users, key, s); + break; + } + } + + s = (struct my_struct *) malloc(sizeof(struct my_struct)); + strncpy(s->key, "sock_id", 64); + snprintf(s->val, 64, "%d", sock_id); + HASH_ADD_STR(users, key, s); } @@ -241,47 +157,67 @@ static void parse_buffer(int sock_id, char* receive_buffer) // 26.Sept.2019 - RP - added parameter of socket ip static int create_server(int port_number, char my_ip[], int max_connections) { - int sockfd, reuse = 1; - struct sockaddr_in serv_addr; + int sockfd, reuse = 1; + struct sockaddr_in serv_addr; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (sockfd < 0) + { + #ifdef __linux__ + fprintf(stderr, "%s- Error: in opening socket at server \n", __progname); + + #elif _WIN32 + fprintf(stderr, "Error: in opening socket at server \n"); - sockfd = socket(AF_INET, SOCK_STREAM, 0); + #endif - if (sockfd < 0) - { - fprintf(stderr, "%s- Error: in opening socket at server \n", __progname); - //exit(1); - return -1; - } + //exit(1); + return -1; + } + /* 18.May.2020 - BM - typecast optval field to char* */ /* 20.Mar.2017 - RM - SO_REUSEADDR option. To take care of TIME_WAIT state.*/ - int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); - - /* 08.Nov.2019 - RP - SO_REUSEPORT and SO_DONTROUTE option.*/ - ret += setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int)); - ret += setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, &reuse, sizeof(int)); - - if (ret < 0) - { - syslog(LOG_ERR, "create_server:setsockopt() failed...."); - // close(sockfd); - // return -1; - } - - bzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = inet_addr(my_ip); // 26.Sept.2019 - RP - Bind to specific IP only - serv_addr.sin_port = htons(port_number); - - if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - { - fprintf(stderr,"%s- Error: could not bind socket to port %d\n", - __progname, port_number); - syslog(LOG_ERR, "Error: could not bind socket to port %d", port_number); - close(sockfd); - exit(1); - } - - // Start listening on the server. + int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(int)); + + /* 08.Nov.2019 - RP - SO_REUSEPORT and SO_DONTROUTE option.*/ + /* 08.June.2020 - BM - SO_REUSEPORT only available in Linux */ + #ifdef __linux__ + ret += setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int)); + #endif + + ret += setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, (char *) &reuse, sizeof(int)); + if (ret < 0) + { + #ifdef __linux__ + syslog(LOG_ERR, "create_server:setsockopt() failed...."); + #endif + // close(sockfd); + // return -1; + } + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(my_ip); // 26.Sept.2019 - RP - Bind to specific IP only + serv_addr.sin_port = htons(port_number); + + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + { + #ifdef __linux__ + fprintf(stderr, "%s- Error: could not bind socket to port %d\n", __progname, port_number); + syslog(LOG_ERR, "Error: could not bind socket to port %d", port_number); + close(sockfd); + + #elif _WIN32 + fprintf(stderr, "Error: could not bind socket to port %d\n", port_number); + closesocket(sockfd); + + #endif + + exit(1); + } + + // Start listening on the server. listen(sockfd, max_connections); return sockfd; @@ -289,91 +225,114 @@ static int create_server(int port_number, char my_ip[], int max_connections) // The server to wait (blocking) for a client connection. -static int connect_to_client(int server_fd) -{ - int ret_val = 0; - int newsockfd = -1; - socklen_t clilen; - struct sockaddr_in cli_addr; - - clilen = sizeof(cli_addr); - - /* 08.Nov.2019 - RP - Blocking Socket (Accept) */ - newsockfd = accept(server_fd, (struct sockaddr *) &cli_addr, &clilen); - if (newsockfd >= 0) - { - syslog(LOG_INFO, "SRV:%d New Client Connection CLT:%d", server_fd, newsockfd); - } - else - { - syslog(LOG_ERR,"Error: failed in accept(), socket=%d", server_fd); - exit(1); - } +static int connect_to_client(int server_fd) +{ + int ret_val = 0; + int newsockfd = -1; + socklen_t clilen; + struct sockaddr_in cli_addr; + + clilen = sizeof(cli_addr); + + /* 08.Nov.2019 - RP - Blocking Socket (Accept) */ + newsockfd = accept(server_fd, (struct sockaddr *) &cli_addr, &clilen); + if (newsockfd >= 0) + { + #ifdef _linux_ + syslog(LOG_INFO, "SRV:%d New Client Connection CLT:%d", server_fd, newsockfd); + #endif + } + else + { + #ifdef __linux__ + syslog(LOG_ERR, "Error: failed in accept(), socket=%d", server_fd); + #endif - return newsockfd; -} + exit(1); + } + + return newsockfd; +} //Receive string from socket and put it inside buffer. -static void receive_string(int sock_id, char* buffer) -{ - int nbytes = 0; +static void receive_string(int sock_id, char *buffer) +{ + int nbytes = 0; - /* 08.Nov.2019 - RP - Blocking Socket - Receive */ + /* 08.Nov.2019 - RP - Blocking Socket - Receive */ nbytes = recv(sock_id, buffer, MAX_BUF_SIZE, 0); if (nbytes <= 0) { perror("receive_string() - READ FAILURE "); exit(1); } -} - - -static void Data_Send(int sockid) -{ - static int trnum; - char* out; - - int i; - char colon = ':'; - char semicolon = ';'; - int wrt_retries = 0; - int ret; - s = NULL; + // 28.May.2020 - BM - Added method to close server by Ngspice after simulation + char *exitstr = "CLOSE_FROM_NGSPICE"; + if (strcmp(buffer, exitstr) == 0) + { + Vhpi_Exit(0); + } +} - out = calloc(1, 2048); - // 5.July.2019 - RP - loop to send all ports at once for an event - for (i=0; i<out_port_num; i++) - { - HASH_FIND_STR(users,Out_Port_Array[i],s); - if (strcmp(Out_Port_Array[i], s->key) == 0) - { - strncat(out, s->key, strlen(s->key)); +static void Data_Send(int sockid) +{ + static int trnum; + char *out; + + int i; + char colon = ':'; + char semicolon = ';'; + int wrt_retries = 0; + int ret; + + s = NULL; + + out = calloc(1, 2048); + + // 5.July.2019 - RP - loop to send all ports at once for an event + for (i = 0; i < out_port_num; i++) + { + HASH_FIND_STR(users, Out_Port_Array[i], s); + if (strcmp(Out_Port_Array[i], s->key) == 0) + { + strncat(out, s->key, strlen(s->key)); strncat(out, &colon, 1); strncat(out, s->val, strlen(s->val)); strncat(out, &semicolon, 1); } else { - syslog(LOG_ERR,"The %s's value not found in the table.", - Out_Port_Array[i]); + #ifdef __linux__ + syslog(LOG_ERR,"The %s's value not found in the table.", + Out_Port_Array[i]); + #endif + free(out); + printf("Error! The %s's value not found in the table. Exiting simulation...", + Out_Port_Array[i]); return; } } - /* 08.Nov.2019 - RP - Blocking Socket (Send) */ - if ((send(sockid, out, strlen(out), 0)) == -1) - { - syslog(LOG_ERR,"Failure sending to CLT:%d buffer:%s", sockid, out); - exit(1); - } + /* 08.Nov.2019 - RP - Blocking Socket (Send) */ + if ((send(sockid, out, strlen(out), 0)) == -1) + { + #ifdef __linux__ + syslog(LOG_ERR, "Failure sending to CLT:%d buffer:%s", sockid, out); + #endif + + exit(1); + } - syslog(LOG_INFO,"SNT:TRNUM:%d to CLT:%d buffer: %s", trnum++, sockid, out); - free(out); -} + #ifdef __linux__ + syslog(LOG_INFO, "SNT:TRNUM:%d to CLT:%d buffer: %s", trnum++, sockid, out); + #endif + + free(out); +} // 26.Sept.2019 - RP - added parameter of socket ip @@ -381,95 +340,125 @@ void Vhpi_Initialize(int sock_port, char sock_ip[]) { DEFAULT_SERVER_PORT = sock_port; - signal(SIGINT,Vhpi_Exit); - signal(SIGTERM,Vhpi_Exit); - signal(SIGUSR1, Vhpi_Exit); //10.Mar.2017 - RM + signal(SIGINT, Vhpi_Exit); + signal(SIGTERM, Vhpi_Exit); + + #ifdef _WIN32 + WSADATA WSAData; + WSAStartup(MAKEWORD(2, 2), &WSAData); + #endif int try_limit = 100; - while(try_limit > 0) - { - // 26.Sept.2019 - RP - server_socket_id = create_server(DEFAULT_SERVER_PORT, sock_ip, DEFAULT_MAX_CONNECTIONS); + while (try_limit > 0) + { + // 26.Sept.2019 - RP + server_socket_id = create_server(DEFAULT_SERVER_PORT, sock_ip, DEFAULT_MAX_CONNECTIONS); - if(server_socket_id >= 0) + if (server_socket_id >= 0) { - syslog(LOG_INFO,"Started the server on port %d SRV:%d", + #ifdef __linux__ + syslog(LOG_INFO, "Started the server on port %d SRV:%d", DEFAULT_SERVER_PORT, server_socket_id); + #endif + break; } - - syslog(LOG_ERR,"Could not start server on port %d,will try again", + + #ifdef __linux__ + syslog(LOG_ERR, "Could not start server on port %d,will try again", DEFAULT_SERVER_PORT); + #endif + usleep(1000); try_limit--; - - if(try_limit==0) + + if (try_limit == 0) { - syslog(LOG_ERR, + #ifdef __linux__ + syslog(LOG_ERR, "Error:Tried to start server on port %d, failed..giving up.", DEFAULT_SERVER_PORT); + #endif + exit(1); } } - - //Reading Output Port name and storing in Out_Port_Array; - char* line = NULL; - size_t len = 0; + + //Reading Output Port name and storing in Out_Port_Array; + char *line = NULL; + size_t len = 0; ssize_t read; char *token; FILE *fp; struct timespec ts; - fp=fopen("connection_info.txt","r"); + fp = fopen("connection_info.txt", "r"); if (!fp) { - syslog(LOG_ERR,"Vhpi_Initialize: Failed to open connection_info.txt. Exiting..."); + #ifdef __linux__ + syslog(LOG_ERR,"Vhpi_Initialize: Failed to open connection_info.txt. Exiting..."); + #endif + exit(1); } - line = (char*) malloc(80); - while ((read = getline(&line, &len, fp)) != -1) - { - if (strstr(line,"OUT") != NULL || strstr(line,"out") != NULL) - { - strtok_r(line, " ",&token); - Out_Port_Array[out_port_num] = line; - out_port_num++; - } - line = (char*) malloc(80); - } + line = (char *) malloc(80); + + #ifdef __linux__ + while ((read = getline(&line, &len, fp)) != -1) + { + if (strstr(line, "OUT") != NULL || strstr(line, "out") != NULL) + { + strtok_r(line, " ", &token); + Out_Port_Array[out_port_num] = line; + out_port_num++; + } + line = (char *) malloc(80); + } + + #elif _WIN32 + while (fgets(line, sizeof(line), fp) != NULL) + { + if (strstr(line, "OUT") != NULL || strstr(line, "out") != NULL) + { + strtok_r(line, " ", &token); + Out_Port_Array[out_port_num] = line; + out_port_num++; + } + line = (char *) malloc(80); + } + + #endif + fclose(fp); free(line); ts.tv_sec = 2; ts.tv_nsec = 0; nanosleep(&ts, NULL); - - // 10.Mar.2017 - RM - Create PID file for the test bench. - create_pid_file(sock_port); } -void Vhpi_Set_Port_Value(char *port_name,char *port_value,int port_width) +void Vhpi_Set_Port_Value(char *port_name, char *port_value, int port_width) { - s = (struct my_struct*)malloc(sizeof(struct my_struct)); - strncpy(s->key, port_name,64); - strncpy(s->val,port_value,64); - HASH_ADD_STR( users, key, s ); + s = (struct my_struct *) malloc(sizeof(struct my_struct)); + strncpy(s->key, port_name, 64); + strncpy(s->val, port_value, 64); + HASH_ADD_STR(users, key, s); } -void Vhpi_Get_Port_Value(char* port_name,char* port_value,int port_width) +void Vhpi_Get_Port_Value(char *port_name, char *port_value, int port_width) { - HASH_FIND_STR(users,port_name,s); - if(s) - { - snprintf(port_value,sizeof(port_value),"%s",s->val); - HASH_DEL(users, s); - free(s); - s=NULL; - } + HASH_FIND_STR(users, port_name, s); + if (s) + { + snprintf(port_value, sizeof(port_value), "%s", s->val); + HASH_DEL(users, s); + free(s); + s = NULL; + } } @@ -478,36 +467,55 @@ void Vhpi_Listen() sendto_sock = connect_to_client(server_socket_id); // 22.Feb.2017 - RM - Kludge char receive_buffer[MAX_BUF_SIZE]; receive_string(sendto_sock, receive_buffer); - - syslog(LOG_INFO, "Vhpi_Listen:New socket connection CLT:%d",sendto_sock); - if(strcmp(receive_buffer, "END")==0) + #ifdef __linux__ + syslog(LOG_INFO, "Vhpi_Listen:New socket connection CLT:%d", sendto_sock); + #endif + + if (strcmp(receive_buffer, "END") == 0) { - syslog(LOG_INFO, "RCVD:CLOSE REQUEST from CLT:%d", sendto_sock); + #ifdef __linux__ + syslog(LOG_INFO, "RCVD:CLOSE REQUEST from CLT:%d", sendto_sock); + #endif + Vhpi_Exit(0); - } + } - parse_buffer(sendto_sock, receive_buffer); + parse_buffer(sendto_sock, receive_buffer); } -void Vhpi_Send() +void Vhpi_Send() { -// 22.Feb.2017 - RM - Kludge - if (prev_sendto_sock != sendto_sock) - { - Data_Send(sendto_sock); + // 22.Feb.2017 - RM - Kludge + if (prev_sendto_sock != sendto_sock) + { + Data_Send(sendto_sock); - close(prev_sendto_sock); // 08.Nov.2019 - RP - Close previous socket - prev_sendto_sock = sendto_sock; - } -// 22.Feb.2017 End kludge + #ifdef __linux__ + close(prev_sendto_sock); // 08.Nov.2019 - RP - Close previous socket + + #elif _WIN32 + closesocket(prev_sendto_sock); + + #endif + + prev_sendto_sock = sendto_sock; + } + // 22.Feb.2017 End kludge } -void Vhpi_Exit(int sig) -{ - close(server_socket_id); - syslog(LOG_INFO, "*** Closed VHPI link. Exiting... ***"); - exit(0); -}
\ No newline at end of file +void Vhpi_Exit(int sig) +{ + #ifdef __linux__ + close(server_socket_id); + syslog(LOG_INFO, "*** Closed VHPI link. Exiting... ***"); + + #elif _WIN32 + closesocket(server_socket_id); + + #endif + + exit(0); +}
\ No newline at end of file diff --git a/src/ghdlserver/ghdlserver.h b/src/ghdlserver/ghdlserver.h index 9f23f0b..e04209b 100644 --- a/src/ghdlserver/ghdlserver.h +++ b/src/ghdlserver/ghdlserver.h @@ -1,13 +1,25 @@ /* 18.Mar.2017 - RM - Cleaned up.*/ +/* 20.June.2020 - BM - Added OS dependent includes*/ +#define _GNU_SOURCE +#include <stdio.h> #include <stdlib.h> #include <stdint.h> -#include <stdio.h> #include <unistd.h> #include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> +#include<string.h> + +#ifdef __linux__ + #include <sys/socket.h> + #include <netinet/in.h> + #include <netdb.h> +#elif _WIN32 + #include<ws2tcpip.h> + #include<winsock2.h> + #include<eventsys.h> + #include<windows.h> +#endif + // Should be enough.. #define MAX_BUF_SIZE 4096 diff --git a/src/ghdlserver/start_server.sh b/src/ghdlserver/start_server.sh deleted file mode 100755 index 548d7d7..0000000 --- a/src/ghdlserver/start_server.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -gcc -c ghdlserver.c -ghdl -a Utility_Package.vhdl && -ghdl -a Vhpi_Package.vhdl && -ghdl -a inverter.vhdl && -ghdl -a inverter_tb.vhdl && - -ghdl -e -Wl,ghdlserver.o inverter_tb && -./inverter_tb - diff --git a/src/model_generation.py b/src/model_generation.py index da8e272..f19a5c9 100644 --- a/src/model_generation.py +++ b/src/model_generation.py @@ -1,7 +1,6 @@ -#!/usr/bin/python3 - import re import os +from configparser import SafeConfigParser class ModelGeneration: @@ -13,6 +12,13 @@ class ModelGeneration: self.fname = os.path.basename(file) print("VHDL filename is : ", self.fname) self.home = os.path.expanduser("~") + self.parser = SafeConfigParser() + self.parser.read(os.path.join( + self.home, os.path.join('.nghdl', 'config.ini'))) + self.ngspice_home = self.parser.get('NGSPICE', 'NGSPICE_HOME') + self.release_dir = self.parser.get('NGSPICE', 'RELEASE') + self.src_home = self.parser.get('SRC', 'SRC_HOME') + self.licensefile = self.parser.get('SRC', 'LICENSE') # #### Creating connection_info.txt file from vhdl file #### # read_vhdl = open(file, 'r') @@ -154,15 +160,25 @@ class ModelGeneration: #include <math.h> #include <string.h> #include <time.h> - #include <sys/socket.h> #include <sys/types.h> - #include <netinet/in.h> - #include <netdb.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> + ''' + if os.name == 'nt': + header += ''' + #undef BOOLEAN + #include<winsock2.h> + ''' + else: + header += ''' + #include <sys/socket.h> + #include <netinet/in.h> + #include <netdb.h> + ''' + function_open = ( '''void cm_''' + self.fname.split('.')[0] + '''(ARGS) \n{''') @@ -177,7 +193,7 @@ class ModelGeneration: // Declaring components of Client FILE *log_client = NULL; log_client=fopen("client.log","a"); - int socket_fd, bytes_recieved; + int bytes_recieved; char send_data[1024]; char recv_data[1024]; char *key_iter; @@ -186,6 +202,11 @@ class ModelGeneration: int sock_port = 5000+PARAM(instance_id); ''' + if os.name != 'nt': + var_section += ''' + int socket_fd; + ''' + temp_input_var = [] for item in self.input_port: temp_input_var.append( @@ -262,29 +283,42 @@ class ModelGeneration: char* my_ip = malloc(16); char ip_filename[40]; - sprintf(ip_filename, "/tmp/NGHDL_COMMON_IP_%d.txt", getpid()); + ''' + + if os.name == 'nt': + client_setup_ip += ''' + sprintf(ip_filename, ''' \ + '''"C:/Windows/Temp/NGHDL_COMMON_IP_%d.txt", getpid()); + ''' + else: + client_setup_ip += ''' + sprintf(ip_filename, "/tmp/NGHDL_COMMON_IP_%d.txt",''' \ + ''' getpid()); + ''' + client_setup_ip += ''' fptr = fopen(ip_filename, "r"); if (fptr) { - char line[20]; - while(fscanf(fptr, "%s", line) == 1) { + char line_ip[20]; + int line_port; + while(fscanf(fptr, "%s %d", line_ip, &line_port) == 2) { ip_count++; } fclose(fptr); } - if (ip_count < 255) { + if (ip_count < 254) { sprintf(my_ip, "127.0.0.%d", ip_count+1); } else { - sprintf(my_ip, "127.0.%d.1", (ip_count+1)%256); + sprintf(my_ip, "127.0.%d.1", (ip_count+3)%256); } fptr = fopen(ip_filename, "a"); if (fptr) { - fprintf(fptr, "%s\\n", my_ip); + fprintf(fptr, "%s %d\\n", my_ip, sock_port); fclose(fptr); } else { perror("Client - cannot open Common_IP file "); @@ -296,7 +330,16 @@ class ModelGeneration: client_fetch_ip = ''' /* Client Fetch IP Addr */ + ''' + + if os.name == 'nt': + client_fetch_ip += ''' + WSADATA WSAData; + SOCKET socket_fd; + WSAStartup(MAKEWORD(2, 2), &WSAData); + ''' + client_fetch_ip += ''' char* my_ip = STATIC_VAR(my_ip); host = gethostbyname(my_ip); @@ -396,7 +439,18 @@ class ModelGeneration: if ( send(socket_fd,send_data,sizeof(send_data),0)==-1) { fprintf(stderr, "Client-Failure Sending Message \\n"); - close(socket_fd); + ''' + + if os.name == 'nt': + send_data += ''' + closesocket(socket_fd); + ''' + else: + send_data += ''' + close(socket_fd); + ''' + + send_data += ''' exit(1); } else @@ -429,7 +483,7 @@ class ModelGeneration: for item in self.output_port: sch_output_event.append( - "\t/* Scheduling event and processing them */\n\ + "\t/* Scheduling event and processing them */\n\ \tif((key_iter=strstr(recv_data, " + '"' + item.split(':')[0] + ':"'")) != NULL)\n\ \t{\n\ \t\twhile(*key_iter++ != ':');\n\ @@ -441,8 +495,8 @@ class ModelGeneration: \t\t\telse if(*key_iter=='1')\n\t\t\t{\n\ \t\t\t\t_op_" + item.split(':')[0] + "[Ii]=ONE;\n\ \t\t\t}\n\t\t\telse\n\t\t\t{\n\ - \t\t\t\tfprintf(log_client,\"Unknow value return from server \\n\");\n\ - \t\t\t\tprintf(\"Client-Unknown value return \\n\");\n\t\t\t}\n\n\ + \t\t\t\tfprintf(log_client,\"Unknown value return from server \\n\");\ + \n\t\t\t\tprintf(\"Client-Unknown value return \\n\");\n\t\t\t}\n\n\ \t\t\tif(ANALYSIS == DC)\n\t\t\t{\n\ \t\t\t\tOUTPUT_STATE(" + item.split(':')[0] + "[Ii]) = _op_" + item.split(':')[0] + "[Ii];\n\ \t\t\t}\n\t\t\telse if(_op_" + item.split(':')[0] + "[Ii] != _op_" + item.split(':')[0] + "_old[Ii])\n\ @@ -496,12 +550,27 @@ class ModelGeneration: cfunc.write(client_setup_ip) cfunc.write("\n") cfunc.write("\t\tchar command[1024];\n") - cfunc.write( - '\t\tsnprintf(command,1024,"' + self.home + - '/ngspice-nghdl/src/xspice/icm/ghdl/' + - self.fname.split('.')[0] + - '/DUTghdl/start_server.sh %d %s &",sock_port,my_ip);' - ) + + if os.name == 'nt': + self.digital_home = self.parser.get('NGSPICE', 'DIGITAL_MODEL') + self.msys_home = self.parser.get('COMPILER', 'MSYS_HOME') + cmd_str2 = "\\'start_server.sh %d %s\\'" + "\\" + "\"" + cmd_str1 = os.path.normpath( + "\"cd " + self.digital_home + "/" + + self.fname.split('.')[0] + "/DUTghdl/ && " + + self.msys_home + "/bash.exe -c " + ) + cmd_str1 = cmd_str1.replace("\\", "/") + cfunc.write('\t\tsnprintf(command,1024, "start /min cmd /c ' + + '\\' + cmd_str1 + cmd_str2 + ' &", sock_port, my_ip);') + else: + cfunc.write( + '\t\tsnprintf(command,1024,"' + self.home + + '/ngspice-nghdl/src/xspice/icm/ghdl/' + + self.fname.split('.')[0] + + '/DUTghdl/start_server.sh %d %s &", sock_port, my_ip);' + ) + cfunc.write('\n\t\tsystem(command);') cfunc.write("\n\t}") cfunc.write("\n") @@ -533,7 +602,10 @@ class ModelGeneration: cfunc.write(item) # Close socket fd - cfunc.write("\tclose(socket_fd);\n\n") + if os.name == 'nt': + cfunc.write("\tclosesocket(socket_fd);\n\n") + else: + cfunc.write("\tclose(socket_fd);\n\n") # close log_client file cfunc.write("\tfclose(log_client);") @@ -973,6 +1045,7 @@ class ModelGeneration: def createServerScript(self): # ####### Creating and writing components in start_server.sh ####### # + self.digital_home = self.parser.get('NGSPICE', 'DIGITAL_MODEL') start_server = open('start_server.sh', 'w') @@ -981,10 +1054,16 @@ class ModelGeneration: "###This server run ghdl testebench for infinite time till " + "ngspice send END signal to stop it\n\n" ) - start_server.write( - "cd "+self.home+"/ngspice-nghdl/src/xspice/icm/ghdl/" + - self.fname.split('.')[0]+"/DUTghdl/\n" - ) + + if os.name == 'nt': + pathstr = self.digital_home + "/" + \ + self.fname.split('.')[0] + "/DUTghdl/" + pathstr = pathstr.replace("\\", "/") + start_server.write("cd "+pathstr+"\n") + else: + start_server.write("cd "+self.digital_home + + "/" + self.fname.split('.')[0] + "/DUTghdl/\n") + start_server.write("chmod 775 sock_pkg_create.sh &&\n") start_server.write("./sock_pkg_create.sh $1 $2 &&\n") start_server.write("ghdl -i *.vhdl &&\n") @@ -993,10 +1072,16 @@ class ModelGeneration: start_server.write( "ghdl -a "+self.fname.split('.')[0]+"_tb.vhdl &&\n" ) - start_server.write( - "ghdl -e -Wl,ghdlserver.o " + self.fname.split('.')[0] + "_tb &&\n" - ) - start_server.write("./"+self.fname.split('.')[0]+"_tb") + + if os.name == 'nt': + start_server.write("ghdl -e -Wl,ghdlserver.o " + + "-Wl,libws2_32.a " + + self.fname.split('.')[0] + "_tb &&\n") + start_server.write("./"+self.fname.split('.')[0]+"_tb.exe") + else: + start_server.write("ghdl -e -Wl,ghdlserver.o " + + self.fname.split('.')[0] + "_tb &&\n") + start_server.write("./"+self.fname.split('.')[0]+"_tb") start_server.close() diff --git a/src/ngspice_ghdl.py b/src/ngspice_ghdl.py index 9991793..fd17d7f 100755 --- a/src/ngspice_ghdl.py +++ b/src/ngspice_ghdl.py @@ -1,30 +1,28 @@ #!/usr/bin/python3 - -# This file create the gui to install code model in the ngspice. +# This file create the GUI to install code model in the Ngspice. import os import sys import shutil import subprocess -from PyQt4 import QtGui -from PyQt4 import QtCore -from configparser import SafeConfigParser +from PyQt5 import QtGui, QtCore, QtWidgets +from configparser import ConfigParser from Appconfig import Appconfig from createKicadLibrary import AutoSchematic from model_generation import ModelGeneration -class Mainwindow(QtGui.QWidget): +class Mainwindow(QtWidgets.QWidget): def __init__(self): # super(Mainwindow, self).__init__() - QtGui.QMainWindow.__init__(self) + QtWidgets.QMainWindow.__init__(self) print("Initializing..........") self.home = os.path.expanduser("~") # Reading all variables from config.ini - self.parser = SafeConfigParser() + self.parser = ConfigParser() self.parser.read( os.path.join(self.home, os.path.join('.nghdl', 'config.ini')) ) @@ -41,20 +39,20 @@ class Mainwindow(QtGui.QWidget): self.initUI() def initUI(self): - self.uploadbtn = QtGui.QPushButton('Upload') + self.uploadbtn = QtWidgets.QPushButton('Upload') self.uploadbtn.clicked.connect(self.uploadModel) - self.exitbtn = QtGui.QPushButton('Exit') + self.exitbtn = QtWidgets.QPushButton('Exit') self.exitbtn.clicked.connect(self.closeWindow) - self.browsebtn = QtGui.QPushButton('Browse') + self.browsebtn = QtWidgets.QPushButton('Browse') self.browsebtn.clicked.connect(self.browseFile) - self.addbtn = QtGui.QPushButton('Add Files') + self.addbtn = QtWidgets.QPushButton('Add Files') self.addbtn.clicked.connect(self.addFiles) - self.removebtn = QtGui.QPushButton('Remove Files') + self.removebtn = QtWidgets.QPushButton('Remove Files') self.removebtn.clicked.connect(self.removeFiles) - self.ledit = QtGui.QLineEdit(self) - self.sedit = QtGui.QTextEdit(self) + self.ledit = QtWidgets.QLineEdit(self) + self.sedit = QtWidgets.QTextEdit(self) self.process = QtCore.QProcess(self) - self.termedit = QtGui.QTextEdit(self) + self.termedit = QtWidgets.QTextEdit(self) self.termedit.setReadOnly(1) pal = QtGui.QPalette() bgc = QtGui.QColor(0, 0, 0) @@ -63,7 +61,7 @@ class Mainwindow(QtGui.QWidget): self.termedit.setStyleSheet("QTextEdit {color:white}") # Creating gridlayout - grid = QtGui.QGridLayout() + grid = QtWidgets.QGridLayout() grid.setSpacing(5) grid.addWidget(self.ledit, 1, 0) grid.addWidget(self.browsebtn, 1, 1) @@ -90,15 +88,15 @@ class Mainwindow(QtGui.QWidget): def browseFile(self): print("Browse button clicked") - self.filename = QtGui.QFileDialog.getOpenFileName( - self, 'Open File', '.') + self.filename = QtWidgets.QFileDialog.getOpenFileName( + self, 'Open File', '.')[0] self.ledit.setText(self.filename) print("Vhdl file uploaded to process :", self.filename) def addFiles(self): print("Starts adding supporting files") title = self.addbtn.text() - for file in QtGui.QFileDialog.getOpenFileNames(self, title): + for file in QtWidgets.QFileDialog.getOpenFileNames(self, title)[0]: self.sedit.append(str(file)) self.file_list.append(file) print("Supporting Files are :", self.file_list) @@ -116,7 +114,7 @@ class Mainwindow(QtGui.QWidget): self.file_list.remove(file) if nonvhdl_count > 0: - QtGui.QMessageBox.critical( + QtWidgets.QMessageBox.critical( self, 'Critical', '''<b>Important Message.</b> <br/><br/>Supporting files should be <b>.vhdl</b> file ''' ) @@ -131,16 +129,19 @@ class Mainwindow(QtGui.QWidget): # Looking if model directory is present or not if os.path.isdir(self.modelname): print("Model Already present") - ret = QtGui.QMessageBox.warning( + ret = QtWidgets.QMessageBox.warning( self, "Warning", "<b>This model already exist. Do you want to " + "overwrite it?</b><br/> If yes press ok, else cancel it and " + "change the name of your vhdl file.", - QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel + QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel ) - if ret == QtGui.QMessageBox.Ok: + if ret == QtWidgets.QMessageBox.Ok: print("Overwriting existing model " + self.modelname) - cmd = "rm -rf " + self.modelname + if os.name == 'nt': + cmd = "rmdir " + self.modelname + "/s /q" + else: + cmd = "rm -rf " + self.modelname # process = subprocess.Popen( # cmd, stdout=subprocess.PIPE, # stderr=subprocess.PIPE, shell=True @@ -215,18 +216,30 @@ class Mainwindow(QtGui.QWidget): shutil.copy(os.path.join(self.home, self.src_home) + "/src/ghdlserver/Vhpi_Package.vhdl", path + "/DUTghdl/") + if os.name == 'nt': + shutil.copy(os.path.join(self.home, self.src_home) + + "/src/ghdlserver/libws2_32.a", path + "/DUTghdl/") + for file in self.file_list: shutil.copy(str(file), path + "/DUTghdl/") os.chdir(path + "/DUTghdl") - subprocess.call("bash " + path + "/DUTghdl/compile.sh", shell=True) - subprocess.call("chmod a+x start_server.sh", shell=True) - subprocess.call("chmod a+x sock_pkg_create.sh", shell=True) + if os.name == 'nt': + # path to msys bin directory where bash is located + self.msys_bin = self.parser.get('COMPILER', 'MSYS_HOME') + subprocess.call(self.msys_bin+"/bash.exe " + + path + "/DUTghdl/compile.sh", shell=True) + subprocess.call(self.msys_bin+"/bash.exe -c " + + "'chmod a+x start_server.sh'", shell=True) + subprocess.call(self.msys_bin+"/bash.exe -c " + + "'chmod a+x sock_pkg_create.sh'", shell=True) + else: + subprocess.call("bash " + path + "/DUTghdl/compile.sh", shell=True) + subprocess.call("chmod a+x start_server.sh", shell=True) + subprocess.call("chmod a+x sock_pkg_create.sh", shell=True) + os.remove("compile.sh") os.remove("ghdlserver.c") - # os.remove("ghdlserver.h") - # os.remove("Utility_Package.vhdl") - # os.remove("Vhpi_Package.vhdl") # Slot to redirect stdout and stderr to window console @QtCore.pyqtSlot() @@ -235,17 +248,25 @@ class Mainwindow(QtGui.QWidget): str(self.process.readAllStandardOutput().data(), encoding='utf-8') ) stderror = self.process.readAllStandardError() - if stderror.toUpper().contains("ERROR"): + if stderror.toUpper().contains(b"ERROR"): self.errorFlag = True self.termedit.append(str(stderror.data(), encoding='utf-8')) def runMake(self): print("run Make Called") self.release_home = self.parser.get('NGSPICE', 'RELEASE') - os.chdir(self.release_home) + path_icm = os.path.join(self.release_home, "src/xspice/icm") + os.chdir(path_icm) + try: - cmd = " make" - print("Running Make command in " + self.release_home) + if os.name == 'nt': + # path to msys bin directory where make is located + self.msys_bin = self.parser.get('COMPILER', 'MSYS_HOME') + cmd = self.msys_bin+"\\make.exe" + else: + cmd = " make" + + print("Running Make command in " + path_icm) path = os.getcwd() # noqa self.process = QtCore.QProcess(self) self.process.start(cmd) @@ -257,7 +278,11 @@ class Mainwindow(QtGui.QWidget): def runMakeInstall(self): print("run Make Install Called") try: - cmd = " make install" + if os.name == 'nt': + self.msys_bin = self.parser.get('COMPILER', 'MSYS_HOME') + cmd = self.msys_bin+"\\make.exe install" + else: + cmd = " make install" print("Running Make Install") path = os.getcwd() # noqa try: @@ -268,10 +293,7 @@ class Mainwindow(QtGui.QWidget): self.process = QtCore.QProcess(self) self.process.start(cmd) self.process.finished.connect(self.createSchematicLib) - QtCore.QObject.connect( - self.process, QtCore.SIGNAL("readyReadStandardOutput()"), - self, QtCore.SLOT("readAllStandard()") - ) + self.process.readyReadStandardOutput.connect(self.readAllStandard) os.chdir(self.cur_dir) except BaseException: @@ -282,16 +304,16 @@ class Mainwindow(QtGui.QWidget): if Appconfig.esimFlag == 1: if not self.errorFlag: print('Creating library files................................') - schematicLib = AutoSchematic(self.modelname) + schematicLib = AutoSchematic(self, self.modelname) schematicLib.createKicadLibrary() else: - QtGui.QMessageBox.critical( + QtWidgets.QMessageBox.critical( self, 'Error', '''Cannot create Schematic Library of ''' + '''your model. Resolve the <b>errors</b> shown on ''' + '''console of NGHDL window. ''' ) else: - QtGui.QMessageBox.information( + QtWidgets.QMessageBox.information( self, 'Message', '''<b>Important Message</b><br/><br/>''' + '''To create Schematic Library of your model, ''' + '''use NGHDL through <b>eSim</b> ''' @@ -317,15 +339,15 @@ class Mainwindow(QtGui.QWidget): self.runMake() self.runMakeInstall() else: - QtGui.QMessageBox.information( + QtWidgets.QMessageBox.information( self, 'Message', '''<b>Important Message.</b><br/>''' + '''<br/>This accepts only <b>.vhdl</b> file ''' ) except Exception as e: - QtGui.QMessageBox.critical(self, 'Error', str(e)) + QtWidgets.QMessageBox.critical(self, 'Error', str(e)) -class FileRemover(QtGui.QWidget): +class FileRemover(QtWidgets.QWidget): def __init__(self, main_obj): super(FileRemover, self).__init__() @@ -338,8 +360,8 @@ class FileRemover(QtGui.QWidget): print(self.files) - self.grid = QtGui.QGridLayout() - removebtn = QtGui.QPushButton('Remove', self) + self.grid = QtWidgets.QGridLayout() + removebtn = QtWidgets.QPushButton('Remove', self) removebtn.clicked.connect(self.removeFiles) self.grid.addWidget(self.createCheckBox(), 0, 0) @@ -349,15 +371,15 @@ class FileRemover(QtGui.QWidget): self.show() def createCheckBox(self): - self.checkbox = QtGui.QGroupBox() + self.checkbox = QtWidgets.QGroupBox() self.checkbox.setTitle('Remove Files') - self.checkgrid = QtGui.QGridLayout() + self.checkgrid = QtWidgets.QGridLayout() - self.checkgroupbtn = QtGui.QButtonGroup() + self.checkgroupbtn = QtWidgets.QButtonGroup() for path in self.files: print(path) - self.cb_dict[path] = QtGui.QCheckBox(path) + self.cb_dict[path] = QtWidgets.QCheckBox(path) self.checkgroupbtn.addButton(self.cb_dict[path]) self.checkgrid.addWidget(self.cb_dict[path], self.row, self.col) self.row += 1 @@ -393,7 +415,7 @@ class FileRemover(QtGui.QWidget): def main(): - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) if len(sys.argv) > 1: if sys.argv[1] == '-e': Appconfig.esimFlag = 1 diff --git a/src/outitf.c b/src/outitf.c index fba5224..1ac92ab 100644 --- a/src/outitf.c +++ b/src/outitf.c @@ -3,17 +3,6 @@ Copyright 1990 Regents of the University of California. All rights reserved. Author: 1988 Wayne A. Christopher, U. C. Berkeley CAD Group Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski **********/ -/************************************************************************** - * 10.Mar.2017 - RM - Added a dirty fix to handle orphan FOSSEE test bench - * processes. The following static functions were added in the process: - * o nghdl_orphan_tb() - * o nghdl_tb_SIGUSR1() - **************************************************************************/ -/************************************************************************** - * 22.Oct.2019 - RP - Read all the PIDs and send kill signal to all those - * processes. Also, Remove the common file of used IPs and PIDs for this - * Ngspice's instance rather than depending on GHDLServer to do the same. - **************************************************************************/ /* * This module replaces the old "writedata" routines in nutmeg. * Unlike the writedata routines, the OUT routines are only called by @@ -21,7 +10,25 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski * of nutmeg doesn't deal with OUT at all. */ +/************************************************************************** + * 08.June.2020 - RP, BM - Added OS (Windows and Linux) dependent + * preprocessors and sockets + ************************************************************************** + * 29.May.2020 - RP, BM - Read all the IPs and ports from NGHDL_COMMON_IP + * file from /tmp folder. It connects to each of the ghdlserver and sends + * CLOSE_FROM_NGSPICE message to terminate themselves + **************************************************************************/ + #include "ngspice/ngspice.h" + +/*05.June.2020 - BM - Added follwing includes for Win OS */ +#ifdef _WIN32 + #undef BOOLEAN /* Undefine it due to conflicting definitions in Win OS */ + + #include <ws2tcpip.h> + #include <winsock2.h> +#endif + #include "ngspice/cpdefs.h" #include "ngspice/ftedefs.h" #include "ngspice/dvec.h" @@ -34,7 +41,6 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski #include "circuits.h" #include "outitf.h" #include "variable.h" -#include <fcntl.h> #include "ngspice/cktdefs.h" #include "ngspice/inpdefs.h" #include "breakp2.h" @@ -42,14 +48,21 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski #include "plotting/graf.h" #include "../misc/misc_time.h" -/* 10.Mar.2917 - RM - Added the following #include */ -#include <dirent.h> +/* 10.Mar.2017 - RM - Added the following #include */ +#include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> #include <errno.h> +/* 27.May.2020 - BM - Added the following #include */ +#ifdef __linux__ + #include <sys/socket.h> + #include <arpa/inet.h> + #include <unistd.h> +#endif + extern char *spice_analysis_get_name(int index); extern char *spice_analysis_get_description(int index); @@ -95,9 +108,7 @@ extern bool orflag; int fixme_onoise_type = SV_NOTYPE; int fixme_inoise_type = SV_NOTYPE; - -#define DOUBLE_PRECISION 15 - +#define DOUBLE_PRECISION 15 static clock_t lastclock, currclock; static double *rowbuf; @@ -112,102 +123,101 @@ static double *valueold, *valuenew; static bool savenone = FALSE; #endif -/* 10.Mar.2017 - RM - Added nghdl_tb_SIGUSR1().*/ -static void nghdl_tb_SIGUSR1(char* pid_file) -{ - int ret; - char line[80]; - char* nptr; - pid_t pid[256], tmp; - int count=0, i; - - FILE* fp = fopen(pid_file, "r"); - - if (fp) - { - /* 22.Oct.2019 - RP - Scan and store all the PIDs in this file */ - while (fscanf(fp, "%s", line) == 1) - { - // PID is converted to a decimal value. - tmp = (pid_t) strtol(line, &nptr, 10); - if ((errno != ERANGE) && (errno!= EINVAL)) + +/* 28.May.2020 - RP, BM - Closing the GHDL server after simulation is over */ +static void close_server() +{ + FILE *fptr; + char ip_filename[48]; + + #ifdef __linux__ + sprintf(ip_filename, "/tmp/NGHDL_COMMON_IP_%d.txt", getpid()); + #elif _WIN32 + WSADATA WSAData; + SOCKADDR_IN addr; + WSAStartup(MAKEWORD(2, 2), &WSAData); + sprintf(ip_filename, "C:\\Windows\\Temp\\NGHDL_COMMON_IP_%d.txt", getpid()); + #endif + + fptr = fopen(ip_filename, "r"); + + if(fptr) + { + char server_ip[20], *message = "CLOSE_FROM_NGSPICE"; + int port = -1, sock = -1, try_limit = 0, skip_flag = 0; + struct sockaddr_in serv_addr; + serv_addr.sin_family = AF_INET; + + /* scan server ip and port to send close message */ + while(fscanf(fptr, "%s %d\n", server_ip, &port) == 2) + { + /* Create socket descriptor */ + try_limit = 10, skip_flag = 0; + while(try_limit > 0) { - pid[count++] = tmp; + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + sleep(0.2); + try_limit--; + if(try_limit == 0) + { + perror("\nClient Termination - Socket Failed: "); + skip_flag = 1; + } + } + else + break; } - } - fclose(fp); - } + if (skip_flag) + continue; + + serv_addr.sin_port = htons(port); + serv_addr.sin_addr.s_addr = inet_addr(server_ip); - /* 22.Oct.2019 - RP - Kill all the active PIDs */ - for(i=0; i<count; i++) - { - if (pid[i]) - { - // Check if a process with this pid really exists. - ret = kill(pid[i], 0); - if (ret == 0) + /* connect with the server */ + try_limit = 10, skip_flag = 0; + while(try_limit > 0) { - kill(pid[i], SIGUSR1); + if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + sleep(0.2); + try_limit--; + if(try_limit == 0) + { + perror("\nClient Termination - Connection Failed: "); + skip_flag = 1; + } + } + else + break; } - } - } + + if (skip_flag) + continue; - // 22.Oct.2019 - RP - remove(pid_file); -} + /* send close message to the server */ + #ifdef __linux__ + send(sock, message, strlen(message), 0); + close(sock); + #elif _WIN32 + send(sock, message, strlen(message) + 1, 0); + closesocket(sock); + #endif + } -/* 10.Mar.2017 - RM - Added nghdl_orphan_tb().*/ -static void nghdl_orphan_tb(void) -{ - struct dirent* dirp; - DIR* dirfd; - char* dir = "/tmp"; - char filename_tmp[1024]; - char pid_file_prefix[256]; - - sprintf(pid_file_prefix, "NGHDL_%d", getpid()); - - if ((dirfd = opendir(dir)) == NULL) - { - fprintf(stderr, "nghdl_orphan_tb(): Cannot open /tmp\n"); - return; - } + fclose(fptr); + } - /* Loop through /tmp directories looking for "NGHDL_<my pid>*" files.*/ - while ((dirp = readdir(dirfd)) != NULL) - { - struct stat stbuf; - sprintf(filename_tmp, "/tmp/%s", dirp->d_name); - if (strstr(filename_tmp, pid_file_prefix)) - { - if (stat(filename_tmp, &stbuf) == -1) - { - fprintf(stderr, - "nghdl_orphan_tb: stat() failed; ERRNO=%d on file:%s\n", - errno, filename_tmp); - continue; - } + #ifdef _WIN32 + WSACleanup(); + #endif - if ((stbuf.st_mode & S_IFMT) == S_IFDIR) - { - continue; - } - else - { - nghdl_tb_SIGUSR1(filename_tmp); - } - } - } - - // 22.Oct.2019 - RP - char ip_filename[40]; - sprintf(ip_filename, "/tmp/NGHDL_COMMON_IP_%d.txt", getpid()); - remove(ip_filename); + remove(ip_filename); } -/* End 10.Mar.2017 - RM */ -/* The two "begin plot" routines share all their internals... */ + +// The two "begin plot" routines share all their internals... int OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, @@ -253,7 +263,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam int i, j, depind = 0; char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP]; char *ch, tmpname[BSIZE_SP]; - bool saveall = TRUE; + bool saveall = TRUE; bool savealli = FALSE; char *an_name; int initmem; @@ -355,7 +365,6 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam run->refIndex = -1; } - /* Pass 1. */ if (numsaves && !saveall) { for (i = 0; i < numsaves; i++) @@ -439,7 +448,6 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam } } - /* Pass 2. */ for (i = 0; i < numsaves; i++) { @@ -626,10 +634,10 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) dataDesc *d; -#ifdef TCL_MODULE + #ifdef TCL_MODULE /*Locks the blt vector to stop access*/ blt_lockvec(i); -#endif + #endif d = &run->data[i]; @@ -658,10 +666,10 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) fprintf(stderr, "OUTpData: unsupported data type\n"); } -#ifdef TCL_MODULE + #ifdef TCL_MODULE /*relinks and unlocks vector*/ blt_relink(i, d->vec); -#endif + #endif } } @@ -1133,12 +1141,13 @@ fileEndPoint(FILE *fp, bool bin) static void fileEnd(runDesc *run) { - /* 10.Mar.2017 - RM - Check if any orphan test benches are running. If any are + /* 28.May.2020 - RP, BM - Check if any orphan test benches are running. If any are * found, force them to exit. */ - nghdl_orphan_tb(); - /* End 10.Mar.2017 */ + /* 28.May.2020 - BM */ + close_server(); + /* End 28.May.2020 */ if (run->fp != stdout) { @@ -1293,9 +1302,9 @@ plotAddComplexValue(dataDesc *desc, IFcomplex value) static void plotEnd(runDesc *run) { - /* 10.Mar.2017 - RM */ - nghdl_orphan_tb(); - /* End 10.Mar.2017 */ + /* 28.May.2020 - BM, RP */ + close_server(); + /* End 28.May.2020 */ fprintf(stdout, "\nNo. of Data Rows : %d\n", run->pointCount); } |