LTspice: bugfixes.

This commit is contained in:
Alex Shvartzkop 2023-12-21 13:55:52 +03:00
parent fc85112a72
commit 2de8991752
2 changed files with 135 additions and 49 deletions

View File

@ -74,8 +74,8 @@ void LTSPICE_SCH_PARSER::Parse( SCH_SHEET_PATH* aSheet,
void LTSPICE_SCH_PARSER::readIncludes( std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs ) void LTSPICE_SCH_PARSER::readIncludes( std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs )
{ {
wxString ltSubDir = m_lt_schematic->GetLTspiceDataDir().GetFullPath() + wxS( "lib/sub/" ); wxFileName ltSubDir( m_lt_schematic->GetLTspiceDataDir().GetFullPath(), wxEmptyString );
wxString path; ltSubDir.AppendDir( wxS( "sub" ) );
for( const LTSPICE_SCHEMATIC::LT_ASC& asc : outLT_ASCs ) for( const LTSPICE_SCHEMATIC::LT_ASC& asc : outLT_ASCs )
{ {
@ -83,19 +83,22 @@ void LTSPICE_SCH_PARSER::readIncludes( std::vector<LTSPICE_SCHEMATIC::LT_ASC>& o
{ {
for( wxString& line : wxSplit( lt_text.Value, '\n' ) ) for( wxString& line : wxSplit( lt_text.Value, '\n' ) )
{ {
if( line.StartsWith( wxS( ".inc " ), &path ) ) if( line.StartsWith( wxS( ".include " ) ) || line.StartsWith( wxS( ".inc " ) )
|| line.StartsWith( wxS( ".lib " ) ) )
{ {
wxString path = line.AfterFirst( ' ' );
path.Replace( '\\', '/' ); path.Replace( '\\', '/' );
wxFileName fileName( path ); wxFileName fileName( path );
if( fileName.IsAbsolute() ) if( fileName.IsAbsolute() )
{ {
m_includes[ fileName.GetName() ] = fileName.GetFullPath(); m_includes[fileName.GetName()] = fileName.GetFullPath();
} }
else else
{ {
wxFileName absolute( ltSubDir + path ); fileName.MakeAbsolute( ltSubDir.GetFullPath() );
m_includes[ absolute.GetName() ] = absolute.GetFullPath(); m_includes[fileName.GetName()] = fileName.GetFullPath();
} }
} }
} }
@ -514,14 +517,23 @@ void LTSPICE_SCH_PARSER::CreateKicadSCH_ITEMs( SCH_SHEET_PATH* aSheet,
} }
else else
{ {
screen->Append( CreateSCH_LABEL( SCH_LABEL_T, lt_flag.Offset, lt_flag.Value, screen->Append( CreateSCH_LABEL( SCH_GLOBAL_LABEL_T, lt_flag.Offset, lt_flag.Value,
lt_flag.FontSize ) ); lt_flag.FontSize ) );
} }
} }
for( const LTSPICE_SCHEMATIC::TEXT& lt_text : lt_asc.Texts ) for( const LTSPICE_SCHEMATIC::TEXT& lt_text : lt_asc.Texts )
{ {
screen->Append( CreateSCH_TEXT( lt_text.Offset, lt_text.Value, lt_text.FontSize, wxString textVal = lt_text.Value;
// Includes are already handled through Sim.Library, comment them out
if( textVal.StartsWith( ".include " ) || textVal.StartsWith( ".inc " )
|| textVal.StartsWith( ".lib " ) )
{
textVal = wxS( "* " ) + textVal;
}
screen->Append( CreateSCH_TEXT( lt_text.Offset, textVal, lt_text.FontSize,
lt_text.Justification ) ); lt_text.Justification ) );
} }
@ -895,13 +907,13 @@ SCH_LABEL_BASE* LTSPICE_SCH_PARSER::CreateSCH_LABEL( KICAD_T aType, const VECTOR
{ {
SCH_LABEL_BASE* label = nullptr; SCH_LABEL_BASE* label = nullptr;
if( aType == SCH_LABEL_T ) if( aType == SCH_GLOBAL_LABEL_T )
{ {
label = new SCH_LABEL(); label = new SCH_GLOBALLABEL();
label->SetText( aValue ); label->SetText( aValue );
label->SetTextSize( ToKicadFontSize( aFontSize ) ); label->SetTextSize( ToKicadFontSize( aFontSize ) );
label->SetSpinStyle( SPIN_STYLE::RIGHT ); label->SetSpinStyle( SPIN_STYLE::UP );
} }
else if( aType == SCH_DIRECTIVE_LABEL_T ) else if( aType == SCH_DIRECTIVE_LABEL_T )
{ {
@ -935,50 +947,109 @@ SCH_LABEL_BASE* LTSPICE_SCH_PARSER::CreateSCH_LABEL( KICAD_T aType, const VECTOR
void LTSPICE_SCH_PARSER::CreateFields( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, void LTSPICE_SCH_PARSER::CreateFields( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheet ) SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheet )
{ {
wxString libPath = m_lt_schematic->GetLTspiceDataDir().GetFullPath() + wxS( "lib/" ); wxString libPath = m_lt_schematic->GetLTspiceDataDir().GetFullPath();
wxString symbolName = aLTSymbol.Name.Upper(); wxString symbolName = aLTSymbol.Name.Upper();
wxString type = aLTSymbol.SymAttributes[ wxS( "TYPE" ) ].Upper(); wxString type = aLTSymbol.SymAttributes[wxS( "TYPE" )].Upper();
wxString prefix = aLTSymbol.SymAttributes[ wxS( "PREFIX" ) ].Upper(); wxString prefix = aLTSymbol.SymAttributes[wxS( "PREFIX" )].Upper();
wxString instName = aLTSymbol.SymAttributes[ wxS( "INSTNAME" ) ].Upper(); wxString instName = aLTSymbol.SymAttributes[wxS( "INSTNAME" )].Upper();
wxString value = aLTSymbol.SymAttributes[ wxS( "VALUE" ) ]; wxString value = aLTSymbol.SymAttributes[wxS( "VALUE" )];
wxString value2 = aLTSymbol.SymAttributes[wxS( "VALUE2" )];
if( value.IsEmpty() )
{
value = value2;
value2 = wxEmptyString;
}
aSymbol->SetRef( aSheet, instName ); aSymbol->SetRef( aSheet, instName );
aSymbol->SetValueFieldText( value ); aSymbol->SetValueFieldText( value );
auto setupNonInferredPassive = if( !value2.IsEmpty() )
[&]( const wxString& aPrefix ) {
{ SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Value2" ) );
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) ); paramsField.SetText( value2 );
deviceField.SetText( aPrefix ); aSymbol->AddField( paramsField );
aSymbol->AddField( deviceField ); }
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) ); auto setupNonInferredPassive = [&]( const wxString& aDevice, const wxString& aValueKey )
paramsField.SetText( aPrefix + wxS( "=${VALUE}" ) ); {
aSymbol->AddField( paramsField ); SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
}; deviceField.SetText( aDevice );
aSymbol->AddField( deviceField );
if( symbolName == wxS( "RES" ) ) SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( aValueKey + wxS( "=${VALUE}" ) );
aSymbol->AddField( paramsField );
};
auto setupBehavioral = [&]( const wxString& aDevice, const wxString& aType )
{ {
if( !instName.StartsWith( 'R' ) ) aSymbol->SetValueFieldText( wxS( "${Sim.Params}" ) );
setupNonInferredPassive( wxS( "R" ) );
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( aDevice );
aSymbol->AddField( deviceField );
SCH_FIELD typeField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Type" ) );
typeField.SetText( aType );
aSymbol->AddField( typeField );
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( value );
aSymbol->AddField( paramsField );
};
static const std::set<wxString> prefixWithGain = { wxS( "E" ), wxS( "F" ), wxS( "G" ),
wxS( "H" ) };
if( prefix == wxS( "R" ) )
{
setupNonInferredPassive( prefix, wxS( "R" ) );
} }
else if( symbolName == wxS( "CAP" ) ) else if( prefix == wxS( "C" ) )
{ {
if( !instName.StartsWith( 'C' ) ) setupNonInferredPassive( prefix, wxS( "C" ) );
setupNonInferredPassive( wxS( "C" ) );
} }
else if( symbolName == wxS( "IND" ) ) else if( prefix == wxS( "L" ) )
{ {
if( !instName.StartsWith( 'L' ) ) setupNonInferredPassive( prefix, wxS( "L" ) );
setupNonInferredPassive( wxS( "L" ) );
} }
else if( symbolName == wxS( "VOLTAGE" ) || symbolName == wxS( "CURRENT" ) ) else if( prefixWithGain.count( prefix ) > 0 )
{ {
// inference had better work.... setupNonInferredPassive( prefix, wxS( "gain" ) );
}
else if( prefix == wxS( "B" ) )
{
if( symbolName.StartsWith( wxS( "BV" ) ) )
{
setupBehavioral( wxS( "V" ), wxS( "=" ) );
}
else if( symbolName.StartsWith( wxS( "BI" ) ) )
{
setupBehavioral( wxS( "I" ), wxS( "=" ) );
}
}
else if( prefix == wxS( "V" ) || symbolName == wxS( "I" ) )
{
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( wxS( "SPICE" ) );
aSymbol->AddField( deviceField );
wxString simParams;
simParams << "type=" << '"' << prefix << '"' << ' ';
if( value2.IsEmpty() )
simParams << "model=" << '"' << "${VALUE}" << '"' << ' ';
else
simParams << "model=" << '"' << "${VALUE} ${VALUE2}" << '"' << ' ';
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( simParams );
aSymbol->AddField( paramsField );
} }
else else
{ {
wxString libFile = aLTSymbol.SymAttributes[ wxS( "MODELFILE" ) ]; wxString libFile = aLTSymbol.SymAttributes[wxS( "MODELFILE" )];
if( prefix == wxS( "X" ) ) if( prefix == wxS( "X" ) )
{ {
@ -990,18 +1061,18 @@ void LTSPICE_SCH_PARSER::CreateFields( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
if( type.IsEmpty() ) if( type.IsEmpty() )
type = symbolName; type = symbolName;
if( type == "DIODE" ) if( value == "DIODE" )
libFile = libPath + wxS( "cmp/standard.dio" ); libFile = libPath + wxS( "cmp/standard.dio" );
else if( type == "NPN" || type == "PNP" ) else if( value == "NPN" || value == "PNP" )
libFile = libPath + wxS( "cmp/standard.bjt" ); libFile = libPath + wxS( "cmp/standard.bjt" );
else if( type == "NJF" || type == "PJF" ) else if( value == "NJF" || value == "PJF" )
libFile = libPath + wxS( "cmp/standard.jft" ); libFile = libPath + wxS( "cmp/standard.jft" );
else if( type == "NMOS" || type == "PMOS" ) else if( value == "NMOS" || value == "PMOS" )
libFile = libPath + wxS( "cmp/standard.mos" ); libFile = libPath + wxS( "cmp/standard.mos" );
} }
if( libFile.IsEmpty() ) if( libFile.IsEmpty() )
libFile = m_includes[ value ]; libFile = m_includes[value];
if( !libFile.IsEmpty() ) if( !libFile.IsEmpty() )
{ {
@ -1010,25 +1081,34 @@ void LTSPICE_SCH_PARSER::CreateFields( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
aSymbol->AddField( libField ); aSymbol->AddField( libField );
} }
SCH_FIELD nameField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Name" ) );
nameField.SetText( wxS( "${VALUE}" ) );
aSymbol->AddField( nameField );
if( type == wxS( "X" ) ) if( type == wxS( "X" ) )
{ {
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) ); SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( wxS( "SUBCKT" ) ); deviceField.SetText( wxS( "SUBCKT" ) );
aSymbol->AddField( deviceField ); aSymbol->AddField( deviceField );
} }
else
{
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( wxS( "SPICE" ) );
aSymbol->AddField( deviceField );
}
wxString spiceLine = aLTSymbol.SymAttributes[ wxS( "SPICELINE" ) ]; wxString spiceLine = aLTSymbol.SymAttributes[wxS( "SPICELINE" )];
if( !spiceLine.IsEmpty() ) if( !spiceLine.IsEmpty() )
{ {
// TODO: append value
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) ); SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( spiceLine ); paramsField.SetText( spiceLine );
aSymbol->AddField( paramsField ); aSymbol->AddField( paramsField );
} }
else
{
SCH_FIELD modelField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
modelField.SetText( "model=\"" + value + "\"" );
aSymbol->AddField( modelField );
}
} }
for( LTSPICE_SCHEMATIC::LT_WINDOW& lt_window : aLTSymbol.Windows ) for( LTSPICE_SCHEMATIC::LT_WINDOW& lt_window : aLTSymbol.Windows )

View File

@ -723,7 +723,10 @@ LTSPICE_SCHEMATIC::LT_SYMBOL LTSPICE_SCHEMATIC::SymbolBuilder( const wxString& a
wxString key = tokens[1]; wxString key = tokens[1];
wxString value = tokens[2]; wxString value = tokens[2];
lt_symbol.SymAttributes[ key.Capitalize() ] = value; if( value == wxS( "\"\"" ) )
value = wxEmptyString;
lt_symbol.SymAttributes[ key.Upper() ] = value;
} }
else if( element == "PIN" ) else if( element == "PIN" )
{ {
@ -920,6 +923,9 @@ std::vector<LTSPICE_SCHEMATIC::LT_ASC> LTSPICE_SCHEMATIC::StructureBuilder()
wxString name = tokens[1]; wxString name = tokens[1];
wxString value = tokens[2]; wxString value = tokens[2];
if( value == wxS( "\"\"" ) )
value = wxEmptyString;
ascFile.Symbols.back().SymAttributes[ name.Upper() ] = value; ascFile.Symbols.back().SymAttributes[ name.Upper() ] = value;
} }
else if( element == "LINE" ) else if( element == "LINE" )