Multiline directives

/*
  • This program source code file is part of KiCad, a free EDA CAD application.
  • Copyright © 1992-2013 jp.charras at wanadoo.fr
  • Copyright © 2013 SoftPLC Corporation, Dick Hollenbeck dick@softplc.com
  • Copyright © 1992-2019 KiCad Developers, see AUTHORS.TXT for contributors.
  • This program is free software; you can redistribute it and/or
  • modify it under the terms of the GNU General Public License
  • as published by the Free Software Foundation; either version 2
  • of the License, or (at your option) any later version.
  • This program is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.
  • You should have received a copy of the GNU General Public License
  • along with this program; if not, you may find one here:
  • http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  • or you may search the http://www.gnu.org website for the version 2 license,
  • or you may write to the Free Software Foundation, Inc.,
  • 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
    */

#include “netlist_exporter_pspice.h”
#include <fctsys.h>
#include <build_version.h>
#include <confirm.h>

#include
#include <search_stack.h>

#include <sch_edit_frame.h>
#include <netlist.h>
#include <sch_reference_list.h>
#include <env_paths.h>

#include <wx/tokenzr.h>
#include <wx/regex.h>

.
.
.
.

Start here \//
// Analyze each line of a text field
wxStringTokenizer tokenizer( text, “\r\n” );

        // Flag to follow multiline directives
        bool directiveStarted = false;

        while( tokenizer.HasMoreTokens() )
        {
            wxString line( tokenizer.GetNextToken() );

            // Cleanup: remove preceding and trailing white-space characters
            line.Trim( true ).Trim( false );
            // Convert to lower-case for parsing purposes only
            wxString lowercaseline = line;
            lowercaseline.MakeLower();

            // 'Include' directive stores the library file name, so it
            // can be later resolved using a list of paths
            if( lowercaseline.StartsWith( ".inc" ) )
            {
                wxString lib = line.AfterFirst( ' ' );

                if( lib.IsEmpty() )
                    continue;

                // Strip quotes if present
                if( ( lib.StartsWith( "\"" ) && lib.EndsWith( "\"" ) )
                    || ( lib.StartsWith( "'" ) && lib.EndsWith( "'" ) ) )
                {
                    lib = lib.Mid( 1, lib.Length() - 2 );
                }

                m_libraries.insert( lib );
            }

            // Store the title to be sure it appears
            // in the first line of output
            else if( lowercaseline.StartsWith( ".title " ) )
            {
                m_title = line.AfterFirst( ' ' );
            }

            // Handle .control .. .endc blocks
            else if( lowercaseline.IsSameAs( ".control" ) && ( !controlBlock ) )
            {
                controlBlock = true;
                m_directives.push_back( line );
            }
            else if( lowercaseline.IsSameAs( ".endc" ) && controlBlock )
            {
                controlBlock = false;
                m_directives.push_back( line );
            }

            else if( line.StartsWith( '.' )                           // one-line directives
                    || controlBlock                                   // .control .. .endc block
                    || ( directiveStarted && line.StartsWith( '+' ) ) ) // multiline directives
            {
                m_directives.push_back( line );
            }

            // Mark directive as started or continued in case it is a multi-line one
            directiveStarted = line.StartsWith( '.' )
                || ( directiveStarted && line.StartsWith( '+' ) );
        }
    }
}

}

void NETLIST_EXPORTER_PSPICE::writeDirectives( OUTPUTFORMATTER* aFormatter, unsigned aCtl ) const
{
for( auto& dir : m_directives )
{
aFormatter->Print( 0, “%s\n”, (const char*) dir.c_str() );
}
}

// Entries in the vector below have to follow the order in SPICE_FIELD enum
const std::vector NETLIST_EXPORTER_PSPICE::m_spiceFields = {
“Spice_Primitive”,
“Spice_Model”,
“Spice_Netlist_Enabled”,
“Spice_Node_Sequence”,
“Spice_Lib_File”
};

Checked sourcecode its no line in code for export KXXX.
Only thing it have - include librarys, but it work fine from component properties. and ‘.’ directives. But ngspise doesn’t understand '.Kxxxx ’ it wont starting simulation with that.

Sorry for long post. Don`t know how to make spoiler here.

Same with current nightly.

kicad-r12318.076499f3a-x86_64.exe

Seth has uploaded a fix.

Well I also have couple other bug report for pspice relative mater, so I will listed here for just reference since this issue isn’t new, but developer think they fix it:

For me it is difficult to understand what you try to achieve.

There are two ways running a simulation in KiCad:

  • Use the integrated ngspice
  • Generate a netlist and simulate externally with whatever simulator (e.g. PSPICE).

**Set current directory to project before run custom simulator
What do you mean by: “ngspice tool do not understand windows system absolute file path that automatically send by KiCad” ? Could you give an example?

** simulation: TEMP sweep not able to plot anything
You are using eeschema/ngspice in a way that has not been intended by the devs and that is not supported. KiCad sends the netlist, .tran etc. command and a ‘run’ command to ngspice and gets back all simulation results for plotting. Your setup generates its own simulation command and issues a request for plotting, both from inside of ngspice. Whereas running the simulation this way is possible, it is not possible to plot the data, because shared ngspice does not have its own plot interface, and eeschema does not know about the data generated by ngspice. So you only might save the data by ‘write’ command and use an external plotting program (e.g. stand-alone ngspice).

**Can’t start a multi-line SPICE directive with a commented-out line
Did you check with a recent nightly if this has been fixed? If not, I could have a look.

** ngspice use net name “0” (Zero) as a reference ground not GND
This is wrong. ngspice always understood GND. Internally it will be transformed into ‘0’. ‘0’ is required somewhere as a reference. If you do not want this automated translation, you may give the command ‘set no_auto_gnd’. Then you have to provide your own ‘0’ somewhere in the netlist.

If you intend to generate a netlist compatible with an external other simulator, you have to state that clearly in your bug report. And then the devs have to decide if this should be supported.

This is the issue when I try to run simulate externally… ngspice seem to not able to run my netlist file, and it very hard to run under interactive mode when I have to type so much for the “absolute” path. When I start Kicad under my current netlist folder, everything run automatically and avoid type so much for absolute path. But if I start KiCad form the Windows -> Start menu it just not working with absolute path.

In this case, I don’t have problem with run “external” method. But I just to to let developer know it not support for “integrated” mode.

Yes sir. I know the new method. BUT is not help “multi-line” JUST like you are discussion in here!

Wrong if ngpsice is only the world you working with, sir.

Please give an example line that is not working with ngspice. This will be the only way that I can have a look if there is a bug.

I think you can try it yourself. Make a simple simulation schematic. eeschema->Tools->Generate Netlist file… -> Spice -> run simulator with Simulator Command: "c:\ngspice\bin\ngspice.exe

You would get “absolute_path_to_netlist_file” : Invalid argument on the ngspice.
Also, I found that the ngspice.exe did not find it own init file correctly, but if the “current” path is set to where the netlist file at. Then copy the spinit file to that folder. I will be able to run my simulator by using the Simulator Command: “c:\ngspice\bin\ngspice.exe sim.cir” perfectly.

I think both KiCad and ngpsice need to fix. But that most importance is the fix from KiCad so that I can run other netlist simulation directly from the ngspice console without typing long absolute path of every netlist file, and what about the include path that I use as relative from the netlist file where include statement at.!

What I did (on Windows 10):
Expand https://sourceforge.net/projects/ngspice/files/ng-spice-rework/30/ngspice-30_64.zip/download into directory C:, so you have ngspice in C:\Spice64\bin.

Copy C:\Program Files\KiCad\share\kicad\demos\simulation into C:\KiCad, to get C:\KiCad\simulation\laser_driver. This just serves as an example for an arbitrary eeschema project placed into an arbitrary folder.

Set the access for the whole directory tree C:\KiCad to full access for all users. This allows KiCad to read and write to this directory without the need for having admin rights.

Install recent KiCad nightly 5.1rc.

Run eeschema

Open file c:\KiCad\simulation\laser_driver\laser_driver.sch

Replace the text box entry

.tran 10p 150n

by

.tran 10p 150n
.control
run
rusage
set filetype=ascii
write c:\Kicad\laser.out "/in" "/out"
plot "/in" "/out"
.endc

File–>Save current sheet
Tools–>Generate netlist file…–>Spice
Select ‘Default format’
Simulator command: C:\Spice64\bin\ngspice.exe
Button: Generate netlist
Button: Save (Store laser_driver.cir to C:\KiCad\Simulation\laser_driver)
Button: Run Simulator

Voila:
ngspice.exe simulates the file laser_driver.cir and plots the resulting output. No problem finding the spinit file. No need to type anything in addition. No “absolute_path_to_netlist_file” : Invalid argument response.

BTW: My ngspice version is 28

Above I have shown a way for external simulation using ngspice.exe. My conclusionis that there is no need for a fix to achieve this, neither in ngspice nor in KiCad.

Concerning the multiline request: Problem if first line in text box starts with a ‘*’:
I changed the textbox ofthe example given above to

*bug fix test
.tran 10p 150n
*.control
*run
*rusage
*set filetype=ascii
*write c:\Kicad\laser.out "/in" "/out"
*plot "/in" "/out"
*.endc

Using the procedure above, ngspice opens, loads the netlist file and then stops waiting for a command like’run’ --> o.k.

Using internal ngspice with Tools–>Simulator–>Run Simulation o.k. as well.
So this bug has been fixed by the KiCad devs.

Well I giving up on you since I feel like my issue seem to not to be believable by you. Also, It seem typing 20+ characters each time when run ngspice from KiCad is not a concerning to you. Then yes, there is not fix need to be done. If your present solution is work for ngspice version 30 then that to me it already fix from 28 to 30 version. But it not going to solve the typing long characters issue for absolute path. Thank you @holger.

This is the exactly issue with KiCad for multiline directive. I cannot have that whole directive include in my netlist with the new style of line by line directive with the “.” at beginning. I would like +pspice for include everything in the text box exclude the first line in the text box. In addition with the line by line directive!. Most of my simulations directive contains full simulation control block, or event a short sub circuitry model. By removing the +pspice for multi-line is it become some what impossible to do any useful simulation on my case.

As current state for the KiCad software - I would not consider using this way for “serious” simulations.

There are several commands, procedures and tools available that might help here.

ngspice has a command ‘cd ‘directory’’ to be placed into a control section to change its working directory. The command ‘getcwd’ will show the actual working directory for ngspice.

You may add a ‘.include ‘filename’’ command to the text box to get additional subcircuits into your netlist. You just have to place them into file ‘filename’.

If you are on MS Windows, and you want to avoid any typing, you may use my small GUI to be found at http://ngspice.sourceforge.net/download.html#bin1 . This allows you to select any input file and start external ngspice.exe without any typing, just mouse clicks.

If you always have the same ngspice input file directories, you may add a command 'set sourcepath . path1 path2 ’ to spice.rc or to the beginning of your .control section. ngspice the will search for the input file in the current directory (the dot .) and in any other directory given.

You may even set an environmental variable NGSPICE_INPUT_DIR to the search path for input files.

So there are many options to customize a working environment without need to patch KiCad or ngspice.

It might be useful to switch to ngspice-30, because there are included many fixes that have been requested by users, and it is more stable than ngspice-28.

3 Likes

I still like to have KiCad do the job for the path. It would allow my stuff can run on other coworker computer without the need of exactly path setting. They first two solution are what I had tried, The source path is one that new to me. But again it do not give me what I needed - that is my coworker can just open, run simulation without need to set up exactly path and location in this machine. This mean, he also don’t need to event need to do anything with environment variables too.