├── .gitignore ├── nghdl-simulator-source.tar.xz ├── src ├── ghdlserver │ ├── compile.sh │ ├── ghdlserver.h │ ├── Vhpi_Package.vhdl │ ├── Utility_Package.vhdl │ ├── ghdlserver.c │ └── uthash.h ├── Appconfig.py ├── createKicadLibrary.py ├── ngspice_ghdl.py └── model_generation.py ├── Example ├── logic_gates │ ├── inverter.vhdl │ ├── nor_gate.vhdl │ ├── xor_gate.vhdl │ ├── or_gate.vhdl │ ├── and_gate.vhdl │ └── nand_gate.vhdl ├── combinational_logic │ ├── bin_to_gray │ │ └── bin_to_gray.vhdl │ ├── half_adder │ │ └── half_adder.vhdl │ ├── full_adder │ │ ├── full_adder_sl.vhdl │ │ ├── full_adder_sl_slv.vhdl │ │ ├── full_adder_slv.vhdl │ │ └── full_adder_structural.vhdl │ ├── counter │ │ ├── decadecounter.vhdl │ │ ├── up_counter_slv.vhdl │ │ ├── updown_counter.vhdl │ │ └── up_counter.vhdl │ ├── mux-demux │ │ ├── mux.vhdl │ │ └── demux.vhdl │ └── decoder │ │ └── decoder.vhdl └── PWM │ ├── pwmdecrement.vhdl │ └── pwmincrement.vhdl ├── CONTRIBUTION.md ├── LICENSE ├── GHDLside.md ├── README.md └── Workflow.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /nghdl-simulator-source.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/nghdl/HEAD/nghdl-simulator-source.tar.xz -------------------------------------------------------------------------------- /src/ghdlserver/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | gcc -c ghdlserver.c 3 | ghdl -a Utility_Package.vhdl && 4 | ghdl -a Vhpi_Package.vhdl 5 | 6 | 7 | -------------------------------------------------------------------------------- /Example/logic_gates/inverter.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity inverter is 5 | port ( i: in std_logic; 6 | o: out std_logic); 7 | end inverter; 8 | 9 | architecture beh of inverter is 10 | begin 11 | o <= not i; 12 | end beh; 13 | 14 | 15 | -------------------------------------------------------------------------------- /Example/logic_gates/nor_gate.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity nor_gate is 5 | port (a : in std_logic; 6 | b : in std_logic; 7 | c : out std_logic); 8 | end nor_gate; 9 | 10 | architecture rtl of nor_gate is 11 | begin 12 | c <= a nor b; 13 | end rtl; 14 | -------------------------------------------------------------------------------- /Example/logic_gates/xor_gate.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity xor_gate is 5 | port (a : in std_logic; 6 | b : in std_logic; 7 | c : out std_logic); 8 | end xor_gate; 9 | 10 | architecture rtl of xor_gate is 11 | begin 12 | c <= a xor b; 13 | end rtl; 14 | -------------------------------------------------------------------------------- /Example/logic_gates/or_gate.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity or_gate is 5 | Port ( a : in STD_LOGIC; 6 | b : in STD_LOGIC; 7 | c : out STD_LOGIC); 8 | end or_gate; 9 | 10 | architecture behavioral of or_gate is 11 | begin 12 | c <= a or b; 13 | end behavioral; 14 | -------------------------------------------------------------------------------- /Example/combinational_logic/bin_to_gray/bin_to_gray.vhdl: -------------------------------------------------------------------------------- 1 | LIBRARY ieee; 2 | USE ieee.std_logic_1164.ALL; 3 | 4 | entity bin_to_gray is 5 | port( 6 | bin : in std_logic_vector(3 downto 0); 7 | G : out std_logic_vector(3 downto 0) 8 | ); 9 | end bin_to_gray; 10 | 11 | 12 | architecture gate_level of bin_to_gray is 13 | 14 | begin 15 | 16 | G(3) <= bin(3); 17 | G(2) <= bin(3) xor bin(2); 18 | G(1) <= bin(2) xor bin(1); 19 | G(0) <= bin(1) xor bin(0); 20 | 21 | end gate_level; -------------------------------------------------------------------------------- /Example/logic_gates/and_gate.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity and_gate is 6 | 7 | port( a: in std_logic; 8 | b: in std_logic; 9 | c: out std_logic 10 | ); 11 | 12 | end and_gate; 13 | 14 | architecture beh of and_gate is 15 | 16 | begin 17 | 18 | process(a, b) 19 | 20 | begin 21 | 22 | if (a='1' and b='1') then 23 | c <= '1'; 24 | 25 | else 26 | 27 | c <= '0'; 28 | 29 | end if; 30 | 31 | end process; 32 | 33 | end beh; 34 | -------------------------------------------------------------------------------- /Example/logic_gates/nand_gate.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity nand_gate is 6 | 7 | port( a: in std_logic; 8 | b: in std_logic; 9 | c: out std_logic 10 | ); 11 | 12 | end nand_gate; 13 | 14 | architecture beh of nand_gate is 15 | 16 | begin 17 | 18 | process(a, b) 19 | 20 | begin 21 | 22 | if (a='1' and b='1') then 23 | c <= '0'; 24 | 25 | else 26 | 27 | c <= '1'; 28 | 29 | end if; 30 | 31 | end process; 32 | 33 | end beh; 34 | -------------------------------------------------------------------------------- /Example/combinational_logic/half_adder/half_adder.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity half_adder is 6 | port ( 7 | i_bit0 : in std_logic_vector(0 downto 0); 8 | i_bit1 : in std_logic_vector(0 downto 0); 9 | o_sum : out std_logic_vector(0 downto 0); 10 | o_carry : out std_logic_vector(0 downto 0) 11 | ); 12 | end half_adder; 13 | 14 | architecture rtl of half_adder is 15 | begin 16 | o_sum <= i_bit0 xor i_bit1; 17 | o_carry <= i_bit0 and i_bit1; 18 | end rtl; 19 | -------------------------------------------------------------------------------- /Example/combinational_logic/full_adder/full_adder_sl.vhdl: -------------------------------------------------------------------------------- 1 | -- This file uses only std_logic(sl) variable types 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity full_adder_sl is 7 | port ( 8 | i_bit1 : in std_logic; 9 | i_bit2 : in std_logic; 10 | i_bit3 : in std_logic; 11 | o_sum : out std_logic; 12 | o_carry : out std_logic 13 | ); 14 | end full_adder_sl; 15 | 16 | architecture rtl of full_adder_sl is 17 | begin 18 | o_sum <= i_bit1 xor i_bit2 xor i_bit3; 19 | o_carry <= (i_bit1 and i_bit2) or (i_bit2 and i_bit3) or (i_bit3 and i_bit1); 20 | end rtl; 21 | -------------------------------------------------------------------------------- /Example/combinational_logic/counter/decadecounter.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity decadecounter is 6 | port(CLK : in std_logic; 7 | RST : in std_logic; 8 | Count : out std_logic_vector(9 downto 0)); 9 | end decadecounter; 10 | 11 | architecture beh of decadecounter is 12 | signal a: std_logic_vector(9 downto 0) := "0000000001"; 13 | begin 14 | process(CLK, RST) 15 | begin 16 | if RST = '1' then 17 | a <= "0000000001"; 18 | elsif rising_edge(CLK) then 19 | a <= a(0) & a(9 downto 1); -- rotating left 20 | end if; 21 | end process; 22 | Count <= std_logic_vector (a); 23 | end beh; 24 | -------------------------------------------------------------------------------- /Example/combinational_logic/mux-demux/mux.vhdl: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.all; 3 | 4 | entity mux is 5 | port(A : in std_logic; 6 | B : in std_logic; 7 | C : in std_logic; 8 | D : in std_logic; 9 | S0 : in std_logic; 10 | S1 : in std_logic; 11 | Z: out std_logic); 12 | end mux; 13 | 14 | architecture bhv of mux is 15 | begin 16 | process (A,B,C,D,S0,S1) is 17 | begin 18 | if (S0 ='0' and S1 = '0') then 19 | Z <= A; 20 | elsif (S0 ='0' and S1 = '1') then 21 | Z <= B; 22 | elsif (S0 ='1' and S1 = '0') then 23 | Z <= C; 24 | else 25 | Z <= D; 26 | end if; 27 | 28 | end process; 29 | end bhv; 30 | 31 | -------------------------------------------------------------------------------- /Example/combinational_logic/full_adder/full_adder_sl_slv.vhdl: -------------------------------------------------------------------------------- 1 | --This file uses combination of std_logic(sl) and std_logic_vector(slv) variable types 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity full_adder_sl_slv is 7 | port ( 8 | i_bit1 : in std_logic; 9 | i_bit2 : in std_logic; 10 | i_bit3 : in std_logic_vector(0 downto 0); 11 | o_sum : out std_logic; 12 | o_carry : out std_logic_vector(0 downto 0) 13 | ); 14 | end full_adder_sl_slv; 15 | 16 | architecture rtl of full_adder_sl_slv is 17 | begin 18 | o_sum <= i_bit1 xor i_bit2 xor i_bit3(0); 19 | o_carry(0) <= (i_bit1 and i_bit2) or (i_bit2 and i_bit3(0)) or (i_bit3(0) and i_bit1); 20 | end rtl; 21 | -------------------------------------------------------------------------------- /Example/combinational_logic/full_adder/full_adder_slv.vhdl: -------------------------------------------------------------------------------- 1 | --This file uses only std_logic_vector(slv) variable type 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity full_adder_slv is 7 | port ( 8 | i_bit1 : in std_logic_vector(0 downto 0); 9 | i_bit2 : in std_logic_vector(0 downto 0); 10 | i_bit3 : in std_logic_vector(0 downto 0); 11 | o_sum : out std_logic_vector(0 downto 0); 12 | o_carry : out std_logic_vector(0 downto 0) 13 | ); 14 | end full_adder_slv; 15 | 16 | architecture rtl of full_adder_slv is 17 | begin 18 | o_sum <= i_bit1 xor i_bit2 xor i_bit3; 19 | o_carry <= (i_bit1 and i_bit2) or (i_bit2 and i_bit3) or (i_bit3 and i_bit1); 20 | end rtl; 21 | -------------------------------------------------------------------------------- /Example/combinational_logic/mux-demux/demux.vhdl: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.all; 3 | 4 | entity demux is 5 | port( 6 | 7 | F : in STD_LOGIC_vector(0 downto 0); 8 | S0: in STD_LOGIC_vector(0 downto 0); 9 | S1: in STD_LOGIC_vector(0 downto 0); 10 | A: out STD_LOGIC_vector(0 downto 0); 11 | B: out STD_LOGIC_vector(0 downto 0); 12 | C: out STD_LOGIC_vector(0 downto 0); 13 | D: out STD_LOGIC_vector(0 downto 0) 14 | ); 15 | end demux; 16 | 17 | architecture bhv of demux is 18 | begin 19 | process (F,S0,S1) is 20 | begin 21 | if (S0 ="0" and S1 = "0") then 22 | A <= F; 23 | elsif (S0 ="1" and S1 = "0") then 24 | B <= F; 25 | elsif (S0 ="0" and S1 = "1") then 26 | C <= F; 27 | else 28 | D <= F; 29 | end if; 30 | 31 | end process; 32 | end bhv; 33 | -------------------------------------------------------------------------------- /Example/combinational_logic/counter/up_counter_slv.vhdl: -------------------------------------------------------------------------------- 1 | -- This logic is implemented in up_counter.vhdl example as well, but there tmp variable is declared as unsigned 2 | --whereas here it is declared as std_logic_vector; which requires type conversion. 3 | --slv stands for std_logic_vector 4 | library ieee; 5 | 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | 9 | entity up_counter_slv is 10 | port(C : in std_logic; 11 | CLR : in std_logic; 12 | Q : out std_logic_vector(3 downto 0)); 13 | end up_counter_slv; 14 | 15 | architecture bhv of up_counter_slv is 16 | 17 | signal tmp: std_logic_vector(3 downto 0); 18 | begin 19 | process (C, CLR) 20 | begin 21 | if (CLR='1') then 22 | tmp <= "0000"; 23 | 24 | elsif (C'event and C='1') then 25 | tmp <= std_logic_vector(to_unsigned(1+to_integer(unsigned(tmp)), tmp'length)); 26 | 27 | end if; 28 | 29 | end process; 30 | Q <= tmp; 31 | 32 | end bhv; 33 | -------------------------------------------------------------------------------- /Example/combinational_logic/counter/updown_counter.vhdl: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | use IEEE.numeric_std.ALL; 4 | 5 | 6 | entity updown_counter is 7 | Port ( clk: in std_logic; 8 | reset: in std_logic; 9 | up_down: in std_logic; 10 | counter: out std_logic_vector(3 downto 0) 11 | ); 12 | end updown_counter; 13 | 14 | architecture Behavioral of updown_counter is 15 | signal tmp: std_logic_vector(3 downto 0); 16 | begin 17 | 18 | process(clk,reset) 19 | begin 20 | if(reset='1') then 21 | tmp <= "0000"; 22 | elsif(clk'event and clk='1') then 23 | if(up_down='1') then 24 | tmp <= std_logic_vector(to_unsigned(to_integer(unsigned(tmp)-1), tmp'length)); 25 | else 26 | tmp <= std_logic_vector(to_unsigned(to_integer(unsigned(tmp)+1), tmp'length)); 27 | end if; 28 | end if; 29 | end process; 30 | counter <= std_logic_vector(tmp); 31 | 32 | end Behavioral; -------------------------------------------------------------------------------- /src/ghdlserver/ghdlserver.h: -------------------------------------------------------------------------------- 1 | /* 18.Mar.2017 - RM - Cleaned up.*/ 2 | /* 20.June.2020 - BM - Added OS dependent includes*/ 3 | #define _GNU_SOURCE 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef __linux__ 13 | #include 14 | #include 15 | #include 16 | #elif _WIN32 17 | #include 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | 24 | // Should be enough.. 25 | #define MAX_BUF_SIZE 4096 26 | 27 | //Defualt port number 28 | 29 | //unlikely to have more than 16 active 30 | //threads talking to the TB? 31 | #define DEFAULT_MAX_CONNECTIONS 65535 32 | 33 | int DEFAULT_SERVER_PORT; 34 | 35 | //Vhpi Functions. 36 | void Vhpi_Initialize(int sock_port, char sock_ip[]); /* 26.Sept.2019 - RP */ 37 | void Vhpi_Exit(); 38 | void Vhpi_Listen(); 39 | void Vhpi_Send(); 40 | void Vhpi_Set_Port_Value(char* reg_name, char* reg_value, int port_width); 41 | void Vhpi_Get_Port_Value(char* reg_name, char* reg_value, int port_width); 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Example/combinational_logic/counter/up_counter.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity up_counter is 6 | port(Clock : in std_logic; 7 | CLR : in std_logic; 8 | Q : out std_logic_vector(3 downto 0)); 9 | end up_counter; 10 | 11 | architecture beh of up_counter is 12 | signal tmp: unsigned(3 downto 0) := "0000"; 13 | 14 | --------------- Other ways to initialize -------------- 15 | -- signal tmp: unsigned(3 downto 0) := x"0"; 16 | -- signal tmp: unsigned(3 downto 0) := (others => '0'); 17 | ------------------------------------------------------- 18 | 19 | begin 20 | process (Clock, CLR) 21 | begin 22 | if (CLR='1') then 23 | tmp <= "0000"; 24 | elsif (Clock'event and Clock='1') then 25 | if tmp="1111" then 26 | tmp <= x"0"; 27 | else 28 | tmp <= tmp +1; 29 | end if; 30 | end if; 31 | end process; 32 | 33 | Q <= std_logic_vector (tmp); 34 | end beh; 35 | -------------------------------------------------------------------------------- /CONTRIBUTION.md: -------------------------------------------------------------------------------- 1 | ## Contribution 2 | 3 | If you want to add any enhancement feature or have found any bug and want to work on it, please open a new issue regarding that and put a message "I would like to work on it." And make sure every pull request should reference to an issue. 4 | 5 | #### Points on how to make pull request 6 | * You need to fork this repository to your account. 7 | 8 | * Clone it using ``` git clone https://github.com/FOSSEE/nghdl.git ``` 9 | 10 | * Always create a new branch before making any changes. You can create new branch using ```git branch ``` 11 | 12 | * Checkout into your new branch using ```git checkout ``` 13 | 14 | * Make changes to code and once you are done use ```git add ```. Now commit changes with proper message using ```git commit -m "Your message"```. 15 | 16 | * After commiting your changes push your changes to your forked repository using ```git push origin ``` 17 | Finally create a pull request from github. 18 | There should be only one commit per pull request. 19 | 20 | 21 | * Please follow below guidelines for your commit message : 22 | * Commit message should be like : Fixes issue #[issue_number] - one line message of work you did. 23 | * After commit message, there should be a commit body where you can mention what you did in short or in detail. 24 | 25 | Please follow above method to file pull requests. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Please note that the following codes are copyrighted under BSD license. 3 | 4 | src/ghdlserver/ghdlserver.c 5 | src/ghdlserver/ghdlserver.h 6 | src/ghdlserver/Utility_Package.vhdl 7 | src/ghdlserver/Vhpi_Package.vhdl 8 | 9 | Copyright 2015 Prof.M.P Desai (madhav@ee.iitb.ac.in) and Powai Labs. 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 13 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 14 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | 19 | -------------------------------------------------------------------------------- /Example/PWM/pwmdecrement.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity pwmdecrement is 6 | port(C : in std_logic; 7 | D : in std_logic; 8 | Q : out std_logic); 9 | end pwmdecrement; 10 | 11 | 12 | architecture bhv of pwmdecrement is 13 | signal count: integer:=0; 14 | signal alpha: integer:=0; --counts number of clocks 15 | signal beta : integer:=1; --counts number of times 'D' is low w.r.t Clock signal(C) 16 | signal tmp : integer:=9; --stores the value of beta for which Q will be set HIGH 17 | begin 18 | process (C,D) 19 | 20 | begin 21 | if(C='1' and C'event) then 22 | alpha<=alpha+1; --counts number of rising edges 23 | if(count=0) then --initial pulse 24 | Q <= '1'; 25 | count<=1; 26 | end if; 27 | if(D='0') then --if D is low, increase beta by 1 28 | beta<=beta+1; 29 | end if; 30 | if(alpha=9) then --when aplha is 9, decrease beta by 1 and store in tmp //--set to 9 on purpose(so that first pwm signal has 90% duty cycle) 31 | tmp<=beta-1; --decrease beta and store in tmp, so that we get 10% less duty cycle than previous 32 | alpha<=0; 33 | beta<=0; 34 | count<=0; 35 | end if; 36 | if(tmp=alpha) then --the moment when number of clocks(alpha) equals previous number of times Q was high(tmp), we turn Q off. 37 | Q<='0'; 38 | end if; 39 | end if; 40 | end process; 41 | end bhv; 42 | -------------------------------------------------------------------------------- /GHDLside.md: -------------------------------------------------------------------------------- 1 | # Code Documentation (GHDL Side) 2 | 3 | This documentation will help you to know about the code written for communication between server and Digital logic written in VHDL 4 | 5 | ## Files generated automatically for GHDL side 6 | 7 | * modelname_tb.vhdl 8 | * Note: where modelname will be the name of your model 9 | 10 | ## modelname_tb.vhdl 11 | 12 | * This is a testbench created to send and receive values from server and gives the input values to the digital design. 13 | * It uses VHPI library of VHDL, by including this library we can use functions written in C program, in VHDL. 14 | * In this test bench there are two processes used. 15 | * First process is used to initialize, listen server and sending the output to server. 16 | * Second process is used to giving inputs from server to digital design and taking the values to send through the server. 17 | 18 | ### C functions used in modelname_tb.vhdl 19 | #### Vhpi_Initialize 20 | * This function is used to create the port and initialize the server. 21 | 22 | #### Vhpi_Listen 23 | * This function is used to start communication between client and server. 24 | 25 | #### Vhpi_Send 26 | * This function is used to send the values to client. 27 | 28 | #### Pack_String_To_Vhpi_String 29 | * As we are sending values along with there variable name, we are using this function which convert the vhdl string to VHPI string. 30 | 31 | #### Vhpi_Get_Port_Value 32 | * This function takes input values from server, when Vhpi_Listen called, and give it to digital design. 33 | 34 | #### Vhpi_Set_Port_Value 35 | * This function is used to takes output values from digital design and send it through server when Vhpi_Send called. 36 | -------------------------------------------------------------------------------- /Example/PWM/pwmincrement.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity pwmincrement is 6 | port(C : in std_logic; 7 | D : in std_logic; 8 | Q : out std_logic); 9 | end pwmincrement; 10 | --working code for incrementing duty cycle \ Output of oscillator is fed back using a LPF and Comparator in F/B loop 11 | architecture bhv of pwmincrement is 12 | signal count: integer:=0; 13 | signal alpha: integer:=0; --counts number of clocks 14 | signal beta : integer:=0; --counts number of times 'D' is low w.r.t Clock signal(C) 15 | signal tmp : integer:=0; --stores the value of beta for which Q will be set HIGH 16 | begin 17 | process (C,D) 18 | 19 | begin 20 | if(C='1' and C'event) then 21 | alpha<=alpha+1; --counts number of rising edges 22 | if(count=0) then --initial pulse 23 | Q <= '1'; 24 | count<=1; 25 | end if; 26 | if(D='0') then --if D is low, increase beta by 1 27 | beta<=beta+1; 28 | end if; 29 | if(alpha=8) then --when aplha is 8, incremement beta by 1 and store in tmp //--set to 8 on purpose(so that first pwm signal has 10% duty cycle) 30 | tmp<=beta+1; --increase beta and store in tmp, so that we get 10% more duty cycle than previous 31 | alpha<=0; --reset alpha 32 | beta<=0; --reset beta 33 | count<=0; --reset count 34 | end if; 35 | if(tmp=alpha) then --the moment when number of clocks(alpha) equals previous number of times Q was high(tmp), we turn Q off. Effectively incrementing duty cycle by 10% 36 | Q<='0'; 37 | tmp<=0; 38 | end if; 39 | end if; 40 | end process; 41 | end bhv; 42 | -------------------------------------------------------------------------------- /Example/combinational_logic/full_adder/full_adder_structural.vhdl: -------------------------------------------------------------------------------- 1 | --This file uses structural style and uses only std_logic variable type 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | 5 | entity full_adder_structural is 6 | port(a: in std_logic; 7 | b: in std_logic; 8 | cin: in std_logic; 9 | sum: out std_logic; 10 | carry: out std_logic); 11 | end full_adder_structural; 12 | 13 | library ieee; 14 | use ieee.std_logic_1164.all; 15 | 16 | entity andgate is 17 | port(a: in std_logic; 18 | b: in std_logic; 19 | z: out std_logic); 20 | end andgate; 21 | 22 | architecture e1 of andgate is 23 | begin 24 | z <= a and b; 25 | end e1; 26 | 27 | library ieee; 28 | use ieee.std_logic_1164.all; 29 | 30 | entity xorgate is 31 | port(a: in std_logic; 32 | b: in std_logic; 33 | z: out std_logic); 34 | end xorgate; 35 | 36 | architecture e2 of xorgate is 37 | begin 38 | z <= a xor b; 39 | end e2; 40 | 41 | library ieee; 42 | use ieee.std_logic_1164.all; 43 | 44 | entity orgate is 45 | port(a: in std_logic; 46 | b: in std_logic; 47 | z: out std_logic); 48 | end orgate; 49 | 50 | architecture e3 of orgate is 51 | begin 52 | z <= a or b; 53 | end e3; 54 | 55 | 56 | 57 | architecture structural of full_adder_structural is 58 | 59 | component andgate 60 | port(a: in std_logic; 61 | b: in std_logic; 62 | z: out std_logic); 63 | end component; 64 | 65 | component xorgate 66 | port(a: in std_logic; 67 | b: in std_logic; 68 | z: out std_logic); 69 | end component; 70 | 71 | component orgate 72 | port(a: in std_logic; 73 | b: in std_logic; 74 | z: out std_logic); 75 | end component; 76 | 77 | signal c1,c2,c3: std_logic; 78 | 79 | begin 80 | 81 | u1 : xorgate port map(a,b,c1); 82 | u2 : xorgate port map(c1,cin,sum); 83 | u3 : andgate port map(c1,cin,c2); 84 | u4 : andgate port map(a,b,c3); 85 | u5 : orgate port map(c2,c3,carry); 86 | 87 | 88 | end structural; 89 | -------------------------------------------------------------------------------- /Example/combinational_logic/decoder/decoder.vhdl: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity decoder is 5 | port ( 6 | p : in std_logic_vector(4 downto 0); 7 | d : out std_logic_vector(31 downto 0) 8 | ); 9 | end decoder; 10 | 11 | architecture behav of decoder is 12 | 13 | begin 14 | 15 | with p select 16 | d<="00000000000000000000000000000001" when "00000", 17 | "00000000000000000000000000000010" when "00001", 18 | "00000000000000000000000000000100" when "00010", 19 | "00000000000000000000000000001000" when "00011", 20 | "00000000000000000000000000010000" when "00100", 21 | "00000000000000000000000000100000" when "00101", 22 | "00000000000000000000000001000000" when "00110", 23 | "00000000000000000000000010000000" when "00111", 24 | "00000000000000000000000100000000" when "01000", 25 | "00000000000000000000001000000000" when "01001", 26 | "00000000000000000000010000000000" when "01010", 27 | "00000000000000000000100000000000" when "01011", 28 | "00000000000000000001000000000000" when "01100", 29 | "00000000000000000010000000000000" when "01101", 30 | "00000000000000000100000000000000" when "01110", 31 | "00000000000000001000000000000000" when "01111", 32 | "00000000000000010000000000000000" when "10000", 33 | "00000000000000100000000000000000" when "10001", 34 | "00000000000001000000000000000000" when "10010", 35 | "00000000000010000000000000000000" when "10011", 36 | "00000000000100000000000000000000" when "10100", 37 | "00000000001000000000000000000000" when "10101", 38 | "00000000010000000000000000000000" when "10110", 39 | "00000000100000000000000000000000" when "10111", 40 | "00000001000000000000000000000000" when "11000", 41 | "00000010000000000000000000000000" when "11001", 42 | "00000100000000000000000000000000" when "11010", 43 | "00001000000000000000000000000000" when "11011", 44 | "00010000000000000000000000000000" when "11100", 45 | "00100000000000000000000000000000" when "11101", 46 | "01000000000000000000000000000000" when "11110", 47 | "10000000000000000000000000000000" when "11111", 48 | "00000000000000000000000000000000" when others; 49 | 50 | end behav; 51 | -------------------------------------------------------------------------------- /src/Appconfig.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from configparser import ConfigParser 3 | 4 | 5 | class Appconfig: 6 | if os.name == 'nt': 7 | home = os.path.join('library', 'config') 8 | else: 9 | home = os.path.expanduser('~') 10 | 11 | # Reading all variables from eSim config.ini 12 | parser_esim = ConfigParser() 13 | parser_esim.read(os.path.join(home, os.path.join('.esim', 'config.ini'))) 14 | try: 15 | src_home = parser_esim.get('eSim', 'eSim_HOME') 16 | xml_loc = os.path.join(src_home, 'library/modelParamXML') 17 | lib_loc = os.path.expanduser('~') 18 | except BaseException: 19 | pass 20 | esimFlag = 0 21 | 22 | # Reading all variables from nghdl config.ini 23 | parser_nghdl = ConfigParser() 24 | parser_nghdl.read(os.path.join(home, os.path.join('.nghdl', 'config.ini'))) 25 | 26 | # KiCad V6 Symbol Template 27 | kicad_sym_template = { 28 | "start_def": "(symbol \"comp_name\" (pin_names (offset 1.016)) " + 29 | "(in_bom yes) (on_board yes)", 30 | "U_field": "(property \"Reference\" \"U\" (id 0) (at 6 7 0)" + 31 | "(effects (font (size 1.524 1.524))))", 32 | "comp_name_field": "(property \"Value\" \"comp_name\" (id 1) " + 33 | "(at 8 10 0)(effects (font (size 1.524 1.524))))", 34 | "blank_field": [ 35 | "(property \"Footprint\" blank_quotes (id 2) " + 36 | "(at 72.39 49.53 0)(effects (font (size 1.524 1.524))))", 37 | "(property \"Datasheet\" blank_quotes (id 3) " + 38 | "(at 72.39 49.53 0)(effects (font (size 1.524 1.524))))" 39 | ], 40 | "draw_pos": "(symbol \"comp_name\"(rectangle (start 0 0 ) " + 41 | "(end 15.25 2 )(stroke (width 0) (type default) " + 42 | "(color 0 0 0 0))(fill (type none))))", 43 | "start_draw": "(symbol", 44 | "input_port": "(pin input line(at -5.15 0.54 0 )(length 5.08 )" + 45 | "(name \"in\" (effects(font(size 1.27 1.27))))" + 46 | "(number \"1\" (effects (font (size 1.27 1.27)))))", 47 | "output_port": "(pin output line(at 20.38 0.54 180 )(length 5.08 )" + 48 | "(name \"out\" (effects(font(size 1.27 1.27))))" + 49 | "(number \"2\" (effects (font (size 1.27 1.27)))))", 50 | "end_draw": "))" 51 | } 52 | -------------------------------------------------------------------------------- /src/ghdlserver/Vhpi_Package.vhdl: -------------------------------------------------------------------------------- 1 | -- author: Madhav P. Desai 2 | -- modified: Rahul Paknikar 3 | -- -changed procedure of Vhpi_Initialize - 26.Sept.2019 4 | -- -removed procedure Vhpi_Close - 15.Oct.2019 5 | 6 | library ieee; 7 | use ieee.std_logic_1164.all; 8 | library work; 9 | use work.Utility_Package.all; 10 | package Vhpi_Foreign is 11 | 12 | ----------------------------------------------------------------------------- 13 | -- foreign Vhpi function 14 | ----------------------------------------------------------------------------- 15 | procedure Vhpi_Initialize(sock_port : in integer; sock_ip : in VhpiString); 16 | attribute foreign of Vhpi_Initialize : procedure is "VHPIDIRECT Vhpi_Initialize"; 17 | 18 | procedure Vhpi_Listen; 19 | attribute foreign of Vhpi_Listen : procedure is "VHPIDIRECT Vhpi_Listen"; 20 | 21 | procedure Vhpi_Send; 22 | attribute foreign of Vhpi_Send : procedure is "VHPIDIRECT Vhpi_Send"; 23 | 24 | procedure Vhpi_Set_Port_Value(port_name: in VhpiString; port_value: in VhpiString; port_width: in integer); 25 | attribute foreign of Vhpi_Set_Port_Value: procedure is "VHPIDIRECT Vhpi_Set_Port_Value"; 26 | 27 | procedure Vhpi_Get_Port_Value(port_name: in VhpiString; port_value : out VhpiString; port_width: in integer); 28 | attribute foreign of Vhpi_Get_Port_Value : procedure is "VHPIDIRECT Vhpi_Get_Port_Value"; 29 | 30 | procedure Vhpi_Log(message_string: in VhpiString); 31 | attribute foreign of Vhpi_Log : procedure is "VHPIDIRECT Vhpi_Log"; 32 | 33 | end Vhpi_Foreign; 34 | 35 | package body Vhpi_Foreign is 36 | 37 | ----------------------------------------------------------------------------- 38 | -- subprogram bodies for foreign vhpi routines. will never be called 39 | ----------------------------------------------------------------------------- 40 | procedure Vhpi_Initialize(sock_port: in integer; sock_ip : in VhpiString) is 41 | begin 42 | assert false report "fatal: this should never be called" severity failure; 43 | end Vhpi_Initialize; 44 | 45 | procedure Vhpi_Listen is 46 | begin 47 | assert false report "fatal: this should never be called" severity failure; 48 | end Vhpi_Listen; 49 | 50 | procedure Vhpi_Send is 51 | begin 52 | assert false report "fatal: this should never be called" severity failure; 53 | end Vhpi_Send; 54 | 55 | procedure Vhpi_Set_Port_Value(port_name: in VhpiString; port_value: in VhpiString; port_width: in integer) is 56 | begin 57 | assert false report "fatal: this should never be called" severity failure; 58 | end Vhpi_Set_Port_Value; 59 | 60 | procedure Vhpi_Get_Port_Value(port_name : in VhpiString; port_value: out VhpiString; port_width: in integer)is 61 | begin 62 | assert false report "fatal: this should never be called" severity failure; 63 | end Vhpi_Get_Port_Value; 64 | 65 | procedure Vhpi_Log(message_string: in VhpiString) is 66 | begin 67 | assert false report "fatal: this should never be called" severity failure; 68 | end Vhpi_Log; 69 | 70 | end Vhpi_Foreign; 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/fossee/nghdl?color=blueviolet) 2 | ![Python](https://img.shields.io/badge/python-v3.6+-blue.svg) 3 | [![PEP8](https://img.shields.io/badge/code%20style-pep8-orange.svg)](https://www.python.org/dev/peps/pep-0008/) 4 | [![GitHub forks](https://img.shields.io/github/forks/fossee/nghdl)](https://github.com/fossee/nghdl/network) 5 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/fossee/nghdl) 6 | ![GitHub contributors](https://img.shields.io/github/contributors/fossee/nghdl) 7 | 8 | 9 | Ngspice Ghdl Interfacing Documentation 10 | ==== 11 | 12 | It contains all the documentation for Ngspice and GHDL related work. 13 | 14 | 15 | ## How is Ngspice interfaced with GHDL? 16 | Ngspice supports mixed-signal simulation. It can simulate both digital and analog components. 17 | 18 | Ngspice has something called code-model which defines the behavior of your component and can be used in the netlist. For example you can create a full-adder's code-model in Ngspice and use it in any circuit netlist of Ngspice. 19 | 20 | Now the question is if we already have digital model creation in Ngspice, then why this interfacing? 21 | 22 | Well, in Ngspice, it is difficult to write your own digital code-models. Though, many people are familiar with GHDL and can easily write the VHDL code. 23 | So the idea of interfacing is just to write VHDL code for a model and use it as a dummy model in Ngspice. Thus, whenever Ngspice looks for that model, it will actually call GHDL to get the results. 24 | GHDL's foreign language interface is used for this inter-process communication. 25 | 26 | 27 | ## Releases 28 | * Ubuntu 18.04 and 20.04 LTS versions. 29 | * Microsoft Windows 7, 8 and 10. 30 | 31 | > Note for other distributions: You can refer [`installers`](https://github.com/fossee/nghdl/tree/installers) branch for documentation on packaging (for above mentioned distributions) to build installers for your operating system in a similar way. For providing your build, please check the `Contribution` section mentioned below. 32 | 33 | 34 | ## Features 35 | * Support for nearly 500 VHDL digital models. 36 | * Support for VHDL digital models upto 64 output ports/pins. 37 | * Support for Verilog digital models. 38 | 39 | 40 | ## Pre-requisites 41 | * [GHDL (LLVM - v0.37)](http://ghdl.free.fr/) 42 | * [Verilator (v4.210)](https://www.veripool.org/verilator/) 43 | * [Ngspice (v35+)](https://ngspice.sourceforge.io/) 44 | 45 | 46 | ## How to install? 47 | This module is made available with eSim (Electronic Circuit Simulation). 48 | Refer https://esim.fossee.in/ for more information. 49 | 50 | 51 | ## How to use the Examples provided with NGHDL? 52 | 1. Launch eSim --> Click on "NGHDL" icon from the left toolbar --> Click on "Browse" button --> Go to `nghdl/Example/` 53 | 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. 54 | 3. Click on "Upload" button in the NGHDL window. File will be processed in the backend for few seconds. Now exit the NGHDL window. 55 | 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. 56 | 5. Click on the "Simulation" button on eSim Main window. 57 | 58 | 59 | ## Contribution 60 | Please refer [here](https://github.com/FOSSEE/nghdl/blob/master/CONTRIBUTION.md) for further details. 61 | -------------------------------------------------------------------------------- /Workflow.md: -------------------------------------------------------------------------------- 1 | 1. When `nghdl` button clicked in `eSim` it calls the `ngspice_ghdl.py` from `nghdl` installed directory 2 | - `ngspice_ghdl.py` defines the UI for nghdl, and the functionality of each button 3 | - When `Upload` clicked, it calls `uploadModel` function from `ngspice_ghdl.py` 4 | - Similarly functions called on each button click defined 5 | - `uploadModel` inturn calls these 5 functions sequentially => 6 | - - createModelDirectory() 7 | - - addingModelInModpath() 8 | - - createModelFiles() 9 | - - runMake() 10 | - - runMakeInstall() 11 | 12 | 2. `createModelDirectory()` 13 | - Create directory for the specified file name at `~/nghdl-simulator/src/xspice/icm/ghdl/` 14 | - The location where the directory is created in mentioned at `~/.nghdl/config.ini`, this config file is inside a hidden folder `.ngdhl`, created when nghdl is installed 15 | - If a folder of the same name exists, it asks to overwrite, then removes earlier folder, and writes new one 16 | 17 | 3. `addingModelInModpath()` 18 | - This adds the name of the new model created to `modpath.lst` file 19 | - `modpath.lst` is located at `~/nghdl-simulator/src/xspice/icm/ghdl`, this should contain name of all the models that the folder has 20 | - Similarly you can look at `~/nghdl-simulator/src/xspice/icm/digital` which also contains a `modpath.list` for all the models in that folder 21 | - This `modpath.lst` is used in the `GNUMakefile` at `~/nghdl-simulator/release/src/xspice/icm` 22 | - This file used to keep a track of all components created 23 | - If model already there it isn't added to the list 24 | 25 | 4. `createModelFiles()` 26 | - Calls `model_generation.py` at the installed nghdl location under `src/model_generation.py` 27 | - Moves the generated `cfunc.mod` and `ifspec.ifs` files to `~/nghdl-simulator/src/xspice/icm/ghdl/modelName` 28 | - Creates `DUTghdl` folder at `~/nghdl-simulator/src/xspice/icm/ghdl/modelName` 29 | - Move `compile.sh`, `uthash.sh`, `ghdlserver.c`, `ghdlserver.h`, `Utility_Package.vhdl`, `Vhpi_Package.vhdl` to the `DUTghdl` folder 30 | - Copy `modelName.vhdl` file from source location to `DUTghdl` folder 31 | - Rum `compile.sh` which generates the object file for `ghdlserver.c` 32 | - Give permission to `start_server.sh` and `sock_pkg_create.sh` to execute _chod a+x_ 33 | - Finally remove `compile.sh` and `ghdlserver.c` 34 | 35 | 5. `model_generation.py` 36 | - Creates the following files => 37 | - - `connection_info.txt` 38 | - - `cfunc.mod` 39 | - - `ifspec.ifs` 40 | - - `modelName_tb.vhdl` => testbench file for the model 41 | - - `start_server.sh` 42 | - - `sock_pkg_create.sh` 43 | - The above files can be found either at `~/nghdl-simulator/src/xspice/icm/ghdl/modelName` or `DUTghdl` folder inside it 44 | 45 | 6. `runMake()` 46 | - Runs the `Makefile` at `~/nghdl-simulator/release` 47 | - Executing by running `make` command 48 | 49 | 7. `runMakeInstall()` 50 | - Executes `make install` 51 | - Finally calls `createSchematicLib()` 52 | 53 | 8. `createSchematicLib()` 54 | - Connects with `createKicadLibrary.py` file at `~/nghdl/src` 55 | - Generates the `lib` file for the model, to be used by `KiCad` 56 | - This is generated from a template stored at `Appconfig.py` 57 | - The generated `lib` is stored at `~/eSim_kicad.lib` 58 | - Also creates `xml` file for the model, which is stored at eSim under `eSimLoc/src/modelParamXML/Nghdl` 59 | 60 |
61 | 62 | Finally all the relevant files are generated, now while executing ngspice, we need to make sure to run the ngspice, which is located at - 63 | - `~/nghdl-simulator/install_dir/bin/ngspice` this has the binary for the ngspice, 64 | - And also the script at `~/nghdl-simulator/install_dir/share/ngspice/scripts/spinit` 65 | = ` spinit` has the line `codemodel ...` mentioning a `cm` file to execute at runtime 66 | - This has mention of `ghdl.cm` which makes sure that our `cfunc.c` file is executed at runtime 67 | - You can see the `ghdl.cm` file is located at `~/nghdl-simulator/release/src/xspice/icm/ghdl` 68 | - Also the `cfunc.c` files, located at `~/nghdl-simulator/release/src/xspice/icm/ghdl/modelName` 69 | - These have mention of the `start_server.sh` file at `DUTghdl`, hence server is started and values passed as well 70 | - Also you can look at `~/nghdl-simulator/release/src/xspice/icm/digital` it has `digital.cm` and the folders inside have `cfunc.c` 71 | - Also has `ifspec.c` which defines the interface 72 | 73 |
74 | 75 | - If you have ngspice currently installed remove it and genearate a softlink or command for the ngspice installed at - 76 | `~/nghdl-simulator/install_dir/bin/ngspice` 77 | - `whereis ngspice`, run this to get the location from where `ngspice` is being executed currently 78 |
79 | 80 | - To generate softlink refer - [Creating softlink](https://askubuntu.com/questions/56339/how-to-create-a-soft-or-symbolic-link)i 81 | - Exeecute `ln -s ~/nghdl-simulator/install_dir/bin/ngspice /usr/bin/ngspice` 82 | 83 | - Note that all the paths mentioned here are specific to a Linux machine. 84 | 85 |
86 | 87 | - Also the installation script doesn't install ghdl, you will have to do it manually, either through a `.deb` package or build it from [source](https://github.com/ghdl/ghdl) 88 | - Note that since we are using socket programming here, we require either the `llvm` architecture or `gcc`. Using `mcode` backend won't work here 89 | 90 |
91 | 92 | - To install ghdl from source, [this](https://github.com/ghdl/ghdl/issues/550) Github issue might be helpful, the steps are - 93 | - - `sudo ./configure --with-llvm-config` 94 | - - sudo make 95 | - - sudo make install 96 | - Check [this](https://github.com/ghdl/ghdl/issues/166) Github issue for those building from `.deb` package 97 | - To check current version and architecure of ghdl use - 98 | - - `ghdl --version` command, it should have `llvm` code generator or `gcc` 99 |
100 | 101 | - Also once ghdl is installed, to check syntax of your vhdl files use - 102 | `ghdl -s ` 103 | -------------------------------------------------------------------------------- /src/ghdlserver/Utility_Package.vhdl: -------------------------------------------------------------------------------- 1 | -- author: Madhav P. Desai 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | 5 | package Utility_Package is 6 | 7 | ----------------------------------------------------------------------------- 8 | -- constants 9 | ----------------------------------------------------------------------------- 10 | constant c_word_length : integer := 32; 11 | constant c_vhpi_max_string_length : integer := 1024; 12 | 13 | ----------------------------------------------------------------------------- 14 | -- types 15 | ----------------------------------------------------------------------------- 16 | subtype VhpiString is string(1 to c_vhpi_max_string_length); 17 | 18 | ----------------------------------------------------------------------------- 19 | -- utility functions 20 | ----------------------------------------------------------------------------- 21 | function Minimum(x,y: integer) return integer; -- returns minimum 22 | function Pack_String_To_Vhpi_String(x: string) return VhpiString; -- converts x to null terminated string 23 | function Pack_SLV_To_Vhpi_String(x: std_logic_vector) return VhpiString; -- converts slv x to null terminated string 24 | function Unpack_String(x: VhpiString; lgth: integer) return std_logic_vector; -- convert null term string to slv 25 | function To_Std_Logic(x: VhpiString) return std_logic; -- string to sl 26 | function To_String(x: std_logic) return VhpiString; -- string to sl 27 | function Convert_To_String(val : natural) return STRING; -- convert val to string. 28 | function Convert_SLV_To_String(val : std_logic_vector) return STRING; -- convert val to string. 29 | function To_Hex_Char (constant val: std_logic_vector) return character; 30 | function Convert_SLV_To_Hex_String(val : std_logic_vector) return STRING; -- convert val to string. 31 | 32 | end package Utility_Package; 33 | 34 | package body Utility_Package is 35 | 36 | ----------------------------------------------------------------------------- 37 | -- utility functions 38 | ----------------------------------------------------------------------------- 39 | function Minimum(x,y: integer) return integer is 40 | begin 41 | if( x < y) then return x; else return y; end if; 42 | end Minimum; 43 | 44 | function Ceiling(x,y: integer) return integer is 45 | variable ret_var : integer; 46 | begin 47 | assert x /= 0 report "divide by zero in ceiling function" severity failure; 48 | ret_var := x/y; 49 | if(ret_var*y < x) then ret_var := ret_var + 1; end if; 50 | return(ret_var); 51 | end Ceiling; 52 | 53 | function Pack_String_To_Vhpi_String(x: string) return VhpiString is 54 | alias lx: string(1 to x'length) is x; 55 | variable strlen: integer; 56 | variable ret_var : VhpiString; 57 | begin 58 | strlen := Minimum(c_vhpi_max_string_length-1,x'length); 59 | for I in 1 to strlen loop 60 | ret_var(I) := lx(I); 61 | end loop; 62 | ret_var(strlen+1) := nul; 63 | return(ret_var); 64 | end Pack_String_To_Vhpi_String; 65 | 66 | function Pack_SLV_To_Vhpi_String(x: std_logic_vector) return VhpiString is 67 | alias lx : std_logic_vector(1 to x'length) is x; 68 | variable strlen: integer; 69 | variable ret_var : VhpiString; 70 | begin 71 | strlen := Minimum(c_vhpi_max_string_length-1,x'length); 72 | for I in 1 to strlen loop 73 | if(lx(I) = '1') then 74 | ret_var(I) := '1'; 75 | else 76 | ret_var(I) := '0'; 77 | end if; 78 | end loop; 79 | ret_var(strlen+1) := nul; 80 | return(ret_var); 81 | end Pack_SLV_To_Vhpi_String; 82 | 83 | function Unpack_String(x: VhpiString; lgth: integer) return std_logic_vector is 84 | variable ret_var : std_logic_vector(1 to lgth); 85 | variable strlen: integer; 86 | begin 87 | strlen := Minimum(c_vhpi_max_string_length-1,lgth); 88 | for I in 1 to strlen loop 89 | if(x(I) = '1') then 90 | ret_var(I) := '1'; 91 | else 92 | ret_var(I) := '0'; 93 | end if; 94 | end loop; 95 | return(ret_var); 96 | end Unpack_String; 97 | 98 | function To_Std_Logic(x: VhpiString) return std_logic is 99 | variable s: std_logic_vector(0 downto 0); 100 | begin 101 | s := Unpack_String(x,1); 102 | return(s(0)); 103 | end To_Std_Logic; 104 | 105 | function To_String(x: std_logic) return VhpiString is 106 | variable s: std_logic_vector(0 downto 0); 107 | begin 108 | s(0) := x; 109 | return(Pack_SLV_To_Vhpi_String(s)); 110 | end To_String; 111 | 112 | -- Thanks to: D. Calvet calvet@hep.saclay.cea.fr 113 | function Convert_To_String(val : NATURAL) return STRING is 114 | variable result : STRING(10 downto 1) := (others => '0'); -- smallest natural, longest string 115 | variable pos : NATURAL := 1; 116 | variable tmp, digit : NATURAL; 117 | begin 118 | tmp := val; 119 | loop 120 | digit := abs(tmp MOD 10); 121 | tmp := tmp / 10; 122 | result(pos) := character'val(character'pos('0') + digit); 123 | pos := pos + 1; 124 | exit when tmp = 0; 125 | end loop; 126 | return result((pos-1) downto 1); 127 | end Convert_To_String; 128 | 129 | function Convert_SLV_To_String(val : std_logic_vector) return STRING is 130 | alias lval: std_logic_vector(1 to val'length) is val; 131 | variable ret_var: string( 1 to lval'length); 132 | begin 133 | for I in lval'range loop 134 | if(lval(I) = '1') then 135 | ret_var(I) := '1'; 136 | elsif (lval(I) = '0') then 137 | ret_var(I) := '0'; 138 | else 139 | ret_var(I) := 'X'; 140 | end if; 141 | end loop; 142 | return(ret_var); 143 | end Convert_SLV_To_String; 144 | 145 | function To_Hex_Char (constant val: std_logic_vector) return character is 146 | alias lval: std_logic_vector(1 to val'length) is val; 147 | variable tvar : std_logic_vector(1 to 4); 148 | variable ret_val : character; 149 | begin 150 | if(lval'length >= 4) then 151 | tvar := lval(1 to 4); 152 | else 153 | tvar := (others => '0'); 154 | tvar(1 to lval'length) := lval; 155 | end if; 156 | 157 | case tvar is 158 | when "0000" => ret_val := '0'; 159 | when "0001" => ret_val := '1'; 160 | when "0010" => ret_val := '2'; 161 | when "0011" => ret_val := '3'; 162 | when "0100" => ret_val := '4'; 163 | when "0101" => ret_val := '5'; 164 | when "0110" => ret_val := '6'; 165 | when "0111" => ret_val := '7'; 166 | when "1000" => ret_val := '8'; 167 | when "1001" => ret_val := '9'; 168 | when "1010" => ret_val := 'a'; 169 | when "1011" => ret_val := 'b'; 170 | when "1100" => ret_val := 'c'; 171 | when "1101" => ret_val := 'd'; 172 | when "1110" => ret_val := 'e'; 173 | when "1111" => ret_val := 'f'; 174 | when others => ret_val := 'f'; 175 | end case; 176 | 177 | return(ret_val); 178 | end To_Hex_Char; 179 | 180 | function Convert_SLV_To_Hex_String(val : std_logic_vector) return STRING is 181 | alias lval: std_logic_vector(val'length downto 1) is val; 182 | variable ret_var: string( 1 to Ceiling(lval'length,4)); 183 | variable hstr : std_logic_vector(4 downto 1); 184 | variable I : integer; 185 | begin 186 | 187 | I := 0; 188 | 189 | while I < (lval'length/4) loop 190 | hstr := lval(4*(I+1) downto (4*I)+1); 191 | ret_var(ret_var'length - I) := To_Hex_Char(hstr); 192 | I := (I + 1); 193 | end loop; -- I 194 | 195 | hstr := (others => '0'); 196 | if(ret_var'length > (lval'length/4)) then 197 | hstr((lval'length-((lval'length/4)*4)) downto 1) := lval(lval'length downto (4*(lval'length/4))+1); 198 | ret_var(1) := To_Hex_Char(hstr); 199 | end if; 200 | 201 | return(ret_var); 202 | end Convert_SLV_To_Hex_String; 203 | end Utility_Package; 204 | 205 | -------------------------------------------------------------------------------- /src/createKicadLibrary.py: -------------------------------------------------------------------------------- 1 | from Appconfig import Appconfig 2 | import re 3 | import os 4 | import xml.etree.cElementTree as ET 5 | from PyQt5 import QtWidgets 6 | 7 | 8 | class AutoSchematic(QtWidgets.QWidget): 9 | 10 | def __init__(self, parent, modelname): 11 | QtWidgets.QWidget.__init__(self) 12 | self.parent = parent 13 | self.modelname = modelname.split('.')[0] 14 | self.template = Appconfig.kicad_sym_template.copy() 15 | self.xml_loc = Appconfig.xml_loc 16 | self.lib_loc = Appconfig.lib_loc 17 | if os.name == 'nt': 18 | eSim_src = Appconfig.src_home 19 | inst_dir = eSim_src.replace('\\eSim', '') 20 | self.kicad_nghdl_sym = \ 21 | inst_dir + '/KiCad/share/kicad/symbols/eSim_Nghdl.kicad_sym' 22 | else: 23 | self.kicad_nghdl_sym = \ 24 | '/usr/share/kicad/symbols/eSim_Nghdl.kicad_sym' 25 | self.parser = Appconfig.parser_nghdl 26 | 27 | def createKicadSymbol(self): 28 | xmlFound = None 29 | for root, dirs, files in os.walk(self.xml_loc): 30 | if (str(self.modelname) + '.xml') in files: 31 | xmlFound = root 32 | print(xmlFound) 33 | if xmlFound is None: 34 | self.getPortInformation() 35 | self.createXML() 36 | self.createSym() 37 | elif (xmlFound == os.path.join(self.xml_loc, 'Nghdl')): 38 | print('Library already exists...') 39 | ret = QtWidgets.QMessageBox.warning( 40 | self.parent, "Warning", '''Library files for this model''' + 41 | ''' already exist. Do you want to overwrite it?
42 | If yes press ok, else cancel it and ''' + 43 | '''change the name of your vhdl file.''', 44 | QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel 45 | ) 46 | if ret == QtWidgets.QMessageBox.Ok: 47 | print("Overwriting existing libraries") 48 | self.getPortInformation() 49 | self.createXML() 50 | self.removeOldLibrary() # Removes the existng library 51 | self.createSym() 52 | else: 53 | print("Exiting Nghdl") 54 | quit() 55 | else: 56 | print('Pre existing library...') 57 | ret = QtWidgets.QMessageBox.critical( 58 | self.parent, "Error", '''A standard library already ''' + 59 | '''exists with this name.
Please change the ''' + 60 | '''name of your vhdl file and upload it again.''', 61 | QtWidgets.QMessageBox.Ok 62 | ) 63 | 64 | # quit() 65 | 66 | def getPortInformation(self): 67 | ''' 68 | getting the port information here 69 | ''' 70 | portInformation = PortInfo(self) 71 | portInformation.getPortInfo() 72 | self.portInfo = portInformation.bit_list 73 | self.input_length = portInformation.input_len 74 | 75 | def createXML(self): 76 | ''' 77 | creating the XML files in eSim /library/modelParamXML/Nghdl 78 | ''' 79 | cwd = os.getcwd() 80 | xmlDestination = os.path.join(self.xml_loc, 'Nghdl') 81 | self.splitText = "" 82 | for bit in self.portInfo[:-1]: 83 | self.splitText += bit + "-V:" 84 | self.splitText += self.portInfo[-1] + "-V" 85 | 86 | print("changing directory to ", xmlDestination) 87 | os.chdir(xmlDestination) 88 | 89 | root = ET.Element("model") 90 | ET.SubElement(root, "name").text = self.modelname 91 | ET.SubElement(root, "type").text = "Nghdl" 92 | ET.SubElement(root, "node_number").text = str(len(self.portInfo)) 93 | ET.SubElement(root, "title").text = ( 94 | "Add parameters for " + str(self.modelname)) 95 | ET.SubElement(root, "split").text = self.splitText 96 | param = ET.SubElement(root, "param") 97 | ET.SubElement(param, "rise_delay", default="1.0e-9").text = ( 98 | "Enter Rise Delay (default=1.0e-9)") 99 | ET.SubElement(param, "fall_delay", default="1.0e-9").text = ( 100 | "Enter Fall Delay (default=1.0e-9)") 101 | ET.SubElement(param, "input_load", default="1.0e-12").text = ( 102 | "Enter Input Load (default=1.0e-12)") 103 | ET.SubElement(param, "instance_id", default="1").text = ( 104 | "Enter Instance ID (Between 0-99)") 105 | tree = ET.ElementTree(root) 106 | tree.write(str(self.modelname) + '.xml') 107 | print("Leaving the directory ", xmlDestination) 108 | os.chdir(cwd) 109 | 110 | def findBlockSize(self): 111 | ''' 112 | Calculates the maximum between input and output ports 113 | ''' 114 | ind = self.input_length 115 | return max( 116 | self.char_sum(self.portInfo[:ind]), 117 | self.char_sum(self.portInfo[ind:]) 118 | ) 119 | 120 | def char_sum(self, ls): 121 | return sum([int(x) for x in ls]) 122 | 123 | def removeOldLibrary(self): 124 | ''' 125 | removing the old library 126 | ''' 127 | cwd = os.getcwd() 128 | os.chdir(self.lib_loc) 129 | print("Changing directory to ", self.lib_loc) 130 | sym_file = open(self.kicad_nghdl_sym) 131 | lines = sym_file.readlines() 132 | lines = lines[0:-2] 133 | sym_file.close() 134 | 135 | output = [] 136 | line_reading_flag = False 137 | 138 | for line in lines: 139 | if line.startswith("(symbol"): # Eeschema template start 140 | if line.split()[1] == f"\"{self.modelname}\"": 141 | line_reading_flag = True 142 | if not line_reading_flag: 143 | output.append(line) 144 | if line.startswith("))"): # Eeschema template end 145 | line_reading_flag = False 146 | 147 | sym_file = open(self.kicad_nghdl_sym, 'w') 148 | for line in output: 149 | sym_file.write(line) 150 | sym_file.close() 151 | os.chdir(cwd) 152 | print("Leaving directory, ", self.lib_loc) 153 | 154 | def createSym(self): 155 | self.dist_port = 2.54 # Distance between two ports (mil) 156 | self.inc_size = 2.54 # Increment size of a block (mil) 157 | cwd = os.getcwd() 158 | os.chdir(self.lib_loc) 159 | print("Changing directory to ", self.lib_loc) 160 | 161 | # Removing ")" from "eSim_Nghdl.kicad_sym" 162 | file = open(self.kicad_nghdl_sym, "r") 163 | content_file = file.read() 164 | new_content_file = content_file[:-2] 165 | file.close() 166 | file = open(self.kicad_nghdl_sym, "w") 167 | file.write(new_content_file) 168 | file.close() 169 | 170 | # Appending new schematic block 171 | sym_file = open(self.kicad_nghdl_sym, "a") 172 | line1 = self.template["start_def"] 173 | line1 = line1.split() 174 | line1 = [w.replace('comp_name', self.modelname) for w in line1] 175 | self.template["start_def"] = ' '.join(line1) 176 | 177 | if os.stat(self.kicad_nghdl_sym).st_size == 0: 178 | sym_file.write( 179 | "(kicad_symbol_lib (version 20211014) " + 180 | "(generator kicad_symbol_editor)" + "\n\n" 181 | ) # Eeschema starter code 182 | 183 | sym_file.write( 184 | self.template["start_def"] + "\n" + self.template["U_field"] + "\n" 185 | ) 186 | 187 | line3 = self.template["comp_name_field"] 188 | line3 = line3.split() 189 | line3 = [w.replace('comp_name', self.modelname) for w in line3] 190 | self.template["comp_name_field"] = ' '.join(line3) 191 | 192 | sym_file.write(self.template["comp_name_field"] + "\n") 193 | 194 | line4 = self.template["blank_field"] 195 | line4_1 = line4[0] 196 | line4_2 = line4[1] 197 | line4_1 = line4_1.split() 198 | line4_1 = [w.replace('blank_quotes', '""') for w in line4_1] 199 | line4_2 = line4_2.split() 200 | line4_2 = [w.replace('blank_quotes', '""') for w in line4_2] 201 | line4[0] = ' '.join(line4_1) 202 | line4[1] = ' '.join(line4_2) 203 | self.template["blank_qoutes"] = line4 204 | 205 | sym_file.write(line4[0] + "\n" + line4[1] + "\n") 206 | 207 | draw_pos = self.template["draw_pos"] 208 | draw_pos = draw_pos.split() 209 | 210 | draw_pos = \ 211 | [w.replace('comp_name', f"{self.modelname}_0_1") for w in draw_pos] 212 | draw_pos[8] = str( 213 | float(draw_pos[8]) + float(self.findBlockSize() * self.inc_size) 214 | ) 215 | draw_pos_rec = draw_pos[8] 216 | 217 | self.template["draw_pos"] = ' '.join(draw_pos) 218 | 219 | sym_file.write( 220 | self.template["draw_pos"] + "\n" + self.template["start_draw"] + 221 | " \"" + f"{self.modelname}_1_1\"" + "\n" 222 | ) 223 | 224 | input_port = self.template["input_port"] 225 | input_port = input_port.split() 226 | output_port = self.template["output_port"] 227 | output_port = output_port.split() 228 | inputs = self.portInfo[0: self.input_length] 229 | outputs = self.portInfo[self.input_length:] 230 | 231 | inputs = self.char_sum(inputs) 232 | outputs = self.char_sum(outputs) 233 | 234 | total = inputs + outputs 235 | 236 | port_list = [] 237 | 238 | # Set input & output port 239 | input_port[4] = draw_pos_rec 240 | output_port[4] = draw_pos_rec 241 | 242 | for i in range(total): 243 | if (i < inputs): 244 | input_port[9] = f"\"in{str(i + 1)}\"" 245 | input_port[13] = f"\"{str(i + 1)}\"" 246 | input_port[4] = \ 247 | str(float(input_port[4]) - float(self.dist_port)) 248 | input_list = ' '.join(input_port) 249 | port_list.append(input_list) 250 | 251 | else: 252 | output_port[9] = f"\"out{str(i - inputs + 1)}\"" 253 | output_port[13] = f"\"{str(i + 1)}\"" 254 | output_port[4] = \ 255 | str(float(output_port[4]) - float(self.dist_port)) 256 | output_list = ' '.join(output_port) 257 | port_list.append(output_list) 258 | 259 | for ports in port_list: 260 | sym_file.write(ports + "\n") 261 | sym_file.write( 262 | self.template["end_draw"] + "\n\n" + ")" 263 | ) 264 | sym_file.close() 265 | os.chdir(cwd) 266 | 267 | print('Leaving directory, ', self.lib_loc) 268 | QtWidgets.QMessageBox.information( 269 | self.parent, "Symbol Added", 270 | '''Symbol details for this model is added to the \'''' + 271 | '''eSim_Nghdl.kicad_sym\' in the KiCad shared directory.''', 272 | QtWidgets.QMessageBox.Ok 273 | ) 274 | 275 | 276 | class PortInfo: 277 | ''' 278 | The class contains port information 279 | ''' 280 | def __init__(self, model): 281 | self.modelname = model.modelname 282 | self.model_loc = os.path.join( 283 | model.parser.get('NGHDL', 'DIGITAL_MODEL'), 'ghdl' 284 | ) 285 | self.bit_list = [] 286 | self.input_len = 0 287 | 288 | def getPortInfo(self): 289 | info_loc = os.path.join(self.model_loc, self.modelname + '/DUTghdl/') 290 | input_list = [] 291 | output_list = [] 292 | read_file = open(info_loc + 'connection_info.txt', 'r') 293 | data = read_file.readlines() 294 | read_file.close() 295 | 296 | for line in data: 297 | if re.match(r'^\s*$', line): 298 | pass 299 | else: 300 | in_items = re.findall( 301 | "IN", line, re.MULTILINE | re.IGNORECASE 302 | ) 303 | out_items = re.findall( 304 | "OUT", line, re.MULTILINE | re.IGNORECASE 305 | ) 306 | if in_items: 307 | input_list.append(line.split()) 308 | if out_items: 309 | output_list.append(line.split()) 310 | 311 | for in_list in input_list: 312 | self.bit_list.append(in_list[2]) 313 | self.input_len = len(self.bit_list) 314 | for out_list in output_list: 315 | self.bit_list.append(out_list[2]) 316 | -------------------------------------------------------------------------------- /src/ghdlserver/ghdlserver.c: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | * eSim Team, FOSSEE, IIT-Bombay 3 | ************************************************************************************ 4 | * 8.June.2020 - Bladen Martin - Added OS (Windows and Linux) dependent 5 | * - Rahul Paknikar preprocessors for ease of maintenance 6 | * 7 | * 28.May.2020 - Bladen Martin - Termination of testbench: Replaced Process ID 8 | * - Rahul Paknikar mechanism with socket connection from client 9 | * receiving the special close message 10 | ************************************************************************************ 11 | ************************************************************************************ 12 | * 08.Nov.2019 - Rahul Paknikar - Switched to blocking sockets from non-blocking 13 | * - Close previous used socket to prevent from 14 | * generating too many socket descriptors 15 | * - Enabled SO_REUSEPORT, SO_DONTROUTE socket options 16 | * 5.July.2019 - Rahul Paknikar - Added loop to send all port values for 17 | * a given event. 18 | ************************************************************************************ 19 | ************************************************************************************ 20 | * 24.Mar.2017 - Raj Mohan - Added syslog interface for logging. 21 | * - Enabled SO_REUSEADDR socket option. 22 | * 22.Feb.2017 - Raj Mohan - Implemented a kludge to fix a problem in the 23 | * test bench VHDL code. 24 | * - Changed sleep() to nanosleep(). 25 | * 10.Feb.2017 - Raj Mohan - Log messages with timestamp/code clean up. 26 | * Added the following functions: 27 | * o curtim() 28 | * o print_hash_table() 29 | ***********************************************************************************/ 30 | 31 | #include 32 | #include "ghdlserver.h" 33 | #include "uthash.h" 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #ifdef __linux__ 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #elif _WIN32 53 | #include 54 | #include 55 | #include 56 | #include 57 | #endif 58 | 59 | #define _XOPEN_SOURCE 500 60 | #define MAX_NUMBER_PORT 100 61 | #define NGSPICE "ngspice" // 17.Mar.2017 - RM 62 | 63 | static FILE *pid_file; 64 | static char pid_filename[80]; 65 | static char *Out_Port_Array[MAX_NUMBER_PORT]; 66 | static int out_port_num = 0; 67 | static int server_socket_id = -1; 68 | static int sendto_sock; // 22.Feb.2017 - RM - Kludge 69 | static int prev_sendto_sock; // 22.Feb.2017 - RM - Kludge 70 | static int pid_file_created; // 10.Mar.2017 - RM 71 | 72 | #ifdef __linux__ 73 | extern char* __progname; // 26.Feb.2017 May not be portable to non-GNU systems. 74 | #endif 75 | 76 | void Vhpi_Exit(int sig); 77 | 78 | struct my_struct { 79 | char val[1024]; 80 | char key[1024]; 81 | UT_hash_handle hh; //Makes this structure hashable. 82 | }; 83 | 84 | static struct my_struct *s, *users, *tmp = NULL; 85 | 86 | 87 | #ifdef DEBUG 88 | static char* curtim(void) 89 | { 90 | static char ct[50]; 91 | struct timeval tv; 92 | struct tm *ptm; 93 | long milliseconds; 94 | char time_string[40]; 95 | 96 | gettimeofday (&tv, NULL); 97 | ptm = localtime (&tv.tv_sec); 98 | strftime (time_string, sizeof (time_string), "%Y-%m-%d %H:%M:%S", ptm); 99 | milliseconds = tv.tv_usec / 1000; 100 | sprintf (ct, "%s.%03ld", time_string, milliseconds); 101 | return(ct); 102 | } 103 | #endif 104 | 105 | 106 | #ifdef DEBUG 107 | static void print_hash_table(void) 108 | { 109 | struct my_struct *sptr; 110 | 111 | #ifdef __linux__ 112 | for(sptr = users; sptr != NULL; sptr = sptr->hh.next) 113 | syslog(LOG_INFO, "Hash table:val:%s: key: %s", sptr->val, sptr->key); 114 | #endif 115 | } 116 | #endif 117 | 118 | 119 | static void parse_buffer(int sock_id, char *receive_buffer) 120 | { 121 | static int rcvnum; 122 | 123 | #ifdef __linux__ 124 | syslog(LOG_INFO, "RCVD RCVN:%d from CLT:%d buffer : %s", 125 | rcvnum++, sock_id, receive_buffer); 126 | #endif 127 | 128 | /*Parsing buffer to store in hash table */ 129 | char *rest; 130 | char *token; 131 | char *ptr1 = receive_buffer; 132 | char *var; 133 | char *value; 134 | 135 | // Processing tokens. 136 | while (token = strtok_r(ptr1, ",", &rest)) 137 | { 138 | ptr1 = rest; 139 | while (var = strtok_r(token, ":", &value)) 140 | { 141 | s = (struct my_struct *) malloc(sizeof(struct my_struct)); 142 | strncpy(s->key, var, 64); 143 | strncpy(s->val, value, 64); 144 | HASH_ADD_STR(users, key, s); 145 | break; 146 | } 147 | } 148 | 149 | s = (struct my_struct *) malloc(sizeof(struct my_struct)); 150 | strncpy(s->key, "sock_id", 64); 151 | snprintf(s->val, 64, "%d", sock_id); 152 | HASH_ADD_STR(users, key, s); 153 | } 154 | 155 | 156 | //Create Server and listen for client connections. 157 | // 26.Sept.2019 - RP - added parameter of socket ip 158 | static int create_server(int port_number, char my_ip[], int max_connections) 159 | { 160 | int sockfd, reuse = 1; 161 | struct sockaddr_in serv_addr; 162 | 163 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 164 | 165 | if (sockfd < 0) 166 | { 167 | #ifdef __linux__ 168 | fprintf(stderr, "%s- Error: in opening socket at server \n", __progname); 169 | 170 | #elif _WIN32 171 | fprintf(stderr, "Error: in opening socket at server \n"); 172 | 173 | #endif 174 | 175 | //exit(1); 176 | return -1; 177 | } 178 | 179 | /* 18.May.2020 - BM - typecast optval field to char* */ 180 | /* 20.Mar.2017 - RM - SO_REUSEADDR option. To take care of TIME_WAIT state.*/ 181 | int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(int)); 182 | 183 | /* 08.Nov.2019 - RP - SO_REUSEPORT and SO_DONTROUTE option.*/ 184 | /* 08.June.2020 - BM - SO_REUSEPORT only available in Linux */ 185 | #ifdef __linux__ 186 | ret += setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int)); 187 | #endif 188 | 189 | ret += setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, (char *) &reuse, sizeof(int)); 190 | if (ret < 0) 191 | { 192 | #ifdef __linux__ 193 | syslog(LOG_ERR, "create_server:setsockopt() failed...."); 194 | #endif 195 | // close(sockfd); 196 | // return -1; 197 | } 198 | 199 | memset(&serv_addr, 0, sizeof(serv_addr)); 200 | serv_addr.sin_family = AF_INET; 201 | serv_addr.sin_addr.s_addr = inet_addr(my_ip); // 26.Sept.2019 - RP - Bind to specific IP only 202 | serv_addr.sin_port = htons(port_number); 203 | 204 | if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 205 | { 206 | #ifdef __linux__ 207 | fprintf(stderr, "%s- Error: could not bind socket to port %d\n", __progname, port_number); 208 | syslog(LOG_ERR, "Error: could not bind socket to port %d", port_number); 209 | close(sockfd); 210 | 211 | #elif _WIN32 212 | fprintf(stderr, "Error: could not bind socket to port %d\n", port_number); 213 | closesocket(sockfd); 214 | 215 | #endif 216 | 217 | exit(1); 218 | } 219 | 220 | // Start listening on the server. 221 | listen(sockfd, max_connections); 222 | 223 | return sockfd; 224 | } 225 | 226 | 227 | // The server to wait (blocking) for a client connection. 228 | static int connect_to_client(int server_fd) 229 | { 230 | int ret_val = 0; 231 | int newsockfd = -1; 232 | socklen_t clilen; 233 | struct sockaddr_in cli_addr; 234 | 235 | clilen = sizeof(cli_addr); 236 | 237 | /* 08.Nov.2019 - RP - Blocking Socket (Accept) */ 238 | newsockfd = accept(server_fd, (struct sockaddr *) &cli_addr, &clilen); 239 | if (newsockfd >= 0) 240 | { 241 | #ifdef _linux_ 242 | syslog(LOG_INFO, "SRV:%d New Client Connection CLT:%d", server_fd, newsockfd); 243 | #endif 244 | } 245 | else 246 | { 247 | #ifdef __linux__ 248 | syslog(LOG_ERR, "Error: failed in accept(), socket=%d", server_fd); 249 | #endif 250 | 251 | exit(1); 252 | } 253 | 254 | return newsockfd; 255 | } 256 | 257 | 258 | //Receive string from socket and put it inside buffer. 259 | static void receive_string(int sock_id, char *buffer) 260 | { 261 | int nbytes = 0; 262 | 263 | /* 08.Nov.2019 - RP - Blocking Socket - Receive */ 264 | nbytes = recv(sock_id, buffer, MAX_BUF_SIZE, 0); 265 | if (nbytes <= 0) 266 | { 267 | perror("receive_string() - READ FAILURE "); 268 | exit(1); 269 | } 270 | 271 | // 28.May.2020 - BM - Added method to close server by Ngspice after simulation 272 | char *exitstr = "CLOSE_FROM_NGSPICE"; 273 | if (strcmp(buffer, exitstr) == 0) 274 | { 275 | Vhpi_Exit(0); 276 | } 277 | } 278 | 279 | 280 | static void Data_Send(int sockid) 281 | { 282 | static int trnum; 283 | char *out; 284 | 285 | int i; 286 | char colon = ':'; 287 | char semicolon = ';'; 288 | int wrt_retries = 0; 289 | int ret; 290 | 291 | s = NULL; 292 | 293 | out = calloc(1, 2048); 294 | 295 | // 5.July.2019 - RP - loop to send all ports at once for an event 296 | for (i = 0; i < out_port_num; i++) 297 | { 298 | HASH_FIND_STR(users, Out_Port_Array[i], s); 299 | if (strcmp(Out_Port_Array[i], s->key) == 0) 300 | { 301 | strncat(out, s->key, strlen(s->key)); 302 | strncat(out, &colon, 1); 303 | strncat(out, s->val, strlen(s->val)); 304 | strncat(out, &semicolon, 1); 305 | } 306 | else 307 | { 308 | #ifdef __linux__ 309 | syslog(LOG_ERR,"The %s's value not found in the table.", 310 | Out_Port_Array[i]); 311 | #endif 312 | 313 | free(out); 314 | printf("Error! The %s's value not found in the table. Exiting simulation...", 315 | Out_Port_Array[i]); 316 | return; 317 | } 318 | } 319 | 320 | /* 08.Nov.2019 - RP - Blocking Socket (Send) */ 321 | if ((send(sockid, out, strlen(out), 0)) == -1) 322 | { 323 | #ifdef __linux__ 324 | syslog(LOG_ERR, "Failure sending to CLT:%d buffer:%s", sockid, out); 325 | #endif 326 | 327 | exit(1); 328 | } 329 | 330 | #ifdef __linux__ 331 | syslog(LOG_INFO, "SNT:TRNUM:%d to CLT:%d buffer: %s", trnum++, sockid, out); 332 | #endif 333 | 334 | free(out); 335 | } 336 | 337 | 338 | // 26.Sept.2019 - RP - added parameter of socket ip 339 | void Vhpi_Initialize(int sock_port, char sock_ip[]) 340 | { 341 | DEFAULT_SERVER_PORT = sock_port; 342 | 343 | signal(SIGINT, Vhpi_Exit); 344 | signal(SIGTERM, Vhpi_Exit); 345 | 346 | #ifdef _WIN32 347 | WSADATA WSAData; 348 | WSAStartup(MAKEWORD(2, 2), &WSAData); 349 | #endif 350 | 351 | int try_limit = 100; 352 | 353 | while (try_limit > 0) 354 | { 355 | // 26.Sept.2019 - RP 356 | server_socket_id = create_server(DEFAULT_SERVER_PORT, sock_ip, DEFAULT_MAX_CONNECTIONS); 357 | 358 | if (server_socket_id >= 0) 359 | { 360 | #ifdef __linux__ 361 | syslog(LOG_INFO, "Started the server on port %d SRV:%d", 362 | DEFAULT_SERVER_PORT, server_socket_id); 363 | #endif 364 | 365 | break; 366 | } 367 | 368 | #ifdef __linux__ 369 | syslog(LOG_ERR, "Could not start server on port %d,will try again", 370 | DEFAULT_SERVER_PORT); 371 | #endif 372 | 373 | usleep(1000); 374 | try_limit--; 375 | 376 | if (try_limit == 0) 377 | { 378 | #ifdef __linux__ 379 | syslog(LOG_ERR, 380 | "Error:Tried to start server on port %d, failed..giving up.", 381 | DEFAULT_SERVER_PORT); 382 | #endif 383 | 384 | exit(1); 385 | } 386 | } 387 | 388 | //Reading Output Port name and storing in Out_Port_Array; 389 | char *line = NULL; 390 | size_t len = 0; 391 | ssize_t read; 392 | char *token; 393 | FILE *fp; 394 | struct timespec ts; 395 | 396 | fp = fopen("connection_info.txt", "r"); 397 | if (!fp) 398 | { 399 | #ifdef __linux__ 400 | syslog(LOG_ERR,"Vhpi_Initialize: Failed to open connection_info.txt. Exiting..."); 401 | #endif 402 | 403 | exit(1); 404 | } 405 | 406 | line = (char *) malloc(80); 407 | 408 | #ifdef __linux__ 409 | while ((read = getline(&line, &len, fp)) != -1) 410 | { 411 | if (strstr(line, "OUT") != NULL || strstr(line, "out") != NULL) 412 | { 413 | strtok_r(line, " ", &token); 414 | Out_Port_Array[out_port_num] = line; 415 | out_port_num++; 416 | } 417 | line = (char *) malloc(80); 418 | } 419 | 420 | #elif _WIN32 421 | while (fgets(line, sizeof(line), fp) != NULL) 422 | { 423 | if (strstr(line, "OUT") != NULL || strstr(line, "out") != NULL) 424 | { 425 | strtok_r(line, " ", &token); 426 | Out_Port_Array[out_port_num] = line; 427 | out_port_num++; 428 | } 429 | line = (char *) malloc(80); 430 | } 431 | 432 | #endif 433 | 434 | fclose(fp); 435 | free(line); 436 | 437 | ts.tv_sec = 2; 438 | ts.tv_nsec = 0; 439 | nanosleep(&ts, NULL); 440 | } 441 | 442 | 443 | void Vhpi_Set_Port_Value(char *port_name, char *port_value, int port_width) 444 | { 445 | s = (struct my_struct *) malloc(sizeof(struct my_struct)); 446 | strncpy(s->key, port_name, 64); 447 | strncpy(s->val, port_value, 64); 448 | HASH_ADD_STR(users, key, s); 449 | } 450 | 451 | 452 | void Vhpi_Get_Port_Value(char *port_name, char *port_value, int port_width) 453 | { 454 | HASH_FIND_STR(users, port_name, s); 455 | if (s) 456 | { 457 | snprintf(port_value, sizeof(port_value), "%s", s->val); 458 | HASH_DEL(users, s); 459 | free(s); 460 | s = NULL; 461 | } 462 | } 463 | 464 | 465 | void Vhpi_Listen() 466 | { 467 | sendto_sock = connect_to_client(server_socket_id); // 22.Feb.2017 - RM - Kludge 468 | char receive_buffer[MAX_BUF_SIZE]; 469 | receive_string(sendto_sock, receive_buffer); 470 | 471 | #ifdef __linux__ 472 | syslog(LOG_INFO, "Vhpi_Listen:New socket connection CLT:%d", sendto_sock); 473 | #endif 474 | 475 | if (strcmp(receive_buffer, "END") == 0) 476 | { 477 | #ifdef __linux__ 478 | syslog(LOG_INFO, "RCVD:CLOSE REQUEST from CLT:%d", sendto_sock); 479 | #endif 480 | 481 | Vhpi_Exit(0); 482 | } 483 | 484 | parse_buffer(sendto_sock, receive_buffer); 485 | } 486 | 487 | 488 | void Vhpi_Send() 489 | { 490 | // 22.Feb.2017 - RM - Kludge 491 | if (prev_sendto_sock != sendto_sock) 492 | { 493 | Data_Send(sendto_sock); 494 | 495 | #ifdef __linux__ 496 | close(prev_sendto_sock); // 08.Nov.2019 - RP - Close previous socket 497 | 498 | #elif _WIN32 499 | closesocket(prev_sendto_sock); 500 | 501 | #endif 502 | 503 | prev_sendto_sock = sendto_sock; 504 | } 505 | // 22.Feb.2017 End kludge 506 | } 507 | 508 | 509 | void Vhpi_Exit(int sig) 510 | { 511 | #ifdef __linux__ 512 | close(server_socket_id); 513 | syslog(LOG_INFO, "*** Closed VHPI link. Exiting... ***"); 514 | 515 | #elif _WIN32 516 | closesocket(server_socket_id); 517 | 518 | #endif 519 | 520 | exit(0); 521 | } -------------------------------------------------------------------------------- /src/ngspice_ghdl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # This file create the GUI to install code model in the Ngspice. 4 | 5 | import os 6 | import sys 7 | import shutil 8 | import subprocess 9 | from PyQt5 import QtGui, QtCore, QtWidgets 10 | from configparser import ConfigParser 11 | from Appconfig import Appconfig 12 | from createKicadLibrary import AutoSchematic 13 | from model_generation import ModelGeneration 14 | 15 | 16 | class Mainwindow(QtWidgets.QWidget): 17 | 18 | def __init__(self): 19 | # super(Mainwindow, self).__init__() 20 | QtWidgets.QMainWindow.__init__(self) 21 | print("Initializing..........") 22 | 23 | if os.name == 'nt': 24 | self.home = os.path.join('library', 'config') 25 | else: 26 | self.home = os.path.expanduser('~') 27 | 28 | # Reading all variables from config.ini 29 | self.parser = ConfigParser() 30 | self.parser.read( 31 | os.path.join(self.home, os.path.join('.nghdl', 'config.ini')) 32 | ) 33 | self.nghdl_home = self.parser.get('NGHDL', 'NGHDL_HOME') 34 | self.release_dir = self.parser.get('NGHDL', 'RELEASE') 35 | self.src_home = self.parser.get('SRC', 'SRC_HOME') 36 | self.licensefile = self.parser.get('SRC', 'LICENSE') 37 | # Printing LICENCE file on terminal 38 | fileopen = open(self.licensefile, 'r') 39 | print(fileopen.read()) 40 | fileopen.close() 41 | self.file_list = [] # to keep the supporting files 42 | self.errorFlag = False # to keep the check of "make install" errors 43 | self.initUI() 44 | 45 | def initUI(self): 46 | self.uploadbtn = QtWidgets.QPushButton('Upload') 47 | self.uploadbtn.clicked.connect(self.uploadModel) 48 | self.exitbtn = QtWidgets.QPushButton('Exit') 49 | self.exitbtn.clicked.connect(self.closeWindow) 50 | self.browsebtn = QtWidgets.QPushButton('Browse') 51 | self.browsebtn.clicked.connect(self.browseFile) 52 | self.addbtn = QtWidgets.QPushButton('Add Files') 53 | self.addbtn.clicked.connect(self.addFiles) 54 | self.removebtn = QtWidgets.QPushButton('Remove Files') 55 | self.removebtn.clicked.connect(self.removeFiles) 56 | self.ledit = QtWidgets.QLineEdit(self) 57 | self.sedit = QtWidgets.QTextEdit(self) 58 | self.process = QtCore.QProcess(self) 59 | self.termedit = QtWidgets.QTextEdit(self) 60 | self.termedit.setReadOnly(1) 61 | pal = QtGui.QPalette() 62 | bgc = QtGui.QColor(0, 0, 0) 63 | pal.setColor(QtGui.QPalette.Base, bgc) 64 | self.termedit.setPalette(pal) 65 | self.termedit.setStyleSheet("QTextEdit {color:white}") 66 | 67 | # Creating gridlayout 68 | grid = QtWidgets.QGridLayout() 69 | grid.setSpacing(5) 70 | grid.addWidget(self.ledit, 1, 0) 71 | grid.addWidget(self.browsebtn, 1, 1) 72 | grid.addWidget(self.sedit, 2, 0, 4, 1) 73 | grid.addWidget(self.addbtn, 2, 1) 74 | grid.addWidget(self.removebtn, 3, 1) 75 | grid.addWidget(self.termedit, 6, 0, 10, 1) 76 | grid.addWidget(self.uploadbtn, 17, 0) 77 | grid.addWidget(self.exitbtn, 17, 1) 78 | 79 | self.setLayout(grid) 80 | self.setGeometry(300, 300, 600, 600) 81 | self.setWindowTitle("Ngspice Digital Model Creator (from VHDL)") 82 | # self.setWindowIcon(QtGui.QIcon('logo.png')) 83 | self.show() 84 | 85 | def closeWindow(self): 86 | try: 87 | self.process.close() 88 | except BaseException: 89 | pass 90 | print("Close button clicked") 91 | sys.exit() 92 | 93 | def browseFile(self): 94 | print("Browse button clicked") 95 | self.filename = QtWidgets.QFileDialog.getOpenFileName( 96 | self, 'Open File', '.')[0] 97 | self.ledit.setText(self.filename) 98 | print("Vhdl file uploaded to process :", self.filename) 99 | 100 | def addFiles(self): 101 | print("Starts adding supporting files") 102 | title = self.addbtn.text() 103 | for file in QtWidgets.QFileDialog.getOpenFileNames(self, title)[0]: 104 | self.sedit.append(str(file)) 105 | self.file_list.append(file) 106 | print("Supporting Files are :", self.file_list) 107 | 108 | def removeFiles(self): 109 | self.fileRemover = FileRemover(self) 110 | 111 | # Check extensions of all supporting files 112 | def checkSupportFiles(self): 113 | nonvhdl_count = 0 114 | for file in self.file_list: 115 | extension = os.path.splitext(str(file))[1] 116 | if extension != ".vhdl": 117 | nonvhdl_count += 1 118 | self.file_list.remove(file) 119 | 120 | if nonvhdl_count > 0: 121 | QtWidgets.QMessageBox.critical( 122 | self, 'Critical', '''Important Message. 123 |

Supporting files should be .vhdl file ''' 124 | ) 125 | 126 | def createModelDirectory(self): 127 | print("Create Model Directory Called") 128 | self.digital_home = self.parser.get('NGHDL', 'DIGITAL_MODEL') 129 | self.digital_home = os.path.join(self.digital_home, "ghdl") 130 | os.chdir(self.digital_home) 131 | print("Current Working Directory Changed to", os.getcwd()) 132 | self.modelname = os.path.basename(str(self.filename)).split('.')[0] 133 | print("Model to be created :", self.modelname) 134 | # Looking if model directory is present or not 135 | if os.path.isdir(self.modelname): 136 | print("Model Already present") 137 | ret = QtWidgets.QMessageBox.warning( 138 | self, "Warning", 139 | "This model already exist. Do you want to " + 140 | "overwrite it?
If yes press ok, else cancel it and " + 141 | "change the name of your vhdl file.", 142 | QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel 143 | ) 144 | if ret == QtWidgets.QMessageBox.Ok: 145 | print("Overwriting existing model " + self.modelname) 146 | if os.name == 'nt': 147 | cmd = "rmdir " + self.modelname + "/s /q" 148 | else: 149 | cmd = "rm -rf " + self.modelname 150 | # process = subprocess.Popen( 151 | # cmd, stdout=subprocess.PIPE, 152 | # stderr=subprocess.PIPE, shell=True 153 | # ) 154 | subprocess.call(cmd, shell=True) 155 | os.mkdir(self.modelname) 156 | else: 157 | print("Exiting application") 158 | sys.exit() 159 | else: 160 | print("Creating model " + self.modelname + " directory") 161 | os.mkdir(self.modelname) 162 | 163 | def addingModelInModpath(self): 164 | print("Adding Model " + self.modelname + 165 | " in Modpath file " + self.digital_home) 166 | # Adding name of model in the modpath file 167 | # Check if the string is already in the file 168 | with open(self.digital_home + "/modpath.lst", 'r+') as f: 169 | flag = 0 170 | for line in f: 171 | if line.strip() == self.modelname: 172 | print("Found model "+self.modelname+" in the modpath.lst") 173 | flag = 1 174 | break 175 | 176 | if flag == 0: 177 | print("Adding model name "+self.modelname+" into modpath.lst") 178 | f.write(self.modelname + "\n") 179 | else: 180 | print("Model name is already into modpath.lst") 181 | 182 | def createModelFiles(self): 183 | print("Create Model Files Called") 184 | os.chdir(self.cur_dir) 185 | print("Current Working directory changed to " + self.cur_dir) 186 | 187 | # Generate model corresponding to the uploaded VHDL file 188 | model = ModelGeneration(str(self.ledit.text())) 189 | model.readPortInfo() 190 | model.createCfuncModFile() 191 | model.createIfSpecFile() 192 | model.createTestbench() 193 | model.createServerScript() 194 | model.createSockScript() 195 | 196 | # Moving file to model directory 197 | path = os.path.join(self.digital_home, self.modelname) 198 | shutil.move("cfunc.mod", path) 199 | shutil.move("ifspec.ifs", path) 200 | 201 | # Creating directory inside model directoy 202 | print("Creating DUT directory at " + os.path.join(path, "DUTghdl")) 203 | os.mkdir(path + "/DUTghdl/") 204 | print("Copying required file to DUTghdl directory") 205 | shutil.move("connection_info.txt", path + "/DUTghdl/") 206 | shutil.move("start_server.sh", path + "/DUTghdl/") 207 | shutil.move("sock_pkg_create.sh", path + "/DUTghdl/") 208 | shutil.move(self.modelname + "_tb.vhdl", path + "/DUTghdl/") 209 | 210 | shutil.copy(str(self.filename), path + "/DUTghdl/") 211 | shutil.copy(os.path.join(self.home, self.src_home) + 212 | "/src/ghdlserver/compile.sh", path + "/DUTghdl/") 213 | shutil.copy(os.path.join(self.home, self.src_home) + 214 | "/src/ghdlserver/uthash.h", path + "/DUTghdl/") 215 | shutil.copy(os.path.join(self.home, self.src_home) + 216 | "/src/ghdlserver/ghdlserver.c", path + "/DUTghdl/") 217 | shutil.copy(os.path.join(self.home, self.src_home) + 218 | "/src/ghdlserver/ghdlserver.h", path + "/DUTghdl/") 219 | shutil.copy(os.path.join(self.home, self.src_home) + 220 | "/src/ghdlserver/Utility_Package.vhdl", path + "/DUTghdl/") 221 | shutil.copy(os.path.join(self.home, self.src_home) + 222 | "/src/ghdlserver/Vhpi_Package.vhdl", path + "/DUTghdl/") 223 | 224 | if os.name == 'nt': 225 | shutil.copy(os.path.join(self.home, self.src_home) + 226 | "/src/ghdlserver/libws2_32.a", path + "/DUTghdl/") 227 | 228 | for file in self.file_list: 229 | shutil.copy(str(file), path + "/DUTghdl/") 230 | 231 | os.chdir(path + "/DUTghdl") 232 | if os.name == 'nt': 233 | # path to msys bin directory where bash is located 234 | self.msys_home = self.parser.get('COMPILER', 'MSYS_HOME') 235 | subprocess.call(self.msys_home + "/usr/bin/bash.exe " + 236 | path + "/DUTghdl/compile.sh", shell=True) 237 | subprocess.call(self.msys_home + "/usr/bin/bash.exe -c " + 238 | "'chmod a+x start_server.sh'", shell=True) 239 | subprocess.call(self.msys_home + "/usr/bin/bash.exe -c " + 240 | "'chmod a+x sock_pkg_create.sh'", shell=True) 241 | else: 242 | subprocess.call("bash " + path + "/DUTghdl/compile.sh", shell=True) 243 | subprocess.call("chmod a+x start_server.sh", shell=True) 244 | subprocess.call("chmod a+x sock_pkg_create.sh", shell=True) 245 | 246 | os.remove("compile.sh") 247 | os.remove("ghdlserver.c") 248 | 249 | # Slot to redirect stdout and stderr to window console 250 | @QtCore.pyqtSlot() 251 | def readAllStandard(self): 252 | self.termedit.append( 253 | str(self.process.readAllStandardOutput().data(), encoding='utf-8') 254 | ) 255 | stderror = self.process.readAllStandardError() 256 | if stderror.toUpper().contains(b"ERROR"): 257 | self.errorFlag = True 258 | self.termedit.append(str(stderror.data(), encoding='utf-8')) 259 | 260 | def runMake(self): 261 | print("run Make Called") 262 | self.release_home = self.parser.get('NGHDL', 'RELEASE') 263 | path_icm = os.path.join(self.release_home, "src/xspice/icm") 264 | os.chdir(path_icm) 265 | 266 | try: 267 | if os.name == 'nt': 268 | # path to msys bin directory where make is located 269 | self.msys_home = self.parser.get('COMPILER', 'MSYS_HOME') 270 | cmd = self.msys_home + "/mingw64/bin/mingw32-make.exe" 271 | else: 272 | cmd = " make" 273 | 274 | print("Running Make command in " + path_icm) 275 | path = os.getcwd() # noqa 276 | self.process = QtCore.QProcess(self) 277 | self.process.start(cmd) 278 | print("make command process pid ---------- >", self.process.pid()) 279 | 280 | if os.name == "nt": 281 | self.process.finished.connect(self.createSchematicLib) 282 | self.process \ 283 | .readyReadStandardOutput.connect(self.readAllStandard) 284 | 285 | except BaseException: 286 | print("There is error in 'make' ") 287 | sys.exit() 288 | 289 | def runMakeInstall(self): 290 | print("run Make Install Called") 291 | try: 292 | if os.name == 'nt': 293 | self.msys_home = self.parser.get('COMPILER', 'MSYS_HOME') 294 | cmd = self.msys_home + "/mingw64/bin/mingw32-make.exe install" 295 | else: 296 | cmd = " make install" 297 | print("Running Make Install") 298 | path = os.getcwd() # noqa 299 | try: 300 | self.process.close() 301 | except BaseException: 302 | pass 303 | 304 | self.process = QtCore.QProcess(self) 305 | self.process.start(cmd) 306 | self.process.finished.connect(self.createSchematicLib) 307 | self.process.readyReadStandardOutput.connect(self.readAllStandard) 308 | os.chdir(self.cur_dir) 309 | 310 | except BaseException: 311 | print("There is error in 'make install' ") 312 | sys.exit() 313 | 314 | def createSchematicLib(self): 315 | if os.name == "nt": 316 | shutil.copy("ghdl/ghdl.cm", "../../../../lib/ngspice/") 317 | 318 | os.chdir(self.cur_dir) 319 | if Appconfig.esimFlag == 1: 320 | if not self.errorFlag: 321 | print('Creating library files................................') 322 | schematicLib = AutoSchematic(self, self.modelname) 323 | schematicLib.createKicadSymbol() 324 | else: 325 | QtWidgets.QMessageBox.critical( 326 | self, 'Error', '''Cannot create Schematic Library of ''' + 327 | '''your model. Resolve the errors shown on ''' + 328 | '''console of NGHDL window. ''' 329 | ) 330 | else: 331 | QtWidgets.QMessageBox.information( 332 | self, 'Message', '''Important Message

''' + 333 | '''To create Schematic Library of your model, ''' + 334 | '''use NGHDL through eSim ''' 335 | ) 336 | 337 | def uploadModel(self): 338 | print("Upload button clicked") 339 | try: 340 | self.process.close() 341 | except BaseException: 342 | pass 343 | try: 344 | self.file_extension = os.path.splitext(str(self.filename))[1] 345 | print("Uploaded File extension :" + self.file_extension) 346 | self.cur_dir = os.getcwd() 347 | print("Current Working Directory :" + self.cur_dir) 348 | self.checkSupportFiles() 349 | if self.file_extension == ".vhdl": 350 | self.errorFlag = False 351 | self.createModelDirectory() 352 | self.addingModelInModpath() 353 | self.createModelFiles() 354 | self.runMake() 355 | if os.name != 'nt': 356 | self.runMakeInstall() 357 | else: 358 | QtWidgets.QMessageBox.information( 359 | self, 'Message', '''Important Message.
''' + 360 | '''
This accepts only .vhdl file ''' 361 | ) 362 | except Exception as e: 363 | QtWidgets.QMessageBox.critical(self, 'Error', str(e)) 364 | 365 | 366 | class FileRemover(QtWidgets.QWidget): 367 | 368 | def __init__(self, main_obj): 369 | super(FileRemover, self).__init__() 370 | self.row = 0 371 | self.col = 0 372 | self.cb_dict = {} 373 | self.marked_list = [] 374 | self.files = main_obj.file_list 375 | self.sedit = main_obj.sedit 376 | 377 | print(self.files) 378 | 379 | self.grid = QtWidgets.QGridLayout() 380 | removebtn = QtWidgets.QPushButton('Remove', self) 381 | removebtn.clicked.connect(self.removeFiles) 382 | 383 | self.grid.addWidget(self.createCheckBox(), 0, 0) 384 | self.grid.addWidget(removebtn, 1, 1) 385 | 386 | self.setLayout(self.grid) 387 | self.show() 388 | 389 | def createCheckBox(self): 390 | self.checkbox = QtWidgets.QGroupBox() 391 | self.checkbox.setTitle('Remove Files') 392 | self.checkgrid = QtWidgets.QGridLayout() 393 | 394 | self.checkgroupbtn = QtWidgets.QButtonGroup() 395 | 396 | for path in self.files: 397 | print(path) 398 | self.cb_dict[path] = QtWidgets.QCheckBox(path) 399 | self.checkgroupbtn.addButton(self.cb_dict[path]) 400 | self.checkgrid.addWidget(self.cb_dict[path], self.row, self.col) 401 | self.row += 1 402 | 403 | self.checkgroupbtn.setExclusive(False) 404 | self.checkgroupbtn.buttonClicked.connect(self.mark_file) 405 | self.checkbox.setLayout(self.checkgrid) 406 | 407 | return self.checkbox 408 | 409 | def mark_file(self): 410 | for path in self.cb_dict: 411 | if self.cb_dict[path].isChecked(): 412 | if path not in self.marked_list: 413 | self.marked_list.append(path) 414 | else: 415 | if path in self.marked_list: 416 | self.marked_list.remove(path) 417 | 418 | def removeFiles(self): 419 | for path in self.marked_list: 420 | print(path + " is removed") 421 | self.sedit.append(path + " removed") 422 | self.files.remove(path) 423 | 424 | self.sedit.clear() 425 | for path in self.files: 426 | self.sedit.append(path) 427 | 428 | self.marked_list[:] = [] 429 | self.files[:] = [] 430 | self.close() 431 | 432 | 433 | def main(): 434 | app = QtWidgets.QApplication(sys.argv) 435 | if len(sys.argv) > 1: 436 | if sys.argv[1] == '-e': 437 | Appconfig.esimFlag = 1 438 | 439 | # Mainwindow() object must be assigned to a variable. 440 | # Otherwise, it is destroyed as soon as it gets created. 441 | w = Mainwindow() # noqa 442 | sys.exit(app.exec_()) 443 | 444 | 445 | if __name__ == '__main__': 446 | main() 447 | -------------------------------------------------------------------------------- /src/model_generation.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | from configparser import ConfigParser 4 | 5 | 6 | class ModelGeneration: 7 | 8 | def __init__(self, file): 9 | 10 | # Script starts from here 11 | print("Arguement is : ", file) 12 | self.fname = os.path.basename(file) 13 | print("VHDL filename is : ", self.fname) 14 | 15 | if os.name == 'nt': 16 | self.home = os.path.join('library', 'config') 17 | else: 18 | self.home = os.path.expanduser('~') 19 | 20 | self.parser = ConfigParser() 21 | self.parser.read(os.path.join( 22 | self.home, os.path.join('.nghdl', 'config.ini'))) 23 | self.nghdl_home = self.parser.get('NGHDL', 'NGHDL_HOME') 24 | self.release_dir = self.parser.get('NGHDL', 'RELEASE') 25 | self.src_home = self.parser.get('SRC', 'SRC_HOME') 26 | self.licensefile = self.parser.get('SRC', 'LICENSE') 27 | 28 | # #### Creating connection_info.txt file from vhdl file #### # 29 | read_vhdl = open(file, 'r') 30 | vhdl_data = read_vhdl.readlines() 31 | read_vhdl.close() 32 | 33 | start_flag = -1 # Used for scaning part of data 34 | scan_data = [] 35 | # p=re.search('port(.*?)end',read_vhdl,re.M|re.I|re.DOTALL).group() 36 | 37 | for item in vhdl_data: 38 | if re.search('port', item, re.I): 39 | start_flag = 1 40 | 41 | elif re.search("end", item, re.I): 42 | start_flag = 0 43 | 44 | if start_flag == 1: 45 | item = re.sub("port", " ", item, flags=re.I) 46 | item = re.sub("\(", " ", item, flags=re.I) # noqa 47 | item = re.sub("\)", " ", item, flags=re.I) # noqa 48 | item = re.sub(";", " ", item, flags=re.I) 49 | if item.find(','): 50 | temp1 = item.split(",") 51 | item = "" + temp1[-1] 52 | temp2 = temp1[-1].split(":") 53 | for i in range(len(temp1) - 1): 54 | temp3 = temp1[i] + ":" + temp2[-1] 55 | scan_data.append(temp3.rstrip()) 56 | scan_data.append(item.rstrip()) 57 | scan_data = [_f for _f in scan_data if _f] 58 | elif start_flag == 0: 59 | break 60 | 61 | port_info = [] 62 | self.port_vector_info = [] 63 | 64 | for item in scan_data: 65 | print("Scan Data :", item) 66 | if re.search("in", item, flags=re.I): 67 | if re.search("std_logic_vector", item, flags=re.I): 68 | temp = re.compile(r"\s*std_logic_vector\s*", flags=re.I) 69 | elif re.search("std_logic", item, flags=re.I): 70 | temp = re.compile(r"\s*std_logic\s*", flags=re.I) 71 | else: 72 | raise ValueError("Please check your vhdl " + 73 | "code for datatype of input port") 74 | elif re.search("out", item, flags=re.I): 75 | if re.search("std_logic_vector", item, flags=re.I): 76 | temp = re.compile(r"\s*std_logic_vector\s*", flags=re.I) 77 | elif re.search("std_logic", item, flags=re.I): 78 | temp = re.compile(r"\s*std_logic\s*", flags=re.I) 79 | else: 80 | raise ValueError("Please check your vhdl " + 81 | "code for datatype of output port") 82 | else: 83 | raise ValueError( 84 | "Please check the in/out direction of your port" 85 | ) 86 | 87 | lhs = temp.split(item)[0] 88 | rhs = temp.split(item)[1] 89 | bit_info = re.compile(r"\s*downto\s*", flags=re.I).split(rhs)[0] 90 | if bit_info: 91 | port_info.append(lhs + ":" + str(int(bit_info) + int(1))) 92 | self.port_vector_info.append(1) 93 | else: 94 | port_info.append(lhs + ":" + str(int(1))) 95 | self.port_vector_info.append(0) 96 | 97 | print("Port Info :", port_info) 98 | 99 | # Open connection_info.txt file 100 | con_ifo = open('connection_info.txt', 'w') 101 | 102 | for item in port_info: 103 | word = item.split(':') 104 | con_ifo.write( 105 | word[0].strip() + ' ' + word[1].strip() + ' ' + word[2].strip() 106 | ) 107 | con_ifo.write("\n") 108 | con_ifo.close() 109 | 110 | def readPortInfo(self): 111 | 112 | # ############## Reading connection/port information ############## # 113 | 114 | # Declaring input and output list 115 | input_list = [] 116 | output_list = [] 117 | 118 | # Reading connection_info.txt file for port infomation 119 | read_file = open('connection_info.txt', 'r') 120 | data = read_file.readlines() 121 | read_file.close() 122 | 123 | # Extracting input and output port list from data 124 | print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") 125 | for line in data: 126 | print(line) 127 | if re.match(r'^\s*$', line): 128 | pass 129 | else: 130 | in_items = re.findall( 131 | "IN", line, re.MULTILINE | re.IGNORECASE 132 | ) 133 | out_items = re.findall( 134 | "OUT", line, re.MULTILINE | re.IGNORECASE 135 | ) 136 | 137 | if in_items: 138 | input_list.append(line.split()) 139 | if out_items: 140 | output_list.append(line.split()) 141 | 142 | print("Input List :", input_list) 143 | print("Output list :", output_list) 144 | 145 | self.input_port = [] 146 | self.output_port = [] 147 | 148 | # creating list of input and output port with its weight 149 | for input in input_list: 150 | self.input_port.append(input[0] + ":" + input[2]) 151 | for output in output_list: 152 | self.output_port.append(output[0] + ":" + output[2]) 153 | 154 | print("Output Port List : ", self.output_port) 155 | print("Input Port List : ", self.input_port) 156 | 157 | def createCfuncModFile(self): 158 | 159 | # ############## Creating content for cfunc.mod file ############## # 160 | 161 | print("Starting With cfunc.mod file") 162 | cfunc = open('cfunc.mod', 'w') 163 | print("Building content for cfunc.mod file") 164 | 165 | comment = '''/* This is cfunc.mod file auto generated by \ 166 | model_generation.py \nDeveloped by Fahim, Rahul at IIT Bombay */\n 167 | ''' 168 | 169 | header = ''' 170 | #include 171 | #include 172 | #include 173 | #include 174 | #include 175 | #include 176 | #include 177 | #include 178 | 179 | ''' 180 | 181 | if os.name == 'nt': 182 | header += ''' 183 | #undef BOOLEAN 184 | #include 185 | ''' 186 | else: 187 | header += ''' 188 | #include 189 | #include 190 | #include 191 | ''' 192 | 193 | function_open = ( 194 | '''void cm_''' + self.fname.split('.')[0] + '''(ARGS) \n{''') 195 | 196 | digital_state_output = [] 197 | for item in self.output_port: 198 | digital_state_output.append( 199 | "Digital_State_t *_op_" + item.split(':')[0] + 200 | ", *_op_" + item.split(':')[0] + "_old;" 201 | ) 202 | 203 | var_section = ''' 204 | // Declaring components of Client 205 | FILE *log_client = NULL; 206 | log_client=fopen("client.log","a"); 207 | int bytes_recieved; 208 | char send_data[1024]; 209 | char recv_data[1024]; 210 | char *key_iter; 211 | struct hostent *host; 212 | struct sockaddr_in server_addr; 213 | int sock_port = 5000+PARAM(instance_id); 214 | ''' 215 | 216 | if os.name != 'nt': 217 | var_section += ''' 218 | int socket_fd; 219 | ''' 220 | 221 | temp_input_var = [] 222 | for item in self.input_port: 223 | temp_input_var.append( 224 | "char temp_" + item.split(':')[0] + "[1024];" 225 | ) 226 | 227 | # Start of INIT function 228 | init_start_function = ''' 229 | if(INIT) 230 | { 231 | /* Allocate storage for output ports ''' \ 232 | '''and set the load for input ports */ 233 | ''' 234 | 235 | cm_event_alloc = [] 236 | cm_count_output = 0 237 | for item in self.output_port: 238 | cm_event_alloc.append( 239 | "cm_event_alloc(" + 240 | str(cm_count_output) + "," + item.split(':')[1] + 241 | "*sizeof(Digital_State_t));" 242 | ) 243 | cm_count_output = cm_count_output + 1 244 | 245 | load_in_port = [] 246 | for item in self.input_port: 247 | load_in_port.append( 248 | "for(Ii=0;Iih_addr); 379 | bzero(&(server_addr.sin_zero),8); 380 | 381 | ''' 382 | 383 | connect_server = ''' 384 | fprintf(log_client,"Client-Connecting to server \\n"); 385 | 386 | //Connecting to server 387 | int try_limit=10; 388 | while(try_limit>0) 389 | { 390 | if (connect(socket_fd, (struct sockaddr*)&server_addr,''' \ 391 | '''sizeof(struct sockaddr)) == -1) 392 | { 393 | sleep(1); 394 | try_limit--; 395 | if(try_limit==0) 396 | { 397 | fprintf(stderr,"Connect- Error:Tried to connect server on port,''' \ 398 | '''failed...giving up \\n"); 399 | fprintf(log_client,"Connect- Error:Tried to connect server on ''' \ 400 | '''port, failed...giving up \\n"); 401 | exit(1); 402 | } 403 | } 404 | else 405 | { 406 | printf("Client-Connected to server \\n"); 407 | fprintf(log_client,"Client-Connected to server \\n"); 408 | break; 409 | } 410 | } 411 | ''' 412 | 413 | # Assign bit value to every input 414 | assign_data_to_input = [] 415 | for item in self.input_port: 416 | assign_data_to_input.append("\tfor(Ii=0;Ii " + item.split(':')[0] + ",\n") 916 | 917 | for item in self.output_port: 918 | if self.output_port.index(item) == len(self.output_port) - 1: 919 | map.append("\t\t\t\t" + item.split(':')[0] + 920 | " => " + item.split(':')[0] + "\n") 921 | else: 922 | map.append("\t\t\t\t" + item.split(':')[0] + 923 | " => " + item.split(':')[0] + ",\n") 924 | map.append("\t\t\t);") 925 | 926 | # Testbench Clock 927 | tb_clk = "clk_s <= not clk_s after 5 us;\n\n" 928 | 929 | # Adding Process block for Vhpi 930 | process_Vhpi = [] 931 | process_Vhpi.append( 932 | "process\n\t\tvariable sock_port : integer;" + 933 | "\n\t\ttype string_ptr is access string;" + 934 | "\n\t\tvariable sock_ip : string_ptr;" + 935 | "\n\t\tbegin\n\t\tsock_port := sock_port_fun;" + 936 | "\n\t\tsock_ip := new string'(sock_ip_fun);" + 937 | "\n\t\tVhpi_Initialize(sock_port," + 938 | "Pack_String_To_Vhpi_String(sock_ip.all));" + 939 | "\n\t\twait until clk_s = '1';" + 940 | "\n\t\twhile true loop\n\t\t\twait until clk_s = '0';" + 941 | "\n\t\t\tVhpi_Listen;\n\t\t\twait for 1 us;\n\t\t\t" + 942 | "Vhpi_Send;" + 943 | "\n\t\tend loop;\n\t\twait;\n\tend process;\n\n" 944 | ) 945 | 946 | # Adding process block 947 | process = [] 948 | process.append("\tprocess\n") 949 | process.append("\t\tvariable count : integer:=0;\n") 950 | 951 | for item in self.input_port: 952 | process.append( 953 | "\t\tvariable " + item.split(':')[0] + "_v : VhpiString;\n" 954 | ) 955 | 956 | for item in self.output_port: 957 | process.append( 958 | "\t\tvariable " + item.split(':')[0] + "_v : VhpiString;\n" 959 | ) 960 | 961 | process.append("\t\tvariable obj_ref : VhpiString;\n") 962 | process.append("\tbegin\n") 963 | process.append("\t\twhile true loop\n") 964 | process.append("\t\t\twait until clk_s = '0';\n\n") 965 | 966 | port_vector_count = 0 967 | 968 | for item in self.input_port: 969 | process.append( 970 | '\t\t\tobj_ref := Pack_String_To_Vhpi_String("' + 971 | item.split(':')[0] + '");\n' 972 | ) 973 | process.append( 974 | '\t\t\tVhpi_Get_Port_Value(obj_ref,' + 975 | item.split(':')[0] + '_v,' + item.split(':')[1] + ');\n' 976 | ) 977 | 978 | if self.port_vector_info[port_vector_count]: 979 | process.append( 980 | '\t\t\t' + item.split(':')[0] + 981 | ' <= Unpack_String(' + item.split(':')[0] + '_v,' + 982 | item.split(':')[1] + ');\n' 983 | ) 984 | else: 985 | process.append( 986 | '\t\t\t' + item.split(':')[0] + 987 | ' <= To_Std_Logic(' + item.split(':')[0] + '_v' + ');\n' 988 | ) 989 | 990 | port_vector_count += 1 991 | process.append("\n") 992 | 993 | process.append('\t\t\twait for 1 us;\n') 994 | 995 | for item in self.output_port: 996 | if self.port_vector_info[port_vector_count]: 997 | process.append( 998 | '\t\t\t' + item.split(':')[0] + 999 | '_v := Pack_String_To_Vhpi_String' + 1000 | '(Convert_SLV_To_String(' + 1001 | item.split(':')[0] + '));\n' 1002 | ) 1003 | else: 1004 | process.append( 1005 | '\t\t\t' + item.split(':')[0] + 1006 | '_v := Pack_String_To_Vhpi_String(To_String(' + 1007 | item.split(':')[0] + '));\n' 1008 | ) 1009 | 1010 | port_vector_count += 1 1011 | 1012 | process.append( 1013 | '\t\t\tobj_ref := Pack_String_To_Vhpi_String("' + 1014 | item.split(':')[0] + '");\n' 1015 | ) 1016 | process.append( 1017 | '\t\t\tVhpi_Set_Port_Value(obj_ref,' + 1018 | item.split(':')[0] + '_v,' + item.split(':')[1] + ');\n' 1019 | ) 1020 | process.append("\n") 1021 | 1022 | process.append( 1023 | '\t\t\treport "Iteration - "' + 1024 | "& integer'image(count) severity note;\n" 1025 | ) 1026 | process.append('\t\t\tcount := count + 1;\n') 1027 | process.append("\t\tend loop;\n") 1028 | process.append("\tend process;\n\n") 1029 | process.append("end architecture;") 1030 | 1031 | # Writing all the components to testbench file 1032 | testbench.write(comment_vhdl) 1033 | testbench.write(tb_header) 1034 | testbench.write(tb_entity) 1035 | testbench.write(arch) 1036 | 1037 | for item in components: 1038 | testbench.write(item) 1039 | 1040 | for item in signals: 1041 | testbench.write(item) 1042 | 1043 | testbench.write("\n\n") 1044 | 1045 | testbench.write("begin\n\n") 1046 | 1047 | for item in map: 1048 | testbench.write(item) 1049 | 1050 | testbench.write("\n\t" + tb_clk) 1051 | 1052 | for item in process_Vhpi: 1053 | testbench.write(item) 1054 | 1055 | for item in process: 1056 | testbench.write(item) 1057 | 1058 | testbench.close() 1059 | 1060 | def createServerScript(self): 1061 | 1062 | # ####### Creating and writing components in start_server.sh ####### # 1063 | self.digital_home = self.parser.get('NGHDL', 'DIGITAL_MODEL') 1064 | self.digital_home = os.path.join(self.digital_home, "ghdl") 1065 | 1066 | start_server = open('start_server.sh', 'w') 1067 | 1068 | start_server.write("#!/bin/bash\n\n") 1069 | start_server.write( 1070 | "###This server run ghdl testbench for infinite time till " + 1071 | "Ngspice sends kill signal to stop it\n\n" 1072 | ) 1073 | 1074 | if os.name == 'nt': 1075 | pathstr = self.digital_home + "/" + \ 1076 | self.fname.split('.')[0] + "/DUTghdl/" 1077 | pathstr = pathstr.replace("\\", "/") 1078 | start_server.write("cd " + pathstr + "\n") 1079 | else: 1080 | start_server.write("cd " + self.digital_home + 1081 | "/" + self.fname.split('.')[0] + "/DUTghdl/\n") 1082 | 1083 | start_server.write("chmod 775 sock_pkg_create.sh &&\n") 1084 | start_server.write("./sock_pkg_create.sh $1 $2 &&\n") 1085 | start_server.write("ghdl -i *.vhdl &&\n") 1086 | start_server.write("ghdl -a *.vhdl &&\n") 1087 | start_server.write("ghdl -a " + self.fname + " &&\n") 1088 | start_server.write( 1089 | "ghdl -a " + self.fname.split('.')[0] + "_tb.vhdl &&\n" 1090 | ) 1091 | 1092 | if os.name == 'nt': 1093 | start_server.write("ghdl -e -Wl,ghdlserver.o " + 1094 | "-Wl,libws2_32.a " + 1095 | self.fname.split('.')[0] + "_tb &&\n") 1096 | start_server.write("./" + self.fname.split('.')[0] + "_tb.exe") 1097 | else: 1098 | start_server.write("ghdl -e -Wl,ghdlserver.o " + 1099 | self.fname.split('.')[0] + "_tb &&\n") 1100 | start_server.write( 1101 | "./" + 1102 | self.fname.split('.')[0] + 1103 | "_tb --vcd=" + 1104 | self.fname.split('.')[0] + 1105 | "_tb.vcd\n") 1106 | start_server.write( 1107 | "gtkwave " + 1108 | self.fname.split('.')[0] + 1109 | "_tb.vcd 2>/dev/null") 1110 | 1111 | start_server.close() 1112 | 1113 | def createSockScript(self): 1114 | 1115 | # ########### Creating and writing in sock_pkg_create.sh ########### # 1116 | 1117 | sock_pkg_create = open('sock_pkg_create.sh', 'w') 1118 | 1119 | sock_pkg_create.write("#!/bin/bash\n\n") 1120 | sock_pkg_create.write( 1121 | "##This file creates sock_pkg.vhdl file and sets the port " + 1122 | "and ip from parameters passed to it\n\n" 1123 | ) 1124 | sock_pkg_create.write("echo \"library ieee;\n") 1125 | sock_pkg_create.write("package sock_pkg is\n") 1126 | sock_pkg_create.write("\tfunction sock_port_fun return integer;\n") 1127 | sock_pkg_create.write("\tfunction sock_ip_fun return string;\n") 1128 | sock_pkg_create.write("end;\n\n") 1129 | sock_pkg_create.write("package body sock_pkg is\n") 1130 | sock_pkg_create.write("\tfunction sock_port_fun return integer is\n") 1131 | sock_pkg_create.write("\t\tvariable sock_port : integer;\n") 1132 | sock_pkg_create.write("\t\t\tbegin\n") 1133 | sock_pkg_create.write("\t\t\t\tsock_port := $1;\n") 1134 | sock_pkg_create.write("\t\t\t\treturn sock_port;\n") 1135 | sock_pkg_create.write("\t\t\tend function;\n\n") 1136 | sock_pkg_create.write("\tfunction sock_ip_fun return string is\n") 1137 | sock_pkg_create.write("\t\ttype string_ptr is access string;\n") 1138 | sock_pkg_create.write("\t\tvariable sock_ip : string_ptr;\n") 1139 | sock_pkg_create.write("\t\t\tbegin\n") 1140 | sock_pkg_create.write('\t\t\t\tsock_ip := new string\'(\\"$2\\");\n') 1141 | sock_pkg_create.write("\t\t\t\treturn sock_ip.all;\n") 1142 | sock_pkg_create.write("\t\t\tend function;\n\n") 1143 | sock_pkg_create.write("\t\tend package body;\" > sock_pkg.vhdl") 1144 | -------------------------------------------------------------------------------- /src/ghdlserver/uthash.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef UTHASH_H 25 | #define UTHASH_H 26 | 27 | #include /* memcmp,strlen */ 28 | #include /* ptrdiff_t */ 29 | #include /* exit() */ 30 | 31 | /* These macros use decltype or the earlier __typeof GNU extension. 32 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ 33 | when compiling c++ source) this code uses whatever method is needed 34 | or, for VS2008 where neither is available, uses casting workarounds. */ 35 | #ifdef _MSC_VER /* MS compiler */ 36 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ 37 | #define DECLTYPE(x) (decltype(x)) 38 | #else /* VS2008 or older (or VS2010 in C mode) */ 39 | #define NO_DECLTYPE 40 | #define DECLTYPE(x) 41 | #endif 42 | #else /* GNU, Sun and other compilers */ 43 | #define DECLTYPE(x) (__typeof(x)) 44 | #endif 45 | 46 | #ifdef NO_DECLTYPE 47 | #define DECLTYPE_ASSIGN(dst,src) \ 48 | do { \ 49 | char **_da_dst = (char**)(&(dst)); \ 50 | *_da_dst = (char*)(src); \ 51 | } while(0) 52 | #else 53 | #define DECLTYPE_ASSIGN(dst,src) \ 54 | do { \ 55 | (dst) = DECLTYPE(dst)(src); \ 56 | } while(0) 57 | #endif 58 | 59 | /* a number of the hash function use uint32_t which isn't defined on win32 */ 60 | #ifdef _MSC_VER 61 | typedef unsigned int uint32_t; 62 | typedef unsigned char uint8_t; 63 | #else 64 | #include /* uint32_t */ 65 | #endif 66 | 67 | #define UTHASH_VERSION 1.9.9 68 | 69 | #ifndef uthash_fatal 70 | #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ 71 | #endif 72 | #ifndef uthash_malloc 73 | #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ 74 | #endif 75 | #ifndef uthash_free 76 | #define uthash_free(ptr,sz) free(ptr) /* free fcn */ 77 | #endif 78 | 79 | #ifndef uthash_noexpand_fyi 80 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ 81 | #endif 82 | #ifndef uthash_expand_fyi 83 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ 84 | #endif 85 | 86 | /* initial number of buckets */ 87 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ 88 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ 89 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ 90 | 91 | /* calculate the element whose hash handle address is hhe */ 92 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) 93 | 94 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ 95 | do { \ 96 | unsigned _hf_bkt,_hf_hashv; \ 97 | out=NULL; \ 98 | if (head) { \ 99 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ 100 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ 101 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ 102 | keyptr,keylen,out); \ 103 | } \ 104 | } \ 105 | } while (0) 106 | 107 | #ifdef HASH_BLOOM 108 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) 109 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) 110 | #define HASH_BLOOM_MAKE(tbl) \ 111 | do { \ 112 | (tbl)->bloom_nbits = HASH_BLOOM; \ 113 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ 114 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ 115 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ 116 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ 117 | } while (0) 118 | 119 | #define HASH_BLOOM_FREE(tbl) \ 120 | do { \ 121 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ 122 | } while (0) 123 | 124 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) 125 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) 126 | 127 | #define HASH_BLOOM_ADD(tbl,hashv) \ 128 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 129 | 130 | #define HASH_BLOOM_TEST(tbl,hashv) \ 131 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 132 | 133 | #else 134 | #define HASH_BLOOM_MAKE(tbl) 135 | #define HASH_BLOOM_FREE(tbl) 136 | #define HASH_BLOOM_ADD(tbl,hashv) 137 | #define HASH_BLOOM_TEST(tbl,hashv) (1) 138 | #define HASH_BLOOM_BYTELEN 0 139 | #endif 140 | 141 | #define HASH_MAKE_TABLE(hh,head) \ 142 | do { \ 143 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ 144 | sizeof(UT_hash_table)); \ 145 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ 146 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ 147 | (head)->hh.tbl->tail = &((head)->hh); \ 148 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ 149 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ 150 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ 151 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ 152 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 153 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ 154 | memset((head)->hh.tbl->buckets, 0, \ 155 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 156 | HASH_BLOOM_MAKE((head)->hh.tbl); \ 157 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ 158 | } while(0) 159 | 160 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ 161 | HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) 162 | 163 | #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ 164 | do { \ 165 | replaced=NULL; \ 166 | HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ 167 | if (replaced!=NULL) { \ 168 | HASH_DELETE(hh,head,replaced); \ 169 | }; \ 170 | HASH_ADD(hh,head,fieldname,keylen_in,add); \ 171 | } while(0) 172 | 173 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ 174 | do { \ 175 | unsigned _ha_bkt; \ 176 | (add)->hh.next = NULL; \ 177 | (add)->hh.key = (char*)(keyptr); \ 178 | (add)->hh.keylen = (unsigned)(keylen_in); \ 179 | if (!(head)) { \ 180 | head = (add); \ 181 | (head)->hh.prev = NULL; \ 182 | HASH_MAKE_TABLE(hh,head); \ 183 | } else { \ 184 | (head)->hh.tbl->tail->next = (add); \ 185 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ 186 | (head)->hh.tbl->tail = &((add)->hh); \ 187 | } \ 188 | (head)->hh.tbl->num_items++; \ 189 | (add)->hh.tbl = (head)->hh.tbl; \ 190 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ 191 | (add)->hh.hashv, _ha_bkt); \ 192 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ 193 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ 194 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ 195 | HASH_FSCK(hh,head); \ 196 | } while(0) 197 | 198 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ 199 | do { \ 200 | bkt = ((hashv) & ((num_bkts) - 1)); \ 201 | } while(0) 202 | 203 | /* delete "delptr" from the hash table. 204 | * "the usual" patch-up process for the app-order doubly-linked-list. 205 | * The use of _hd_hh_del below deserves special explanation. 206 | * These used to be expressed using (delptr) but that led to a bug 207 | * if someone used the same symbol for the head and deletee, like 208 | * HASH_DELETE(hh,users,users); 209 | * We want that to work, but by changing the head (users) below 210 | * we were forfeiting our ability to further refer to the deletee (users) 211 | * in the patch-up process. Solution: use scratch space to 212 | * copy the deletee pointer, then the latter references are via that 213 | * scratch pointer rather than through the repointed (users) symbol. 214 | */ 215 | #define HASH_DELETE(hh,head,delptr) \ 216 | do { \ 217 | unsigned _hd_bkt; \ 218 | struct UT_hash_handle *_hd_hh_del; \ 219 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ 220 | uthash_free((head)->hh.tbl->buckets, \ 221 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 222 | HASH_BLOOM_FREE((head)->hh.tbl); \ 223 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 224 | head = NULL; \ 225 | } else { \ 226 | _hd_hh_del = &((delptr)->hh); \ 227 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ 228 | (head)->hh.tbl->tail = \ 229 | (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ 230 | (head)->hh.tbl->hho); \ 231 | } \ 232 | if ((delptr)->hh.prev) { \ 233 | ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ 234 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ 235 | } else { \ 236 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ 237 | } \ 238 | if (_hd_hh_del->next) { \ 239 | ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ 240 | (head)->hh.tbl->hho))->prev = \ 241 | _hd_hh_del->prev; \ 242 | } \ 243 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ 244 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ 245 | (head)->hh.tbl->num_items--; \ 246 | } \ 247 | HASH_FSCK(hh,head); \ 248 | } while (0) 249 | 250 | 251 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ 252 | #define HASH_FIND_STR(head,findstr,out) \ 253 | HASH_FIND(hh,head,findstr,strlen(findstr),out) 254 | #define HASH_ADD_STR(head,strfield,add) \ 255 | HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add) 256 | #define HASH_REPLACE_STR(head,strfield,add,replaced) \ 257 | HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced) 258 | #define HASH_FIND_INT(head,findint,out) \ 259 | HASH_FIND(hh,head,findint,sizeof(int),out) 260 | #define HASH_ADD_INT(head,intfield,add) \ 261 | HASH_ADD(hh,head,intfield,sizeof(int),add) 262 | #define HASH_REPLACE_INT(head,intfield,add,replaced) \ 263 | HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) 264 | #define HASH_FIND_PTR(head,findptr,out) \ 265 | HASH_FIND(hh,head,findptr,sizeof(void *),out) 266 | #define HASH_ADD_PTR(head,ptrfield,add) \ 267 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) 268 | #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ 269 | HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) 270 | #define HASH_DEL(head,delptr) \ 271 | HASH_DELETE(hh,head,delptr) 272 | 273 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. 274 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. 275 | */ 276 | #ifdef HASH_DEBUG 277 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) 278 | #define HASH_FSCK(hh,head) \ 279 | do { \ 280 | unsigned _bkt_i; \ 281 | unsigned _count, _bkt_count; \ 282 | char *_prev; \ 283 | struct UT_hash_handle *_thh; \ 284 | if (head) { \ 285 | _count = 0; \ 286 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ 287 | _bkt_count = 0; \ 288 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ 289 | _prev = NULL; \ 290 | while (_thh) { \ 291 | if (_prev != (char*)(_thh->hh_prev)) { \ 292 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ 293 | _thh->hh_prev, _prev ); \ 294 | } \ 295 | _bkt_count++; \ 296 | _prev = (char*)(_thh); \ 297 | _thh = _thh->hh_next; \ 298 | } \ 299 | _count += _bkt_count; \ 300 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ 301 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ 302 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ 303 | } \ 304 | } \ 305 | if (_count != (head)->hh.tbl->num_items) { \ 306 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ 307 | (head)->hh.tbl->num_items, _count ); \ 308 | } \ 309 | /* traverse hh in app order; check next/prev integrity, count */ \ 310 | _count = 0; \ 311 | _prev = NULL; \ 312 | _thh = &(head)->hh; \ 313 | while (_thh) { \ 314 | _count++; \ 315 | if (_prev !=(char*)(_thh->prev)) { \ 316 | HASH_OOPS("invalid prev %p, actual %p\n", \ 317 | _thh->prev, _prev ); \ 318 | } \ 319 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ 320 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ 321 | (head)->hh.tbl->hho) : NULL ); \ 322 | } \ 323 | if (_count != (head)->hh.tbl->num_items) { \ 324 | HASH_OOPS("invalid app item count %d, actual %d\n", \ 325 | (head)->hh.tbl->num_items, _count ); \ 326 | } \ 327 | } \ 328 | } while (0) 329 | #else 330 | #define HASH_FSCK(hh,head) 331 | #endif 332 | 333 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to 334 | * the descriptor to which this macro is defined for tuning the hash function. 335 | * The app can #include to get the prototype for write(2). */ 336 | #ifdef HASH_EMIT_KEYS 337 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ 338 | do { \ 339 | unsigned _klen = fieldlen; \ 340 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ 341 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ 342 | } while (0) 343 | #else 344 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) 345 | #endif 346 | 347 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ 348 | #ifdef HASH_FUNCTION 349 | #define HASH_FCN HASH_FUNCTION 350 | #else 351 | #define HASH_FCN HASH_JEN 352 | #endif 353 | 354 | /* The Bernstein hash function, used in Perl prior to v5.6 */ 355 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ 356 | do { \ 357 | unsigned _hb_keylen=keylen; \ 358 | char *_hb_key=(char*)(key); \ 359 | (hashv) = 0; \ 360 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ 361 | bkt = (hashv) & (num_bkts-1); \ 362 | } while (0) 363 | 364 | 365 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at 366 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ 367 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ 368 | do { \ 369 | unsigned _sx_i; \ 370 | char *_hs_key=(char*)(key); \ 371 | hashv = 0; \ 372 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ 373 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ 374 | bkt = hashv & (num_bkts-1); \ 375 | } while (0) 376 | 377 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ 378 | do { \ 379 | unsigned _fn_i; \ 380 | char *_hf_key=(char*)(key); \ 381 | hashv = 2166136261UL; \ 382 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ 383 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ 384 | bkt = hashv & (num_bkts-1); \ 385 | } while(0) 386 | 387 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ 388 | do { \ 389 | unsigned _ho_i; \ 390 | char *_ho_key=(char*)(key); \ 391 | hashv = 0; \ 392 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ 393 | hashv += _ho_key[_ho_i]; \ 394 | hashv += (hashv << 10); \ 395 | hashv ^= (hashv >> 6); \ 396 | } \ 397 | hashv += (hashv << 3); \ 398 | hashv ^= (hashv >> 11); \ 399 | hashv += (hashv << 15); \ 400 | bkt = hashv & (num_bkts-1); \ 401 | } while(0) 402 | 403 | #define HASH_JEN_MIX(a,b,c) \ 404 | do { \ 405 | a -= b; a -= c; a ^= ( c >> 13 ); \ 406 | b -= c; b -= a; b ^= ( a << 8 ); \ 407 | c -= a; c -= b; c ^= ( b >> 13 ); \ 408 | a -= b; a -= c; a ^= ( c >> 12 ); \ 409 | b -= c; b -= a; b ^= ( a << 16 ); \ 410 | c -= a; c -= b; c ^= ( b >> 5 ); \ 411 | a -= b; a -= c; a ^= ( c >> 3 ); \ 412 | b -= c; b -= a; b ^= ( a << 10 ); \ 413 | c -= a; c -= b; c ^= ( b >> 15 ); \ 414 | } while (0) 415 | 416 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ 417 | do { \ 418 | unsigned _hj_i,_hj_j,_hj_k; \ 419 | unsigned char *_hj_key=(unsigned char*)(key); \ 420 | hashv = 0xfeedbeef; \ 421 | _hj_i = _hj_j = 0x9e3779b9; \ 422 | _hj_k = (unsigned)(keylen); \ 423 | while (_hj_k >= 12) { \ 424 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ 425 | + ( (unsigned)_hj_key[2] << 16 ) \ 426 | + ( (unsigned)_hj_key[3] << 24 ) ); \ 427 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ 428 | + ( (unsigned)_hj_key[6] << 16 ) \ 429 | + ( (unsigned)_hj_key[7] << 24 ) ); \ 430 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ 431 | + ( (unsigned)_hj_key[10] << 16 ) \ 432 | + ( (unsigned)_hj_key[11] << 24 ) ); \ 433 | \ 434 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 435 | \ 436 | _hj_key += 12; \ 437 | _hj_k -= 12; \ 438 | } \ 439 | hashv += keylen; \ 440 | switch ( _hj_k ) { \ 441 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ 442 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ 443 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ 444 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ 445 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ 446 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ 447 | case 5: _hj_j += _hj_key[4]; \ 448 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ 449 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ 450 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ 451 | case 1: _hj_i += _hj_key[0]; \ 452 | } \ 453 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 454 | bkt = hashv & (num_bkts-1); \ 455 | } while(0) 456 | 457 | /* The Paul Hsieh hash function */ 458 | #undef get16bits 459 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ 460 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) 461 | #define get16bits(d) (*((const uint16_t *) (d))) 462 | #endif 463 | 464 | #if !defined (get16bits) 465 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ 466 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 467 | #endif 468 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ 469 | do { \ 470 | unsigned char *_sfh_key=(unsigned char*)(key); \ 471 | uint32_t _sfh_tmp, _sfh_len = keylen; \ 472 | \ 473 | int _sfh_rem = _sfh_len & 3; \ 474 | _sfh_len >>= 2; \ 475 | hashv = 0xcafebabe; \ 476 | \ 477 | /* Main loop */ \ 478 | for (;_sfh_len > 0; _sfh_len--) { \ 479 | hashv += get16bits (_sfh_key); \ 480 | _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ 481 | hashv = (hashv << 16) ^ _sfh_tmp; \ 482 | _sfh_key += 2*sizeof (uint16_t); \ 483 | hashv += hashv >> 11; \ 484 | } \ 485 | \ 486 | /* Handle end cases */ \ 487 | switch (_sfh_rem) { \ 488 | case 3: hashv += get16bits (_sfh_key); \ 489 | hashv ^= hashv << 16; \ 490 | hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ 491 | hashv += hashv >> 11; \ 492 | break; \ 493 | case 2: hashv += get16bits (_sfh_key); \ 494 | hashv ^= hashv << 11; \ 495 | hashv += hashv >> 17; \ 496 | break; \ 497 | case 1: hashv += *_sfh_key; \ 498 | hashv ^= hashv << 10; \ 499 | hashv += hashv >> 1; \ 500 | } \ 501 | \ 502 | /* Force "avalanching" of final 127 bits */ \ 503 | hashv ^= hashv << 3; \ 504 | hashv += hashv >> 5; \ 505 | hashv ^= hashv << 4; \ 506 | hashv += hashv >> 17; \ 507 | hashv ^= hashv << 25; \ 508 | hashv += hashv >> 6; \ 509 | bkt = hashv & (num_bkts-1); \ 510 | } while(0) 511 | 512 | #ifdef HASH_USING_NO_STRICT_ALIASING 513 | /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. 514 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. 515 | * MurmurHash uses the faster approach only on CPU's where we know it's safe. 516 | * 517 | * Note the preprocessor built-in defines can be emitted using: 518 | * 519 | * gcc -m64 -dM -E - < /dev/null (on gcc) 520 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) 521 | */ 522 | #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) 523 | #define MUR_GETBLOCK(p,i) p[i] 524 | #else /* non intel */ 525 | #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) 526 | #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) 527 | #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) 528 | #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) 529 | #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) 530 | #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) 531 | #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) 532 | #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) 533 | #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) 534 | #else /* assume little endian non-intel */ 535 | #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) 536 | #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) 537 | #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) 538 | #endif 539 | #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ 540 | (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ 541 | (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ 542 | MUR_ONE_THREE(p)))) 543 | #endif 544 | #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) 545 | #define MUR_FMIX(_h) \ 546 | do { \ 547 | _h ^= _h >> 16; \ 548 | _h *= 0x85ebca6b; \ 549 | _h ^= _h >> 13; \ 550 | _h *= 0xc2b2ae35l; \ 551 | _h ^= _h >> 16; \ 552 | } while(0) 553 | 554 | #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ 555 | do { \ 556 | const uint8_t *_mur_data = (const uint8_t*)(key); \ 557 | const int _mur_nblocks = (keylen) / 4; \ 558 | uint32_t _mur_h1 = 0xf88D5353; \ 559 | uint32_t _mur_c1 = 0xcc9e2d51; \ 560 | uint32_t _mur_c2 = 0x1b873593; \ 561 | uint32_t _mur_k1 = 0; \ 562 | const uint8_t *_mur_tail; \ 563 | const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ 564 | int _mur_i; \ 565 | for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ 566 | _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ 567 | _mur_k1 *= _mur_c1; \ 568 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 569 | _mur_k1 *= _mur_c2; \ 570 | \ 571 | _mur_h1 ^= _mur_k1; \ 572 | _mur_h1 = MUR_ROTL32(_mur_h1,13); \ 573 | _mur_h1 = _mur_h1*5+0xe6546b64; \ 574 | } \ 575 | _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ 576 | _mur_k1=0; \ 577 | switch((keylen) & 3) { \ 578 | case 3: _mur_k1 ^= _mur_tail[2] << 16; \ 579 | case 2: _mur_k1 ^= _mur_tail[1] << 8; \ 580 | case 1: _mur_k1 ^= _mur_tail[0]; \ 581 | _mur_k1 *= _mur_c1; \ 582 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 583 | _mur_k1 *= _mur_c2; \ 584 | _mur_h1 ^= _mur_k1; \ 585 | } \ 586 | _mur_h1 ^= (keylen); \ 587 | MUR_FMIX(_mur_h1); \ 588 | hashv = _mur_h1; \ 589 | bkt = hashv & (num_bkts-1); \ 590 | } while(0) 591 | #endif /* HASH_USING_NO_STRICT_ALIASING */ 592 | 593 | /* key comparison function; return 0 if keys equal */ 594 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) 595 | 596 | /* iterate over items in a known bucket to find desired item */ 597 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ 598 | do { \ 599 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ 600 | else out=NULL; \ 601 | while (out) { \ 602 | if ((out)->hh.keylen == keylen_in) { \ 603 | if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ 604 | } \ 605 | if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ 606 | else out = NULL; \ 607 | } \ 608 | } while(0) 609 | 610 | /* add an item to a bucket */ 611 | #define HASH_ADD_TO_BKT(head,addhh) \ 612 | do { \ 613 | head.count++; \ 614 | (addhh)->hh_next = head.hh_head; \ 615 | (addhh)->hh_prev = NULL; \ 616 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ 617 | (head).hh_head=addhh; \ 618 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ 619 | && (addhh)->tbl->noexpand != 1) { \ 620 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ 621 | } \ 622 | } while(0) 623 | 624 | /* remove an item from a given bucket */ 625 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ 626 | (head).count--; \ 627 | if ((head).hh_head == hh_del) { \ 628 | (head).hh_head = hh_del->hh_next; \ 629 | } \ 630 | if (hh_del->hh_prev) { \ 631 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ 632 | } \ 633 | if (hh_del->hh_next) { \ 634 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ 635 | } 636 | 637 | /* Bucket expansion has the effect of doubling the number of buckets 638 | * and redistributing the items into the new buckets. Ideally the 639 | * items will distribute more or less evenly into the new buckets 640 | * (the extent to which this is true is a measure of the quality of 641 | * the hash function as it applies to the key domain). 642 | * 643 | * With the items distributed into more buckets, the chain length 644 | * (item count) in each bucket is reduced. Thus by expanding buckets 645 | * the hash keeps a bound on the chain length. This bounded chain 646 | * length is the essence of how a hash provides constant time lookup. 647 | * 648 | * The calculation of tbl->ideal_chain_maxlen below deserves some 649 | * explanation. First, keep in mind that we're calculating the ideal 650 | * maximum chain length based on the *new* (doubled) bucket count. 651 | * In fractions this is just n/b (n=number of items,b=new num buckets). 652 | * Since the ideal chain length is an integer, we want to calculate 653 | * ceil(n/b). We don't depend on floating point arithmetic in this 654 | * hash, so to calculate ceil(n/b) with integers we could write 655 | * 656 | * ceil(n/b) = (n/b) + ((n%b)?1:0) 657 | * 658 | * and in fact a previous version of this hash did just that. 659 | * But now we have improved things a bit by recognizing that b is 660 | * always a power of two. We keep its base 2 log handy (call it lb), 661 | * so now we can write this with a bit shift and logical AND: 662 | * 663 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) 664 | * 665 | */ 666 | #define HASH_EXPAND_BUCKETS(tbl) \ 667 | do { \ 668 | unsigned _he_bkt; \ 669 | unsigned _he_bkt_i; \ 670 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ 671 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ 672 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 673 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 674 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ 675 | memset(_he_new_buckets, 0, \ 676 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 677 | tbl->ideal_chain_maxlen = \ 678 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ 679 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ 680 | tbl->nonideal_items = 0; \ 681 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ 682 | { \ 683 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ 684 | while (_he_thh) { \ 685 | _he_hh_nxt = _he_thh->hh_next; \ 686 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ 687 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ 688 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ 689 | tbl->nonideal_items++; \ 690 | _he_newbkt->expand_mult = _he_newbkt->count / \ 691 | tbl->ideal_chain_maxlen; \ 692 | } \ 693 | _he_thh->hh_prev = NULL; \ 694 | _he_thh->hh_next = _he_newbkt->hh_head; \ 695 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ 696 | _he_thh; \ 697 | _he_newbkt->hh_head = _he_thh; \ 698 | _he_thh = _he_hh_nxt; \ 699 | } \ 700 | } \ 701 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 702 | tbl->num_buckets *= 2; \ 703 | tbl->log2_num_buckets++; \ 704 | tbl->buckets = _he_new_buckets; \ 705 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ 706 | (tbl->ineff_expands+1) : 0; \ 707 | if (tbl->ineff_expands > 1) { \ 708 | tbl->noexpand=1; \ 709 | uthash_noexpand_fyi(tbl); \ 710 | } \ 711 | uthash_expand_fyi(tbl); \ 712 | } while(0) 713 | 714 | 715 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ 716 | /* Note that HASH_SORT assumes the hash handle name to be hh. 717 | * HASH_SRT was added to allow the hash handle name to be passed in. */ 718 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) 719 | #define HASH_SRT(hh,head,cmpfcn) \ 720 | do { \ 721 | unsigned _hs_i; \ 722 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ 723 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ 724 | if (head) { \ 725 | _hs_insize = 1; \ 726 | _hs_looping = 1; \ 727 | _hs_list = &((head)->hh); \ 728 | while (_hs_looping) { \ 729 | _hs_p = _hs_list; \ 730 | _hs_list = NULL; \ 731 | _hs_tail = NULL; \ 732 | _hs_nmerges = 0; \ 733 | while (_hs_p) { \ 734 | _hs_nmerges++; \ 735 | _hs_q = _hs_p; \ 736 | _hs_psize = 0; \ 737 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ 738 | _hs_psize++; \ 739 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 740 | ((void*)((char*)(_hs_q->next) + \ 741 | (head)->hh.tbl->hho)) : NULL); \ 742 | if (! (_hs_q) ) break; \ 743 | } \ 744 | _hs_qsize = _hs_insize; \ 745 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ 746 | if (_hs_psize == 0) { \ 747 | _hs_e = _hs_q; \ 748 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 749 | ((void*)((char*)(_hs_q->next) + \ 750 | (head)->hh.tbl->hho)) : NULL); \ 751 | _hs_qsize--; \ 752 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ 753 | _hs_e = _hs_p; \ 754 | if (_hs_p){ \ 755 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 756 | ((void*)((char*)(_hs_p->next) + \ 757 | (head)->hh.tbl->hho)) : NULL); \ 758 | } \ 759 | _hs_psize--; \ 760 | } else if (( \ 761 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ 762 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ 763 | ) <= 0) { \ 764 | _hs_e = _hs_p; \ 765 | if (_hs_p){ \ 766 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 767 | ((void*)((char*)(_hs_p->next) + \ 768 | (head)->hh.tbl->hho)) : NULL); \ 769 | } \ 770 | _hs_psize--; \ 771 | } else { \ 772 | _hs_e = _hs_q; \ 773 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 774 | ((void*)((char*)(_hs_q->next) + \ 775 | (head)->hh.tbl->hho)) : NULL); \ 776 | _hs_qsize--; \ 777 | } \ 778 | if ( _hs_tail ) { \ 779 | _hs_tail->next = ((_hs_e) ? \ 780 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ 781 | } else { \ 782 | _hs_list = _hs_e; \ 783 | } \ 784 | if (_hs_e) { \ 785 | _hs_e->prev = ((_hs_tail) ? \ 786 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ 787 | } \ 788 | _hs_tail = _hs_e; \ 789 | } \ 790 | _hs_p = _hs_q; \ 791 | } \ 792 | if (_hs_tail){ \ 793 | _hs_tail->next = NULL; \ 794 | } \ 795 | if ( _hs_nmerges <= 1 ) { \ 796 | _hs_looping=0; \ 797 | (head)->hh.tbl->tail = _hs_tail; \ 798 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ 799 | } \ 800 | _hs_insize *= 2; \ 801 | } \ 802 | HASH_FSCK(hh,head); \ 803 | } \ 804 | } while (0) 805 | 806 | /* This function selects items from one hash into another hash. 807 | * The end result is that the selected items have dual presence 808 | * in both hashes. There is no copy of the items made; rather 809 | * they are added into the new hash through a secondary hash 810 | * hash handle that must be present in the structure. */ 811 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ 812 | do { \ 813 | unsigned _src_bkt, _dst_bkt; \ 814 | void *_last_elt=NULL, *_elt; \ 815 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ 816 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ 817 | if (src) { \ 818 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ 819 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ 820 | _src_hh; \ 821 | _src_hh = _src_hh->hh_next) { \ 822 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ 823 | if (cond(_elt)) { \ 824 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ 825 | _dst_hh->key = _src_hh->key; \ 826 | _dst_hh->keylen = _src_hh->keylen; \ 827 | _dst_hh->hashv = _src_hh->hashv; \ 828 | _dst_hh->prev = _last_elt; \ 829 | _dst_hh->next = NULL; \ 830 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ 831 | if (!dst) { \ 832 | DECLTYPE_ASSIGN(dst,_elt); \ 833 | HASH_MAKE_TABLE(hh_dst,dst); \ 834 | } else { \ 835 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ 836 | } \ 837 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ 838 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ 839 | (dst)->hh_dst.tbl->num_items++; \ 840 | _last_elt = _elt; \ 841 | _last_elt_hh = _dst_hh; \ 842 | } \ 843 | } \ 844 | } \ 845 | } \ 846 | HASH_FSCK(hh_dst,dst); \ 847 | } while (0) 848 | 849 | #define HASH_CLEAR(hh,head) \ 850 | do { \ 851 | if (head) { \ 852 | uthash_free((head)->hh.tbl->buckets, \ 853 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ 854 | HASH_BLOOM_FREE((head)->hh.tbl); \ 855 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 856 | (head)=NULL; \ 857 | } \ 858 | } while(0) 859 | 860 | #define HASH_OVERHEAD(hh,head) \ 861 | (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ 862 | ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ 863 | (sizeof(UT_hash_table)) + \ 864 | (HASH_BLOOM_BYTELEN))) 865 | 866 | #ifdef NO_DECLTYPE 867 | #define HASH_ITER(hh,head,el,tmp) \ 868 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ 869 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 870 | #else 871 | #define HASH_ITER(hh,head,el,tmp) \ 872 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ 873 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) 874 | #endif 875 | 876 | /* obtain a count of items in the hash */ 877 | #define HASH_COUNT(head) HASH_CNT(hh,head) 878 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) 879 | 880 | typedef struct UT_hash_bucket { 881 | struct UT_hash_handle *hh_head; 882 | unsigned count; 883 | 884 | /* expand_mult is normally set to 0. In this situation, the max chain length 885 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If 886 | * the bucket's chain exceeds this length, bucket expansion is triggered). 887 | * However, setting expand_mult to a non-zero value delays bucket expansion 888 | * (that would be triggered by additions to this particular bucket) 889 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. 890 | * (The multiplier is simply expand_mult+1). The whole idea of this 891 | * multiplier is to reduce bucket expansions, since they are expensive, in 892 | * situations where we know that a particular bucket tends to be overused. 893 | * It is better to let its chain length grow to a longer yet-still-bounded 894 | * value, than to do an O(n) bucket expansion too often. 895 | */ 896 | unsigned expand_mult; 897 | 898 | } UT_hash_bucket; 899 | 900 | /* random signature used only to find hash tables in external analysis */ 901 | #define HASH_SIGNATURE 0xa0111fe1 902 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 903 | 904 | typedef struct UT_hash_table { 905 | UT_hash_bucket *buckets; 906 | unsigned num_buckets, log2_num_buckets; 907 | unsigned num_items; 908 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ 909 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ 910 | 911 | /* in an ideal situation (all buckets used equally), no bucket would have 912 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ 913 | unsigned ideal_chain_maxlen; 914 | 915 | /* nonideal_items is the number of items in the hash whose chain position 916 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven 917 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ 918 | unsigned nonideal_items; 919 | 920 | /* ineffective expands occur when a bucket doubling was performed, but 921 | * afterward, more than half the items in the hash had nonideal chain 922 | * positions. If this happens on two consecutive expansions we inhibit any 923 | * further expansion, as it's not helping; this happens when the hash 924 | * function isn't a good fit for the key domain. When expansion is inhibited 925 | * the hash will still work, albeit no longer in constant time. */ 926 | unsigned ineff_expands, noexpand; 927 | 928 | uint32_t signature; /* used only to find hash tables in external analysis */ 929 | #ifdef HASH_BLOOM 930 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ 931 | uint8_t *bloom_bv; 932 | char bloom_nbits; 933 | #endif 934 | 935 | } UT_hash_table; 936 | 937 | typedef struct UT_hash_handle { 938 | struct UT_hash_table *tbl; 939 | void *prev; /* prev element in app order */ 940 | void *next; /* next element in app order */ 941 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ 942 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ 943 | void *key; /* ptr to enclosing struct's key */ 944 | unsigned keylen; /* enclosing struct's key len */ 945 | unsigned hashv; /* result of hash-fcn(key) */ 946 | } UT_hash_handle; 947 | 948 | #endif /* UTHASH_H */ 949 | --------------------------------------------------------------------------------